Merge commit 'e90c98ed1d6bf900c9d699b49f479d23f631ee6b' into dev-release
diff --git a/.gitignore b/.gitignore
index 7a9429b..470dd43 100644
--- a/.gitignore
+++ b/.gitignore
@@ -59,6 +59,8 @@
third_party/benchmarks/santa-tracker.tar.gz
third_party/benchmarks/wordpress
third_party/benchmarks/wordpress.tar.gz
+third_party/binary_compatibility_tests/compiler_api_tests.tar.gz
+third_party/binary_compatibility_tests/compiler_api_tests
third_party/cf_segments
third_party/cf_segments.tar.gz
third_party/chrome/*
diff --git a/build.gradle b/build.gradle
index ce0bc7f..360f21a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -273,8 +273,6 @@
def r8LibGeneratedKeepRulesPath = "$buildDir/generated/keep.txt"
def r8LibTestPath = "$buildDir/classes/r8libtest"
def java11ClassFiles = "$buildDir/classes/java/mainJava11"
-def r8RetracePath = "$buildDir/libs/r8retrace.jar"
-def r8RetraceExludeDepsPath = "$buildDir/libs/r8retrace-exclude-deps.jar"
def osString = OperatingSystem.current().isLinux() ? "linux" :
OperatingSystem.current().isMacOsX() ? "mac" : "windows"
@@ -303,6 +301,7 @@
"android_jar/api-versions",
"android_jar/api-database",
"api-outlining/simple-app-dump",
+ "binary_compatibility_tests/compiler_api_tests",
"core-lambda-stubs",
"dart-sdk",
"ddmlib",
@@ -1106,30 +1105,6 @@
outputs.file r8DesugaredPath
}
-task R8Retrace {
- dependsOn R8Lib
- dependsOn r8LibCreateTask(
- "Retrace",
- ["src/main/keep_retrace.txt"],
- R8Lib,
- r8RetracePath,
- ).dependsOn(R8Lib)
- outputs.file r8RetracePath
-}
-
-task R8RetraceNoDeps {
- dependsOn R8LibNoDeps
- dependsOn r8LibCreateTask(
- "RetraceNoDeps",
- ["src/main/keep_retrace.txt"],
- R8LibNoDeps,
- r8RetraceExludeDepsPath,
- "--release",
- repackageDeps.outputs.files
- ).dependsOn(R8LibNoDeps)
- outputs.file r8RetraceExludeDepsPath
-}
-
task sourceJar(type: Jar, dependsOn: classes) {
classifier = 'src'
from sourceSets.main.allSource
@@ -1185,42 +1160,6 @@
dependsOn buildR8ApiUsageSample
}
-task buildDebugInfoExamplesDex {
- def examplesDir = file("src/test/java")
- def hostJar = "debuginfo_examples.jar"
- def hostDexJar = "debuginfo_examples_dex.jar"
- task "compile_debuginfo_examples"(type: JavaCompile) {
- source = fileTree(dir: examplesDir, include: "com/android/tools/r8/debuginfo/*Test.java")
- destinationDir = file("build/test/debuginfo_examples/classes")
- classpath = sourceSets.main.compileClasspath
- sourceCompatibility = JavaVersion.VERSION_1_7
- targetCompatibility = JavaVersion.VERSION_1_7
- options.compilerArgs += ["-Xlint:-options"]
- }
- task "jar_debuginfo_examples"(type: Jar, dependsOn: "compile_debuginfo_examples") {
- archiveName = hostJar
- destinationDir = file("build/test/")
- from "build/test/debuginfo_examples/classes"
- include "**/*.class"
- }
- task "dex_debuginfo_examples"(type: Exec,
- dependsOn: ["jar_debuginfo_examples", "downloadDeps"]) {
- if (OperatingSystem.current().isWindows()) {
- executable file("tools/windows/dx/bin/dx.bat")
- } else if (OperatingSystem.current().isMacOsX()) {
- executable file("tools/mac/dx/bin/dx");
- } else {
- executable file("tools/linux/dx/bin/dx");
- }
- args "--dex"
- args "--output=build/test/${hostDexJar}"
- args "build/test/${hostJar}"
- inputs.files files("build/test/${hostJar}")
- outputs.file file("build/test/${hostDexJar}")
- }
- dependsOn dex_debuginfo_examples
-}
-
task buildDebugTestResourcesJars {
def resourcesDir = file("src/test/debugTestResources")
def hostJar = "debug_test_resources.jar"
@@ -2379,7 +2318,6 @@
dependsOn buildSmali
dependsOn jctfCommonJar
dependsOn jctfTestsClasses
- dependsOn buildDebugInfoExamplesDex
dependsOn buildPreNJdwpTestsJar
dependsOn buildPreNJdwpTestsDex
dependsOn compileTestNGRunner
diff --git a/infra/config/global/generated/cr-buildbucket.cfg b/infra/config/global/generated/cr-buildbucket.cfg
index 6dd5ceb..11ad90f 100644
--- a/infra/config/global/generated/cr-buildbucket.cfg
+++ b/infra/config/global/generated/cr-buildbucket.cfg
@@ -31,7 +31,6 @@
cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
cipd_version: "refs/heads/master"
properties_j: "builder_group:\"internal.client.r8\""
- properties_j: "test_options:[\"not_used_but_evaluates_to_python_true\"]"
properties_j: "test_wrapper:\"tools/archive.py\""
}
priority: 25
@@ -57,7 +56,6 @@
cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
cipd_version: "refs/heads/master"
properties_j: "builder_group:\"internal.client.r8\""
- properties_j: "test_options:[\"not_used_but_evaluates_to_python_true\"]"
properties_j: "test_wrapper:\"tools/archive.py\""
}
priority: 25
@@ -133,7 +131,6 @@
cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
cipd_version: "refs/heads/master"
properties_j: "builder_group:\"internal.client.r8\""
- properties_j: "test_options:[\"not_used_but_evaluates_to_python_true\"]"
properties_j: "test_wrapper:\"tools/archive_desugar_jdk_libs.py\""
}
priority: 25
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index e7efbfa..fdf35d6 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -47,7 +47,6 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;
-import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -109,12 +108,10 @@
private StringConsumer proguardConfigurationConsumer = null;
private GraphConsumer keptGraphConsumer = null;
private GraphConsumer mainDexKeptGraphConsumer = null;
- private BiFunction<String, Long, Boolean> dexClassChecksumFilter = (name, checksum) -> true;
private final List<FeatureSplit> featureSplits = new ArrayList<>();
private String synthesizedClassPrefix = "";
private boolean skipDump = false;
- private boolean allowPartiallyImplementedProguardOptions = false;
private boolean allowTestProguardOptions =
System.getProperty("com.android.tools.r8.allowTestProguardOptions") != null;
@@ -614,11 +611,6 @@
}
- // Internal for-testing method to add post-processors of the proguard configuration.
- void allowPartiallyImplementedProguardOptions() {
- allowPartiallyImplementedProguardOptions = true;
- }
-
// Internal for-testing method to allow proguard options only available for testing.
void allowTestProguardOptions() {
allowTestProguardOptions = true;
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java b/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
index d7c008c..7a8a3f6 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
@@ -191,7 +191,10 @@
}
startLine = position.line;
emittedPosition =
- new Position(position.line, null, position.getOutermostCaller().method, null);
+ Position.builder()
+ .setLine(position.line)
+ .setMethod(position.getOutermostCaller().method)
+ .build();
}
assert emittedPc != pc;
int previousPc = emittedPc == NO_PC_INFO ? 0 : emittedPc;
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessFlags.java b/src/main/java/com/android/tools/r8/graph/FieldAccessFlags.java
index 29e68bf..95b2a6f 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessFlags.java
@@ -81,6 +81,10 @@
Constants.ACC_PUBLIC | Constants.ACC_FINAL | Constants.ACC_SYNTHETIC);
}
+ public static FieldAccessFlags createPublicSynthetic() {
+ return fromSharedAccessFlags(Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC);
+ }
+
public static FieldAccessFlags fromSharedAccessFlags(int access) {
assert (access & FLAGS) == access;
return new FieldAccessFlags(access & FLAGS);
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index 296f792..0c78a72 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -276,7 +276,7 @@
assert enclosingMember == null;
DexType ownerType = application.getTypeFromName(owner);
enclosingMember =
- name == null
+ name == null || name.equals("<clinit>")
? new EnclosingMethodAttribute(ownerType)
: new EnclosingMethodAttribute(application.getMethod(ownerType, name, desc));
}
diff --git a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
index c554ca5..cd91733 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -997,7 +997,9 @@
@Override
public void visitLineNumber(int line, Label start) {
if (debugParsingOptions.lineInfo) {
- instructions.add(new CfPosition(getLabel(start), new Position(line, null, method, null)));
+ instructions.add(
+ new CfPosition(
+ getLabel(start), Position.builder().setLine(line).setMethod(method).build()));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraproceduralDataflowAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraproceduralDataflowAnalysis.java
index 60136ce..4f00ef0 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraproceduralDataflowAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraproceduralDataflowAnalysis.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.ir.analysis.framework.intraprocedural.DataflowAnalysisResult.SuccessfulDataflowAnalysisResult;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.WorkList;
import java.util.IdentityHashMap;
import java.util.Map;
@@ -33,6 +34,11 @@
// The state of the analysis.
private final Map<BasicBlock, StateType> blockExitStates = new IdentityHashMap<>();
+ // The entry states for each block that satisfies the predicate
+ // shouldCacheBlockEntryStateFor(block). These entry states can be computed from the exit states
+ // of the predecessors, but doing so can be expensive when a block has many predecessors.
+ private final Map<BasicBlock, StateType> blockEntryStatesCache = new IdentityHashMap<>();
+
public IntraproceduralDataflowAnalysis(
StateType bottom, AbstractTransferFunction<StateType> transfer) {
this.bottom = bottom;
@@ -40,20 +46,29 @@
}
public DataflowAnalysisResult run(BasicBlock root) {
- return run(WorkList.newIdentityWorkList(root));
+ return run(root, Timing.empty());
}
- private DataflowAnalysisResult run(WorkList<BasicBlock> worklist) {
+ public DataflowAnalysisResult run(BasicBlock root, Timing timing) {
+ return run(WorkList.newIdentityWorkList(root), timing);
+ }
+
+ private DataflowAnalysisResult run(WorkList<BasicBlock> worklist, Timing timing) {
while (worklist.hasNext()) {
- BasicBlock block = worklist.next();
+ BasicBlock initialBlock = worklist.next();
+ BasicBlock block = initialBlock;
BasicBlock end = null;
// Compute the abstract state upon entry to the basic block, by joining all the predecessor
// exit states.
- StateType state = computeBlockEntryState(block);
+ StateType state =
+ timing.time("Compute block entry state", () -> computeBlockEntryState(initialBlock));
+
+ timing.begin("Compute transfers");
do {
for (Instruction instruction : block.getInstructions()) {
TransferFunctionResult<StateType> transferResult = transfer.apply(instruction, state);
if (transferResult.isFailedTransferResult()) {
+ timing.end();
return new FailedDataflowAnalysisResult();
}
assert transferResult.isAbstractState();
@@ -66,16 +81,25 @@
block = null;
}
} while (block != null);
+ timing.end();
+
// Update the block exit state, and re-enqueue all successor blocks if the abstract state
// changed.
if (setBlockExitState(end, state)) {
worklist.addAllIgnoringSeenSet(end.getSuccessors());
}
+
+ // Add the computed exit state to the entry state of each successor that satisfies the
+ // predicate shouldCacheBlockEntryStateFor(successor).
+ updateBlockEntryStateCacheForSuccessors(end, state);
}
return new SuccessfulDataflowAnalysisResult<>(blockExitStates);
}
private StateType computeBlockEntryState(BasicBlock block) {
+ if (shouldCacheBlockEntryStateFor(block)) {
+ return blockEntryStatesCache.getOrDefault(block, bottom);
+ }
StateType result = bottom;
for (BasicBlock predecessor : block.getPredecessors()) {
StateType edgeState =
@@ -92,4 +116,18 @@
assert previous == null || state.isGreaterThanOrEquals(previous);
return !state.equals(previous);
}
+
+ private void updateBlockEntryStateCacheForSuccessors(BasicBlock block, StateType state) {
+ for (BasicBlock successor : block.getSuccessors()) {
+ if (shouldCacheBlockEntryStateFor(successor)) {
+ StateType edgeState = transfer.computeBlockEntryState(successor, block, state);
+ StateType previous = blockEntryStatesCache.getOrDefault(successor, bottom);
+ blockEntryStatesCache.put(successor, previous.join(edgeState));
+ }
+ }
+ }
+
+ private boolean shouldCacheBlockEntryStateFor(BasicBlock block) {
+ return block.getPredecessors().size() > 2;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/CanonicalPositions.java b/src/main/java/com/android/tools/r8/ir/code/CanonicalPositions.java
index 06537e3..ad16c77 100644
--- a/src/main/java/com/android/tools/r8/ir/code/CanonicalPositions.java
+++ b/src/main/java/com/android/tools/r8/ir/code/CanonicalPositions.java
@@ -35,7 +35,12 @@
preamblePosition =
methodIsSynthesized
? callerPosition
- : getCanonical(new Position(0, null, method, callerPosition));
+ : getCanonical(
+ Position.builder()
+ .setLine(0)
+ .setMethod(method)
+ .setCallerPosition(callerPosition)
+ .build());
} else {
this.callerPosition = null;
isCompilerSynthesizedInlinee = false;
@@ -77,7 +82,7 @@
return getCanonical(
caller.isNone()
? Position.noneWithMethod(caller.method, callerOfCaller)
- : new Position(caller.line, caller.file, caller.method, callerOfCaller));
+ : caller.builderWithCopy().setCallerPosition(callerOfCaller).build());
}
// If we need to emit a synthetic position for exceptional monitor exits, we try to cook up a
diff --git a/src/main/java/com/android/tools/r8/ir/code/Position.java b/src/main/java/com/android/tools/r8/ir/code/Position.java
index 09a2631..259c18b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Position.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Position.java
@@ -46,12 +46,6 @@
.withNullableItem(p -> p.callerPosition);
}
- public Position(int line, DexString file, DexMethod method, Position callerPosition) {
- this(line, file, method, callerPosition, false);
- assert line >= 0;
- assert method != null;
- }
-
private Position(
int line, DexString file, DexMethod method, Position callerPosition, boolean synthetic) {
this.line = line;
@@ -141,15 +135,13 @@
return callerPosition;
}
- public Position withCallerPosition(Position callerPosition) {
- return new Position(line, file, method, callerPosition, synthetic);
- }
-
public Position withOutermostCallerPosition(Position newOutermostCallerPosition) {
- return withCallerPosition(
- hasCallerPosition()
- ? getCallerPosition().withOutermostCallerPosition(newOutermostCallerPosition)
- : newOutermostCallerPosition);
+ return builderWithCopy()
+ .setCallerPosition(
+ hasCallerPosition()
+ ? getCallerPosition().withOutermostCallerPosition(newOutermostCallerPosition)
+ : newOutermostCallerPosition)
+ .build();
}
@Override
@@ -193,4 +185,57 @@
public String toString() {
return toString(false);
}
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public Builder builderWithCopy() {
+ return new Builder()
+ .setLine(line)
+ .setFile(file)
+ .setMethod(method)
+ .setCallerPosition(callerPosition)
+ .setSynthetic(synthetic);
+ }
+
+ public static class Builder {
+
+ public int line;
+ public DexString file;
+ public boolean synthetic;
+ public DexMethod method;
+ public Position callerPosition;
+
+ public Builder setLine(int line) {
+ this.line = line;
+ return this;
+ }
+
+ public Builder setFile(DexString file) {
+ this.file = file;
+ return this;
+ }
+
+ public Builder setSynthetic(boolean synthetic) {
+ this.synthetic = synthetic;
+ return this;
+ }
+
+ public Builder setMethod(DexMethod method) {
+ this.method = method;
+ return this;
+ }
+
+ public Builder setCallerPosition(Position callerPosition) {
+ this.callerPosition = callerPosition;
+ return this;
+ }
+
+ public Position build() {
+ assert line >= 0;
+ assert method != null;
+ return new Position(line, file, method, callerPosition, synthetic);
+ }
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
index 83dbd55..5abeb6e 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
@@ -901,10 +901,10 @@
public Position getCanonicalPosition(Position position) {
return canonicalPositions.getCanonical(
- new Position(
- position.line,
- position.file,
- position.method,
- canonicalPositions.canonicalizeCallerPosition(position.callerPosition)));
+ position
+ .builderWithCopy()
+ .setCallerPosition(
+ canonicalPositions.canonicalizeCallerPosition(position.callerPosition))
+ .build());
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
index 211f77b..4181373 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
@@ -258,11 +258,12 @@
|| entry.callerPosition.getOutermostCaller().method == originalMethod;
return canonicalPositions.getCanonical(
- new Position(
- entry.line,
- entry.sourceFile,
- entry.method,
- canonicalPositions.canonicalizeCallerPosition(entry.callerPosition)));
+ Position.builder()
+ .setLine(entry.line)
+ .setFile(entry.sourceFile)
+ .setMethod(entry.method)
+ .setCallerPosition(canonicalPositions.canonicalizeCallerPosition(entry.callerPosition))
+ .build());
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 4f92d5b..6359283 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -750,18 +750,25 @@
outliner.rewriteWithLens();
timing.begin("IR conversion phase 2");
+ timing.begin("Build post method processor");
PostMethodProcessor postMethodProcessor =
postMethodProcessorBuilder.build(appView, executorService, timing);
+ timing.end();
if (postMethodProcessor != null) {
assert !options.debug;
assert appView.graphLens() == graphLensForSecondaryOptimizationPass;
+ timing.begin("Process code");
postMethodProcessor.forEachMethod(
(method, methodProcessingContext) ->
processDesugaredMethod(
method, feedback, postMethodProcessor, methodProcessingContext),
feedback,
- executorService);
+ executorService,
+ timing);
+ timing.end();
+ timing.begin("Update visible optimization info");
feedback.updateVisibleOptimizationInfo();
+ timing.end();
assert appView.graphLens() == graphLensForSecondaryOptimizationPass;
}
timing.end();
@@ -1143,7 +1150,7 @@
new MutableMethodConversionOptions(methodProcessor);
assert holder != null;
- Timing timing = Timing.create(method.qualifiedName(), options);
+ Timing timing = Timing.create(context.toSourceString(), options);
if (Log.ENABLED) {
Log.debug(getClass(), "Initial (SSA) flow graph for %s:\n%s", method.toSourceString(), code);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java b/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
index 36c8dc6..a25e9dc 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
@@ -14,20 +14,22 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.PrimaryMethodProcessor.MethodAction;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.utils.Timing.TimingMerger;
import com.android.tools.r8.utils.collections.LongLivedProgramMethodSetBuilder;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.android.tools.r8.utils.collections.SortedProgramMethodSet;
import java.util.ArrayDeque;
+import java.util.Collection;
import java.util.Deque;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
-import java.util.function.BiConsumer;
public class PostMethodProcessor extends MethodProcessorWithWave {
@@ -126,25 +128,35 @@
return waves;
}
- void forEachMethod(
- BiConsumer<ProgramMethod, MethodProcessingContext> consumer,
+ <E extends Exception> void forEachMethod(
+ MethodAction<E> consumer,
OptimizationFeedbackDelayed feedback,
- ExecutorService executorService)
+ ExecutorService executorService,
+ Timing timing)
throws ExecutionException {
+ TimingMerger merger =
+ timing.beginMerger("secondary-processor", ThreadUtils.getNumberOfThreads(executorService));
while (!waves.isEmpty()) {
wave = waves.removeFirst();
assert !wave.isEmpty();
assert waveExtension.isEmpty();
do {
assert feedback.noUpdatesLeft();
- ThreadUtils.processItems(
- wave,
- method -> consumer.accept(method, createMethodProcessingContext(method)),
- executorService);
+ Collection<Timing> timings =
+ ThreadUtils.processItemsWithResults(
+ wave,
+ method -> {
+ Timing time = consumer.apply(method, createMethodProcessingContext(method));
+ time.end();
+ return time;
+ },
+ executorService);
+ merger.add(timings);
feedback.updateVisibleOptimizationInfo();
processed.addAll(wave);
prepareForWaveExtensionProcessing();
} while (!wave.isEmpty());
}
+ merger.end();
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index bbc30e8..cd17565 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -236,7 +236,10 @@
fields.add(
DexEncodedField.syntheticBuilder()
.setField(getCaptureField(i))
- .setAccessFlags(FieldAccessFlags.createPublicFinalSynthetic())
+ .setAccessFlags(
+ appView.options().desugarSpecificOptions().lambdaClassFieldsFinal
+ ? FieldAccessFlags.createPublicFinalSynthetic()
+ : FieldAccessFlags.createPublicSynthetic())
// The api level is computed when tracing.
.disableAndroidApiLevelCheck()
.build());
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/BottomParameterUsages.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/BottomParameterUsages.java
index 84bae0e..d087365 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/BottomParameterUsages.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/BottomParameterUsages.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.optimize.classinliner.analysis;
+import com.android.tools.r8.utils.IntObjToObjFunction;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class BottomParameterUsages extends ParameterUsages {
@@ -39,6 +40,12 @@
}
@Override
+ ParameterUsages rebuildParameters(
+ IntObjToObjFunction<ParameterUsagePerContext, ParameterUsagePerContext> transformation) {
+ return this;
+ }
+
+ @Override
public boolean equals(Object other) {
return other == INSTANCE;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ClassInlinerMethodConstraintAnalysis.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ClassInlinerMethodConstraintAnalysis.java
index b8f406a..854188e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ClassInlinerMethodConstraintAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ClassInlinerMethodConstraintAnalysis.java
@@ -12,11 +12,12 @@
import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
import com.android.tools.r8.ir.optimize.classinliner.constraint.ConditionalClassInlinerMethodConstraint;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.Timing;
public class ClassInlinerMethodConstraintAnalysis {
public static ClassInlinerMethodConstraint analyze(
- AppView<AppInfoWithLiveness> appView, ProgramMethod method, IRCode code) {
+ AppView<AppInfoWithLiveness> appView, ProgramMethod method, IRCode code, Timing timing) {
if (method.getDefinition().isClassInitializer()
|| method.getDefinition().getNumberOfArguments() == 0) {
return ClassInlinerMethodConstraint.alwaysFalse();
@@ -27,11 +28,13 @@
new IntraproceduralDataflowAnalysis<>(
ParameterUsages.bottom(), new TransferFunction(appView, method, code));
SuccessfulDataflowAnalysisResult<ParameterUsages> result =
- analysis.run(code.entryBlock()).asSuccessfulAnalysisResult();
+ timing.time(
+ "Data flow analysis",
+ () -> analysis.run(code.entryBlock(), timing).asSuccessfulAnalysisResult());
if (result == null) {
return ClassInlinerMethodConstraint.alwaysFalse();
}
- ParameterUsages usages = result.join().externalize();
+ ParameterUsages usages = timing.time("Externalize", () -> result.join().externalize());
if (usages.isBottom()) {
return ClassInlinerMethodConstraint.alwaysTrue();
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/NonEmptyParameterUsagePerContext.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/NonEmptyParameterUsagePerContext.java
index 9460e7e..715d88f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/NonEmptyParameterUsagePerContext.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/NonEmptyParameterUsagePerContext.java
@@ -9,6 +9,7 @@
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
+import java.util.function.BiPredicate;
class NonEmptyParameterUsagePerContext extends ParameterUsagePerContext {
@@ -28,6 +29,15 @@
ImmutableMap.of(DefaultAnalysisContext.getInstance(), ParameterUsage.bottom()));
}
+ public boolean allMatch(BiPredicate<AnalysisContext, ParameterUsage> predicate) {
+ for (Map.Entry<AnalysisContext, ParameterUsage> entry : backing.entrySet()) {
+ if (!predicate.test(entry.getKey(), entry.getValue())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
void forEach(BiConsumer<AnalysisContext, ParameterUsage> consumer) {
backing.forEach(consumer);
}
@@ -85,6 +95,10 @@
return backing.getOrDefault(context, ParameterUsage.top());
}
+ public int getNumberOfContexts() {
+ return backing.size();
+ }
+
@Override
ParameterUsagePerContext rebuild(
BiFunction<AnalysisContext, ParameterUsage, ParameterUsage> transformation) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/NonEmptyParameterUsages.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/NonEmptyParameterUsages.java
index f7b2cae..50fa8a7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/NonEmptyParameterUsages.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/NonEmptyParameterUsages.java
@@ -176,6 +176,7 @@
: usagePerContext);
}
+ @Override
NonEmptyParameterUsages rebuildParameters(
IntObjToObjFunction<ParameterUsagePerContext, ParameterUsagePerContext> transformation) {
Int2ObjectMap<ParameterUsagePerContext> rebuiltBacking = null;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ParameterUsages.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ParameterUsages.java
index 0cb3a5e..ac81581 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ParameterUsages.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ParameterUsages.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.ir.optimize.classinliner.analysis;
import com.android.tools.r8.ir.analysis.framework.intraprocedural.AbstractState;
+import com.android.tools.r8.utils.IntObjToObjFunction;
public abstract class ParameterUsages extends AbstractState<ParameterUsages> {
@@ -56,6 +57,9 @@
abstract ParameterUsages put(int parameter, ParameterUsagePerContext usagePerContext);
+ abstract ParameterUsages rebuildParameters(
+ IntObjToObjFunction<ParameterUsagePerContext, ParameterUsagePerContext> transformation);
+
public static BottomParameterUsages bottom() {
return BottomParameterUsages.getInstance();
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java
index 822b965..17d5658 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java
@@ -93,7 +93,7 @@
// argument that may be eligible for class inlining.
if (argument == lastArgument
&& result.asNonEmpty().allMatch((context, usagePerContext) -> usagePerContext.isTop())) {
- return new FailedTransferFunctionResult<>();
+ return fail();
}
return result;
}
@@ -104,7 +104,8 @@
}
assert !state.isBottom();
assert !state.isTop();
- return apply(instruction, state.asNonEmpty());
+ ParameterUsages outState = apply(instruction, state.asNonEmpty());
+ return outState != state ? widen(outState) : outState;
}
private ParameterUsages apply(Instruction instruction, NonEmptyParameterUsages state) {
@@ -338,6 +339,10 @@
theReturn.returnValue(), (context, usage) -> usage.setParameterReturned());
}
+ private FailedTransferFunctionResult<ParameterUsages> fail() {
+ return new FailedTransferFunctionResult<>();
+ }
+
private ParameterUsages fail(Instruction instruction, NonEmptyParameterUsages state) {
return state.abandonClassInliningInCurrentContexts(
instruction.inValues(), this::isArgumentOfInterest);
@@ -383,4 +388,29 @@
// We can only class inline a parameter that is either java.lang.Object or an interface type.
return clazz.getType() == dexItemFactory.objectType || clazz.isInterface();
}
+
+ private TransferFunctionResult<ParameterUsages> widen(ParameterUsages state) {
+ // Currently we only fork one context.
+ int maxNumberOfContexts = 1;
+ ParameterUsages widened =
+ state.rebuildParameters(
+ (parameter, usagePerContext) -> {
+ if (usagePerContext.isBottom() || usagePerContext.isTop()) {
+ return usagePerContext;
+ }
+ NonEmptyParameterUsagePerContext nonEmptyUsagePerContext = usagePerContext.asKnown();
+ if (nonEmptyUsagePerContext.getNumberOfContexts() == maxNumberOfContexts
+ && nonEmptyUsagePerContext.allMatch(
+ (context, usageInContext) -> usageInContext.isTop())) {
+ return ParameterUsagePerContext.top();
+ }
+ return usagePerContext;
+ });
+ if (!widened.isBottom()
+ && !widened.isTop()
+ && widened.asNonEmpty().allMatch((parameter, usagePerContext) -> usagePerContext.isTop())) {
+ return fail();
+ }
+ return widened;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/UnknownParameterUsages.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/UnknownParameterUsages.java
index 13e32a7..f6725a9 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/UnknownParameterUsages.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/UnknownParameterUsages.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.ir.optimize.classinliner.analysis;
+import com.android.tools.r8.utils.IntObjToObjFunction;
+
public class UnknownParameterUsages extends ParameterUsages {
private static final UnknownParameterUsages INSTANCE = new UnknownParameterUsages();
@@ -35,6 +37,12 @@
}
@Override
+ ParameterUsages rebuildParameters(
+ IntObjToObjFunction<ParameterUsagePerContext, ParameterUsagePerContext> transformation) {
+ return this;
+ }
+
+ @Override
public boolean equals(Object other) {
return other == INSTANCE;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index 9836791..e28b6ad 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -783,15 +783,10 @@
OptimizationFeedback feedback,
Timing timing) {
timing.begin("Compute class inlining constraint");
- computeClassInlinerMethodConstraint(method, code, feedback);
- timing.end();
- }
-
- private void computeClassInlinerMethodConstraint(
- ProgramMethod method, IRCode code, OptimizationFeedback feedback) {
ClassInlinerMethodConstraint classInlinerMethodConstraint =
- ClassInlinerMethodConstraintAnalysis.analyze(appView, method, code);
+ ClassInlinerMethodConstraintAnalysis.analyze(appView, method, code, timing);
feedback.setClassInlinerMethodConstraint(method, classInlinerMethodConstraint);
+ timing.end();
}
private void computeEnumUnboxerMethodClassification(
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
index 00028ff..373f584 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.naming.MemberNaming.Signature;
import com.android.tools.r8.naming.MemberNaming.Signature.SignatureKind;
import com.android.tools.r8.naming.mappinginformation.MappingInformation;
+import com.android.tools.r8.naming.mappinginformation.OutlineCallsiteMappingInformation;
import com.android.tools.r8.naming.mappinginformation.RewriteFrameMappingInformation;
import com.android.tools.r8.utils.ChainableStringConsumer;
import com.android.tools.r8.utils.ThrowingConsumer;
@@ -23,6 +24,8 @@
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
/**
* Stores name information for a class.
@@ -428,7 +431,6 @@
private MappedRange(
Range minifiedRange, MethodSignature signature, Range originalRange, String renamedName) {
-
this.minifiedRange = minifiedRange;
this.signature = signature;
this.originalRange = originalRange;
@@ -448,23 +450,45 @@
public boolean isCompilerSynthesized() {
for (MappingInformation info : additionalMappingInfo) {
- if (info.isCompilerSynthesizedMappingInformation()) {
+ if (info.isCompilerSynthesizedMappingInformation() || info.isOutlineMappingInformation()) {
return true;
}
}
return false;
}
- public List<RewriteFrameMappingInformation> getRewriteFrameMappingInformation() {
- ImmutableList.Builder<RewriteFrameMappingInformation> builder = ImmutableList.builder();
+ public boolean isOutlineFrame() {
+ for (MappingInformation info : additionalMappingInfo) {
+ if (info.isOutlineMappingInformation()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public <T> List<T> filter(
+ Predicate<MappingInformation> predicate, Function<MappingInformation, T> mapper) {
+ ImmutableList.Builder<T> builder = ImmutableList.builder();
for (MappingInformation mappingInformation : additionalMappingInfo) {
- if (mappingInformation.isRewriteFrameMappingInformation()) {
- builder.add(mappingInformation.asRewriteFrameMappingInformation());
+ if (predicate.test(mappingInformation)) {
+ builder.add(mapper.apply(mappingInformation));
}
}
return builder.build();
}
+ public List<OutlineCallsiteMappingInformation> getOutlineCallsiteInformation() {
+ return filter(
+ MappingInformation::isOutlineCallsiteInformation,
+ MappingInformation::asOutlineCallsiteInformation);
+ }
+
+ public List<RewriteFrameMappingInformation> getRewriteFrameMappingInformation() {
+ return filter(
+ MappingInformation::isRewriteFrameMappingInformation,
+ MappingInformation::asRewriteFrameMappingInformation);
+ }
+
public int getOriginalLineNumber(int lineNumberAfterMinification) {
if (minifiedRange == null) {
// General mapping without concrete line numbers: "a() -> b"
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
index 7e7cff8..85e7b1a 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
@@ -59,7 +59,6 @@
private ProguardMapSupplier(ClassNameMapper classNameMapper, InternalOptions options) {
assert classNameMapper != null;
- assert !classNameMapper.isEmpty();
this.classNameMapper = classNameMapper.sorted();
this.consumer =
InternalOptions.assertionsEnabled()
@@ -71,7 +70,7 @@
public static ProguardMapSupplier create(
ClassNameMapper classNameMapper, InternalOptions options) {
- return classNameMapper.isEmpty() ? null : new ProguardMapSupplier(classNameMapper, options);
+ return new ProguardMapSupplier(classNameMapper, options);
}
public ProguardMapId writeProguardMap() {
diff --git a/src/main/java/com/android/tools/r8/naming/Range.java b/src/main/java/com/android/tools/r8/naming/Range.java
index a8d8563..8624aad 100644
--- a/src/main/java/com/android/tools/r8/naming/Range.java
+++ b/src/main/java/com/android/tools/r8/naming/Range.java
@@ -49,6 +49,13 @@
return from == range.from && to == range.to && isCardinal == range.isCardinal;
}
+ public int span() {
+ if (isCardinal) {
+ return 1;
+ }
+ return (to - from) + 1;
+ }
+
@Override
public int hashCode() {
return Objects.hash(from, to, isCardinal);
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
index 9232500..00a411f 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
@@ -34,10 +34,18 @@
return false;
}
+ public boolean isOutlineCallsiteInformation() {
+ return false;
+ }
+
public boolean isCompilerSynthesizedMappingInformation() {
return false;
}
+ public boolean isOutlineMappingInformation() {
+ return false;
+ }
+
public MapVersionMappingInformation asMapVersionMappingInformation() {
return null;
}
@@ -58,6 +66,10 @@
return null;
}
+ public OutlineCallsiteMappingInformation asOutlineCallsiteInformation() {
+ return null;
+ }
+
public abstract boolean allowOther(MappingInformation information);
public static void fromJsonObject(
@@ -113,6 +125,12 @@
case RewriteFrameMappingInformation.ID:
RewriteFrameMappingInformation.deserialize(version, object, onMappingInfo);
return;
+ case OutlineMappingInformation.ID:
+ OutlineMappingInformation.deserialize(version, onMappingInfo);
+ return;
+ case OutlineCallsiteMappingInformation.ID:
+ OutlineCallsiteMappingInformation.deserialize(version, object, onMappingInfo);
+ return;
default:
diagnosticsHandler.info(MappingInformationDiagnostics.noHandlerFor(lineNumber, id));
UnknownJsonMappingInformation.deserialize(id, object, onMappingInfo);
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineCallsiteMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineCallsiteMappingInformation.java
new file mode 100644
index 0000000..d451d82
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineCallsiteMappingInformation.java
@@ -0,0 +1,89 @@
+// Copyright (c) 2021, 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.naming.mappinginformation;
+
+import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.naming.MapVersion;
+import com.google.gson.JsonObject;
+import it.unimi.dsi.fastutil.ints.Int2IntLinkedOpenHashMap;
+import it.unimi.dsi.fastutil.ints.Int2IntSortedMap;
+import java.util.function.Consumer;
+
+public class OutlineCallsiteMappingInformation extends MappingInformation {
+
+ public static final MapVersion SUPPORTED_VERSION = MapVersion.MAP_VERSION_EXPERIMENTAL;
+ public static final String ID = "com.android.tools.r8.outlineCallsite";
+
+ private static final String POSITIONS_KEY = "positions";
+
+ private final Int2IntSortedMap positions;
+
+ private OutlineCallsiteMappingInformation(Int2IntSortedMap positions) {
+ this.positions = positions;
+ }
+
+ @Override
+ public String getId() {
+ return ID;
+ }
+
+ @Override
+ public String serialize() {
+ throw new CompilationError("Should not yet serialize this");
+ }
+
+ @Override
+ public boolean allowOther(MappingInformation information) {
+ return !information.isOutlineCallsiteInformation();
+ }
+
+ @Override
+ public boolean isOutlineCallsiteInformation() {
+ return true;
+ }
+
+ @Override
+ public OutlineCallsiteMappingInformation asOutlineCallsiteInformation() {
+ return this;
+ }
+
+ public int rewritePosition(int originalPosition) {
+ return positions.getOrDefault(originalPosition, originalPosition);
+ }
+
+ public static OutlineCallsiteMappingInformation create(Int2IntSortedMap positions) {
+ return new OutlineCallsiteMappingInformation(positions);
+ }
+
+ public static boolean isSupported(MapVersion version) {
+ return version.isGreaterThanOrEqualTo(SUPPORTED_VERSION);
+ }
+
+ public static void deserialize(
+ MapVersion version, JsonObject object, Consumer<MappingInformation> onMappingInfo) {
+ if (isSupported(version)) {
+ JsonObject postionsMapObject = object.getAsJsonObject(POSITIONS_KEY);
+ if (postionsMapObject == null) {
+ throw new CompilationError(
+ "Expected '" + POSITIONS_KEY + "' to be present: " + object.getAsString());
+ }
+ Int2IntSortedMap positionsMap = new Int2IntLinkedOpenHashMap();
+ postionsMapObject
+ .entrySet()
+ .forEach(
+ entry -> {
+ try {
+ String key = entry.getKey();
+ int originalPosition = Integer.parseInt(key);
+ int newPosition = entry.getValue().getAsInt();
+ positionsMap.put(originalPosition, newPosition);
+ } catch (Throwable ex) {
+ throw new CompilationError("Invalid position entry: " + entry.toString());
+ }
+ });
+ onMappingInfo.accept(OutlineCallsiteMappingInformation.create(positionsMap));
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineMappingInformation.java
new file mode 100644
index 0000000..697c5b6
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineMappingInformation.java
@@ -0,0 +1,56 @@
+// Copyright (c) 2021, 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.naming.mappinginformation;
+
+import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.naming.MapVersion;
+import java.util.function.Consumer;
+
+public class OutlineMappingInformation extends MappingInformation {
+
+ public static final MapVersion SUPPORTED_VERSION = MapVersion.MAP_VERSION_EXPERIMENTAL;
+ public static final String ID = "com.android.tools.r8.outline";
+
+ @Override
+ public String getId() {
+ return ID;
+ }
+
+ @Override
+ public String serialize() {
+ throw new CompilationError("Should not yet serialize this");
+ }
+
+ @Override
+ public boolean allowOther(MappingInformation information) {
+ return true;
+ }
+
+ @Override
+ public boolean isOutlineMappingInformation() {
+ return true;
+ }
+
+ public static boolean isSupported(MapVersion version) {
+ return version.isGreaterThanOrEqualTo(SUPPORTED_VERSION);
+ }
+
+ public static void deserialize(MapVersion version, Consumer<MappingInformation> onMappingInfo) {
+ if (isSupported(version)) {
+ onMappingInfo.accept(new OutlineMappingInformation());
+ }
+ }
+
+ public static OutlineMappingInformation.Builder builder() {
+ return new OutlineMappingInformation.Builder();
+ }
+
+ public static class Builder {
+
+ public OutlineMappingInformation build() {
+ return new OutlineMappingInformation();
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/RewriteFrameMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/RewriteFrameMappingInformation.java
index cc8c795..d9d8c4b 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/RewriteFrameMappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/RewriteFrameMappingInformation.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.naming.mappinginformation;
+import static com.android.tools.r8.naming.mappinginformation.RewriteFrameMappingInformation.RemoveInnerFramesAction.REMOVE_INNER_FRAMES_NAME;
+
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.naming.MapVersion;
@@ -15,6 +17,7 @@
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
+import it.unimi.dsi.fastutil.ints.Int2IntMap;
import java.util.List;
import java.util.function.Consumer;
@@ -99,6 +102,11 @@
return this;
}
+ public static RewriteFrameMappingInformation create(
+ List<Condition> conditions, List<RewriteAction> actions) {
+ return new RewriteFrameMappingInformation(conditions, actions);
+ }
+
public abstract static class Condition {
protected abstract JsonPrimitive serialize();
@@ -114,7 +122,7 @@
if (ThrowsCondition.FUNCTION_NAME.equals(functionName)) {
return ThrowsCondition.deserialize(contents);
}
- throw new Unimplemented("Unexpected condition: " + elementString);
+ throw new CompilationError("Unexpected condition: " + elementString);
}
public boolean isThrowsCondition() {
@@ -173,21 +181,7 @@
public abstract static class RewriteAction {
- static final String REMOVE_INNER_FRAMES_SERIALIZED_NAME = "removeInnerFrames";
-
- private static final String FUNCTION_KEY = "function";
- private static final String ARGUMENTS_KEY = "arguments";
-
- abstract String serializeName();
-
- abstract JsonArray getArguments();
-
- JsonElement serialize() {
- JsonObject jsonObject = new JsonObject();
- jsonObject.add(FUNCTION_KEY, new JsonPrimitive(serializeName()));
- jsonObject.add(ARGUMENTS_KEY, getArguments());
- return jsonObject;
- }
+ abstract JsonElement serialize();
private static RewriteAction deserialize(JsonElement element) {
String functionString = element.getAsString();
@@ -198,8 +192,8 @@
}
String functionName = functionString.substring(0, startArgsIndex);
String args = functionString.substring(startArgsIndex + 1, endArgsIndex);
- if (REMOVE_INNER_FRAMES_SERIALIZED_NAME.equals(functionName)) {
- return RemoveInnerFramesAction.create(args);
+ if (REMOVE_INNER_FRAMES_NAME.equals(functionName)) {
+ return RemoveInnerFramesAction.deserialize(args);
}
assert false : "Unknown function " + functionName;
throw new Unimplemented("Unexpected action: " + functionName);
@@ -218,6 +212,8 @@
public static class RemoveInnerFramesAction extends RewriteAction {
+ static final String REMOVE_INNER_FRAMES_NAME = "removeInnerFrames";
+
private final int numberOfFrames;
public RemoveInnerFramesAction(int numberOfFrames) {
@@ -229,19 +225,8 @@
}
@Override
- String serializeName() {
- return REMOVE_INNER_FRAMES_SERIALIZED_NAME;
- }
-
- @Override
- JsonArray getArguments() {
- JsonArray arguments = new JsonArray();
- arguments.add(numberOfFrames);
- return arguments;
- }
-
- static RemoveInnerFramesAction create(String args) {
- return new RemoveInnerFramesAction(Integer.parseInt(args));
+ JsonElement serialize() {
+ return new JsonPrimitive(REMOVE_INNER_FRAMES_NAME + "(" + numberOfFrames + ")");
}
@Override
@@ -258,5 +243,41 @@
public void evaluate(RetraceStackTraceCurrentEvaluationInformation.Builder builder) {
builder.incrementRemoveInnerFramesCount(numberOfFrames);
}
+
+ static RemoveInnerFramesAction create(int numberOfFrames) {
+ return new RemoveInnerFramesAction(numberOfFrames);
+ }
+
+ public static RemoveInnerFramesAction deserialize(String contents) {
+ try {
+ return create(Integer.parseInt(contents));
+ } catch (NumberFormatException nfe) {
+ throw new CompilationError(
+ "Unexpected number for " + REMOVE_INNER_FRAMES_NAME + ": " + contents);
+ }
+ }
+ }
+
+ public static class RewritePreviousObfuscatedPosition extends RewriteAction {
+
+ private final Int2IntMap rewriteMap;
+
+ private RewritePreviousObfuscatedPosition(Int2IntMap rewriteMap) {
+ this.rewriteMap = rewriteMap;
+ }
+
+ @Override
+ JsonElement serialize() {
+ throw new CompilationError("Do not serialize this");
+ }
+
+ @Override
+ public void evaluate(RetraceStackTraceCurrentEvaluationInformation.Builder builder) {
+ builder.setPosition(rewriteMap.getOrDefault(builder.getPosition(), builder.getPosition()));
+ }
+
+ public static RewritePreviousObfuscatedPosition create(Int2IntMap rewriteMap) {
+ return new RewritePreviousObfuscatedPosition(rewriteMap);
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/Retrace.java b/src/main/java/com/android/tools/r8/retrace/Retrace.java
index c474a8a..5bb9ca1 100644
--- a/src/main/java/com/android/tools/r8/retrace/Retrace.java
+++ b/src/main/java/com/android/tools/r8/retrace/Retrace.java
@@ -199,8 +199,9 @@
ST parsedLine = stackTraceLineParser.parse(stackTraceLine);
List<RetracedNodeState<T, ST>> newLeaves = new ArrayList<>();
for (RetracedNodeState<T, ST> previousNode : acc) {
- proxyRetracer
- .retrace(parsedLine, previousNode.context)
+ RetraceStackTraceElementProxyResult<T, ST> result =
+ proxyRetracer.retrace(parsedLine, previousNode.context);
+ result.stream()
.forEach(
retracedElement -> {
if (retracedElement.isTopFrame() || !retracedElement.hasRetracedClass()) {
@@ -212,7 +213,7 @@
if (!previousNode.hasChildren()) {
// This happens when there is nothing to retrace. Add the node to newLeaves to
// ensure we keep retracing this path.
- previousNode.addChild(null, RetraceStackTraceContext.empty());
+ previousNode.addChild(null, result.getResultContext());
}
newLeaves.addAll(previousNode.getChildren());
}
@@ -232,8 +233,7 @@
Map<RetraceStackTraceElementProxy<T, ST>, List<T>> ambiguousBlocks = new HashMap<>();
List<RetraceStackTraceElementProxy<T, ST>> ambiguousKeys = new ArrayList<>();
ST parsedLine = stackTraceLineParser.parse(stackTraceFrame);
- proxyRetracer
- .retrace(parsedLine, RetraceStackTraceContext.empty())
+ proxyRetracer.retrace(parsedLine, RetraceStackTraceContext.empty()).stream()
.forEach(
retracedElement -> {
if (retracedElement.isTopFrame() || !retracedElement.hasRetracedClass()) {
@@ -259,8 +259,7 @@
*/
public List<T> retraceLine(T stackTraceLine) {
ST parsedLine = stackTraceLineParser.parse(stackTraceLine);
- return proxyRetracer
- .retrace(parsedLine, RetraceStackTraceContext.empty())
+ return proxyRetracer.retrace(parsedLine, RetraceStackTraceContext.empty()).stream()
.map(
retraceFrame -> {
retraceFrame.getOriginalItem().toRetracedItem(retraceFrame, isVerbose);
@@ -483,15 +482,20 @@
one,
other,
RetraceStackTraceElementProxy::hasSourceFile,
- RetraceStackTraceElementProxy::getSourceFile)
- // TODO(b/201042571): This will have to change.
- || testNotEqualProperty(
- one,
- other,
- RetraceStackTraceElementProxy::hasLineNumber,
- RetraceStackTraceElementProxy::getLineNumber)) {
+ RetraceStackTraceElementProxy::getSourceFile)) {
return false;
}
+ assert one.getOriginalItem() == other.getOriginalItem();
+ if (isVerbose
+ || (one.getOriginalItem().hasLineNumber() && one.getOriginalItem().getLineNumber() > 0)) {
+ if (testNotEqualProperty(
+ one,
+ other,
+ RetraceStackTraceElementProxy::hasLineNumber,
+ RetraceStackTraceElementProxy::getLineNumber)) {
+ return false;
+ }
+ }
if (one.hasRetracedMethod() != other.hasRetracedMethod()) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java
index 9f5bc71..c2bd31a 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java
@@ -12,8 +12,6 @@
@Keep
public interface RetraceClassResult extends RetraceResult<RetraceClassElement> {
- boolean hasRetraceResult();
-
RetraceFieldResult lookupField(String fieldName);
RetraceFieldResult lookupField(String fieldName, TypeReference fieldType);
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceFrameElement.java b/src/main/java/com/android/tools/r8/retrace/RetraceFrameElement.java
index 419f6b3..ff7d330 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceFrameElement.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceFrameElement.java
@@ -29,5 +29,5 @@
List<? extends RetracedMethodReference> getOuterFrames();
- RetraceStackTraceContext getContext();
+ RetraceStackTraceContext getRetraceStackTraceContext();
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java
index 805443c..f06fad3 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java
@@ -5,9 +5,10 @@
package com.android.tools.r8.retrace;
import com.android.tools.r8.Keep;
+import java.util.OptionalInt;
@Keep
public interface RetraceMethodResult extends RetraceResult<RetraceMethodElement> {
- RetraceFrameResult narrowByPosition(RetraceStackTraceContext context, int position);
+ RetraceFrameResult narrowByPosition(RetraceStackTraceContext context, OptionalInt position);
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceResult.java
index 1bc6ed6..7ff9c4e 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceResult.java
@@ -31,4 +31,6 @@
default void forEach(Consumer<E> action) {
stream().forEach(action);
}
+
+ boolean isEmpty();
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceStackTraceElementProxyResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceStackTraceElementProxyResult.java
new file mode 100644
index 0000000..1db1f08
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceStackTraceElementProxyResult.java
@@ -0,0 +1,22 @@
+// Copyright (c) 2021, 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.retrace;
+
+import com.android.tools.r8.Keep;
+import java.util.stream.Stream;
+
+@Keep
+public interface RetraceStackTraceElementProxyResult<T, ST extends StackTraceElementProxy<T, ST>> {
+
+ Stream<? extends RetraceStackTraceElementProxy<T, ST>> stream();
+
+ /**
+ * If the stream is empty, use getResultContext to obtain the resulting stack trace context. Due
+ * to the lazyness of streams the result is only populated after querying the stream.
+ *
+ * @return the resulting stack trace context.
+ */
+ RetraceStackTraceContext getResultContext();
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/Retracer.java b/src/main/java/com/android/tools/r8/retrace/Retracer.java
index 34d413b..293ac8e 100644
--- a/src/main/java/com/android/tools/r8/retrace/Retracer.java
+++ b/src/main/java/com/android/tools/r8/retrace/Retracer.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.TypeReference;
import com.android.tools.r8.retrace.internal.RetracerImpl;
+import java.util.OptionalInt;
/** This is the main api interface for retrace. */
@Keep
@@ -20,10 +21,10 @@
RetraceMethodResult retraceMethod(MethodReference methodReference);
- RetraceFrameResult retraceFrame(MethodReference methodReference, int position);
+ RetraceFrameResult retraceFrame(MethodReference methodReference, OptionalInt position);
RetraceFrameResult retraceFrame(
- MethodReference methodReference, int position, RetraceStackTraceContext context);
+ MethodReference methodReference, OptionalInt position, RetraceStackTraceContext context);
RetraceFieldResult retraceField(FieldReference fieldReference);
diff --git a/src/main/java/com/android/tools/r8/retrace/StackTraceElementProxyRetracer.java b/src/main/java/com/android/tools/r8/retrace/StackTraceElementProxyRetracer.java
index 851bbc2..e792ef0 100644
--- a/src/main/java/com/android/tools/r8/retrace/StackTraceElementProxyRetracer.java
+++ b/src/main/java/com/android/tools/r8/retrace/StackTraceElementProxyRetracer.java
@@ -6,13 +6,11 @@
import com.android.tools.r8.Keep;
import com.android.tools.r8.retrace.internal.StackTraceElementProxyRetracerImpl;
-import java.util.stream.Stream;
@Keep
public interface StackTraceElementProxyRetracer<T, ST extends StackTraceElementProxy<T, ST>> {
- Stream<? extends RetraceStackTraceElementProxy<T, ST>> retrace(
- ST element, RetraceStackTraceContext context);
+ RetraceStackTraceElementProxyResult<T, ST> retrace(ST element, RetraceStackTraceContext context);
static <T, ST extends StackTraceElementProxy<T, ST>>
StackTraceElementProxyRetracer<T, ST> createDefault(Retracer retracer) {
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
index f94035b..0d834a3 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.naming.ClassNamingForNameMapper;
-import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRange;
import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRangesOfName;
import com.android.tools.r8.naming.MemberNaming;
import com.android.tools.r8.naming.mappinginformation.MappingInformation;
@@ -20,7 +19,6 @@
import com.android.tools.r8.retrace.RetraceStackTraceContext;
import com.android.tools.r8.retrace.RetraceUnknownJsonMappingInformationResult;
import com.android.tools.r8.retrace.RetracedSourceFile;
-import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.Pair;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
@@ -138,64 +136,19 @@
Reference.method(obfuscatedReference, methodName, formalTypes, returnType)));
}
+ private RetraceFrameResultImpl lookupFrame(
+ RetraceStackTraceContext context, OptionalInt position, MethodDefinition definition) {
+ return lookupMethod(definition).narrowByPosition(context, position);
+ }
+
@Override
public RetraceThrownExceptionResultImpl lookupThrownException(RetraceStackTraceContext context) {
return new RetraceThrownExceptionResultImpl(
(RetraceStackTraceContextImpl) context, obfuscatedReference, mapper);
}
- private RetraceFrameResultImpl lookupFrame(
- RetraceStackTraceContext context, OptionalInt position, MethodDefinition definition) {
- List<Pair<RetraceClassElementImpl, List<MappedRange>>> mappings = new ArrayList<>();
- internalStream()
- .forEach(
- element -> {
- getMappedRangesForFrame(element, definition, position)
- .forEach(
- mappedRanges -> {
- mappings.add(new Pair<>(element, mappedRanges));
- });
- });
- return new RetraceFrameResultImpl(
- this, mappings, definition, position, retracer, (RetraceStackTraceContextImpl) context);
- }
-
- private List<List<MappedRange>> getMappedRangesForFrame(
- RetraceClassElementImpl element, MethodDefinition definition, OptionalInt position) {
- List<List<MappedRange>> overloadedRanges = new ArrayList<>();
- if (mapper == null) {
- overloadedRanges.add(null);
- return overloadedRanges;
- }
- assert element.mapper != null;
- MappedRangesOfName mappedRanges = mapper.mappedRangesByRenamedName.get(definition.getName());
- if (mappedRanges == null || mappedRanges.getMappedRanges().isEmpty()) {
- overloadedRanges.add(null);
- return overloadedRanges;
- }
- List<MappedRange> mappedRangesForPosition = null;
- if (position.isPresent() && position.getAsInt() >= 0) {
- mappedRangesForPosition = mappedRanges.allRangesForLine(position.getAsInt(), false);
- }
- if (mappedRangesForPosition == null || mappedRangesForPosition.isEmpty()) {
- mappedRangesForPosition = mappedRanges.getMappedRanges();
- }
- assert mappedRangesForPosition != null && !mappedRangesForPosition.isEmpty();
- // Mapped ranges can have references to overloaded signatures. We distinguish those by looking
- // at the cardinal mapping range.
- for (MappedRange mappedRange : mappedRangesForPosition) {
- if (overloadedRanges.isEmpty()
- || mappedRange.originalRange == null
- || !mappedRange.originalRange.isCardinal) {
- overloadedRanges.add(new ArrayList<>());
- }
- ListUtils.last(overloadedRanges).add(mappedRange);
- }
- return overloadedRanges;
- }
-
@Override
- public boolean hasRetraceResult() {
+ public boolean isEmpty() {
return mapper != null;
}
@@ -366,23 +319,7 @@
private RetraceFrameResultImpl lookupFrame(
RetraceStackTraceContext context, OptionalInt position, MethodDefinition definition) {
- MethodDefinition methodDefinition =
- MethodDefinition.create(classReference.getClassReference(), definition.getName());
- ImmutableList.Builder<Pair<RetraceClassElementImpl, List<MappedRange>>> builder =
- ImmutableList.builder();
- classResult
- .getMappedRangesForFrame(this, methodDefinition, position)
- .forEach(
- mappedRanges -> {
- builder.add(new Pair<>(this, mappedRanges));
- });
- return new RetraceFrameResultImpl(
- classResult,
- builder.build(),
- methodDefinition,
- position,
- classResult.retracer,
- (RetraceStackTraceContextImpl) context);
+ return classResult.lookupFrame(context, position, definition);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceFieldResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFieldResultImpl.java
index 38667c4..33abecc 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceFieldResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFieldResultImpl.java
@@ -92,6 +92,11 @@
return mappings.size() > 1;
}
+ @Override
+ public boolean isEmpty() {
+ return memberNamings == null || memberNamings.isEmpty();
+ }
+
public static class ElementImpl implements RetraceFieldElement {
private final RetracedFieldReferenceImpl fieldReference;
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java
index a2936bf..ee295e2 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java
@@ -20,6 +20,7 @@
import com.android.tools.r8.retrace.internal.RetraceClassResultImpl.RetraceClassElementImpl;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.OptionalBool;
+import com.android.tools.r8.utils.OptionalUtils;
import com.android.tools.r8.utils.Pair;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
@@ -65,11 +66,15 @@
}
List<MappedRange> methodRanges = mappedRanges.get(0).getSecond();
if (methodRanges != null && !methodRanges.isEmpty()) {
- MappedRange lastRange = methodRanges.get(0);
+ MappedRange initialRange = methodRanges.get(0);
for (MappedRange mappedRange : methodRanges) {
- if (mappedRange != lastRange
+ if (isMappedRangeAmbiguous(mappedRange)) {
+ isAmbiguousCache = OptionalBool.TRUE;
+ return true;
+ }
+ if (mappedRange != initialRange
&& (mappedRange.minifiedRange == null
- || !mappedRange.minifiedRange.equals(lastRange.minifiedRange))) {
+ || !mappedRange.minifiedRange.equals(initialRange.minifiedRange))) {
isAmbiguousCache = OptionalBool.TRUE;
return true;
}
@@ -81,6 +86,16 @@
return isAmbiguousCache.isTrue();
}
+ private boolean isMappedRangeAmbiguous(MappedRange mappedRange) {
+ if (mappedRange.originalRange == null || mappedRange.originalRange.span() == 1) {
+ // If there is no original position or all maps to a single position, the result is not
+ // ambiguous.
+ return false;
+ }
+ return mappedRange.minifiedRange == null
+ || mappedRange.minifiedRange.span() != mappedRange.originalRange.span();
+ }
+
@Override
public Stream<RetraceFrameElement> stream() {
return mappedRanges.stream()
@@ -98,8 +113,7 @@
classElement.getRetracedClass().getClassReference())),
ImmutableList.of(),
obfuscatedPosition,
- retracer,
- context));
+ retracer));
}
// Iterate over mapped ranges that may have different positions than specified.
List<ElementImpl> ambiguousFrames = new ArrayList<>();
@@ -109,50 +123,105 @@
MappedRange mappedRange = mappedRanges.get(i);
if (minifiedRange == null || !minifiedRange.equals(mappedRange.minifiedRange)) {
// This is a new frame
- ambiguousFrames.add(
- elementFromMappedRanges(mappedRangesForElement, classElement));
+ separateAmbiguousOriginalPositions(
+ classElement, mappedRangesForElement, ambiguousFrames);
mappedRangesForElement = new ArrayList<>();
+ minifiedRange = mappedRange.minifiedRange;
}
mappedRangesForElement.add(mappedRange);
}
- ambiguousFrames.add(elementFromMappedRanges(mappedRangesForElement, classElement));
+ separateAmbiguousOriginalPositions(
+ classElement, mappedRangesForElement, ambiguousFrames);
return ambiguousFrames.stream();
});
}
+ private void separateAmbiguousOriginalPositions(
+ RetraceClassElementImpl classElement,
+ List<MappedRange> frames,
+ List<ElementImpl> allAmbiguousElements) {
+ // We have a single list of frames where minified positional information may produce ambiguous
+ // results.
+ if (!isAmbiguous() || !isMappedRangeAmbiguous(frames.get(0))) {
+ allAmbiguousElements.add(
+ elementFromMappedRanges(
+ ListUtils.map(frames, MappedRangeForFrame::create), classElement));
+ return;
+ }
+ assert frames.size() > 0;
+ assert frames.get(0).originalRange != null
+ && frames.get(0).originalRange.to > frames.get(0).originalRange.from;
+ List<List<MappedRangeForFrame>> newFrames = new ArrayList<>();
+ ListUtils.forEachWithIndex(
+ frames,
+ (frame, index) -> {
+ // Only the top inline can give rise to ambiguity since the remaining inline frames will
+ // have a single line number.
+ if (index == 0) {
+ for (int i = frame.originalRange.from; i <= frame.originalRange.to; i++) {
+ List<MappedRangeForFrame> ambiguousFrames = new ArrayList<>();
+ ambiguousFrames.add(MappedRangeForFrame.create(frame, OptionalInt.of(i)));
+ newFrames.add(ambiguousFrames);
+ }
+ } else {
+ newFrames.forEach(
+ ambiguousFrames -> {
+ ambiguousFrames.add(MappedRangeForFrame.create(frame));
+ });
+ }
+ });
+ newFrames.forEach(
+ ambiguousFrames -> {
+ allAmbiguousElements.add(elementFromMappedRanges(ambiguousFrames, classElement));
+ });
+ }
+
private ElementImpl elementFromMappedRanges(
- List<MappedRange> mappedRangesForElement, RetraceClassElementImpl classElement) {
- MappedRange topFrame = mappedRangesForElement.get(0);
+ List<MappedRangeForFrame> mappedRangesForElement, RetraceClassElementImpl classElement) {
+ MappedRangeForFrame topFrame = mappedRangesForElement.get(0);
MethodReference methodReference =
methodReferenceFromMappedRange(
- topFrame, classElement.getRetracedClass().getClassReference());
+ topFrame.mappedRange, classElement.getRetracedClass().getClassReference());
return new ElementImpl(
this,
classElement,
getRetracedMethod(methodReference, topFrame, obfuscatedPosition),
mappedRangesForElement,
obfuscatedPosition,
- retracer,
- context);
+ retracer);
}
private RetracedMethodReferenceImpl getRetracedMethod(
- MethodReference methodReference, MappedRange mappedRange, OptionalInt obfuscatedPosition) {
- if (mappedRange.minifiedRange == null
- || (obfuscatedPosition.orElse(-1) == -1 && !isAmbiguous())) {
+ MethodReference methodReference,
+ MappedRangeForFrame mappedRangeForFrame,
+ OptionalInt obfuscatedPosition) {
+ MappedRange mappedRange = mappedRangeForFrame.mappedRange;
+ OptionalInt originalPosition = mappedRangeForFrame.position;
+ if (!isAmbiguous()
+ && (mappedRange.minifiedRange == null || obfuscatedPosition.orElse(-1) == -1)) {
int originalLineNumber = mappedRange.getFirstLineNumberOfOriginalRange();
if (originalLineNumber > 0) {
- return RetracedMethodReferenceImpl.create(methodReference, originalLineNumber);
+ return RetracedMethodReferenceImpl.create(
+ methodReference, OptionalUtils.orElse(originalPosition, originalLineNumber));
} else {
- return RetracedMethodReferenceImpl.create(methodReference);
+ return RetracedMethodReferenceImpl.create(methodReference, originalPosition);
}
}
if (!obfuscatedPosition.isPresent()
+ || mappedRange.minifiedRange == null
|| !mappedRange.minifiedRange.contains(obfuscatedPosition.getAsInt())) {
- return RetracedMethodReferenceImpl.create(methodReference);
+ return RetracedMethodReferenceImpl.create(methodReference, originalPosition);
}
return RetracedMethodReferenceImpl.create(
- methodReference, mappedRange.getOriginalLineNumber(obfuscatedPosition.getAsInt()));
+ methodReference,
+ OptionalUtils.orElseGet(
+ originalPosition,
+ () -> mappedRange.getOriginalLineNumber(obfuscatedPosition.getAsInt())));
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return !mappedRanges.isEmpty();
}
public static class ElementImpl implements RetraceFrameElement {
@@ -160,33 +229,30 @@
private final RetracedMethodReferenceImpl methodReference;
private final RetraceFrameResultImpl retraceFrameResult;
private final RetraceClassElementImpl classElement;
- private final List<MappedRange> mappedRanges;
+ private final List<MappedRangeForFrame> mappedRanges;
private final OptionalInt obfuscatedPosition;
private final RetracerImpl retracer;
- private final RetraceStackTraceContextImpl context;
ElementImpl(
RetraceFrameResultImpl retraceFrameResult,
RetraceClassElementImpl classElement,
RetracedMethodReferenceImpl methodReference,
- List<MappedRange> mappedRanges,
+ List<MappedRangeForFrame> mappedRanges,
OptionalInt obfuscatedPosition,
- RetracerImpl retracer,
- RetraceStackTraceContextImpl context) {
+ RetracerImpl retracer) {
this.methodReference = methodReference;
this.retraceFrameResult = retraceFrameResult;
this.classElement = classElement;
this.mappedRanges = mappedRanges;
this.obfuscatedPosition = obfuscatedPosition;
this.retracer = retracer;
- this.context = context;
}
private boolean isOuterMostFrameCompilerSynthesized() {
if (mappedRanges == null || mappedRanges.isEmpty()) {
return false;
}
- return ListUtils.last(mappedRanges).isCompilerSynthesized();
+ return ListUtils.last(mappedRanges).mappedRange.isCompilerSynthesized();
}
/**
@@ -246,9 +312,10 @@
RetraceStackTraceCurrentEvaluationInformation currentFrameInformation =
context == null
? RetraceStackTraceCurrentEvaluationInformation.empty()
- : contextImpl.computeRewritingInformation(mappedRanges);
+ : contextImpl.computeRewriteFrameInformation(
+ ListUtils.map(mappedRanges, MappedRangeForFrame::getMappedRange));
int index = 0;
- int numberOfFramesToRemove = currentFrameInformation.getRemoveInnerFrames();
+ int numberOfFramesToRemove = currentFrameInformation.getRemoveInnerFramesCount();
int totalNumberOfFrames =
(mappedRanges == null || mappedRanges.isEmpty()) ? 1 : mappedRanges.size();
if (numberOfFramesToRemove > totalNumberOfFrames) {
@@ -298,17 +365,52 @@
return outerFrames;
}
- private RetracedMethodReferenceImpl getMethodReferenceFromMappedRange(MappedRange mappedRange) {
+ private RetracedMethodReferenceImpl getMethodReferenceFromMappedRange(
+ MappedRangeForFrame mappedRangeForFrame) {
MethodReference methodReference =
methodReferenceFromMappedRange(
- mappedRange, classElement.getRetracedClass().getClassReference());
- return retraceFrameResult.getRetracedMethod(methodReference, mappedRange, obfuscatedPosition);
+ mappedRangeForFrame.getMappedRange(),
+ classElement.getRetracedClass().getClassReference());
+ return retraceFrameResult.getRetracedMethod(
+ methodReference, mappedRangeForFrame, obfuscatedPosition);
}
@Override
- public RetraceStackTraceContext getContext() {
- // This will change when supporting outline frames.
- return RetraceStackTraceContext.empty();
+ public RetraceStackTraceContext getRetraceStackTraceContext() {
+ if (mappedRanges == null
+ || mappedRanges.isEmpty()
+ || !obfuscatedPosition.isPresent()
+ || !ListUtils.last(mappedRanges).getMappedRange().isOutlineFrame()) {
+ return RetraceStackTraceContext.empty();
+ }
+ return RetraceStackTraceContextImpl.builder().setRewritePosition(obfuscatedPosition).build();
+ }
+ }
+
+ private static class MappedRangeForFrame {
+
+ private final MappedRange mappedRange;
+ private final OptionalInt position;
+
+ private MappedRangeForFrame(MappedRange mappedRange, OptionalInt position) {
+ this.mappedRange = mappedRange;
+ this.position = position;
+ }
+
+ private MappedRange getMappedRange() {
+ return mappedRange;
+ }
+
+ private static MappedRangeForFrame create(MappedRange mappedRange) {
+ return create(
+ mappedRange,
+ mappedRange.originalRange == null || mappedRange.originalRange.span() != 1
+ ? OptionalInt.empty()
+ : OptionalInt.of(mappedRange.originalRange.from));
+ }
+
+ private static MappedRangeForFrame create(MappedRange mappedRange, OptionalInt position) {
+ return new MappedRangeForFrame(mappedRange, position);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java
index 978a933..60a6967 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRange;
import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRangesOfName;
+import com.android.tools.r8.naming.mappinginformation.OutlineCallsiteMappingInformation;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.retrace.RetraceMethodElement;
import com.android.tools.r8.retrace.RetraceMethodResult;
@@ -14,11 +15,13 @@
import com.android.tools.r8.retrace.RetracedMethodReference;
import com.android.tools.r8.retrace.RetracedSourceFile;
import com.android.tools.r8.retrace.internal.RetraceClassResultImpl.RetraceClassElementImpl;
+import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.Pair;
-import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.OptionalInt;
+import java.util.Set;
import java.util.stream.Stream;
public class RetraceMethodResultImpl implements RetraceMethodResult {
@@ -62,38 +65,69 @@
}
@Override
- public RetraceFrameResultImpl narrowByPosition(RetraceStackTraceContext context, int position) {
+ public boolean isEmpty() {
+ return mappedRanges == null || mappedRanges.isEmpty();
+ }
+
+ @Override
+ public RetraceFrameResultImpl narrowByPosition(
+ RetraceStackTraceContext context, OptionalInt position) {
List<Pair<RetraceClassElementImpl, List<MappedRange>>> narrowedRanges = new ArrayList<>();
- List<Pair<RetraceClassElementImpl, List<MappedRange>>> noMappingRanges = new ArrayList<>();
+ RetraceStackTraceContextImpl stackTraceContext = null;
+ if (context instanceof RetraceStackTraceContextImpl) {
+ stackTraceContext = (RetraceStackTraceContextImpl) context;
+ }
for (Pair<RetraceClassElementImpl, List<MappedRange>> mappedRange : mappedRanges) {
if (mappedRange.getSecond() == null) {
- noMappingRanges.add(new Pair<>(mappedRange.getFirst(), null));
+ narrowedRanges.add(new Pair<>(mappedRange.getFirst(), null));
continue;
}
- List<MappedRange> ranges =
- new MappedRangesOfName(mappedRange.getSecond()).allRangesForLine(position, false);
- boolean hasAddedRanges = false;
- if (!ranges.isEmpty()) {
- narrowedRanges.add(new Pair<>(mappedRange.getFirst(), ranges));
- hasAddedRanges = true;
- } else {
- narrowedRanges = new ArrayList<>();
- for (MappedRange mapped : mappedRange.getSecond()) {
- if (mapped.minifiedRange == null) {
- narrowedRanges.add(new Pair<>(mappedRange.getFirst(), ImmutableList.of(mapped)));
- hasAddedRanges = true;
+ MappedRangesOfName mappedRangesOfElement = new MappedRangesOfName(mappedRange.getSecond());
+ List<MappedRange> mappedRangesForPosition = null;
+ boolean hasPosition = position.isPresent() && position.getAsInt() >= 0;
+ if (hasPosition) {
+ mappedRangesForPosition =
+ mappedRangesOfElement.allRangesForLine(position.getAsInt(), false);
+ }
+ if (mappedRangesForPosition == null || mappedRangesForPosition.isEmpty()) {
+ mappedRangesForPosition =
+ hasPosition
+ ? ListUtils.filter(
+ mappedRangesOfElement.getMappedRanges(), range -> range.minifiedRange == null)
+ : mappedRangesOfElement.getMappedRanges();
+ }
+ if (mappedRangesForPosition != null && !mappedRangesForPosition.isEmpty()) {
+ if (stackTraceContext != null && stackTraceContext.hasRewritePosition()) {
+ List<OutlineCallsiteMappingInformation> outlineCallsiteInformation =
+ ListUtils.last(mappedRangesForPosition).getOutlineCallsiteInformation();
+ if (!outlineCallsiteInformation.isEmpty()) {
+ assert outlineCallsiteInformation.size() == 1
+ : "There can only be one outline entry for a line";
+ return narrowByPosition(
+ stackTraceContext.buildFromThis().clearRewritePosition().build(),
+ OptionalInt.of(
+ outlineCallsiteInformation
+ .get(0)
+ .rewritePosition(stackTraceContext.getRewritePosition())));
}
}
- }
- if (!hasAddedRanges) {
- narrowedRanges.add(new Pair<>(mappedRange.getFirst(), null));
+ // Mapped ranges can have references to overloaded signatures. We distinguish those by
+ // looking at the cardinal mapping range.
+ for (MappedRange mappedRangeForPosition : mappedRangesForPosition) {
+ if (narrowedRanges.isEmpty()
+ || mappedRangeForPosition.originalRange == null
+ || !mappedRangeForPosition.originalRange.isCardinal) {
+ narrowedRanges.add(new Pair<>(mappedRange.getFirst(), new ArrayList<>()));
+ }
+ ListUtils.last(narrowedRanges).getSecond().add(mappedRangeForPosition);
+ }
}
}
return new RetraceFrameResultImpl(
classResult,
- narrowedRanges.isEmpty() ? noMappingRanges : narrowedRanges,
+ narrowedRanges,
methodDefinition,
- OptionalInt.of(position),
+ position,
retracer,
(RetraceStackTraceContextImpl) context);
}
@@ -114,17 +148,19 @@
methodDefinition.substituteHolder(
classElement.getRetracedClass().getClassReference()))));
}
- return mappedRanges.stream()
- .map(
- mappedRange -> {
- MethodReference methodReference =
- RetraceUtils.methodReferenceFromMappedRange(
- mappedRange, classElement.getRetracedClass().getClassReference());
- return new ElementImpl(
- this,
- classElement,
- RetracedMethodReferenceImpl.create(methodReference));
- });
+ List<ElementImpl> results = new ArrayList<>();
+ Set<MethodReference> seenMethodReferences = new HashSet<>();
+ for (MappedRange mappedRange : mappedRanges) {
+ MethodReference methodReference =
+ RetraceUtils.methodReferenceFromMappedRange(
+ mappedRange, classElement.getRetracedClass().getClassReference());
+ if (seenMethodReferences.add(methodReference)) {
+ results.add(
+ new ElementImpl(
+ this, classElement, RetracedMethodReferenceImpl.create(methodReference)));
+ }
+ }
+ return results.stream();
});
}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceContextImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceContextImpl.java
index 31533d4..94e2d31 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceContextImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceContextImpl.java
@@ -12,20 +12,24 @@
import com.android.tools.r8.retrace.RetraceStackTraceContext;
import com.android.tools.r8.utils.ListUtils;
import java.util.List;
+import java.util.OptionalInt;
public class RetraceStackTraceContextImpl implements RetraceStackTraceContext {
private final ClassReference thrownException;
+ private final OptionalInt rewritePosition;
- private RetraceStackTraceContextImpl(ClassReference thrownException) {
+ private RetraceStackTraceContextImpl(
+ ClassReference thrownException, OptionalInt rewritePosition) {
this.thrownException = thrownException;
+ this.rewritePosition = rewritePosition;
}
public ClassReference getThrownException() {
return thrownException;
}
- RetraceStackTraceCurrentEvaluationInformation computeRewritingInformation(
+ RetraceStackTraceCurrentEvaluationInformation computeRewriteFrameInformation(
List<MappedRange> mappedRanges) {
if (mappedRanges == null || mappedRanges.isEmpty()) {
return RetraceStackTraceCurrentEvaluationInformation.empty();
@@ -44,6 +48,14 @@
return builder.build();
}
+ public boolean hasRewritePosition() {
+ return rewritePosition.isPresent();
+ }
+
+ public int getRewritePosition() {
+ return rewritePosition.getAsInt();
+ }
+
private boolean evaluateConditions(List<Condition> conditions) {
for (Condition condition : conditions) {
if (!condition.evaluate(this)) {
@@ -57,9 +69,14 @@
return Builder.create();
}
+ public Builder buildFromThis() {
+ return builder().setThrownException(thrownException).setRewritePosition(rewritePosition);
+ }
+
public static class Builder {
private ClassReference thrownException;
+ private OptionalInt rewritePosition = OptionalInt.empty();
private Builder() {}
@@ -68,8 +85,18 @@
return this;
}
+ public Builder setRewritePosition(OptionalInt rewritePosition) {
+ this.rewritePosition = rewritePosition;
+ return this;
+ }
+
+ public Builder clearRewritePosition() {
+ this.rewritePosition = OptionalInt.empty();
+ return this;
+ }
+
public RetraceStackTraceContextImpl build() {
- return new RetraceStackTraceContextImpl(thrownException);
+ return new RetraceStackTraceContextImpl(thrownException, rewritePosition);
}
public static Builder create() {
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceCurrentEvaluationInformation.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceCurrentEvaluationInformation.java
index b25454f..275b72e 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceCurrentEvaluationInformation.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceCurrentEvaluationInformation.java
@@ -9,14 +9,14 @@
private static final RetraceStackTraceCurrentEvaluationInformation EMPTY =
new RetraceStackTraceCurrentEvaluationInformation(0);
- private final int removeInnerFrames;
+ private final int removeInnerFramesCount;
- private RetraceStackTraceCurrentEvaluationInformation(int removeInnerFrames) {
- this.removeInnerFrames = removeInnerFrames;
+ private RetraceStackTraceCurrentEvaluationInformation(int removeInnerFramesCount) {
+ this.removeInnerFramesCount = removeInnerFramesCount;
}
- public int getRemoveInnerFrames() {
- return removeInnerFrames;
+ public int getRemoveInnerFramesCount() {
+ return removeInnerFramesCount;
}
public static RetraceStackTraceCurrentEvaluationInformation empty() {
@@ -30,12 +30,22 @@
public static class Builder {
private int removeInnerFramesCount;
+ private int position;
public Builder incrementRemoveInnerFramesCount(int increment) {
removeInnerFramesCount += increment;
return this;
}
+ public int getPosition() {
+ return position;
+ }
+
+ public Builder setPosition(int position) {
+ this.position = position;
+ return this;
+ }
+
RetraceStackTraceCurrentEvaluationInformation build() {
return new RetraceStackTraceCurrentEvaluationInformation(removeInnerFramesCount);
}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceElementProxyResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceElementProxyResultImpl.java
new file mode 100644
index 0000000..1317d9f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceElementProxyResultImpl.java
@@ -0,0 +1,67 @@
+// Copyright (c) 2021, 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.retrace.internal;
+
+import com.android.tools.r8.retrace.RetraceStackTraceContext;
+import com.android.tools.r8.retrace.RetraceStackTraceElementProxyResult;
+import com.android.tools.r8.retrace.StackTraceElementProxy;
+import com.android.tools.r8.retrace.internal.StackTraceElementProxyRetracerImpl.RetraceStackTraceElementProxyImpl;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+public class RetraceStackTraceElementProxyResultImpl<T, ST extends StackTraceElementProxy<T, ST>>
+ implements RetraceStackTraceElementProxyResult<T, ST> {
+
+ private final Stream<? extends RetraceStackTraceElementProxyImpl<T, ST>> resultStream;
+ private final Supplier<RetraceStackTraceContext> resultContext;
+
+ private RetraceStackTraceElementProxyResultImpl(
+ Stream<? extends RetraceStackTraceElementProxyImpl<T, ST>> resultStream,
+ Supplier<RetraceStackTraceContext> resultContext) {
+ this.resultStream = resultStream;
+ this.resultContext = resultContext;
+ }
+
+ @Override
+ public Stream<? extends RetraceStackTraceElementProxyImpl<T, ST>> stream() {
+ return resultStream;
+ }
+
+ @Override
+ public RetraceStackTraceContext getResultContext() {
+ return resultContext.get();
+ }
+
+ Builder<T, ST> builder() {
+ return Builder.<T, ST>create().setResultStream(resultStream).setResultContext(resultContext);
+ }
+
+ static class Builder<T, ST extends StackTraceElementProxy<T, ST>> {
+
+ Stream<? extends RetraceStackTraceElementProxyImpl<T, ST>> resultStream;
+ Supplier<RetraceStackTraceContext> resultContext;
+
+ private Builder() {}
+
+ Builder<T, ST> setResultStream(
+ Stream<? extends RetraceStackTraceElementProxyImpl<T, ST>> resultStream) {
+ this.resultStream = resultStream;
+ return this;
+ }
+
+ Builder<T, ST> setResultContext(Supplier<RetraceStackTraceContext> resultContext) {
+ this.resultContext = resultContext;
+ return this;
+ }
+
+ RetraceStackTraceElementProxyResultImpl<T, ST> build() {
+ return new RetraceStackTraceElementProxyResultImpl<>(resultStream, resultContext);
+ }
+
+ static <T, ST extends StackTraceElementProxy<T, ST>> Builder<T, ST> create() {
+ return new Builder<>();
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceThrownExceptionResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceThrownExceptionResultImpl.java
index aa2c1f0..bb49d70 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceThrownExceptionResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceThrownExceptionResultImpl.java
@@ -34,6 +34,11 @@
return Stream.of(createElement());
}
+ @Override
+ public boolean isEmpty() {
+ return obfuscatedReference == null;
+ }
+
private RetraceThrownExceptionElement createElement() {
return new RetraceThrownExceptionElementImpl(
this,
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetracedMethodReferenceImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetracedMethodReferenceImpl.java
index 49061b2..f896692 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetracedMethodReferenceImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetracedMethodReferenceImpl.java
@@ -12,10 +12,10 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;
+import java.util.OptionalInt;
public abstract class RetracedMethodReferenceImpl implements RetracedMethodReference {
- private static final int NO_POSITION = -1;
private static final Comparator<RetracedMethodReference> comparator =
Comparator.comparing(RetracedMethodReference::getMethodName)
.thenComparing(RetracedMethodReference::isKnown)
@@ -34,7 +34,21 @@
ComparatorUtils.listComparator(
Comparator.comparing(TypeReference::getTypeName))));
- private RetracedMethodReferenceImpl() {}
+ protected final OptionalInt position;
+
+ private RetracedMethodReferenceImpl(OptionalInt position) {
+ this.position = position;
+ }
+
+ @Override
+ public boolean hasPosition() {
+ return position.isPresent();
+ }
+
+ @Override
+ public int getOriginalPositionOrDefault(int defaultPosition) {
+ return position.orElse(defaultPosition);
+ }
@Override
public boolean isUnknown() {
@@ -60,12 +74,12 @@
implements KnownRetracedMethodReference {
private final MethodReference methodReference;
- private final int position;
- private KnownRetracedMethodReferenceImpl(MethodReference methodReference, int position) {
+ private KnownRetracedMethodReferenceImpl(
+ MethodReference methodReference, OptionalInt position) {
+ super(position);
assert methodReference != null;
this.methodReference = methodReference;
- this.position = position;
}
@Override
@@ -94,16 +108,6 @@
}
@Override
- public boolean hasPosition() {
- return position != NO_POSITION;
- }
-
- @Override
- public int getOriginalPositionOrDefault(int defaultPosition) {
- return hasPosition() ? position : defaultPosition;
- }
-
- @Override
public TypeReference getReturnType() {
assert !isVoid();
return methodReference.getReturnType();
@@ -140,11 +144,11 @@
public static final class UnknownRetracedMethodReferenceImpl extends RetracedMethodReferenceImpl {
private final MethodDefinition methodDefinition;
- private final int position;
- private UnknownRetracedMethodReferenceImpl(MethodDefinition methodDefinition, int position) {
+ private UnknownRetracedMethodReferenceImpl(
+ MethodDefinition methodDefinition, OptionalInt position) {
+ super(position);
this.methodDefinition = methodDefinition;
- this.position = position;
}
@Override
@@ -157,16 +161,6 @@
return methodDefinition.getName();
}
- @Override
- public boolean hasPosition() {
- return position != NO_POSITION;
- }
-
- @Override
- public int getOriginalPositionOrDefault(int defaultPosition) {
- return hasPosition() ? position : defaultPosition;
- }
-
public Optional<MethodReference> getMethodReference() {
if (!methodDefinition.isFullMethodDefinition()) {
return Optional.empty();
@@ -176,22 +170,19 @@
}
static RetracedMethodReferenceImpl create(MethodDefinition methodDefinition) {
- return create(methodDefinition, NO_POSITION);
+ if (methodDefinition.isFullMethodDefinition()) {
+ return create(
+ methodDefinition.asFullMethodDefinition().getMethodReference(), OptionalInt.empty());
+ }
+ return new UnknownRetracedMethodReferenceImpl(methodDefinition, OptionalInt.empty());
}
- static RetracedMethodReferenceImpl create(MethodDefinition methodDefinition, int position) {
- if (methodDefinition.isFullMethodDefinition()) {
- return new KnownRetracedMethodReferenceImpl(
- methodDefinition.asFullMethodDefinition().getMethodReference(), position);
- }
- return new UnknownRetracedMethodReferenceImpl(methodDefinition, position);
- }
static RetracedMethodReferenceImpl create(MethodReference methodReference) {
- return create(methodReference, NO_POSITION);
+ return create(methodReference, OptionalInt.empty());
}
- static RetracedMethodReferenceImpl create(MethodReference methodReference, int position) {
+ static RetracedMethodReferenceImpl create(MethodReference methodReference, OptionalInt position) {
return new KnownRetracedMethodReferenceImpl(methodReference, position);
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetracerImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetracerImpl.java
index 9aadbb3..563de26 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetracerImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetracerImpl.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.retrace.RetraceStackTraceContext;
import com.android.tools.r8.retrace.Retracer;
import java.io.BufferedReader;
+import java.util.OptionalInt;
/** A default implementation for the retrace api using the ClassNameMapper defined in R8. */
public class RetracerImpl implements Retracer {
@@ -62,13 +63,13 @@
}
@Override
- public RetraceFrameResult retraceFrame(MethodReference methodReference, int position) {
+ public RetraceFrameResult retraceFrame(MethodReference methodReference, OptionalInt position) {
return retraceFrame(methodReference, position, RetraceStackTraceContext.empty());
}
@Override
public RetraceFrameResult retraceFrame(
- MethodReference methodReference, int position, RetraceStackTraceContext context) {
+ MethodReference methodReference, OptionalInt position, RetraceStackTraceContext context) {
return retraceClass(methodReference.getHolderClass())
.lookupMethod(methodReference.getMethodName())
.narrowByPosition(context, position);
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java
index 8040744..987aead 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java
@@ -7,26 +7,33 @@
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.references.TypeReference;
import com.android.tools.r8.retrace.RetraceClassResult;
+import com.android.tools.r8.retrace.RetraceFieldElement;
import com.android.tools.r8.retrace.RetraceFieldResult;
+import com.android.tools.r8.retrace.RetraceFrameElement;
import com.android.tools.r8.retrace.RetraceFrameResult;
import com.android.tools.r8.retrace.RetraceStackTraceContext;
import com.android.tools.r8.retrace.RetraceStackTraceElementProxy;
+import com.android.tools.r8.retrace.RetraceStackTraceElementProxyResult;
+import com.android.tools.r8.retrace.RetraceThrownExceptionElement;
import com.android.tools.r8.retrace.RetraceTypeResult;
import com.android.tools.r8.retrace.RetraceTypeResult.Element;
import com.android.tools.r8.retrace.RetracedClassReference;
import com.android.tools.r8.retrace.RetracedFieldReference;
import com.android.tools.r8.retrace.RetracedMethodReference;
+import com.android.tools.r8.retrace.RetracedSingleFrame;
import com.android.tools.r8.retrace.RetracedSourceFile;
import com.android.tools.r8.retrace.RetracedTypeReference;
import com.android.tools.r8.retrace.Retracer;
import com.android.tools.r8.retrace.StackTraceElementProxy;
import com.android.tools.r8.retrace.StackTraceElementProxyRetracer;
+import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.ListUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.OptionalInt;
import java.util.function.Consumer;
+import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -40,185 +47,259 @@
}
@Override
- public Stream<? extends RetraceStackTraceElementProxy<T, ST>> retrace(
+ public RetraceStackTraceElementProxyResult<T, ST> retrace(
ST element, RetraceStackTraceContext context) {
- Stream<RetraceStackTraceElementProxyImpl<T, ST>> currentResults =
- Stream.of(RetraceStackTraceElementProxyImpl.create(element, context));
+ RetraceStackTraceElementProxyResultImpl<T, ST> currentResult =
+ RetraceStackTraceElementProxyResultImpl.Builder.<T, ST>create()
+ .setResultStream(Stream.of(RetraceStackTraceElementProxyImpl.create(element, context)))
+ .setResultContext(RetraceStackTraceContext::empty)
+ .build();
if (!element.hasClassName()
&& !element.hasFieldOrReturnType()
&& !element.hasMethodArguments()) {
- return currentResults;
+ return currentResult;
}
- currentResults = retraceFieldOrReturnType(currentResults, element);
- currentResults = retracedMethodArguments(currentResults, element);
+ currentResult = retraceFieldOrReturnType(currentResult, element);
+ currentResult = retracedMethodArguments(currentResult, element);
if (element.hasClassName()) {
RetraceClassResult classResult = retracer.retraceClass(element.getClassReference());
if (element.hasMethodName()) {
- currentResults = retraceMethod(currentResults, element, classResult);
+ currentResult = retraceMethod(currentResult, element, classResult, context);
} else if (element.hasFieldName()) {
- currentResults = retraceField(currentResults, element, classResult);
+ currentResult = retraceField(currentResult, element, classResult);
} else {
- currentResults = retraceClassOrType(currentResults, element, classResult);
+ currentResult = retraceClassOrType(currentResult, classResult);
}
}
- return currentResults;
+ return currentResult;
}
- private Stream<RetraceStackTraceElementProxyImpl<T, ST>> retraceClassOrType(
- Stream<RetraceStackTraceElementProxyImpl<T, ST>> currentResults,
- ST element,
+ private RetraceStackTraceElementProxyResultImpl<T, ST> retraceClassOrType(
+ RetraceStackTraceElementProxyResultImpl<T, ST> currentResult,
RetraceClassResult classResult) {
- return currentResults.flatMap(
- proxy ->
- // We assume, since no method was defined for this stack trace element, that this was a
- // thrown exception.
- classResult.lookupThrownException(proxy.getContext()).stream()
- .map(
- thrownExceptionElement ->
- proxy
- .builder()
- .setRetracedClass(thrownExceptionElement.getRetracedClass())
- .joinAmbiguous(classResult.isAmbiguous())
- .setTopFrame(true)
- .setContext(thrownExceptionElement.getContext())
- .applyIf(
- element.hasSourceFile(),
- builder -> {
- RetracedSourceFile sourceFile =
- thrownExceptionElement.getSourceFile();
- builder.setSourceFile(
- sourceFile.hasRetraceResult()
- ? sourceFile.getSourceFile()
- : RetraceUtils.inferSourceFile(
- thrownExceptionElement
- .getRetracedClass()
- .getTypeName(),
- element.getSourceFile(),
- classResult.hasRetraceResult()));
- })
- .build()));
+ return currentResult
+ .builder()
+ .setResultStream(
+ currentResult.stream()
+ .flatMap(
+ proxy ->
+ // We assume, since no method was defined for this stack trace element, that
+ // this was a thrown exception.
+ classResult.lookupThrownException(proxy.getContext()).stream()
+ .map(
+ thrownExceptionElement ->
+ buildProxyForRewrittenThrownExceptionElement(
+ classResult, proxy, thrownExceptionElement))))
+ .build();
}
- private Stream<RetraceStackTraceElementProxyImpl<T, ST>> retraceMethod(
- Stream<RetraceStackTraceElementProxyImpl<T, ST>> currentResults,
+ private RetraceStackTraceElementProxyImpl<T, ST> buildProxyForRewrittenThrownExceptionElement(
+ RetraceClassResult classResult,
+ RetraceStackTraceElementProxyImpl<T, ST> proxy,
+ RetraceThrownExceptionElement thrownExceptionElement) {
+ return proxy
+ .builder()
+ .setRetracedClass(thrownExceptionElement.getRetracedClass())
+ .joinAmbiguous(classResult.isAmbiguous())
+ .setTopFrame(true)
+ .setContext(thrownExceptionElement.getContext())
+ .apply(
+ setSourceFileOnProxy(
+ thrownExceptionElement::getSourceFile,
+ thrownExceptionElement.getRetracedClass(),
+ classResult))
+ .build();
+ }
+
+ private RetraceStackTraceElementProxyResultImpl<T, ST> retraceMethod(
+ RetraceStackTraceElementProxyResultImpl<T, ST> currentResult,
+ ST element,
+ RetraceClassResult classResult,
+ RetraceStackTraceContext context) {
+ Box<RetraceStackTraceContext> resultingContext = new Box<>(RetraceStackTraceContext.empty());
+ RetraceStackTraceElementProxyResultImpl.Builder<T, ST> resultBuilder =
+ currentResult.builder().setResultContext(resultingContext::get);
+ return resultBuilder
+ .setResultStream(
+ currentResult.stream()
+ .flatMap(
+ proxy -> {
+ RetraceFrameResult frameResult =
+ classResult.lookupFrame(
+ context,
+ element.hasLineNumber()
+ ? OptionalInt.of(element.getLineNumber())
+ : OptionalInt.empty(),
+ element.getMethodName());
+ if (!frameResult.isEmpty()) {
+ return classResult.stream()
+ .map(
+ classElement ->
+ proxy
+ .builder()
+ .setTopFrame(true)
+ .joinAmbiguous(classResult.isAmbiguous())
+ .setRetracedClass(classElement.getRetracedClass())
+ .applyIf(
+ element.hasLineNumber(),
+ b -> b.setLineNumber(element.getLineNumber()))
+ .apply(
+ setSourceFileOnProxy(
+ classElement::getSourceFile,
+ classElement.getRetracedClass(),
+ classResult))
+ .build());
+ }
+ return frameResult.stream()
+ .flatMap(
+ frameElement -> {
+ resultingContext.set(frameElement.getRetraceStackTraceContext());
+ return frameElement
+ .streamRewritten(context)
+ .map(
+ singleFrame ->
+ buildProxyForRewrittenFrameElement(
+ element,
+ classResult,
+ proxy,
+ frameResult,
+ frameElement,
+ singleFrame));
+ });
+ }))
+ .build();
+ }
+
+ private RetraceStackTraceElementProxyImpl<T, ST> buildProxyForRewrittenFrameElement(
+ ST element,
+ RetraceClassResult classResult,
+ RetraceStackTraceElementProxyImpl<T, ST> proxy,
+ RetraceFrameResult frameResult,
+ RetraceFrameElement frameElement,
+ RetracedSingleFrame singleFrame) {
+ boolean isTopFrame = singleFrame.getIndex() == 0;
+ RetracedMethodReference method = singleFrame.getMethodReference();
+ return proxy
+ .builder()
+ .setRetracedClass(method.getHolderClass())
+ .setRetracedMethod(method)
+ .joinAmbiguous(frameResult.isAmbiguous())
+ .setTopFrame(isTopFrame)
+ .setContext(frameElement.getRetraceStackTraceContext())
+ .applyIf(
+ element.hasLineNumber(),
+ builder -> {
+ builder.setLineNumber(method.getOriginalPositionOrDefault(element.getLineNumber()));
+ })
+ .apply(
+ setSourceFileOnProxy(
+ () -> frameElement.getSourceFile(method), method.getHolderClass(), classResult))
+ .build();
+ }
+
+ private RetraceStackTraceElementProxyResultImpl<T, ST> retraceField(
+ RetraceStackTraceElementProxyResultImpl<T, ST> currentResult,
ST element,
RetraceClassResult classResult) {
- return currentResults.flatMap(
- proxy -> {
- RetraceFrameResult frameResult =
- classResult.lookupFrame(
- proxy.context,
- element.hasLineNumber()
- ? OptionalInt.of(element.getLineNumber())
- : OptionalInt.empty(),
- element.getMethodName());
- return frameResult.stream()
- .flatMap(
- frameElement ->
- frameElement
- .streamRewritten(proxy.getContext())
+ return currentResult
+ .builder()
+ .setResultStream(
+ currentResult.stream()
+ .flatMap(
+ proxy -> {
+ RetraceFieldResult retraceFieldResult =
+ classResult.lookupField(element.getFieldName());
+ return retraceFieldResult.stream()
.map(
- singleFrame -> {
- boolean isTopFrame = singleFrame.getIndex() == 0;
- RetracedMethodReference method = singleFrame.getMethodReference();
- return proxy
- .builder()
- .setRetracedClass(method.getHolderClass())
- .setRetracedMethod(method)
- .joinAmbiguous(frameResult.isAmbiguous() && isTopFrame)
- .setTopFrame(isTopFrame)
- .setContext(frameElement.getContext())
- .applyIf(
- element.hasLineNumber(),
- builder -> {
- builder.setLineNumber(
- method.getOriginalPositionOrDefault(
- element.getLineNumber()));
- })
- .applyIf(
- element.hasSourceFile(),
- builder -> {
- RetracedSourceFile sourceFileResult =
- frameElement.getSourceFile(method);
- builder.setSourceFile(
- sourceFileResult.hasRetraceResult()
- ? sourceFileResult.getSourceFile()
- : RetraceUtils.inferSourceFile(
- method.getHolderClass().getTypeName(),
- element.getSourceFile(),
- classResult.hasRetraceResult()));
- })
- .build();
- }));
- });
+ fieldElement ->
+ buildProxyForRewrittenFieldElement(
+ classResult, proxy, retraceFieldResult, fieldElement));
+ }))
+ .build();
}
- private Stream<RetraceStackTraceElementProxyImpl<T, ST>> retraceField(
- Stream<RetraceStackTraceElementProxyImpl<T, ST>> currentResults,
- ST element,
+ private RetraceStackTraceElementProxyImpl<T, ST> buildProxyForRewrittenFieldElement(
+ RetraceClassResult classResult,
+ RetraceStackTraceElementProxyImpl<T, ST> proxy,
+ RetraceFieldResult retraceFieldResult,
+ RetraceFieldElement fieldElement) {
+ return proxy
+ .builder()
+ .setRetracedClass(fieldElement.getField().getHolderClass())
+ .setRetracedField(fieldElement.getField())
+ .joinAmbiguous(retraceFieldResult.isAmbiguous())
+ .setTopFrame(true)
+ .apply(
+ setSourceFileOnProxy(
+ fieldElement::getSourceFile, fieldElement.getField().getHolderClass(), classResult))
+ .build();
+ }
+
+ private Consumer<RetraceStackTraceElementProxyImpl.Builder<T, ST>> setSourceFileOnProxy(
+ Supplier<RetracedSourceFile> sourceFile,
+ RetracedClassReference classReference,
RetraceClassResult classResult) {
- return currentResults.flatMap(
- proxy -> {
- RetraceFieldResult retraceFieldResult = classResult.lookupField(element.getFieldName());
- return retraceFieldResult.stream()
- .map(
- fieldElement ->
- proxy
- .builder()
- .setRetracedClass(fieldElement.getField().getHolderClass())
- .setRetracedField(fieldElement.getField())
- .joinAmbiguous(retraceFieldResult.isAmbiguous())
- .setTopFrame(true)
- .applyIf(
- element.hasSourceFile(),
- builder -> {
- RetracedSourceFile sourceFile = fieldElement.getSourceFile();
- builder.setSourceFile(
- sourceFile.hasRetraceResult()
- ? sourceFile.getSourceFile()
- : RetraceUtils.inferSourceFile(
- fieldElement.getField().getHolderClass().getTypeName(),
- element.getSourceFile(),
- classResult.hasRetraceResult()));
- })
- .build());
- });
+ return proxy -> {
+ ST original = proxy.originalElement;
+ if (!original.hasSourceFile()) {
+ return;
+ }
+ RetracedSourceFile retracedSourceFile = sourceFile.get();
+ proxy.setSourceFile(
+ retracedSourceFile.hasRetraceResult()
+ ? retracedSourceFile.getSourceFile()
+ : RetraceUtils.inferSourceFile(
+ classReference.getTypeName(), original.getSourceFile(), classResult.isEmpty()));
+ };
}
- private Stream<RetraceStackTraceElementProxyImpl<T, ST>> retraceFieldOrReturnType(
- Stream<RetraceStackTraceElementProxyImpl<T, ST>> currentResults, ST element) {
+ private RetraceStackTraceElementProxyResultImpl<T, ST> retraceFieldOrReturnType(
+ RetraceStackTraceElementProxyResultImpl<T, ST> currentResult, ST element) {
if (!element.hasFieldOrReturnType()) {
- return currentResults;
+ return currentResult;
}
+ RetraceStackTraceElementProxyResultImpl.Builder<T, ST> resultBuilder = currentResult.builder();
String elementOrReturnType = element.getFieldOrReturnType();
if (elementOrReturnType.equals("void")) {
- return currentResults.map(
- proxy ->
- proxy
- .builder()
- .setRetracedFieldOrReturnType(RetracedTypeReferenceImpl.createVoid())
- .build());
+ return resultBuilder
+ .setResultStream(
+ currentResult.stream()
+ .map(
+ proxy ->
+ buildProxyForRewrittenReturnType(
+ proxy, RetracedTypeReferenceImpl.createVoid(), proxy.isAmbiguous())))
+ .build();
} else {
TypeReference typeReference = Reference.typeFromTypeName(elementOrReturnType);
RetraceTypeResult retraceTypeResult = retracer.retraceType(typeReference);
List<Element> retracedElements = retraceTypeResult.stream().collect(Collectors.toList());
- return currentResults.flatMap(
- proxy ->
- retracedElements.stream()
- .map(
- retracedResult ->
- proxy
- .builder()
- .setRetracedFieldOrReturnType(retracedResult.getType())
- .joinAmbiguous(retraceTypeResult.isAmbiguous())
- .build()));
+ return resultBuilder
+ .setResultStream(
+ currentResult.stream()
+ .flatMap(
+ proxy ->
+ retracedElements.stream()
+ .map(
+ retracedResult ->
+ buildProxyForRewrittenReturnType(
+ proxy,
+ retracedResult.getType(),
+ retraceTypeResult.isAmbiguous()))))
+ .build();
}
}
- private Stream<RetraceStackTraceElementProxyImpl<T, ST>> retracedMethodArguments(
- Stream<RetraceStackTraceElementProxyImpl<T, ST>> currentResults, ST element) {
+ private RetraceStackTraceElementProxyImpl<T, ST> buildProxyForRewrittenReturnType(
+ RetraceStackTraceElementProxyImpl<T, ST> proxy,
+ RetracedTypeReference type,
+ boolean isAmbiguous) {
+ return proxy.builder().setRetracedFieldOrReturnType(type).joinAmbiguous(isAmbiguous).build();
+ }
+
+ private RetraceStackTraceElementProxyResultImpl<T, ST> retracedMethodArguments(
+ RetraceStackTraceElementProxyResultImpl<T, ST> currentResult, ST element) {
if (!element.hasMethodArguments()) {
- return currentResults;
+ return currentResult;
}
List<RetraceTypeResult> retracedResults =
Arrays.stream(element.getMethodArguments().split(","))
@@ -243,19 +324,24 @@
return newResult;
});
boolean isAmbiguous = allRetracedArguments.size() > 1;
- return currentResults.flatMap(
- proxy ->
- allRetracedArguments.stream()
- .map(
- retracedArguments ->
- proxy
- .builder()
- .setRetracedMethodArguments(retracedArguments)
- .joinAmbiguous(isAmbiguous)
- .build()));
+ return currentResult
+ .builder()
+ .setResultStream(
+ currentResult.stream()
+ .flatMap(
+ proxy ->
+ allRetracedArguments.stream()
+ .map(
+ retracedArguments ->
+ proxy
+ .builder()
+ .setRetracedMethodArguments(retracedArguments)
+ .joinAmbiguous(isAmbiguous)
+ .build())))
+ .build();
}
- public static class RetraceStackTraceElementProxyImpl<T, ST extends StackTraceElementProxy<T, ST>>
+ static class RetraceStackTraceElementProxyImpl<T, ST extends StackTraceElementProxy<T, ST>>
implements RetraceStackTraceElementProxy<T, ST> {
private final ST originalItem;
@@ -383,7 +469,7 @@
originalItem, null, null, null, null, null, null, -1, false, false, context);
}
- private Builder<T, ST> builder() {
+ Builder<T, ST> builder() {
Builder<T, ST> builder = new Builder<>(originalItem);
builder.classContext = retracedClass;
builder.methodContext = retracedMethod;
@@ -522,6 +608,11 @@
return this;
}
+ private Builder<T, ST> apply(Consumer<Builder<T, ST>> consumer) {
+ consumer.accept(this);
+ return this;
+ }
+
private Builder<T, ST> applyIf(boolean condition, Consumer<Builder<T, ST>> consumer) {
if (condition) {
consumer.accept(this);
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementStringProxy.java b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementStringProxy.java
index fc195d0..b01f4ea 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementStringProxy.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementStringProxy.java
@@ -237,10 +237,16 @@
new StringIndex(
startIndex,
endIndex,
- (retraced, original, verbose) ->
- (retraced.hasLineNumber()
- ? ((insertSeparatorForRetraced ? ":" : "") + retraced.getLineNumber())
- : original.lineNumberAsString()));
+ (retraced, original, verbose) -> {
+ boolean printLineNumber =
+ retraced.hasLineNumber()
+ && ((original.hasLineNumber() && original.getLineNumber() > -1)
+ || !retraced.isAmbiguous()
+ || verbose);
+ return printLineNumber
+ ? ((insertSeparatorForRetraced ? ":" : "") + retraced.getLineNumber())
+ : original.lineNumberAsString();
+ });
orderedIndices.add(lineNumber);
return this;
}
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index b5235d2..9449f1b 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1203,6 +1203,9 @@
// See b/191469661 for why this is here.
public boolean noCfMarkerForDesugaredCode =
System.getProperty("com.android.tools.r8.noCfMarkerForDesugaredCode") != null;
+ // See b/182065081 for why this is here.
+ public boolean lambdaClassFieldsFinal =
+ System.getProperty("com.android.tools.r8.lambdaClassFieldsNotFinal") == null;
}
public class CallSiteOptimizationOptions {
diff --git a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
index 48af35f..44ab3fc 100644
--- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -106,8 +106,11 @@
}
Position newPosition =
- new Position(nextOptimizedLineNumber, position.file, position.method, null);
- ++nextOptimizedLineNumber;
+ position
+ .builderWithCopy()
+ .setLine(nextOptimizedLineNumber++)
+ .setCallerPosition(null)
+ .build();
previousSourceLine = position.line;
previousMethod = position.method;
return new Pair<>(position, newPosition);
@@ -180,14 +183,17 @@
if (calleePosition != null) {
// Take the first line as the callee position
position =
- new Position(
- calleePosition.getValue().getRange().from,
- position.file,
- position.method,
- position.callerPosition);
+ position
+ .builderWithCopy()
+ .setLine(calleePosition.getValue().getRange().from)
+ .build();
}
return baseRemapper.createRemappedPosition(
- new Position(originalInlineeLine, null, inlinee, position));
+ Position.builder()
+ .setLine(originalInlineeLine)
+ .setMethod(inlinee)
+ .setCallerPosition(position)
+ .build());
}
// This is the same position, so we should really not mark this as an inline position. Fall
// through to the default case.
@@ -244,7 +250,8 @@
private void emitPositionEvents(int currentPc, Position currentPosition) {
if (previousPosition == null) {
startLine = currentPosition.line;
- previousPosition = new Position(startLine, null, method, null);
+ previousPosition =
+ Position.builder().setLine(startLine).setFile(null).setMethod(method).build();
}
DexDebugEventBuilder.emitAdvancementEvents(
previousPc,
@@ -702,11 +709,12 @@
super.visit(defaultEvent);
assert getCurrentLine() >= 0;
Position position =
- new Position(
- getCurrentLine(),
- getCurrentFile(),
- getCurrentMethod(),
- getCurrentCallerPosition());
+ Position.builder()
+ .setLine(getCurrentLine())
+ .setFile(getCurrentFile())
+ .setMethod(getCurrentMethod())
+ .setCallerPosition(getCurrentCallerPosition())
+ .build();
Position currentPosition = remapAndAdd(position, positionRemapper, mappedPositions);
positionEventEmitter.emitPositionEvents(getCurrentPc(), currentPosition);
if (currentPosition != position) {
@@ -801,11 +809,12 @@
}
lastPosition.setFirst(getCurrentPc());
lastPosition.setSecond(
- new Position(
- getCurrentLine(),
- getCurrentFile(),
- getCurrentMethod(),
- getCurrentCallerPosition()));
+ Position.builder()
+ .setLine(getCurrentLine())
+ .setFile(getCurrentFile())
+ .setMethod(getCurrentMethod())
+ .setCallerPosition(getCurrentCallerPosition())
+ .build());
}
};
diff --git a/src/main/java/com/android/tools/r8/utils/OptionalUtils.java b/src/main/java/com/android/tools/r8/utils/OptionalUtils.java
new file mode 100644
index 0000000..974bf0c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/OptionalUtils.java
@@ -0,0 +1,19 @@
+// Copyright (c) 2021, 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;
+
+import java.util.OptionalInt;
+import java.util.function.Supplier;
+
+public class OptionalUtils {
+
+ public static OptionalInt orElse(OptionalInt optional, int orElse) {
+ return optional.isPresent() ? optional : OptionalInt.of(orElse);
+ }
+
+ public static OptionalInt orElseGet(OptionalInt optional, Supplier<Integer> orElse) {
+ return optional.isPresent() ? optional : OptionalInt.of(orElse.get());
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/Timing.java b/src/main/java/com/android/tools/r8/utils/Timing.java
index 5652476..c1046e9 100644
--- a/src/main/java/com/android/tools/r8/utils/Timing.java
+++ b/src/main/java/com/android/tools/r8/utils/Timing.java
@@ -21,6 +21,7 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Stack;
+import java.util.function.Supplier;
public class Timing {
@@ -370,6 +371,15 @@
stack.push(child);
}
+ public <T> T time(String title, Supplier<T> supplier) {
+ begin(title);
+ try {
+ return supplier.get();
+ } finally {
+ end();
+ }
+ }
+
public void end() {
stack.peek().end(); // record time.
stack.pop();
diff --git a/src/main/keep_retrace.txt b/src/main/keep_retrace.txt
deleted file mode 100644
index 6a71f9e..0000000
--- a/src/main/keep_retrace.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright (c) 2021, 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.
-
-# The retrace api is separated out without repackaging which is why this broad
-# rule is used.
--keep public class com.android.tools.r8.retrace.* {
- public <methods>;
- public <fields>;
- }
--keepattributes SourceFile, LineNumberTable, InnerClasses, EnclosingMethod, Exceptions, Signature
--keepparameternames
-# This is run on r8lib so keep everything in lib that is traced. That way
-# we only need a single mapping file
--keep,allowshrinking class * { *; }
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/Collectors.java b/src/test/java/com/android/tools/r8/CollectorsUtils.java
similarity index 92%
rename from src/test/java/com/android/tools/r8/Collectors.java
rename to src/test/java/com/android/tools/r8/CollectorsUtils.java
index 0e05ce0..93d77b0 100644
--- a/src/test/java/com/android/tools/r8/Collectors.java
+++ b/src/test/java/com/android/tools/r8/CollectorsUtils.java
@@ -6,7 +6,7 @@
import java.util.stream.Collector;
-public abstract class Collectors {
+public abstract class CollectorsUtils {
public static <T> Collector<T, ?, T> toSingle() {
return java.util.stream.Collectors.collectingAndThen(
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index be6c8f0..56a2b80 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -176,7 +176,6 @@
public static final Path R8LIB_EXCLUDE_DEPS_MAP =
Paths.get(LIBS_DIR, "r8lib-exclude-deps.jar.map");
public static final Path DEPS = Paths.get(LIBS_DIR, "deps_all.jar");
- public static final Path R8_RETRACE_JAR = Paths.get(LIBS_DIR, "r8retrace.jar");
public static final Path DESUGAR_LIB_CONVERSIONS =
Paths.get(LIBS_DIR, "library_desugar_conversions.zip");
@@ -2127,12 +2126,6 @@
return builder;
}
- public static R8Command.Builder allowPartiallyImplementedProguardOptions(
- R8Command.Builder builder) {
- builder.allowPartiallyImplementedProguardOptions();
- return builder;
- }
-
public static R8Command.Builder allowTestProguardOptions(R8Command.Builder builder) {
builder.allowTestProguardOptions();
return builder;
diff --git a/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapCurrentEqualityTest.java b/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapCurrentEqualityTest.java
index 1a6717f..d1dc197 100644
--- a/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapCurrentEqualityTest.java
+++ b/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapCurrentEqualityTest.java
@@ -10,6 +10,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.ExternalR8TestCompileResult;
@@ -154,9 +155,7 @@
// Produce r81 = R8Lib(R8WithDeps) and r82 = R8LibNoDeps + Deps(R8WithDeps) and test that r81 is
// equal to r82. This test should only run if we are testing r8lib and we expect both R8libs to
// be built by gradle. If we are not testing with R8Lib, do not run this test.
- if (!ToolHelper.isTestingR8Lib()) {
- return;
- }
+ assumeTrue(ToolHelper.isTestingR8Lib());
Path runR81 =
testForExternalR8(parameters.getBackend(), parameters.getRuntime())
.useProvidedR8(ToolHelper.R8LIB_JAR)
diff --git a/src/test/java/com/android/tools/r8/compilerapi/BinaryCompatibilityTestCollection.java b/src/test/java/com/android/tools/r8/compilerapi/BinaryCompatibilityTestCollection.java
new file mode 100644
index 0000000..51a307b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/compilerapi/BinaryCompatibilityTestCollection.java
@@ -0,0 +1,211 @@
+// Copyright (c) 2021, 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.compilerapi;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.CollectorsUtils;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestRuntime;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.transformers.ClassFileTransformer;
+import com.android.tools.r8.transformers.ClassFileTransformer.InnerClassPredicate;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.IntBox;
+import com.android.tools.r8.utils.ZipUtils;
+import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import java.io.File;
+import java.lang.reflect.Method;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+/**
+ * Abstract base to define a collection of API tests that should be run against a checked in jar.
+ */
+public abstract class BinaryCompatibilityTestCollection<T> {
+
+ private static final String JUNIT_JAR = "junit-4.13-beta-2.jar";
+
+ private static final String HAMCREST = "hamcrest-core-1.3.jar";
+
+ /** Jar to run tests against. */
+ public abstract Path getTargetJar();
+
+ /** Jar with tests. */
+ public abstract Path getCheckedInTestJar();
+
+ /** List of classes that make up the checked in test suite. */
+ public abstract List<Class<? extends T>> getCheckedInTestClasses();
+
+ /** List of classes that are yet to become part of the test suite. */
+ public abstract List<Class<? extends T>> getPendingTestClasses();
+
+ /** Additional classes that should always be included together to run tests. */
+ public abstract List<Class<?>> getAdditionalClassesForTests();
+
+ /** Additional JVM args supplied to any external execution. */
+ public abstract List<String> getVmArgs();
+
+ /** Temporary folder for generating jars and so on. */
+ public abstract TemporaryFolder getTemp();
+
+ public String makeProperty(String key, String value) {
+ return "-D" + key + "=" + value;
+ }
+
+ private void verifyConsistency() {
+ assertEquals(
+ ImmutableSet.of(),
+ Sets.intersection(
+ ImmutableSet.copyOf(getCheckedInTestClasses()),
+ ImmutableSet.copyOf(getPendingTestClasses())));
+ }
+
+ private boolean testIsCheckedInOrPending(Class<?> clazz) {
+ return getCheckedInTestClasses().contains(clazz) || getPendingTestClasses().contains(clazz);
+ }
+
+ public void runJunitOnCheckedInJar() throws Exception {
+ runJunitOnTestClasses(getCheckedInTestJar(), getCheckedInTestClasses());
+ }
+
+ public void runJunitOnTestClass(Class<? extends T> test) throws Exception {
+ List<Class<? extends T>> testClasses = Collections.singletonList(test);
+ runJunitOnTestClasses(generateJarForTestClasses(testClasses), testClasses);
+ }
+
+ private void runJunitOnTestClasses(Path testJar, Collection<Class<? extends T>> tests)
+ throws Exception {
+ verifyConsistency();
+ IntBox numberOfTestMethods = new IntBox(0);
+ List<Path> classPaths =
+ ImmutableList.of(getJunitDependency(), getHamcrest(), getTargetJar(), testJar);
+ List<String> args = new ArrayList<>();
+ args.add("org.junit.runner.JUnitCore");
+ tests.forEach(
+ test -> {
+ assertTrue(testIsCheckedInOrPending(test));
+ args.add(test.getTypeName());
+ for (Method method : test.getDeclaredMethods()) {
+ if (method.isAnnotationPresent(Test.class)) {
+ numberOfTestMethods.increment();
+ }
+ }
+ });
+ ProcessResult processResult =
+ ToolHelper.runJava(
+ TestRuntime.getSystemRuntime(),
+ ImmutableList.<String>builder().add("-ea").addAll(getVmArgs()).build(),
+ classPaths,
+ args.toArray(new String[0]));
+ assertEquals(processResult.toString(), 0, processResult.exitCode);
+ assertThat(processResult.stdout, containsString("OK (" + numberOfTestMethods.get() + " test"));
+ }
+
+ private static Path getJunitDependency() {
+ String junitPath =
+ Arrays.stream(System.getProperty("java.class.path").split(File.pathSeparator))
+ .filter(cp -> cp.endsWith(JUNIT_JAR))
+ .collect(CollectorsUtils.toSingle());
+ return Paths.get(junitPath);
+ }
+
+ private static Path getHamcrest() {
+ String junitPath =
+ Arrays.stream(System.getProperty("java.class.path").split(File.pathSeparator))
+ .filter(cp -> cp.endsWith(HAMCREST))
+ .collect(CollectorsUtils.toSingle());
+ return Paths.get(junitPath);
+ }
+
+ public Path generateJarForCheckedInTestClasses() throws Exception {
+ return generateJarForTestClasses(getCheckedInTestClasses());
+ }
+
+ private Path generateJarForTestClasses(Collection<Class<? extends T>> classes) throws Exception {
+ Path jar = getTemp().newFolder().toPath().resolve("test.jar");
+ ZipBuilder zipBuilder = ZipBuilder.builder(jar);
+ for (Class<? extends T> test : classes) {
+ zipBuilder.addFilesRelative(
+ ToolHelper.getClassPathForTests(), ToolHelper.getClassFilesForInnerClasses(test));
+ zipBuilder.addBytes(
+ ZipUtils.zipEntryNameForClass(test),
+ ClassFileTransformer.create(test)
+ .removeInnerClasses(
+ InnerClassPredicate.onName(
+ DescriptorUtils.getBinaryNameFromJavaType(test.getTypeName())))
+ .transform());
+ }
+ zipBuilder.addFilesRelative(
+ ToolHelper.getClassPathForTests(),
+ getAdditionalClassesForTests().stream()
+ .map(ToolHelper::getClassFileForTestClass)
+ .collect(Collectors.toList()));
+ return zipBuilder.build();
+ }
+
+ public void verifyCheckedInJarIsUpToDate() throws Exception {
+ TemporaryFolder temp = getTemp();
+ Path checkedInContents = temp.newFolder().toPath();
+ Path generatedContents = temp.newFolder().toPath();
+ ZipUtils.unzip(getCheckedInTestJar(), checkedInContents);
+ ZipUtils.unzip(generateJarForCheckedInTestClasses(), generatedContents);
+ try (Stream<Path> existingPaths = Files.walk(checkedInContents);
+ Stream<Path> generatedPaths = Files.walk(generatedContents)) {
+ List<Path> existing =
+ existingPaths.filter(FileUtils::isClassFile).collect(Collectors.toList());
+ List<Path> generated =
+ generatedPaths.filter(FileUtils::isClassFile).collect(Collectors.toList());
+ for (Path classFile : generated) {
+ Path otherClassFile = checkedInContents.resolve(generatedContents.relativize(classFile));
+ assertTrue("Could not find file: " + otherClassFile, Files.exists(otherClassFile));
+ assertTrue(
+ "Non-equal files: " + otherClassFile,
+ TestBase.filesAreEqual(classFile, otherClassFile));
+ }
+ assertEquals(existing.size(), generated.size());
+ assertNotEquals(0, existing.size());
+ }
+ }
+
+ public void replaceJarForCheckedInTestClasses() throws Exception {
+ Path checkedInJar = getCheckedInTestJar();
+ Path tarballDir = checkedInJar.getParent();
+ Path parentDir = tarballDir.getParent();
+ if (!Files.exists(Paths.get(tarballDir + ".tar.gz.sha1"))) {
+ throw new RuntimeException("Could not locate the SHA file for " + tarballDir);
+ }
+ Path generatedJar = generateJarForCheckedInTestClasses();
+ Files.move(generatedJar, checkedInJar, StandardCopyOption.REPLACE_EXISTING);
+ System.out.println(
+ "Updated file in: "
+ + checkedInJar
+ + "\nRemember to upload to cloud storage:"
+ + "\n(cd "
+ + parentDir
+ + " && upload_to_google_storage.py -a --bucket r8-deps "
+ + tarballDir.getFileName()
+ + ")");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTest.java b/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTest.java
new file mode 100644
index 0000000..654eafd
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTest.java
@@ -0,0 +1,53 @@
+// Copyright (c) 2021, 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.compilerapi;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Collections;
+import java.util.List;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Base class for any actual API test.
+ *
+ * <p>Subclasses of this must only use the public API and the otherwise linked libraries (junit,
+ * etc).
+ */
+@RunWith(Parameterized.class)
+public abstract class CompilerApiTest {
+
+ public static final String API_TEST_MODE_KEY = "API_TEST_MODE";
+ public static final String API_TEST_MODE_EXTERNAL = "external";
+
+ public static final String API_TEST_LIB_KEY = "API_TEST_LIB";
+ public static final String API_TEST_LIB_YES = "yes";
+ public static final String API_TEST_LIB_NO = "no";
+
+ @Parameters(name = "{0}")
+ public static List<Object> data() {
+ // Simulate only running the API tests directly on the "none" runtime configuration.
+ String runtimes = System.getProperty("runtimes");
+ if (runtimes != null && !runtimes.contains("none")) {
+ return Collections.emptyList();
+ }
+ return Collections.singletonList("none");
+ }
+
+ public CompilerApiTest(Object none) {
+ assertEquals("none", none);
+ }
+
+ /** Predicate to determine if the test is being run externally. */
+ public boolean isRunningExternal() {
+ return API_TEST_MODE_EXTERNAL.equals(System.getProperty(API_TEST_MODE_KEY));
+ }
+
+ /** Predicate to determine if the test is being run for an R8 lib compilation. */
+ public boolean isRunningR8Lib() {
+ return API_TEST_LIB_YES.equals(System.getProperty(API_TEST_LIB_KEY));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java b/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java
new file mode 100644
index 0000000..8c1e8a5
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java
@@ -0,0 +1,80 @@
+// Copyright (c) 2021, 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.compilerapi;
+
+import static com.android.tools.r8.ToolHelper.R8LIB_JAR;
+import static com.android.tools.r8.ToolHelper.R8_JAR;
+import static com.android.tools.r8.ToolHelper.isTestingR8Lib;
+
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.compilerapi.testsetup.ApiTestingSetUpTest;
+import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import org.junit.rules.TemporaryFolder;
+
+/** Collection of API tests for the D8/R8 compilers. */
+public class CompilerApiTestCollection extends BinaryCompatibilityTestCollection<CompilerApiTest> {
+
+ private static final String DIRNAME = "compiler_api_tests";
+ private static final Path BINARY_COMPATIBILITY_JAR =
+ Paths.get(ToolHelper.THIRD_PARTY_DIR, "binary_compatibility_tests", DIRNAME, "tests.jar");
+
+ private static final List<Class<? extends CompilerApiTest>> CLASSES_FOR_BINARY_COMPATIBILITY =
+ ImmutableList.of(ApiTestingSetUpTest.ApiTest.class);
+
+ private static final List<Class<? extends CompilerApiTest>> CLASSES_PENDING_BINARY_COMPATIBILITY =
+ ImmutableList.of(
+ // No pending APIs.
+ );
+
+ private final TemporaryFolder temp;
+
+ public CompilerApiTestCollection(TemporaryFolder temp) {
+ this.temp = temp;
+ }
+
+ @Override
+ public TemporaryFolder getTemp() {
+ return temp;
+ }
+
+ @Override
+ public List<Class<? extends CompilerApiTest>> getCheckedInTestClasses() {
+ return CLASSES_FOR_BINARY_COMPATIBILITY;
+ }
+
+ @Override
+ public List<Class<? extends CompilerApiTest>> getPendingTestClasses() {
+ return CLASSES_PENDING_BINARY_COMPATIBILITY;
+ }
+
+ @Override
+ public List<Class<?>> getAdditionalClassesForTests() {
+ return ImmutableList.of(CompilerApiTest.class);
+ }
+
+ @Override
+ public Path getCheckedInTestJar() {
+ return BINARY_COMPATIBILITY_JAR;
+ }
+
+ // The API tests always link against the jar that the test runner is using.
+ public Path getTargetJar() {
+ return isTestingR8Lib() ? R8LIB_JAR : R8_JAR;
+ }
+
+ // Some tests expectations can depend on the lib/nonlib and internal/external behavior.
+ // This sets up envvars so the test can determine its running context.
+ // This is only called for external invocations.
+ public List<String> getVmArgs() {
+ return ImmutableList.of(
+ makeProperty("com.android.tools.r8.enableTestAssertions", "1"),
+ makeProperty(CompilerApiTest.API_TEST_MODE_KEY, CompilerApiTest.API_TEST_MODE_EXTERNAL),
+ makeProperty(
+ CompilerApiTest.API_TEST_LIB_KEY,
+ isTestingR8Lib() ? CompilerApiTest.API_TEST_LIB_YES : CompilerApiTest.API_TEST_LIB_NO));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollectionTest.java b/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollectionTest.java
new file mode 100644
index 0000000..0aae1dd
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollectionTest.java
@@ -0,0 +1,58 @@
+// Copyright (c) 2021, 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.compilerapi;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class CompilerApiTestCollectionTest extends TestBase {
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public CompilerApiTestCollectionTest(TestParameters parameters) {
+ parameters.assertNoneRuntime();
+ }
+
+ /**
+ * If this test fails the API has changed in a non-compatible way. Likely the changes to the API
+ * will need to be undone/changed to preserve compatibility.
+ */
+ @Test
+ public void runCheckedInTests() throws Exception {
+ new CompilerApiTestCollection(temp).runJunitOnCheckedInJar();
+ }
+
+ /**
+ * If this test fails the test.jar needs to be regenerated and uploaded to cloud storage.
+ *
+ * <p>See: {@code CompilerApiTestCollection.main} to regenerate.
+ *
+ * <p>To preserve compatibility, make sure only to regenerate together with test changes and with
+ * NO changes to the compiler itself.
+ */
+ @Test
+ public void testCheckedInJarIsUpToDate() throws Exception {
+ new CompilerApiTestCollection(temp).verifyCheckedInJarIsUpToDate();
+ }
+
+ /**
+ * To produce a new tests.jar run the code below. This will generate a new jar overwriting the
+ * existing one. Remember to upload to cloud storage afterwards.
+ */
+ public static void main(String[] args) throws Exception {
+ TemporaryFolder temp = new TemporaryFolder();
+ temp.create();
+ new CompilerApiTestCollection(temp).replaceJarForCheckedInTestClasses();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestRunner.java b/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestRunner.java
new file mode 100644
index 0000000..ee135e8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestRunner.java
@@ -0,0 +1,40 @@
+// Copyright (c) 2021, 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.compilerapi;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Base runner for all compiler API tests.
+ *
+ * <p>Using this runner will automatically create an externalized variant of the test. That is
+ * useful to more quickely ensure the test itself is not using resources that are not available.
+ * Note however, that it does not prevent using non-kept code in the compilers unless testing with
+ * r8lib!
+ */
+@RunWith(Parameterized.class)
+public abstract class CompilerApiTestRunner extends TestBase {
+
+ public abstract Class<? extends CompilerApiTest> binaryTestClass();
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public CompilerApiTestRunner(TestParameters parameters) {
+ parameters.assertNoneRuntime();
+ }
+
+ @Test
+ public void testExternal() throws Exception {
+ new CompilerApiTestCollection(temp).runJunitOnTestClass(binaryTestClass());
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/compilerapi/testsetup/ApiTestingSetUpTest.java b/src/test/java/com/android/tools/r8/compilerapi/testsetup/ApiTestingSetUpTest.java
new file mode 100644
index 0000000..7cf5b65
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/compilerapi/testsetup/ApiTestingSetUpTest.java
@@ -0,0 +1,50 @@
+// Copyright (c) 2021, 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.compilerapi.testsetup;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.R8Command;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.compilerapi.CompilerApiTest;
+import com.android.tools.r8.compilerapi.CompilerApiTestRunner;
+import com.android.tools.r8.utils.InternalOptions;
+import org.junit.Test;
+
+public class ApiTestingSetUpTest extends CompilerApiTestRunner {
+
+ public ApiTestingSetUpTest(TestParameters parameters) {
+ super(parameters);
+ }
+
+ @Override
+ public Class<? extends CompilerApiTest> binaryTestClass() {
+ return ApiTest.class;
+ }
+
+ public static class ApiTest extends CompilerApiTest {
+
+ public ApiTest(Object parameters) {
+ super(parameters);
+ }
+
+ @Test
+ public void testValidApiUse() throws Exception {
+ R8Command.builder().setPrintHelp(true).build();
+ }
+
+ @Test
+ public void testNonExistingApiUse() throws Exception {
+ try {
+ new InternalOptions();
+ // When running directly the class is public and visible.
+ assertFalse(isRunningR8Lib());
+ } catch (NoClassDefFoundError e) {
+ // Internal options is not kept, so this access should fail externally.
+ assertTrue(isRunningR8Lib());
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/ArgumentLocalsInLoopTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/ArgumentLocalsInLoopTestRunner.java
index 250bf86..b4de89d 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/ArgumentLocalsInLoopTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/ArgumentLocalsInLoopTestRunner.java
@@ -14,15 +14,12 @@
public void testArgumentLocalsInLoop() throws Exception {
Class clazz = ArgumentLocalsInLoopTest.class;
AndroidApp d8App = compileWithD8(clazz);
- AndroidApp dxApp = getDxCompiledSources();
String expected = "0";
assertEquals(expected, runOnJava(clazz));
assertEquals(expected, runOnArt(d8App, clazz.getCanonicalName()));
- assertEquals(expected, runOnArt(dxApp, clazz.getCanonicalName()));
checkFoo(inspectMethod(d8App, clazz, "int", "foo", "int"), clazz);
- checkFoo(inspectMethod(dxApp, clazz, "int", "foo", "int"), clazz);
}
private void checkFoo(DebugInfoInspector info, Class clazz) {
diff --git a/src/test/java/com/android/tools/r8/debuginfo/BackBranchToSelfTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/BackBranchToSelfTestRunner.java
index 0ad8ecd..6b84390 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/BackBranchToSelfTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/BackBranchToSelfTestRunner.java
@@ -15,15 +15,12 @@
Class clazz = BackBranchToSelfTest.class;
AndroidApp d8App = compileWithD8(clazz);
- AndroidApp dxApp = getDxCompiledSources();
String expected = "42";
assertEquals(expected, runOnJava(clazz));
assertEquals(expected, runOnArt(d8App, clazz.getCanonicalName()));
- assertEquals(expected, runOnArt(dxApp, clazz.getCanonicalName()));
checkBackBranchToSelf(inspectMethod(d8App, clazz, "int", "backBranchToSelf", "boolean"));
- checkBackBranchToSelf(inspectMethod(dxApp, clazz, "int", "backBranchToSelf", "boolean"));
}
private void checkBackBranchToSelf(DebugInfoInspector info) {
diff --git a/src/test/java/com/android/tools/r8/debuginfo/CodeGeneratorTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/CodeGeneratorTestRunner.java
index 062a4d3..1f6520e 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/CodeGeneratorTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/CodeGeneratorTestRunner.java
@@ -24,12 +24,10 @@
Class clazz = CodeGeneratorTest.class;
AndroidApp d8App = compileWithD8(clazz);
- AndroidApp dxApp = getDxCompiledSources();
String expected = "11";
assertEquals(expected, runOnJava(clazz));
assertEquals(expected, runOnArt(d8App, clazz.getCanonicalName()));
- assertEquals(expected, runOnArt(dxApp, clazz.getCanonicalName()));
DebugInfoInspector inspector = inspectMethod(d8App, clazz, "int", "intAddition", "int", "int",
"int");
diff --git a/src/test/java/com/android/tools/r8/debuginfo/ConditionalLocalTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/ConditionalLocalTestRunner.java
index 8348c0b..07fd195 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/ConditionalLocalTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/ConditionalLocalTestRunner.java
@@ -15,15 +15,12 @@
Class clazz = ConditionalLocalTest.class;
AndroidApp d8App = compileWithD8(clazz);
- AndroidApp dxApp = getDxCompiledSources();
String expected = "42";
assertEquals(expected, runOnJava(clazz));
assertEquals(expected, runOnArt(d8App, clazz.getCanonicalName()));
- assertEquals(expected, runOnArt(dxApp, clazz.getCanonicalName()));
checkConditonalLocal(inspectMethod(d8App, clazz, "void", "foo", "int"));
- checkConditonalLocal(inspectMethod(dxApp, clazz, "void", "foo", "int"));
}
private void checkConditonalLocal(DebugInfoInspector info) {
diff --git a/src/test/java/com/android/tools/r8/debuginfo/ConstantFoldingTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/ConstantFoldingTestRunner.java
index a229add..6184b2d 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/ConstantFoldingTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/ConstantFoldingTestRunner.java
@@ -14,18 +14,15 @@
public void testLocalsInSwitch() throws Exception {
Class clazz = ConstantFoldingTest.class;
AndroidApp d8App = compileWithD8(clazz);
- AndroidApp dxApp = getDxCompiledSources();
String expected = "42";
assertEquals(expected, runOnJava(clazz));
assertEquals(expected, runOnArt(d8App, clazz.getCanonicalName()));
- assertEquals(expected, runOnArt(dxApp, clazz.getCanonicalName()));
- checkFoo(inspectMethod(d8App, clazz, "int", "foo", "int"), false);
- checkFoo(inspectMethod(dxApp, clazz, "int", "foo", "int"), true);
+ checkFoo(inspectMethod(d8App, clazz, "int", "foo", "int"));
}
- private void checkFoo(DebugInfoInspector info, boolean dx) {
+ private void checkFoo(DebugInfoInspector info) {
info.checkStartLine(9);
info.checkLineHasExactLocals(9, "x", "int");
info.checkNoLine(10);
@@ -33,10 +30,7 @@
info.checkLineHasExactLocals(12, "x", "int", "res", "int", "tmp", "int");
info.checkNoLine(13);
info.checkLineHasAtLeastLocals(14, "x", "int");
- if (!dx) {
- // DX fails to close the scope of "tmp".
- info.checkLineHasExactLocals(14, "x", "int", "res", "int");
- }
+ info.checkLineHasExactLocals(14, "x", "int", "res", "int");
info.checkNoLine(15);
}
}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/DebugInfoTestBase.java b/src/test/java/com/android/tools/r8/debuginfo/DebugInfoTestBase.java
index da83ed9..09df151 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/DebugInfoTestBase.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/DebugInfoTestBase.java
@@ -26,9 +26,6 @@
public class DebugInfoTestBase {
- public static final Path DX_PREBUILT =
- Paths.get(ToolHelper.BUILD_DIR, "test", "debuginfo_examples_dex.jar");
-
@Rule
public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
@@ -45,10 +42,6 @@
return appSink.build();
}
- static AndroidApp getDxCompiledSources() throws IOException {
- return AndroidApp.builder().addProgramFiles(DX_PREBUILT).build();
- }
-
public static DebugInfoInspector inspectMethod(
AndroidApp app, Class type, String returnType, String methodName, String... parameterTypes)
throws IOException, ExecutionException {
diff --git a/src/test/java/com/android/tools/r8/debuginfo/DexPcWithDebugInfoForOverloadedMethodsTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/DexPcWithDebugInfoForOverloadedMethodsTestRunner.java
index d6e30b4..37d2b6e 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/DexPcWithDebugInfoForOverloadedMethodsTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/DexPcWithDebugInfoForOverloadedMethodsTestRunner.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.debuginfo;
-import static com.android.tools.r8.Collectors.toSingle;
+import static com.android.tools.r8.CollectorsUtils.toSingle;
import static com.android.tools.r8.utils.codeinspector.Matchers.isInlineFrame;
import static com.android.tools.r8.utils.codeinspector.Matchers.isInlineStack;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
diff --git a/src/test/java/com/android/tools/r8/debuginfo/ExceptionLocalTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/ExceptionLocalTestRunner.java
index 2998c70..f56fb6e 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/ExceptionLocalTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/ExceptionLocalTestRunner.java
@@ -16,15 +16,12 @@
Class clazz = ExceptionLocalTest.class;
AndroidApp d8App = compileWithD8(clazz);
- AndroidApp dxApp = getDxCompiledSources();
String expected = "2";
assertEquals(expected, runOnJava(clazz));
assertEquals(expected, runOnArt(d8App, clazz.getCanonicalName()));
- assertEquals(expected, runOnArt(dxApp, clazz.getCanonicalName()));
checkExceptionLocal(inspectMethod(d8App, clazz, "void", "foo", "int"));
- checkExceptionLocal(inspectMethod(dxApp, clazz, "void", "foo", "int"));
}
private void checkExceptionLocal(DebugInfoInspector info) {
diff --git a/src/test/java/com/android/tools/r8/debuginfo/LiveInAllBlocksTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/LiveInAllBlocksTestRunner.java
index 01bcb27..0e723f6 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/LiveInAllBlocksTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/LiveInAllBlocksTestRunner.java
@@ -15,24 +15,17 @@
public void testLiveInAllBlocks() throws Exception {
Class clazz = LiveInAllBlocksTest.class;
AndroidApp d8App = compileWithD8(clazz);
- AndroidApp dxApp = getDxCompiledSources();
String expected = "42";
assertEquals(expected, runOnJava(clazz));
assertEquals(expected, runOnArt(d8App, clazz.getCanonicalName()));
- assertEquals(expected, runOnArt(dxApp, clazz.getCanonicalName()));
- checkFoo(inspectMethod(d8App, clazz, "int", "foo", "int"), false);
- checkFoo(inspectMethod(dxApp, clazz, "int", "foo", "int"), true);
+ checkFoo(inspectMethod(d8App, clazz, "int", "foo", "int"));
}
- private void checkFoo(DebugInfoInspector info, boolean dx) {
+ private void checkFoo(DebugInfoInspector info) {
info.checkStartLine(9);
for (int line : new int[] {14, 18, 23, 24, 25, 27, 28, 30, 31, 34, 35, 37, 38, 40, 41}) {
- if (dx && line == 18) {
- // DX does not keep entry for line 18.
- continue;
- }
info.checkLineHasAtLeastLocals(line, "x", "int", "y", "int");
}
}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/LocalSwapTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/LocalSwapTestRunner.java
index 0ee33bf..12887fe 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/LocalSwapTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/LocalSwapTestRunner.java
@@ -14,27 +14,21 @@
public void testLocalSwap() throws Exception {
Class clazz = LocalSwapTest.class;
AndroidApp d8App = compileWithD8(clazz);
- AndroidApp dxApp = getDxCompiledSources();
String expected = "6";
assertEquals(expected, runOnJava(clazz));
assertEquals(expected, runOnArt(d8App, clazz.getCanonicalName()));
- assertEquals(expected, runOnArt(dxApp, clazz.getCanonicalName()));
- checkFoo(inspectMethod(d8App, clazz, "int", "foo", "int", "int"), false);
- checkFoo(inspectMethod(dxApp, clazz, "int", "foo", "int", "int"), true);
+ checkFoo(inspectMethod(d8App, clazz, "int", "foo", "int", "int"));
}
- private void checkFoo(DebugInfoInspector info, boolean dx) {
+ private void checkFoo(DebugInfoInspector info) {
info.checkStartLine(9);
info.checkLineHasExactLocals(9, "x", "int", "y", "int");
info.checkLineHasExactLocals(11, "x", "int", "y", "int", "sum", "int");
info.checkLineHasExactLocals(12, "x", "int", "y", "int", "sum", "int", "t", "int");
info.checkLineExists(13);
info.checkLineExists(15);
- if (!dx) {
- // DX fails to close the scope of local "t".
- info.checkLineHasExactLocals(15, "x", "int", "y", "int", "sum", "int");
- }
+ info.checkLineHasExactLocals(15, "x", "int", "y", "int", "sum", "int");
}
}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/LocalsAtThrowTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/LocalsAtThrowTestRunner.java
index 8a5b77d..4be9f50 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/LocalsAtThrowTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/LocalsAtThrowTestRunner.java
@@ -15,15 +15,12 @@
Class clazz = LocalsAtThrowTest.class;
AndroidApp d8App = compileWithD8(clazz);
- AndroidApp dxApp = getDxCompiledSources();
String expected = "3";
assertEquals(expected, runOnJava(clazz));
assertEquals(expected, runOnArt(d8App, clazz.getCanonicalName()));
- assertEquals(expected, runOnArt(dxApp, clazz.getCanonicalName()));
checkLocalsAtThrow(inspectMethod(d8App, clazz, "int", "localsAtThrow", "int"));
- checkLocalsAtThrow(inspectMethod(dxApp, clazz, "int", "localsAtThrow", "int"));
}
private void checkLocalsAtThrow(DebugInfoInspector info) {
diff --git a/src/test/java/com/android/tools/r8/debuginfo/LocalsInSwitchTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/LocalsInSwitchTestRunner.java
index af726bf..87141f7 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/LocalsInSwitchTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/LocalsInSwitchTestRunner.java
@@ -16,22 +16,17 @@
Class clazz = LocalsInSwitchTest.class;
AndroidApp d8App = compileWithD8(clazz);
- AndroidApp dxApp = getDxCompiledSources();
String expected = "55" + ToolHelper.LINE_SEPARATOR + "1862" + ToolHelper.LINE_SEPARATOR
+ "15130" + ToolHelper.LINE_SEPARATOR;
assertEquals(expected, runOnJava(clazz));
assertEquals(expected, runOnArt(d8App, clazz.getCanonicalName()));
- assertEquals(expected, runOnArt(dxApp, clazz.getCanonicalName()));
checkNoLocals(inspectMethod(d8App, clazz, "int", "noLocals", "int"));
- checkNoLocals(inspectMethod(dxApp, clazz, "int", "noLocals", "int"));
- checkTempInCase(inspectMethod(d8App, clazz, "int", "tempInCase", "int"), false);
- checkTempInCase(inspectMethod(dxApp, clazz, "int", "tempInCase", "int"), true);
+ checkTempInCase(inspectMethod(d8App, clazz, "int", "tempInCase", "int"));
checkInitInCases(inspectMethod(d8App, clazz, "int", "initInCases", "int"));
- checkInitInCases(inspectMethod(dxApp, clazz, "int", "initInCases", "int"));
}
private void checkNoLocals(DebugInfoInspector info) {
@@ -42,7 +37,7 @@
info.checkLineHasExactLocals(15, "x", "int");
}
- private void checkTempInCase(DebugInfoInspector tempInCase, boolean dx) {
+ private void checkTempInCase(DebugInfoInspector tempInCase) {
// int res =
tempInCase.checkStartLine(20);
tempInCase.checkLineHasExactLocals(20, "x", "int");
@@ -52,17 +47,11 @@
// int rem =
tempInCase.checkLineHasExactLocals(22, "x", "int", "res", "int", "i", "int");
// switch (rem) {
- if (!dx) {
- // DX contains several entries for 23, one of which does not define 'rem'. Go figure...
- tempInCase.checkLineHasExactLocals(23, "x", "int", "res", "int", "i", "int", "rem", "int");
- }
+ tempInCase.checkLineHasExactLocals(23, "x", "int", "res", "int", "i", "int", "rem", "int");
// case 0:
tempInCase.checkNoLine(24);
// return res
- if (!dx) {
- // DX does not produce a position at the return statement. Good stuff.
- tempInCase.checkLineHasExactLocals(25, "x", "int", "res", "int", "i", "int", "rem", "int");
- }
+ tempInCase.checkLineHasExactLocals(25, "x", "int", "res", "int", "i", "int", "rem", "int");
// case 5:
tempInCase.checkNoLine(26);
// int tmp =
@@ -90,14 +79,9 @@
// }
tempInCase.checkNoLine(37);
// res *= x;
- if (!dx) {
- // DX fails to end the scope of "i" after the loop.
- tempInCase.checkLineHasExactLocals(38, "x", "int", "res", "int");
- }
+ tempInCase.checkLineHasExactLocals(38, "x", "int", "res", "int");
// return res;
- if (!dx) {
- tempInCase.checkLineHasExactLocals(39, "x", "int", "res", "int");
- }
+ tempInCase.checkLineHasExactLocals(39, "x", "int", "res", "int");
}
private void checkInitInCases(DebugInfoInspector info) {
diff --git a/src/test/java/com/android/tools/r8/debuginfo/LocalsWithTypeParamsRunner.java b/src/test/java/com/android/tools/r8/debuginfo/LocalsWithTypeParamsRunner.java
index 2dd50ed..09a53ee 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/LocalsWithTypeParamsRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/LocalsWithTypeParamsRunner.java
@@ -22,15 +22,12 @@
@Test
public void testLocalsWithTypeParams() throws Exception {
AndroidApp d8App = compileWithD8(clazzMain, clazzA, clazzB);
- AndroidApp dxApp = getDxCompiledSources();
String expected = "42";
assertEquals(expected, runOnJava(clazzMain));
assertEquals(expected, runOnArt(d8App, nameMain));
- assertEquals(expected, runOnArt(dxApp, nameMain));
checkSyncInstance(inspectMethod(d8App, clazzA, "int", "foo", nameB));
- checkSyncInstance(inspectMethod(dxApp, clazzA, "int", "foo", nameB));
}
private void checkSyncInstance(DebugInfoInspector info) {
diff --git a/src/test/java/com/android/tools/r8/debuginfo/ScopedExceptionsTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/ScopedExceptionsTestRunner.java
index 436334a..dbf9243 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/ScopedExceptionsTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/ScopedExceptionsTestRunner.java
@@ -14,32 +14,23 @@
public void testScopedException() throws Exception {
Class clazz = ScopedExceptionsTest.class;
AndroidApp d8App = compileWithD8(clazz);
- AndroidApp dxApp = getDxCompiledSources();
String expected = "42";
assertEquals(expected, runOnJava(clazz));
assertEquals(expected, runOnArt(d8App, clazz.getCanonicalName()));
- assertEquals(expected, runOnArt(dxApp, clazz.getCanonicalName()));
- checkScopedExceptions(inspectMethod(d8App, clazz, "int", "scopedExceptions"), false);
- checkScopedExceptions(inspectMethod(dxApp, clazz, "int", "scopedExceptions"), true);
+ checkScopedExceptions(inspectMethod(d8App, clazz, "int", "scopedExceptions"));
}
- private void checkScopedExceptions(DebugInfoInspector info, boolean dx) {
+ private void checkScopedExceptions(DebugInfoInspector info) {
info.checkStartLine(10);
info.checkLineHasNoLocals(10);
info.checkNoLine(11);
info.checkLineHasNoLocals(12);
info.checkLineHasNoLocals(13);
info.checkLineHasExactLocals(14, "e", "java.lang.Throwable");
- // DX does not generate a position at the end of the try-catch blocks, Java does and so does D8.
- if (!dx) {
- info.checkLineHasNoLocals(15);
- }
+ info.checkLineHasNoLocals(15);
info.checkLineExists(16);
- // DX will still have an local entry for 'e' after its scope has ended.
- if (!dx) {
- info.checkLineHasNoLocals(16);
- }
+ info.checkLineHasNoLocals(16);
}
}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/SynchronizedMethodTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/SynchronizedMethodTestRunner.java
index cd9e19d..f14d443 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/SynchronizedMethodTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/SynchronizedMethodTestRunner.java
@@ -25,26 +25,18 @@
@Test
public void testSynchronizedMethod() throws Exception {
AndroidApp d8App = compileWithD8(clazz);
- AndroidApp dxApp = getDxCompiledSources();
String expected = StringUtils.lines("42", "42", "2", "2");
assertEquals(expected, runOnJava(clazz));
assertEquals(expected, runOnArt(d8App, clazz.getCanonicalName()));
- assertEquals(expected, runOnArt(dxApp, clazz.getCanonicalName()));
checkSyncStatic(inspectMethod(d8App, clazz, "int", "syncStatic", "int"));
- checkSyncStatic(inspectMethod(dxApp, clazz, "int", "syncStatic", "int"));
checkSyncInstance(inspectMethod(d8App, clazz, "int", "syncInstance", "int"));
- checkSyncInstance(inspectMethod(dxApp, clazz, "int", "syncInstance", "int"));
- checkThrowing(inspectMethod(d8App, clazz, "int", "throwing", "int"), false);
- checkThrowing(inspectMethod(dxApp, clazz, "int", "throwing", "int"), true);
+ checkThrowing(inspectMethod(d8App, clazz, "int", "throwing", "int"));
- checkMonitorExitRegression(
- inspectMethod(d8App, clazz, "int", "monitorExitRegression", "int"), false);
- checkMonitorExitRegression(
- inspectMethod(dxApp, clazz, "int", "monitorExitRegression", "int"), true);
+ checkMonitorExitRegression(inspectMethod(d8App, clazz, "int", "monitorExitRegression", "int"));
}
private void checkSyncStatic(DebugInfoInspector info) {
@@ -66,23 +58,18 @@
info.checkNoLine(20);
}
- private void checkThrowing(DebugInfoInspector info, boolean dx) {
+ private void checkThrowing(DebugInfoInspector info) {
info.checkStartLine(23);
- if (!dx) {
- info.checkLineHasExactLocals(23, "cond", "int");
- }
+ info.checkLineHasExactLocals(23, "cond", "int");
info.checkLineHasExactLocals(24, "cond", "int", "x", "int");
info.checkLineHasExactLocals(25, "cond", "int", "x", "int");
info.checkNoLine(26);
info.checkLineHasExactLocals(27, "cond", "int", "x", "int");
}
- private void checkMonitorExitRegression(DebugInfoInspector info, boolean dx) {
+ private void checkMonitorExitRegression(DebugInfoInspector info) {
info.checkStartLine(31);
for (int line : Arrays.asList(32, 34, 36, 38, 40, 42, 44, 48, 50, 52)) {
- if (dx && line == 40) {
- continue;
- }
info.checkLineHasExactLocals(line, "cond", "int", "x", "int");
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
index 9264433..254ef6d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.desugar.desugaredlibrary.conversiontests;
-import static com.android.tools.r8.Collectors.toSingle;
+import static com.android.tools.r8.CollectorsUtils.toSingle;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
diff --git a/src/test/java/com/android/tools/r8/desugar/enclosingmethod/InvalidEnclosingMethodAttributeTest.java b/src/test/java/com/android/tools/r8/desugar/enclosingmethod/InvalidEnclosingMethodAttributeTest.java
new file mode 100644
index 0000000..6183472
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/enclosingmethod/InvalidEnclosingMethodAttributeTest.java
@@ -0,0 +1,87 @@
+// Copyright (c) 2021, 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.desugar.enclosingmethod;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.references.Reference;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.nio.file.Path;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class InvalidEnclosingMethodAttributeTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public InvalidEnclosingMethodAttributeTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testRuntime() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClasses(Main.class)
+ .addProgramClassFileData(getProgramClassFileDataWithRewrittenEnclosingMethod())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("null", typeName(Main.class));
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(Main.class)
+ .addProgramClassFileData(getProgramClassFileDataWithRewrittenEnclosingMethod())
+ .setMinApi(parameters.getApiLevel())
+ .addKeepAttributeInnerClassesAndEnclosingMethod()
+ .addKeepAllClassesRule()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("null", typeName(Main.class));
+ }
+
+ private byte[] getProgramClassFileDataWithRewrittenEnclosingMethod() throws IOException {
+ Path innerClass = ToolHelper.getClassFilesForInnerClasses(Main.class).iterator().next();
+ return transformer(innerClass, Reference.classFromBinaryName(binaryName(Main.class) + "$1"))
+ .rewriteEnclosingMethod(binaryName(Main.class), "<clinit>", "()V")
+ .transform();
+ }
+
+ public static class Main {
+
+ public static Object a =
+ new Object() {
+ void foo() {
+ System.out.println("Hello World!");
+ }
+ };
+
+ public static void main(String[] args) {
+ Class<? extends Object> aClass = a.getClass();
+ Method enclosingMethod = aClass.getEnclosingMethod();
+ if (enclosingMethod == null) {
+ System.out.println("null");
+ } else {
+ System.out.println(enclosingMethod.getName());
+ }
+ Class<?> enclosingClass = aClass.getEnclosingClass();
+ if (enclosingClass == null) {
+ System.out.println("null");
+ } else {
+ System.out.println(enclosingClass.getName());
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/graph/DexDebugEventsTest.java b/src/test/java/com/android/tools/r8/graph/DexDebugEventsTest.java
index 75eb79f..4f71913 100644
--- a/src/test/java/com/android/tools/r8/graph/DexDebugEventsTest.java
+++ b/src/test/java/com/android/tools/r8/graph/DexDebugEventsTest.java
@@ -133,9 +133,9 @@
List<DexDebugEvent> events = new ArrayList<>();
DexDebugEventBuilder.emitAdvancementEvents(
pc,
- new Position(line, null, method, null),
+ Position.builder().setLine(line).setMethod(method).build(),
nextPc,
- new Position(nextLine, null, method, null),
+ Position.builder().setLine(nextLine).setMethod(method).build(),
events,
factory,
false);
diff --git a/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java b/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java
index 83a8577..cec9053 100644
--- a/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java
+++ b/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java
@@ -154,7 +154,6 @@
builder.setMode(mode);
builder.setProgramConsumer(dexIndexedConsumerSupplier.get());
builder.setMinApiLevel(AndroidApiLevel.L.getLevel());
- ToolHelper.allowPartiallyImplementedProguardOptions(builder);
ToolHelper.addProguardConfigurationConsumer(
builder,
pgConfig -> {
diff --git a/src/test/java/com/android/tools/r8/naming/IdentityMappingFileTest.java b/src/test/java/com/android/tools/r8/naming/IdentityMappingFileTest.java
new file mode 100644
index 0000000..21ece10
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/IdentityMappingFileTest.java
@@ -0,0 +1,126 @@
+// Copyright (c) 2021, 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.naming;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.startsWith;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.DexIndexedConsumer;
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.R8;
+import com.android.tools.r8.R8Command;
+import com.android.tools.r8.StringConsumer;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.BooleanBox;
+import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class IdentityMappingFileTest extends TestBase {
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public IdentityMappingFileTest(TestParameters parameters) {
+ parameters.assertNoneRuntime();
+ }
+
+ private void checkIdentityMappingContent(String mapping) {
+ assertThat(mapping, containsString("# compiler: R8"));
+ assertThat(mapping, containsString("# compiler_version: "));
+ assertThat(mapping, containsString("# min_api: 1"));
+ assertThat(mapping, containsString("# compiler_hash: "));
+ assertThat(mapping, containsString("# common_typos_disable"));
+ assertThat(mapping, containsString("# {\"id\":\"com.android.tools.r8.mapping\",\"version\":"));
+ assertThat(mapping, containsString("# pg_map_id: "));
+ assertThat(mapping, containsString("# pg_map_hash: SHA-256 "));
+ // Check the mapping is the identity, e.g., only comments are defined.
+ // Note, this could change if the mapping is ever changed to be complete, in which case the
+ // mapping will have actual identity mappings.
+ for (String line : StringUtils.splitLines(mapping)) {
+ assertThat(line, startsWith("#"));
+ }
+ }
+
+ @Test
+ public void testTheTestBuilder() throws Exception {
+ String mapping =
+ testForR8(Backend.DEX)
+ .addProgramClasses(Main.class)
+ .setMinApi(AndroidApiLevel.B)
+ .addKeepMainRule(Main.class)
+ .compile()
+ .getProguardMap();
+ checkIdentityMappingContent(mapping);
+ }
+
+ @Test
+ public void testFileOutput() throws Exception {
+ Path mappingPath = temp.newFolder().toPath().resolve("mapping.map");
+ R8.run(
+ R8Command.builder()
+ .addProgramFiles(ToolHelper.getClassFileForTestClass(Main.class))
+ .addProguardConfiguration(
+ ImmutableList.of(keepMainProguardConfiguration(Main.class)), Origin.unknown())
+ .addLibraryFiles(ToolHelper.getJava8RuntimeJar())
+ .setProguardMapOutputPath(mappingPath)
+ .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+ .build());
+ assertTrue(Files.exists(mappingPath));
+ checkIdentityMappingContent(FileUtils.readTextFile(mappingPath, StandardCharsets.UTF_8));
+ }
+
+ @Test
+ public void testStringConsumer() throws Exception {
+ BooleanBox consumerWasCalled = new BooleanBox(false);
+ StringBuilder mappingContent = new StringBuilder();
+ R8.run(
+ R8Command.builder()
+ .addProgramFiles(ToolHelper.getClassFileForTestClass(Main.class))
+ .addProguardConfiguration(
+ ImmutableList.of(keepMainProguardConfiguration(Main.class)), Origin.unknown())
+ .addLibraryFiles(ToolHelper.getJava8RuntimeJar())
+ .setProguardMapConsumer(
+ new StringConsumer() {
+ @Override
+ public void accept(String string, DiagnosticsHandler handler) {
+ mappingContent.append(string);
+ }
+
+ @Override
+ public void finished(DiagnosticsHandler handler) {
+ consumerWasCalled.set(true);
+ }
+ })
+ .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+ .build());
+ assertTrue(consumerWasCalled.get());
+ checkIdentityMappingContent(mappingContent.toString());
+ }
+
+ // Compiling this program with a keep main will result in an identity mapping for the residual
+ // program. The (identity) mapping should still be created and emitted to the client.
+ static class Main {
+
+ public static void main(String[] args) {
+ System.out.println("Hello world!");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingDesugarLambdaTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingDesugarLambdaTest.java
index 9db718e..29bf9fa 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingDesugarLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingDesugarLambdaTest.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.naming.applymapping;
-import static com.android.tools.r8.Collectors.toSingle;
+import static com.android.tools.r8.CollectorsUtils.toSingle;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertNotSame;
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNullCheck.java b/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNullCheck.java
index 232fe30..548025b 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNullCheck.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNullCheck.java
@@ -7,7 +7,6 @@
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
-import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -53,7 +52,6 @@
.addKeepAttributeSourceFile()
.setMinApi(parameters.getApiLevel())
.enableInliningAnnotations()
- .enableNeverClassInliningAnnotations()
.run(parameters.getRuntime(), Caller.class)
.assertFailureWithErrorThatThrows(NullPointerException.class)
// TODO(b/197936862): The two should be the same
@@ -75,7 +73,6 @@
}
}
- @NeverClassInline
static class Caller {
@NeverInline
static void caller(Foo f) {
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNullCheckSequence.java b/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNullCheckSequence.java
new file mode 100644
index 0000000..f7f7b72
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNullCheckSequence.java
@@ -0,0 +1,95 @@
+// Copyright (c) 2021, 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.naming.retrace;
+
+import static com.android.tools.r8.naming.retrace.StackTrace.isSame;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfRuntime;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class RetraceInlineeWithNullCheckSequence extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
+ }
+
+ public StackTrace expectedStackTrace;
+
+ @Before
+ public void setup() throws Exception {
+ // Get the expected stack trace by running on the JVM.
+ expectedStackTrace =
+ testForJvm()
+ .addTestClasspath()
+ .run(CfRuntime.getSystemRuntime(), Caller.class)
+ .assertFailure()
+ .map(StackTrace::extractFromJvm);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Caller.class)
+ .addKeepAttributeLineNumberTable()
+ .addKeepAttributeSourceFile()
+ .setMinApi(parameters.getApiLevel())
+ .enableInliningAnnotations()
+ .run(parameters.getRuntime(), Caller.class)
+ .assertFailureWithErrorThatThrows(NullPointerException.class)
+ .inspectStackTrace(
+ (stackTrace, codeInspector) -> {
+ // TODO(b/197936862): The two stacktraces should be the same
+ assertThat(stackTrace, not(isSame(expectedStackTrace)));
+ });
+ }
+
+ static class Foo {
+ @NeverInline
+ void notInlinable() {
+ System.out.println("Hello, world!");
+ throw new RuntimeException("Foo");
+ }
+
+ void inlinable1() {
+ notInlinable();
+ }
+
+ void inlinable2() {
+ inlinable1();
+ }
+
+ void inlinable3() {
+ inlinable2();
+ }
+ }
+
+ static class Caller {
+
+ @NeverInline
+ static void caller(Foo f) {
+ f.inlinable3();
+ }
+
+ public static void main(String[] args) {
+ caller(System.currentTimeMillis() < 0 ? new Foo() : null);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/resource/KeepDirectoriesTest.java b/src/test/java/com/android/tools/r8/resource/KeepDirectoriesTest.java
index 4cbaf6c..416835f 100644
--- a/src/test/java/com/android/tools/r8/resource/KeepDirectoriesTest.java
+++ b/src/test/java/com/android/tools/r8/resource/KeepDirectoriesTest.java
@@ -15,7 +15,8 @@
import com.android.tools.r8.DataResourceConsumer;
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.R8Command;
-import com.android.tools.r8.StringResource;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.naming.ClassNameMapper;
@@ -51,12 +52,16 @@
@Parameterized.Parameters(name = "Backend: {0}, Minify: {1}")
public static Collection<Object[]> data() {
- return buildParameters(ToolHelper.getBackends(), BooleanUtils.values());
+ return buildParameters(
+ ToolHelper.getBackends(),
+ BooleanUtils.values(),
+ TestParametersBuilder.builder().withNoneRuntime().build());
}
- public KeepDirectoriesTest(Backend backend, boolean minify) {
+ public KeepDirectoriesTest(Backend backend, boolean minify, TestParameters parameters) {
this.backend = backend;
this.minify = minify;
+ parameters.assertNoneRuntime();
}
// Return the original package name for this package.
@@ -66,14 +71,11 @@
// Return the package name in the app for this package.
private String pathForThisPackage(AndroidApp app) throws Exception {
- String name;
- if (app.getProguardMapOutputData() != null) {
- ClassNameMapper mapper =
- ClassNameMapper.mapperFromString(app.getProguardMapOutputData().getString());
- name = mapper.getObfuscatedToOriginalMapping().inverse.get(Main.class.getCanonicalName());
- } else {
- name = Main.class.getTypeName();
- }
+ ClassNameMapper mapper =
+ ClassNameMapper.mapperFromString(app.getProguardMapOutputData().getString());
+ String originalName = Main.class.getTypeName();
+ String name =
+ mapper.getObfuscatedToOriginalMapping().inverse.getOrDefault(originalName, originalName);
return name.substring(0, name.lastIndexOf('.')).replace('.', '/');
}
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java b/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
index 4bba10f..3fb600a 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
@@ -297,12 +297,13 @@
if (testExternal) {
// The external dependency is built on top of R8Lib. If test.py is run with
// no r8lib, do not try and run the external R8 Retrace since it has not been built.
- assumeTrue(Files.exists(ToolHelper.R8LIB_JAR));
+ assumeTrue(ToolHelper.isTestingR8Lib());
+ assertTrue(Files.exists(ToolHelper.R8LIB_JAR));
List<String> command = new ArrayList<>();
command.add(ToolHelper.getSystemJavaExecutable());
command.add("-ea");
command.add("-cp");
- command.add(ToolHelper.R8_RETRACE_JAR.toString());
+ command.add(ToolHelper.R8LIB_JAR.toString());
command.add("com.android.tools.r8.retrace.Retrace");
command.addAll(args);
ProcessBuilder builder = new ProcessBuilder(command);
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceTests.java b/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
index 34e4ca8..3bdef43 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
@@ -7,6 +7,7 @@
import static junit.framework.TestCase.assertEquals;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
@@ -23,8 +24,7 @@
import com.android.tools.r8.retrace.stacktraces.AmbiguousMissingLineStackTrace;
import com.android.tools.r8.retrace.stacktraces.AmbiguousStackTrace;
import com.android.tools.r8.retrace.stacktraces.AmbiguousWithMultipleLineMappingsStackTrace;
-import com.android.tools.r8.retrace.stacktraces.AmbiguousWithSignatureNonVerboseStackTrace;
-import com.android.tools.r8.retrace.stacktraces.AmbiguousWithSignatureVerboseStackTrace;
+import com.android.tools.r8.retrace.stacktraces.AmbiguousWithSignatureStackTrace;
import com.android.tools.r8.retrace.stacktraces.AutoStackTrace;
import com.android.tools.r8.retrace.stacktraces.CircularReferenceStackTrace;
import com.android.tools.r8.retrace.stacktraces.ColonInFileNameStackTrace;
@@ -33,6 +33,7 @@
import com.android.tools.r8.retrace.stacktraces.FoundMethodVerboseStackTrace;
import com.android.tools.r8.retrace.stacktraces.InlineFileNameStackTrace;
import com.android.tools.r8.retrace.stacktraces.InlineFileNameWithInnerClassesStackTrace;
+import com.android.tools.r8.retrace.stacktraces.InlineInOutlineStackTrace;
import com.android.tools.r8.retrace.stacktraces.InlineNoLineNumberStackTrace;
import com.android.tools.r8.retrace.stacktraces.InlineSourceFileContextStackTrace;
import com.android.tools.r8.retrace.stacktraces.InlineWithLineNumbersStackTrace;
@@ -48,6 +49,10 @@
import com.android.tools.r8.retrace.stacktraces.NullStackTrace;
import com.android.tools.r8.retrace.stacktraces.ObfucatedExceptionClassStackTrace;
import com.android.tools.r8.retrace.stacktraces.ObfuscatedRangeToSingleLineStackTrace;
+import com.android.tools.r8.retrace.stacktraces.OutlineInOutlineStackTrace;
+import com.android.tools.r8.retrace.stacktraces.OutlineSimpleStackTrace;
+import com.android.tools.r8.retrace.stacktraces.OutlineWithInliningStackTrace;
+import com.android.tools.r8.retrace.stacktraces.OutsideLineRangeStackTraceTest;
import com.android.tools.r8.retrace.stacktraces.OverloadSameLineTest;
import com.android.tools.r8.retrace.stacktraces.RetraceAssertionErrorStackTrace;
import com.android.tools.r8.retrace.stacktraces.SingleLineNoLineNumberStackTrace;
@@ -177,8 +182,8 @@
}
@Test
- public void testAmbiguousMissingLineNotVerbose() throws Exception {
- runRetraceTest(new AmbiguousWithSignatureNonVerboseStackTrace());
+ public void testAmbiguousMissingLine() throws Exception {
+ runRetraceTest(new AmbiguousWithSignatureStackTrace());
}
@Test
@@ -308,11 +313,6 @@
}
@Test
- public void testAmbiguousMissingLineVerbose() throws Exception {
- runRetraceTest(new AmbiguousWithSignatureVerboseStackTrace());
- }
-
- @Test
public void testNpeInlineRetraceStackTrace() throws Exception {
runExperimentalRetraceTest(new NpeInlineRetraceStackTrace());
}
@@ -327,6 +327,31 @@
runRetraceTest(new DifferentLineNumberSpanStackTrace());
}
+ @Test
+ public void testOutlineSimpleStackTrace() throws Exception {
+ runExperimentalRetraceTest(new OutlineSimpleStackTrace());
+ }
+
+ @Test
+ public void testOutlineWithInliningStackTrace() throws Exception {
+ runExperimentalRetraceTest(new OutlineWithInliningStackTrace());
+ }
+
+ @Test
+ public void testOutlineInOutlineStackTrace() throws Exception {
+ runExperimentalRetraceTest(new OutlineInOutlineStackTrace());
+ }
+
+ @Test
+ public void testInlineInOutlineStackTrace() throws Exception {
+ runExperimentalRetraceTest(new InlineInOutlineStackTrace());
+ }
+
+ @Test
+ public void testOutsideLineRangeStackTraceTest() throws Exception {
+ runRetraceTest(new OutsideLineRangeStackTraceTest());
+ }
+
private void inspectRetraceTest(
StackTraceForTest stackTraceForTest, Consumer<Retracer> inspection) {
inspection.accept(
@@ -356,7 +381,8 @@
assumeTrue(testParameters.isCfRuntime());
// The external dependency is built on top of R8Lib. If test.py is run with
// no r8lib, do not try and run the external R8 Retrace since it has not been built.
- assumeTrue(Files.exists(ToolHelper.R8LIB_JAR));
+ assumeTrue(ToolHelper.isTestingR8Lib());
+ assertTrue(Files.exists(ToolHelper.R8LIB_JAR));
Path path = temp.newFolder().toPath();
Path mappingFile = path.resolve("mapping");
Files.write(mappingFile, stackTraceForTest.mapping().getBytes());
@@ -370,7 +396,7 @@
command.add(testParameters.getRuntime().asCf().getJavaExecutable().toString());
command.add("-ea");
command.add("-cp");
- command.add(ToolHelper.R8_RETRACE_JAR.toString());
+ command.add(ToolHelper.R8LIB_JAR.toString());
if (allowExperimentalMapping) {
command.add("-Dcom.android.tools.r8.experimentalmapping");
}
diff --git a/src/test/java/com/android/tools/r8/retrace/StackTraceRegularExpressionParserTests.java b/src/test/java/com/android/tools/r8/retrace/StackTraceRegularExpressionParserTests.java
index 9af1378..b769752 100644
--- a/src/test/java/com/android/tools/r8/retrace/StackTraceRegularExpressionParserTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/StackTraceRegularExpressionParserTests.java
@@ -517,12 +517,12 @@
@Override
public List<String> retracedStackTrace() {
- return ImmutableList.of("com.android.tools.r8.R8.foo(42)");
+ return ImmutableList.of("com.android.tools.r8.R8.a(42)");
}
@Override
public List<String> retraceVerboseStackTrace() {
- return ImmutableList.of("com.android.tools.r8.R8.boolean foo()(42)");
+ return ImmutableList.of("com.android.tools.r8.R8.a(42)");
}
@Override
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiAmbiguousOriginalRangeTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiAmbiguousOriginalRangeTest.java
new file mode 100644
index 0000000..3f616f0
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiAmbiguousOriginalRangeTest.java
@@ -0,0 +1,87 @@
+// Copyright (c) 2021, 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.retrace.api;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.retrace.ProguardMapProducer;
+import com.android.tools.r8.retrace.RetraceFrameResult;
+import com.android.tools.r8.retrace.Retracer;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.OptionalInt;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RetraceApiAmbiguousOriginalRangeTest extends RetraceApiTestBase {
+
+ public RetraceApiAmbiguousOriginalRangeTest(TestParameters parameters) {
+ super(parameters);
+ }
+
+ @Override
+ protected Class<? extends RetraceApiBinaryTest> binaryTestClass() {
+ return ApiTest.class;
+ }
+
+ public static class ApiTest implements RetraceApiBinaryTest {
+
+ private final ClassReference renamedHolder = Reference.classFromTypeName("a");
+
+ private final String mapping =
+ "com.android.tools.r8.naming.retrace.Main -> a:\n"
+ + " 1:1:void method():42:44 -> a\n"
+ + " 2:4:void method():45:46 -> a\n"
+ + " 5:6:void method():47:47 -> a\n";
+
+ @Test
+ public void testAmbiguousResult() {
+ Retracer retracer =
+ Retracer.createDefault(
+ ProguardMapProducer.fromString(mapping), new DiagnosticsHandler() {});
+ MethodReference methodReference =
+ Reference.methodFromDescriptor(renamedHolder.getDescriptor(), "a", "()V");
+
+ // Check that retracing with position one is ambiguous between line 42, 43 and 44.
+ RetraceFrameResult retraceFrameResult =
+ retracer.retraceFrame(methodReference, OptionalInt.of(1));
+ assertTrue(retraceFrameResult.isAmbiguous());
+ List<Integer> originalPositions =
+ retraceFrameResult.stream()
+ .map(element -> element.getTopFrame().getOriginalPositionOrDefault(1))
+ .collect(Collectors.toList());
+ assertEquals(Arrays.asList(42, 43, 44), originalPositions);
+
+ // Check that retracing with position 3 is ambiguous between 45 and 46.
+ retraceFrameResult = retracer.retraceFrame(methodReference, OptionalInt.of(3));
+ assertTrue(retraceFrameResult.isAmbiguous());
+ originalPositions =
+ retraceFrameResult.stream()
+ .map(element -> element.getTopFrame().getOriginalPositionOrDefault(3))
+ .collect(Collectors.toList());
+ assertEquals(Arrays.asList(45, 46), originalPositions);
+
+ // Check that retracing with position 5 is not ambiguous.
+ retraceFrameResult = retracer.retraceFrame(methodReference, OptionalInt.of(5));
+ assertFalse(retraceFrameResult.isAmbiguous());
+ originalPositions =
+ retraceFrameResult.stream()
+ .map(element -> element.getTopFrame().getOriginalPositionOrDefault(5))
+ .collect(Collectors.toList());
+ assertEquals(Collections.singletonList(47), originalPositions);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiBinaryCompatibilityTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiBinaryCompatibilityTest.java
index 4b8f03f..a4983b2 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiBinaryCompatibilityTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiBinaryCompatibilityTest.java
@@ -4,25 +4,9 @@
package com.android.tools.r8.retrace.api;
-import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertThrows;
-import static org.junit.Assert.assertTrue;
-
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.TestRuntime.CfRuntime;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.utils.ZipUtils;
-import com.google.common.collect.ImmutableList;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
@@ -32,74 +16,23 @@
@RunWith(Parameterized.class)
public class RetraceApiBinaryCompatibilityTest extends TestBase {
- private final TestParameters parameters;
-
@Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withNoneRuntime().build();
}
public RetraceApiBinaryCompatibilityTest(TestParameters parameters) {
- this.parameters = parameters;
- }
-
- private static final Path BINARY_COMPATIBILITY_JAR =
- Paths.get(ToolHelper.THIRD_PARTY_DIR, "retrace", "binary_compatibility", "tests.jar");
-
- private Path generateJar() throws Exception {
- return RetraceApiTestHelper.generateJarForRetraceBinaryTests(
- temp, RetraceApiTestHelper.getBinaryCompatibilityTests());
+ parameters.assertNoneRuntime();
}
@Test
public void testBinaryJarIsUpToDate() throws Exception {
- Path binaryContents = temp.newFolder().toPath();
- Path generatedContents = temp.newFolder().toPath();
- ZipUtils.unzip(BINARY_COMPATIBILITY_JAR, binaryContents);
- ZipUtils.unzip(generateJar(), generatedContents);
- try (Stream<Path> existingPaths = Files.walk(binaryContents);
- Stream<Path> generatedPaths = Files.walk(generatedContents)) {
- List<Path> existing = existingPaths.filter(this::isClassFile).collect(Collectors.toList());
- List<Path> generated = generatedPaths.filter(this::isClassFile).collect(Collectors.toList());
- assertEquals(existing.size(), generated.size());
- assertNotEquals(0, existing.size());
- for (Path classFile : generated) {
- Path otherClassFile = binaryContents.resolve(generatedContents.relativize(classFile));
- assertTrue("Could not find file: " + otherClassFile, Files.exists(otherClassFile));
- assertTrue(
- "Non-equal files: " + otherClassFile,
- TestBase.filesAreEqual(classFile, otherClassFile));
- }
- }
- }
-
- private boolean isClassFile(Path path) {
- return path.toString().endsWith(".class");
+ new RetraceApiTestCollection(temp).verifyCheckedInJarIsUpToDate();
}
@Test
public void runCheckedInBinaryJar() throws Exception {
- // The retrace jar is only built when building r8lib.
- Path jar = ToolHelper.isTestingR8Lib() ? ToolHelper.R8_RETRACE_JAR : ToolHelper.R8_JAR;
- RetraceApiTestHelper.runJunitOnTests(
- CfRuntime.getSystemRuntime(),
- jar,
- BINARY_COMPATIBILITY_JAR,
- RetraceApiTestHelper.getBinaryCompatibilityTests());
- }
-
- @Test
- public void runCheckedInWithNonExistingTest() {
- Path jar = ToolHelper.isTestingR8Lib() ? ToolHelper.R8_RETRACE_JAR : ToolHelper.R8_JAR;
- assertThrows(
- AssertionError.class,
- () -> {
- RetraceApiTestHelper.runJunitOnTests(
- CfRuntime.getSystemRuntime(),
- jar,
- BINARY_COMPATIBILITY_JAR,
- ImmutableList.of(new RetraceApiBinaryTest() {}.getClass()));
- });
+ new RetraceApiTestCollection(temp).runJunitOnCheckedInJar();
}
/**
@@ -109,9 +42,6 @@
public static void main(String[] args) throws Exception {
TemporaryFolder temp = new TemporaryFolder();
temp.create();
- Path generatedJar =
- RetraceApiTestHelper.generateJarForRetraceBinaryTests(
- temp, RetraceApiTestHelper.getBinaryCompatibilityTests());
- Files.move(generatedJar, BINARY_COMPATIBILITY_JAR, REPLACE_EXISTING);
+ new RetraceApiTestCollection(temp).replaceJarForCheckedInTestClasses();
}
}
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiInlineInOutlineTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiInlineInOutlineTest.java
new file mode 100644
index 0000000..7cce489
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiInlineInOutlineTest.java
@@ -0,0 +1,117 @@
+// Copyright (c) 2021, 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.retrace.api;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.retrace.ProguardMapProducer;
+import com.android.tools.r8.retrace.RetraceFrameElement;
+import com.android.tools.r8.retrace.RetraceStackTraceContext;
+import com.android.tools.r8.retrace.RetracedMethodReference;
+import com.android.tools.r8.retrace.RetracedSingleFrame;
+import com.android.tools.r8.retrace.Retracer;
+import java.util.List;
+import java.util.OptionalInt;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RetraceApiInlineInOutlineTest extends RetraceApiTestBase {
+
+ public RetraceApiInlineInOutlineTest(TestParameters parameters) {
+ super(parameters);
+ }
+
+ @Override
+ protected Class<? extends RetraceApiBinaryTest> binaryTestClass() {
+ return ApiTest.class;
+ }
+
+ public static class ApiTest implements RetraceApiBinaryTest {
+
+ private final ClassReference outlineRenamed = Reference.classFromTypeName("a");
+ private final ClassReference callsiteOriginal = Reference.classFromTypeName("some.Class");
+ private final ClassReference callsiteRenamed = Reference.classFromTypeName("b");
+
+ private final String mapping =
+ "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }\n"
+ + "outline.Class -> "
+ + outlineRenamed.getTypeName()
+ + ":\n"
+ + " 1:2:int some.inlinee():75:76 -> a\n"
+ + " 1:2:int outline():0 -> a\n"
+ + "# { 'id':'com.android.tools.r8.outline' }\n"
+ + callsiteOriginal.getTypeName()
+ + " -> "
+ + callsiteRenamed.getTypeName()
+ + ":\n"
+ + " 1:1:void foo.bar.Baz.qux():42:42 -> s\n"
+ + " 5:5:int foo.bar.baz.outlineCaller(int):98:98 -> s\n"
+ + " 5:5:int outlineCaller(int):24 -> s\n"
+ + " 27:27:int outlineCaller(int):0:0 -> s\n"
+ + "# { 'id':'com.android.tools.r8.outlineCallsite', "
+ + " 'positions': { '1': 4, '2': 5 } }\n";
+
+ @Test
+ public void test() {
+ Retracer retracer =
+ Retracer.createExperimental(
+ ProguardMapProducer.fromString(mapping), new DiagnosticsHandler() {});
+ List<RetraceFrameElement> outlineRetraced =
+ retracer
+ .retraceFrame(
+ Reference.methodFromDescriptor(outlineRenamed, "a", "()I"), OptionalInt.of(2))
+ .stream()
+ .collect(Collectors.toList());
+ // The retrace result should not be ambiguous or empty.
+ assertEquals(1, outlineRetraced.size());
+ RetraceFrameElement retraceFrameElement = outlineRetraced.get(0);
+
+ // Check that visiting all frames report the outline.
+ List<RetracedMethodReference> allMethodReferences =
+ retraceFrameElement.stream()
+ .map(RetracedSingleFrame::getMethodReference)
+ .collect(Collectors.toList());
+ assertEquals(2, allMethodReferences.size());
+ assertEquals(76, allMethodReferences.get(0).getOriginalPositionOrDefault(2));
+ assertEquals(0, allMethodReferences.get(1).getOriginalPositionOrDefault(2));
+
+ // Check that visiting rewritten frames will not report anything.
+ List<RetracedMethodReference> rewrittenReferences =
+ retraceFrameElement
+ .streamRewritten(RetraceStackTraceContext.empty())
+ .map(RetracedSingleFrame::getMethodReference)
+ .collect(Collectors.toList());
+ assertEquals(1, rewrittenReferences.size());
+ assertEquals(76, allMethodReferences.get(0).getOriginalPositionOrDefault(2));
+
+ // Retrace the outline position
+ RetraceStackTraceContext context = retraceFrameElement.getRetraceStackTraceContext();
+ List<RetraceFrameElement> retraceOutlineCallee =
+ retracer
+ .retraceFrame(
+ Reference.methodFromDescriptor(callsiteRenamed, "s", "(I)V"),
+ OptionalInt.of(27),
+ context)
+ .stream()
+ .collect(Collectors.toList());
+ assertEquals(1, retraceOutlineCallee.size());
+
+ List<RetracedMethodReference> outlineCallSiteFrames =
+ retraceOutlineCallee.get(0).stream()
+ .map(RetracedSingleFrame::getMethodReference)
+ .collect(Collectors.toList());
+ assertEquals(2, outlineCallSiteFrames.size());
+ assertEquals(98, outlineCallSiteFrames.get(0).getOriginalPositionOrDefault(27));
+ assertEquals(24, outlineCallSiteFrames.get(1).getOriginalPositionOrDefault(27));
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutlineInOutlineStackTrace.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutlineInOutlineStackTrace.java
new file mode 100644
index 0000000..c2b5c47
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutlineInOutlineStackTrace.java
@@ -0,0 +1,141 @@
+// Copyright (c) 2021, 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.retrace.api;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.retrace.ProguardMapProducer;
+import com.android.tools.r8.retrace.RetraceFrameElement;
+import com.android.tools.r8.retrace.RetraceStackTraceContext;
+import com.android.tools.r8.retrace.RetracedMethodReference;
+import com.android.tools.r8.retrace.RetracedSingleFrame;
+import com.android.tools.r8.retrace.Retracer;
+import java.util.List;
+import java.util.OptionalInt;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RetraceApiOutlineInOutlineStackTrace extends RetraceApiTestBase {
+
+ public RetraceApiOutlineInOutlineStackTrace(TestParameters parameters) {
+ super(parameters);
+ }
+
+ @Override
+ protected Class<? extends RetraceApiBinaryTest> binaryTestClass() {
+ return ApiTest.class;
+ }
+
+ public static class ApiTest implements RetraceApiBinaryTest {
+
+ private final ClassReference outline1Renamed = Reference.classFromTypeName("a");
+ private final ClassReference outline2Renamed = Reference.classFromTypeName("b");
+ private final ClassReference callsiteOriginal = Reference.classFromTypeName("some.Class");
+ private final ClassReference callsiteRenamed = Reference.classFromTypeName("c");
+
+ private final String mapping =
+ "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }\n"
+ + "outline1.Class -> "
+ + outline1Renamed.getTypeName()
+ + ":\n"
+ + " 3:4:int outline():0:0 -> a\n"
+ + "# { 'id':'com.android.tools.r8.outline' }\n"
+ + "outline2.Class -> "
+ + outline2Renamed.getTypeName()
+ + ":\n"
+ + " 6:6:int outline():0:0 -> a\n"
+ + "# { 'id':'com.android.tools.r8.outlineCallsite', "
+ + " 'positions': { '3': 42, '4': 43 } }\n"
+ + " 42:43:int outline():0:0 -> a\n" // This is another call to the outline
+ + "# { 'id':'com.android.tools.r8.outline' }\n"
+ + callsiteOriginal.getTypeName()
+ + " -> "
+ + callsiteRenamed.getTypeName()
+ + ":\n"
+ + " 1:1:void foo.bar.Baz.qux():42:42 -> s\n"
+ + " 10:11:int foo.bar.baz.outlineCaller(int):98:99 -> s\n"
+ + " 28:28:int outlineCaller(int):0:0 -> s\n" // This is the actual call to the outline
+ + "# { 'id':'com.android.tools.r8.outlineCallsite', "
+ + " 'positions': { '42': 10, '43': 11 } }\n";
+
+ @Test
+ public void test() {
+ Retracer retracer =
+ Retracer.createExperimental(
+ ProguardMapProducer.fromString(mapping), new DiagnosticsHandler() {});
+ // Retrace the first outline.
+ RetraceStackTraceContext outlineContext =
+ retraceOutline(
+ retracer,
+ Reference.methodFromDescriptor(outline1Renamed, "a", "()I"),
+ 4,
+ RetraceStackTraceContext.empty());
+
+ // Retrace the second outline using the context of the first retracing.
+ outlineContext =
+ retraceOutline(
+ retracer,
+ Reference.methodFromDescriptor(outline2Renamed, "a", "()I"),
+ 6,
+ outlineContext);
+
+ List<RetraceFrameElement> retraceOutlineCallee =
+ retracer
+ .retraceFrame(
+ Reference.methodFromDescriptor(callsiteRenamed, "s", "(I)V"),
+ OptionalInt.of(28),
+ outlineContext)
+ .stream()
+ .collect(Collectors.toList());
+ assertEquals(1, retraceOutlineCallee.size());
+
+ List<RetracedMethodReference> outlineCallSiteFrames =
+ retraceOutlineCallee.get(0).stream()
+ .map(RetracedSingleFrame::getMethodReference)
+ .collect(Collectors.toList());
+ assertEquals(1, outlineCallSiteFrames.size());
+ assertEquals(99, outlineCallSiteFrames.get(0).getOriginalPositionOrDefault(28));
+ }
+
+ private RetraceStackTraceContext retraceOutline(
+ Retracer retracer,
+ MethodReference reference,
+ int position,
+ RetraceStackTraceContext context) {
+ List<RetraceFrameElement> outlineRetraced =
+ retracer.retraceFrame(reference, OptionalInt.of(position), context).stream()
+ .collect(Collectors.toList());
+ // The retrace result should not be ambiguous or empty.
+ assertEquals(1, outlineRetraced.size());
+ RetraceFrameElement retraceFrameElement = outlineRetraced.get(0);
+
+ // Check that visiting all frames report the outline.
+ List<RetracedMethodReference> allMethodReferences =
+ retraceFrameElement.stream()
+ .map(RetracedSingleFrame::getMethodReference)
+ .collect(Collectors.toList());
+ assertEquals(1, allMethodReferences.size());
+ assertEquals(0, allMethodReferences.get(0).getOriginalPositionOrDefault(position));
+
+ // Check that visiting rewritten frames will not report anything.
+ List<RetracedMethodReference> rewrittenReferences =
+ retraceFrameElement
+ .streamRewritten(RetraceStackTraceContext.empty())
+ .map(RetracedSingleFrame::getMethodReference)
+ .collect(Collectors.toList());
+ assertEquals(0, rewrittenReferences.size());
+
+ return retraceFrameElement.getRetraceStackTraceContext();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutlineInlineTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutlineInlineTest.java
new file mode 100644
index 0000000..6d7fe97
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutlineInlineTest.java
@@ -0,0 +1,114 @@
+// Copyright (c) 2021, 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.retrace.api;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.retrace.ProguardMapProducer;
+import com.android.tools.r8.retrace.RetraceFrameElement;
+import com.android.tools.r8.retrace.RetraceStackTraceContext;
+import com.android.tools.r8.retrace.RetracedMethodReference;
+import com.android.tools.r8.retrace.RetracedSingleFrame;
+import com.android.tools.r8.retrace.Retracer;
+import java.util.List;
+import java.util.OptionalInt;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RetraceApiOutlineInlineTest extends RetraceApiTestBase {
+
+ public RetraceApiOutlineInlineTest(TestParameters parameters) {
+ super(parameters);
+ }
+
+ @Override
+ protected Class<? extends RetraceApiBinaryTest> binaryTestClass() {
+ return ApiTest.class;
+ }
+
+ public static class ApiTest implements RetraceApiBinaryTest {
+
+ private final ClassReference outlineRenamed = Reference.classFromTypeName("a");
+ private final ClassReference callsiteOriginal = Reference.classFromTypeName("some.Class");
+ private final ClassReference callsiteRenamed = Reference.classFromTypeName("b");
+
+ private final String mapping =
+ "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }\n"
+ + "outline.Class -> "
+ + outlineRenamed.getTypeName()
+ + ":\n"
+ + " 1:2:int outline():0:0 -> a\n"
+ + "# { 'id':'com.android.tools.r8.outline' }\n"
+ + callsiteOriginal.getTypeName()
+ + " -> "
+ + callsiteRenamed.getTypeName()
+ + ":\n"
+ + " 1:1:void foo.bar.Baz.qux():42:42 -> s\n"
+ + " 4:4:int foo.bar.baz.outlineCaller(int):98:98 -> s\n"
+ + " 4:4:int outlineCaller(int):24 -> s\n"
+ + " 27:27:int outlineCaller(int):0:0 -> s\n" // This is the actual call to the outline
+ + "# { 'id':'com.android.tools.r8.outlineCallsite', "
+ + " 'positions': { '1': 4, '2': 5 } }\n";
+
+ @Test
+ public void test() {
+ Retracer retracer =
+ Retracer.createExperimental(
+ ProguardMapProducer.fromString(mapping), new DiagnosticsHandler() {});
+ List<RetraceFrameElement> outlineRetraced =
+ retracer
+ .retraceFrame(
+ Reference.methodFromDescriptor(outlineRenamed, "a", "()I"), OptionalInt.of(1))
+ .stream()
+ .collect(Collectors.toList());
+ // The retrace result should not be ambiguous or empty.
+ assertEquals(1, outlineRetraced.size());
+ RetraceFrameElement retraceFrameElement = outlineRetraced.get(0);
+
+ // Check that visiting all frames report the outline.
+ List<RetracedMethodReference> allMethodReferences =
+ retraceFrameElement.stream()
+ .map(RetracedSingleFrame::getMethodReference)
+ .collect(Collectors.toList());
+ assertEquals(1, allMethodReferences.size());
+ assertEquals(0, allMethodReferences.get(0).getOriginalPositionOrDefault(2));
+
+ // Check that visiting rewritten frames will not report anything.
+ List<RetracedMethodReference> rewrittenReferences =
+ retraceFrameElement
+ .streamRewritten(RetraceStackTraceContext.empty())
+ .map(RetracedSingleFrame::getMethodReference)
+ .collect(Collectors.toList());
+ assertEquals(0, rewrittenReferences.size());
+
+ // Retrace the outline position
+ RetraceStackTraceContext context = retraceFrameElement.getRetraceStackTraceContext();
+ List<RetraceFrameElement> retraceOutlineCallee =
+ retracer
+ .retraceFrame(
+ Reference.methodFromDescriptor(callsiteRenamed, "s", "(I)V"),
+ OptionalInt.of(27),
+ context)
+ .stream()
+ .collect(Collectors.toList());
+ assertEquals(1, retraceOutlineCallee.size());
+
+ List<RetracedMethodReference> outlineCallSiteFrames =
+ retraceOutlineCallee.get(0).stream()
+ .map(RetracedSingleFrame::getMethodReference)
+ .collect(Collectors.toList());
+ assertEquals(2, outlineCallSiteFrames.size());
+ assertEquals(98, outlineCallSiteFrames.get(0).getOriginalPositionOrDefault(27));
+ assertEquals(24, outlineCallSiteFrames.get(1).getOriginalPositionOrDefault(27));
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutlineNoInlineTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutlineNoInlineTest.java
new file mode 100644
index 0000000..6330587
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutlineNoInlineTest.java
@@ -0,0 +1,115 @@
+// Copyright (c) 2021, 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.retrace.api;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.retrace.ProguardMapProducer;
+import com.android.tools.r8.retrace.RetraceFrameElement;
+import com.android.tools.r8.retrace.RetraceStackTraceContext;
+import com.android.tools.r8.retrace.RetracedMethodReference;
+import com.android.tools.r8.retrace.RetracedSingleFrame;
+import com.android.tools.r8.retrace.Retracer;
+import java.util.List;
+import java.util.OptionalInt;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RetraceApiOutlineNoInlineTest extends RetraceApiTestBase {
+
+ public RetraceApiOutlineNoInlineTest(TestParameters parameters) {
+ super(parameters);
+ }
+
+ @Override
+ protected Class<? extends RetraceApiBinaryTest> binaryTestClass() {
+ return ApiTest.class;
+ }
+
+ public static class ApiTest implements RetraceApiBinaryTest {
+
+ private final ClassReference outlineRenamed = Reference.classFromTypeName("a");
+ private final ClassReference callsiteOriginal = Reference.classFromTypeName("some.Class");
+ private final ClassReference callsiteRenamed = Reference.classFromTypeName("b");
+
+ private final String mapping =
+ "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }\n"
+ + "outline.Class -> "
+ + outlineRenamed.getTypeName()
+ + ":\n"
+ + " 1:2:int outline():0:0 -> a\n"
+ + "# { 'id':'com.android.tools.r8.outline' }\n"
+ + callsiteOriginal.getTypeName()
+ + " -> "
+ + callsiteRenamed.getTypeName()
+ + ":\n"
+ + " 1:1:void foo.bar.Baz.qux():42:42 -> s\n"
+ + " 4:4:int outlineCaller(int):98:98 -> s\n"
+ + " 27:27:int outlineCaller(int):0:0 -> s\n" // This is the actual call to the outline
+ + "# { 'id':'com.android.tools.r8.outlineCallsite', "
+ + " 'positions': { '1': 4, '2': 5 } }\n";
+
+ @Test
+ public void test() {
+ Retracer retracer =
+ Retracer.createExperimental(
+ ProguardMapProducer.fromString(mapping), new DiagnosticsHandler() {});
+ List<RetraceFrameElement> outlineRetraced =
+ retracer
+ .retraceFrame(
+ Reference.methodFromDescriptor(outlineRenamed, "a", "()I"), OptionalInt.of(1))
+ .stream()
+ .collect(Collectors.toList());
+ // The retrace result should not be ambiguous or empty.
+ assertEquals(1, outlineRetraced.size());
+ RetraceFrameElement retraceFrameElement = outlineRetraced.get(0);
+
+ assertTrue(retraceFrameElement.isCompilerSynthesized());
+
+ // Check that visiting all frames report the outline.
+ List<RetracedMethodReference> allMethodReferences =
+ retraceFrameElement.stream()
+ .map(RetracedSingleFrame::getMethodReference)
+ .collect(Collectors.toList());
+ assertEquals(1, allMethodReferences.size());
+ assertEquals(0, allMethodReferences.get(0).getOriginalPositionOrDefault(2));
+
+ // Check that visiting rewritten frames will not report anything.
+ List<RetracedMethodReference> rewrittenReferences =
+ retraceFrameElement
+ .streamRewritten(RetraceStackTraceContext.empty())
+ .map(RetracedSingleFrame::getMethodReference)
+ .collect(Collectors.toList());
+ assertEquals(0, rewrittenReferences.size());
+
+ // Retrace the outline position
+ RetraceStackTraceContext context = retraceFrameElement.getRetraceStackTraceContext();
+ List<RetraceFrameElement> retraceOutlineCallee =
+ retracer
+ .retraceFrame(
+ Reference.methodFromDescriptor(callsiteRenamed, "s", "(I)V"),
+ OptionalInt.of(27),
+ context)
+ .stream()
+ .collect(Collectors.toList());
+ assertEquals(1, retraceOutlineCallee.size());
+
+ List<RetracedMethodReference> outlineCallSiteFrames =
+ retraceOutlineCallee.get(0).stream()
+ .map(RetracedSingleFrame::getMethodReference)
+ .collect(Collectors.toList());
+ assertEquals(1, outlineCallSiteFrames.size());
+ assertEquals(98, outlineCallSiteFrames.get(0).getOriginalPositionOrDefault(27));
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutsideLineRangeTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutsideLineRangeTest.java
new file mode 100644
index 0000000..a3ba721
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutsideLineRangeTest.java
@@ -0,0 +1,91 @@
+// Copyright (c) 2021, 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.retrace.api;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.retrace.ProguardMapProducer;
+import com.android.tools.r8.retrace.RetraceClassElement;
+import com.android.tools.r8.retrace.RetraceFrameElement;
+import com.android.tools.r8.retrace.RetraceMethodElement;
+import com.android.tools.r8.retrace.RetraceMethodResult;
+import com.android.tools.r8.retrace.RetraceStackTraceContext;
+import com.android.tools.r8.retrace.Retracer;
+import java.util.List;
+import java.util.OptionalInt;
+import java.util.stream.Collectors;
+import org.junit.Test;
+
+public class RetraceApiOutsideLineRangeTest extends RetraceApiTestBase {
+
+ public RetraceApiOutsideLineRangeTest(TestParameters parameters) {
+ super(parameters);
+ }
+
+ @Override
+ protected Class<? extends RetraceApiBinaryTest> binaryTestClass() {
+ return ApiTest.class;
+ }
+
+ public static class ApiTest implements RetraceApiBinaryTest {
+
+ private final ClassReference someOtherClassOriginal =
+ Reference.classFromTypeName("some.other.Class");
+ private final ClassReference someOtherClassRenamed = Reference.classFromTypeName("a");
+ private final ClassReference someClassOriginal = Reference.classFromTypeName("some.Class");
+ private final ClassReference someClassRenamed = Reference.classFromTypeName("b");
+
+ private final String mapping =
+ someOtherClassOriginal.getTypeName()
+ + " -> "
+ + someOtherClassRenamed.getTypeName()
+ + ":\n"
+ + " void method1():42:42 -> a\n"
+ + someClassOriginal.getTypeName()
+ + " -> "
+ + someClassRenamed.getTypeName()
+ + ":\n"
+ + " 1:3:void method2():11:13 -> a\n"
+ + " 4:4:void method2():10:10 -> a\n"
+ + " 28:28:void foo.bar.inlinee():92:92 -> a\n"
+ + " 5:5:void method2():14 -> a\n";
+
+ @Test
+ public void testNoLine() {
+ Retracer retracer =
+ Retracer.createDefault(
+ ProguardMapProducer.fromString(mapping), new DiagnosticsHandler() {});
+ retraceClassMethodAndPosition(retracer, someClassRenamed, someClassOriginal, 2, 0);
+ retraceClassMethodAndPosition(retracer, someOtherClassRenamed, someOtherClassOriginal, 1, 1);
+ }
+
+ private void retraceClassMethodAndPosition(
+ Retracer retracer,
+ ClassReference renamedClass,
+ ClassReference originalClass,
+ int methodCount,
+ int frameCount) {
+ List<RetraceClassElement> classResult =
+ retracer.retraceClass(renamedClass).stream().collect(Collectors.toList());
+ assertEquals(classResult.size(), 1);
+ RetraceClassElement retraceClassResult = classResult.get(0);
+ assertEquals(originalClass, retraceClassResult.getRetracedClass().getClassReference());
+ RetraceMethodResult retraceMethodResult = retraceClassResult.lookupMethod("a");
+ List<RetraceMethodElement> classMethodResults =
+ retraceMethodResult.stream().collect(Collectors.toList());
+ assertEquals(methodCount, classMethodResults.size());
+ List<RetraceFrameElement> classResultFrames =
+ retraceMethodResult
+ .narrowByPosition(RetraceStackTraceContext.empty(), OptionalInt.of(6))
+ .stream()
+ .collect(Collectors.toList());
+ assertEquals(frameCount, classResultFrames.size());
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSingleFrameTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSingleFrameTest.java
new file mode 100644
index 0000000..bec1a7f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSingleFrameTest.java
@@ -0,0 +1,75 @@
+// Copyright (c) 2021, 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.retrace.api;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.retrace.ProguardMapProducer;
+import com.android.tools.r8.retrace.RetraceFrameElement;
+import com.android.tools.r8.retrace.RetraceStackTraceContext;
+import com.android.tools.r8.retrace.RetracedMethodReference;
+import com.android.tools.r8.retrace.Retracer;
+import java.util.List;
+import java.util.OptionalInt;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RetraceApiSingleFrameTest extends RetraceApiTestBase {
+
+ public RetraceApiSingleFrameTest(TestParameters parameters) {
+ super(parameters);
+ }
+
+ @Override
+ protected Class<? extends RetraceApiBinaryTest> binaryTestClass() {
+ return ApiTest.class;
+ }
+
+ public static class ApiTest implements RetraceApiBinaryTest {
+
+ private final ClassReference originalClass = Reference.classFromTypeName("some.Class");
+ private final ClassReference renamedClass = Reference.classFromTypeName("a");
+
+ private final String mapping =
+ originalClass.getTypeName()
+ + " -> "
+ + renamedClass.getTypeName()
+ + ":\n"
+ + " int strawberry(int):99:99 -> a\n";
+
+ @Test
+ public void testRetracingFrameEqualToNarrow() {
+ Retracer retracer =
+ Retracer.createDefault(
+ ProguardMapProducer.fromString(mapping), new DiagnosticsHandler() {});
+ checkResults(
+ retracer
+ .retraceFrame(
+ Reference.methodFromDescriptor(renamedClass, "a", "()I"), OptionalInt.empty())
+ .stream()
+ .collect(Collectors.toList()));
+ checkResults(
+ retracer
+ .retraceClass(renamedClass)
+ .lookupFrame(RetraceStackTraceContext.empty(), OptionalInt.empty(), "a")
+ .stream()
+ .collect(Collectors.toList()));
+ }
+
+ private void checkResults(List<RetraceFrameElement> elements) {
+ assertEquals(1, elements.size());
+ RetracedMethodReference topFrame = elements.get(0).getTopFrame();
+ assertEquals("strawberry", topFrame.getMethodName());
+ assertEquals(99, topFrame.getOriginalPositionOrDefault(-1));
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestBase.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestBase.java
index a58102a..4dcd86a 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestBase.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestBase.java
@@ -4,50 +4,31 @@
package com.android.tools.r8.retrace.api;
-import static com.android.tools.r8.retrace.api.RetraceApiTestHelper.runJunitOnTests;
-import static org.junit.Assert.assertTrue;
-
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper;
-import java.nio.file.Files;
-import org.junit.Assume;
import org.junit.Test;
-import org.junit.runner.JUnitCore;
-import org.junit.runner.Result;
-import org.junit.runner.notification.Failure;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
+@RunWith(Parameterized.class)
public abstract class RetraceApiTestBase extends TestBase {
- private final TestParameters parameters;
-
@Parameters(name = "{0}")
public static TestParametersCollection data() {
- return TestParametersBuilder.builder().withSystemRuntime().build();
+ return TestParametersBuilder.builder().withNoneRuntime().build();
}
public RetraceApiTestBase(TestParameters parameters) {
- this.parameters = parameters;
+ parameters.assertNoneRuntime();
}
protected abstract Class<? extends RetraceApiBinaryTest> binaryTestClass();
@Test
- public void testDirect() {
- Result result = JUnitCore.runClasses(binaryTestClass());
- for (Failure failure : result.getFailures()) {
- System.out.println(failure.toString());
- }
- assertTrue(result.wasSuccessful());
- }
-
- @Test
- public void testRetraceLib() throws Exception {
- Assume.assumeTrue(Files.exists(ToolHelper.R8_RETRACE_JAR));
- runJunitOnTests(
- parameters.getRuntime().asCf(), ToolHelper.R8_RETRACE_JAR, binaryTestClass(), temp);
+ public void testExternal() throws Exception {
+ new RetraceApiTestCollection(temp).runJunitOnTestClass(binaryTestClass());
}
}
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestCollection.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestCollection.java
new file mode 100644
index 0000000..77b8aea
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestCollection.java
@@ -0,0 +1,86 @@
+// Copyright (c) 2021, 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.retrace.api;
+
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.compilerapi.BinaryCompatibilityTestCollection;
+import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import org.junit.rules.TemporaryFolder;
+
+public class RetraceApiTestCollection
+ extends BinaryCompatibilityTestCollection<RetraceApiBinaryTest> {
+
+ private static final Path BINARY_COMPATIBILITY_JAR =
+ Paths.get(ToolHelper.THIRD_PARTY_DIR, "retrace", "binary_compatibility", "tests.jar");
+
+ public static List<Class<? extends RetraceApiBinaryTest>> CLASSES_FOR_BINARY_COMPATIBILITY =
+ ImmutableList.of(
+ RetraceApiEmptyTest.RetraceTest.class,
+ RetraceApiSourceFileTest.ApiTest.class,
+ RetraceApiSourceFileNotFoundTest.ApiTest.class,
+ RetraceApiInferSourceFileTest.ApiTest.class,
+ RetraceApiSynthesizedClassTest.ApiTest.class,
+ RetraceApiSynthesizedFieldTest.ApiTest.class,
+ RetraceApiSynthesizedMethodTest.ApiTest.class,
+ RetraceApiSynthesizedFrameTest.ApiTest.class,
+ RetraceApiSynthesizedInnerFrameTest.ApiTest.class,
+ RetraceApiUnknownJsonTest.ApiTest.class,
+ RetraceApiRewriteFrameInlineNpeTest.ApiTest.class,
+ RetraceApiAmbiguousOriginalRangeTest.ApiTest.class,
+ RetraceApiOutsideLineRangeTest.ApiTest.class);
+
+ public static List<Class<? extends RetraceApiBinaryTest>> CLASSES_PENDING_BINARY_COMPATIBILITY =
+ ImmutableList.of(
+ RetraceApiRewriteFrameInlineNpeResidualTest.ApiTest.class,
+ RetraceApiOutlineNoInlineTest.ApiTest.class,
+ RetraceApiOutlineInlineTest.ApiTest.class,
+ RetraceApiOutlineInOutlineStackTrace.ApiTest.class,
+ RetraceApiInlineInOutlineTest.ApiTest.class,
+ RetraceApiSingleFrameTest.ApiTest.class);
+
+ private final TemporaryFolder temp;
+
+ public RetraceApiTestCollection(TemporaryFolder temp) {
+ this.temp = temp;
+ }
+
+ @Override
+ public TemporaryFolder getTemp() {
+ return temp;
+ }
+
+ @Override
+ public Path getTargetJar() {
+ return ToolHelper.isTestingR8Lib() ? ToolHelper.R8LIB_JAR : ToolHelper.R8_JAR;
+ }
+
+ @Override
+ public Path getCheckedInTestJar() {
+ return BINARY_COMPATIBILITY_JAR;
+ }
+
+ @Override
+ public List<Class<? extends RetraceApiBinaryTest>> getCheckedInTestClasses() {
+ return CLASSES_FOR_BINARY_COMPATIBILITY;
+ }
+
+ @Override
+ public List<Class<? extends RetraceApiBinaryTest>> getPendingTestClasses() {
+ return CLASSES_PENDING_BINARY_COMPATIBILITY;
+ }
+
+ @Override
+ public List<Class<?>> getAdditionalClassesForTests() {
+ return ImmutableList.of(RetraceApiBinaryTest.class);
+ }
+
+ @Override
+ public List<String> getVmArgs() {
+ return ImmutableList.of();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestHelper.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestHelper.java
deleted file mode 100644
index 3bbb842..0000000
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestHelper.java
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright (c) 2021, 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.retrace.api;
-
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import com.android.tools.r8.Collectors;
-import com.android.tools.r8.TestRuntime.CfRuntime;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.transformers.ClassFileTransformer;
-import com.android.tools.r8.transformers.ClassFileTransformer.InnerClassPredicate;
-import com.android.tools.r8.utils.DescriptorUtils;
-import com.android.tools.r8.utils.ZipUtils;
-import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
-import com.google.common.collect.ImmutableList;
-import java.io.File;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import org.junit.rules.TemporaryFolder;
-
-public class RetraceApiTestHelper {
-
- private static final String JUNIT_JAR = "junit-4.13-beta-2.jar";
- private static final String HAMCREST = "hamcrest-core-1.3.jar";
-
- public static List<Class<? extends RetraceApiBinaryTest>> CLASSES_FOR_BINARY_COMPATIBILITY =
- ImmutableList.of(
- RetraceApiEmptyTest.RetraceTest.class,
- RetraceApiSourceFileTest.ApiTest.class,
- RetraceApiSourceFileNotFoundTest.ApiTest.class,
- RetraceApiInferSourceFileTest.ApiTest.class,
- RetraceApiSynthesizedClassTest.ApiTest.class,
- RetraceApiSynthesizedFieldTest.ApiTest.class,
- RetraceApiSynthesizedMethodTest.ApiTest.class,
- RetraceApiSynthesizedFrameTest.ApiTest.class,
- RetraceApiSynthesizedInnerFrameTest.ApiTest.class,
- RetraceApiUnknownJsonTest.ApiTest.class,
- RetraceApiRewriteFrameInlineNpeTest.ApiTest.class);
- public static List<Class<? extends RetraceApiBinaryTest>> CLASSES_PENDING_BINARY_COMPATIBILITY =
- ImmutableList.of(RetraceApiRewriteFrameInlineNpeResidualTest.ApiTest.class);
-
- public static void runJunitOnTests(
- CfRuntime runtime,
- Path r8Jar,
- Class<? extends RetraceApiBinaryTest> clazz,
- TemporaryFolder temp)
- throws Exception {
- assertTrue(testIsSpecifiedAsBinaryOrPending(clazz));
- List<Class<? extends RetraceApiBinaryTest>> testClasses = ImmutableList.of(clazz);
- runJunitOnTests(
- runtime, r8Jar, generateJarForRetraceBinaryTests(temp, testClasses), testClasses);
- }
-
- public static void runJunitOnTests(
- CfRuntime runtime,
- Path r8Jar,
- Path testJar,
- Collection<Class<? extends RetraceApiBinaryTest>> tests)
- throws Exception {
- List<Path> classPaths = ImmutableList.of(getJunitDependency(), getHamcrest(), r8Jar, testJar);
- List<String> args = new ArrayList<>();
- args.add("org.junit.runner.JUnitCore");
- tests.forEach(test -> args.add(test.getTypeName()));
- ProcessResult processResult =
- ToolHelper.runJava(runtime, classPaths, args.toArray(new String[0]));
- assertEquals(processResult.toString(), 0, processResult.exitCode);
- assertThat(processResult.stdout, containsString("OK (" + tests.size() + " test"));
- }
-
- private static Path getJunitDependency() {
- String junitPath =
- Arrays.stream(System.getProperty("java.class.path").split(File.pathSeparator))
- .filter(cp -> cp.endsWith(JUNIT_JAR))
- .collect(Collectors.toSingle());
- return Paths.get(junitPath);
- }
-
- private static Path getHamcrest() {
- String junitPath =
- Arrays.stream(System.getProperty("java.class.path").split(File.pathSeparator))
- .filter(cp -> cp.endsWith(HAMCREST))
- .collect(Collectors.toSingle());
- return Paths.get(junitPath);
- }
-
- public static Path generateJarForRetraceBinaryTests(
- TemporaryFolder temp, Collection<Class<? extends RetraceApiBinaryTest>> classes)
- throws Exception {
- Path jar = File.createTempFile("retrace_api_tests", ".jar", temp.getRoot()).toPath();
- ZipBuilder zipBuilder = ZipBuilder.builder(jar);
- for (Class<? extends RetraceApiBinaryTest> retraceApiTest : classes) {
- zipBuilder.addFilesRelative(
- ToolHelper.getClassPathForTests(),
- ToolHelper.getClassFilesForInnerClasses(retraceApiTest));
- zipBuilder.addBytes(
- ZipUtils.zipEntryNameForClass(retraceApiTest),
- ClassFileTransformer.create(retraceApiTest)
- .removeInnerClasses(
- InnerClassPredicate.onName(
- DescriptorUtils.getBinaryNameFromJavaType(retraceApiTest.getTypeName())))
- .transform());
- }
- zipBuilder.addFilesRelative(
- ToolHelper.getClassPathForTests(),
- ToolHelper.getClassFileForTestClass(RetraceApiBinaryTest.class));
- return zipBuilder.build();
- }
-
- public static Collection<Class<? extends RetraceApiBinaryTest>> getBinaryCompatibilityTests() {
- return CLASSES_FOR_BINARY_COMPATIBILITY;
- }
-
- private static boolean testIsSpecifiedAsBinaryOrPending(Class<?> clazz) {
- return CLASSES_FOR_BINARY_COMPATIBILITY.contains(clazz)
- || CLASSES_PENDING_BINARY_COMPATIBILITY.contains(clazz);
- }
-}
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousWithMultipleLineMappingsStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousWithMultipleLineMappingsStackTrace.java
index 1041ace..4015e0e 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousWithMultipleLineMappingsStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousWithMultipleLineMappingsStackTrace.java
@@ -38,9 +38,16 @@
@Override
public List<String> retraceVerboseStackTrace() {
return Arrays.asList(
+ "There are 3 ambiguous stack traces.",
"java.lang.IndexOutOfBoundsException",
"\tat java.util.ArrayList.get(ArrayList.java:411)",
- "\tat com.android.tools.r8.Internal.void foo(int)(Internal.java)");
+ "\tat com.android.tools.r8.Internal.void foo(int)(Internal.java:10)",
+ "<OR> java.lang.IndexOutOfBoundsException",
+ "\tat java.util.ArrayList.get(ArrayList.java:411)",
+ "\tat com.android.tools.r8.Internal.void foo(int)(Internal.java:11)",
+ "<OR> java.lang.IndexOutOfBoundsException",
+ "\tat java.util.ArrayList.get(ArrayList.java:411)",
+ "\tat com.android.tools.r8.Internal.void foo(int)(Internal.java:12)");
}
@Override
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousWithSignatureNonVerboseStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousWithSignatureStackTrace.java
similarity index 93%
rename from src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousWithSignatureNonVerboseStackTrace.java
rename to src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousWithSignatureStackTrace.java
index 7c0c0c2..212976f 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousWithSignatureNonVerboseStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousWithSignatureStackTrace.java
@@ -8,7 +8,7 @@
import java.util.Arrays;
import java.util.List;
-public class AmbiguousWithSignatureNonVerboseStackTrace implements StackTraceForTest {
+public class AmbiguousWithSignatureStackTrace implements StackTraceForTest {
@Override
public List<String> obfuscatedStackTrace() {
@@ -42,16 +42,16 @@
"There are 4 ambiguous stack traces.",
"java.lang.IndexOutOfBoundsException",
"\tat java.util.ArrayList.get(ArrayList.java:411)",
- "\tat com.android.tools.r8.Internal.boolean foo(int,int)(Internal.java)",
+ "\tat com.android.tools.r8.Internal.boolean foo(int,int)(Internal.java:13)",
"<OR> java.lang.IndexOutOfBoundsException",
"\tat java.util.ArrayList.get(ArrayList.java:411)",
- "\tat com.android.tools.r8.Internal.void foo(int)(Internal.java)",
+ "\tat com.android.tools.r8.Internal.void foo(int)(Internal.java:10)",
"<OR> java.lang.IndexOutOfBoundsException",
"\tat java.util.ArrayList.get(ArrayList.java:411)",
- "\tat com.android.tools.r8.Internal.void foo(int,boolean)(Internal.java)",
+ "\tat com.android.tools.r8.Internal.void foo(int,boolean)(Internal.java:12)",
"<OR> java.lang.IndexOutOfBoundsException",
"\tat java.util.ArrayList.get(ArrayList.java:411)",
- "\tat com.android.tools.r8.Internal.void foo(int,int)(Internal.java)");
+ "\tat com.android.tools.r8.Internal.void foo(int,int)(Internal.java:11)");
}
@Override
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousWithSignatureVerboseStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousWithSignatureVerboseStackTrace.java
deleted file mode 100644
index a00b7bf..0000000
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousWithSignatureVerboseStackTrace.java
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2020, 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.retrace.stacktraces;
-
-import com.android.tools.r8.utils.StringUtils;
-import java.util.Arrays;
-import java.util.List;
-
-public class AmbiguousWithSignatureVerboseStackTrace implements StackTraceForTest {
-
- @Override
- public List<String> obfuscatedStackTrace() {
- return Arrays.asList(
- "java.lang.IndexOutOfBoundsException",
- "\tat java.util.ArrayList.get(ArrayList.java:411)",
- "\tat com.android.tools.r8.Internal.zza(Unknown)");
- }
-
- @Override
- public String mapping() {
- return StringUtils.lines(
- "com.android.tools.r8.Internal -> com.android.tools.r8.Internal:",
- " 10:10:void foo(int):10:10 -> zza",
- " 11:11:void foo(int,int):11:11 -> zza",
- " 12:12:void foo(int,boolean):12:12 -> zza",
- " 13:13:boolean foo(int,int):13:13 -> zza");
- }
-
- @Override
- public List<String> retracedStackTrace() {
- return Arrays.asList(
- "java.lang.IndexOutOfBoundsException",
- "\tat java.util.ArrayList.get(ArrayList.java:411)",
- "\tat com.android.tools.r8.Internal.foo(Internal.java)");
- }
-
- @Override
- public List<String> retraceVerboseStackTrace() {
- return Arrays.asList(
- "There are 4 ambiguous stack traces.",
- "java.lang.IndexOutOfBoundsException",
- "\tat java.util.ArrayList.get(ArrayList.java:411)",
- "\tat com.android.tools.r8.Internal.boolean foo(int,int)(Internal.java)",
- "<OR> java.lang.IndexOutOfBoundsException",
- "\tat java.util.ArrayList.get(ArrayList.java:411)",
- "\tat com.android.tools.r8.Internal.void foo(int)(Internal.java)",
- "<OR> java.lang.IndexOutOfBoundsException",
- "\tat java.util.ArrayList.get(ArrayList.java:411)",
- "\tat com.android.tools.r8.Internal.void foo(int,boolean)(Internal.java)",
- "<OR> java.lang.IndexOutOfBoundsException",
- "\tat java.util.ArrayList.get(ArrayList.java:411)",
- "\tat com.android.tools.r8.Internal.void foo(int,int)(Internal.java)");
- }
-
- @Override
- public int expectedWarnings() {
- return 0;
- }
-}
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/DifferentLineNumberSpanStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/DifferentLineNumberSpanStackTrace.java
index 16a2725..b4efedd 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/DifferentLineNumberSpanStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/DifferentLineNumberSpanStackTrace.java
@@ -21,24 +21,33 @@
public String mapping() {
return StringUtils.lines(
"com.android.tools.r8.naming.retrace.Main -> a:",
- " 1:1:void method1(java.lang.String):42:44 -> a");
+ " void method1(java.lang.String):42:44 -> a");
}
@Override
public List<String> retracedStackTrace() {
return Arrays.asList(
"Exception in thread \"main\" java.lang.NullPointerException",
- // TODO(b/201042571): Should be ambiguous or have line number removed
- "\tat com.android.tools.r8.naming.retrace.Main.method1(Main.java:42)");
+ "\tat com.android.tools.r8.naming.retrace.Main.method1(Main.java:42)",
+ "<OR> Exception in thread \"main\" java.lang.NullPointerException",
+ "\tat com.android.tools.r8.naming.retrace.Main.method1(Main.java:43)",
+ "<OR> Exception in thread \"main\" java.lang.NullPointerException",
+ "\tat com.android.tools.r8.naming.retrace.Main.method1(Main.java:44)");
}
@Override
public List<String> retraceVerboseStackTrace() {
return Arrays.asList(
+ "There are 3 ambiguous stack traces.",
"Exception in thread \"main\" java.lang.NullPointerException",
"\tat com.android.tools.r8.naming.retrace.Main.void"
- // TODO(b/201042571): Should be ambiguous or have line number removed
- + " method1(java.lang.String)(Main.java:42)");
+ + " method1(java.lang.String)(Main.java:42)",
+ "<OR> Exception in thread \"main\" java.lang.NullPointerException",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " method1(java.lang.String)(Main.java:43)",
+ "<OR> Exception in thread \"main\" java.lang.NullPointerException",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " method1(java.lang.String)(Main.java:44)");
}
@Override
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/InlineInOutlineStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/InlineInOutlineStackTrace.java
new file mode 100644
index 0000000..a231a0f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/InlineInOutlineStackTrace.java
@@ -0,0 +1,56 @@
+// Copyright (c) 2021, 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.retrace.stacktraces;
+
+import com.android.tools.r8.utils.StringUtils;
+import java.util.Arrays;
+import java.util.List;
+
+public class InlineInOutlineStackTrace implements StackTraceForTest {
+
+ @Override
+ public List<String> obfuscatedStackTrace() {
+ return Arrays.asList("java.io.IOException: INVALID_SENDER", "\tat a.a(:2)", "\tat b.s(:27)");
+ }
+
+ @Override
+ public String mapping() {
+ return StringUtils.lines(
+ "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }",
+ "outline.Class -> a:",
+ " 1:2:int some.inlinee():75:76 -> a",
+ " 1:2:int outline():0 -> a",
+ "# { 'id':'com.android.tools.r8.outline' }",
+ "some.Class -> b:",
+ " 1:1:void foo.bar.Baz.qux():42:42 -> s",
+ " 5:5:int foo.bar.baz.outlineCaller(int):98:98 -> s",
+ " 5:5:int outlineCaller(int):24 -> s",
+ " 27:27:int outlineCaller(int):0:0 -> s",
+ "# { 'id':'com.android.tools.r8.outlineCallsite', 'positions': { '1': 4, '2': 5 } }");
+ }
+
+ @Override
+ public List<String> retracedStackTrace() {
+ return Arrays.asList(
+ "java.io.IOException: INVALID_SENDER",
+ "\tat some.inlinee(some.java:76)",
+ "\tat foo.bar.baz.outlineCaller(baz.java:98)",
+ "\tat some.Class.outlineCaller(Class.java:24)");
+ }
+
+ @Override
+ public List<String> retraceVerboseStackTrace() {
+ return Arrays.asList(
+ "java.io.IOException: INVALID_SENDER",
+ "\tat some.int inlinee()(some.java:76)",
+ "\tat foo.bar.baz.int outlineCaller(int)(baz.java:98)",
+ "\tat some.Class.int outlineCaller(int)(Class.java:24)");
+ }
+
+ @Override
+ public int expectedWarnings() {
+ return 0;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/MultipleLinesNoLineNumberStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/MultipleLinesNoLineNumberStackTrace.java
index 6df2b28..a961d7b 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/MultipleLinesNoLineNumberStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/MultipleLinesNoLineNumberStackTrace.java
@@ -41,10 +41,13 @@
return Arrays.asList(
"There are 2 ambiguous stack traces.",
"Exception in thread \"main\" java.lang.NullPointerException",
- "\tat com.android.tools.r8.naming.retrace.Main.void main(java.lang.String[])(Main.java)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " main(java.lang.String[])(Main.java:153)",
"<OR> Exception in thread \"main\" java.lang.NullPointerException",
- "\tat com.android.tools.r8.naming.retrace.Main.void method1(java.lang.String)(Main.java)",
- "\tat com.android.tools.r8.naming.retrace.Main.void main(java.lang.String[])(Main.java)");
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " method1(java.lang.String)(Main.java:42)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " main(java.lang.String[])(Main.java:28)");
}
@Override
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/MultipleOriginalLinesNoLineNumberStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/MultipleOriginalLinesNoLineNumberStackTrace.java
index d4688c9..a4b4fa3 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/MultipleOriginalLinesNoLineNumberStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/MultipleOriginalLinesNoLineNumberStackTrace.java
@@ -27,17 +27,19 @@
public List<String> retracedStackTrace() {
return Arrays.asList(
"Exception in thread \"main\" java.lang.NullPointerException",
- // TODO(b/201042571): Should not report a line number
- "\tat com.android.tools.r8.naming.retrace.Main.method1(Main.java:42)");
+ "\tat com.android.tools.r8.naming.retrace.Main.method1(Main.java)");
}
@Override
public List<String> retraceVerboseStackTrace() {
return Arrays.asList(
+ "There are 2 ambiguous stack traces.",
"Exception in thread \"main\" java.lang.NullPointerException",
"\tat com.android.tools.r8.naming.retrace.Main.void"
- // TODO(b/201042571): Should not report a line number
- + " method1(java.lang.String)(Main.java:42)");
+ + " method1(java.lang.String)(Main.java:42)",
+ "<OR> Exception in thread \"main\" java.lang.NullPointerException",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " method1(java.lang.String)(Main.java:43)");
}
@Override
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/NoObfuscatedLineNumberWithOverrideTest.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/NoObfuscatedLineNumberWithOverrideTest.java
index 2e57740..273b002 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/NoObfuscatedLineNumberWithOverrideTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/NoObfuscatedLineNumberWithOverrideTest.java
@@ -37,23 +37,13 @@
return Arrays.asList(
"Exception in thread \"main\" java.lang.NullPointerException",
"\tat com.android.tools.r8.naming.retrace.Main.main(Main.java:3)",
- "\tat com.android.tools.r8.naming.retrace.Main.overload1(Main.java:7)",
- "\tat com.android.tools.r8.naming.retrace.Main.definedOverload(Main.java:7)",
+ "\tat com.android.tools.r8.naming.retrace.Main.overload1(Main.java)",
+ "\tat com.android.tools.r8.naming.retrace.Main.definedOverload(Main.java)",
"\tat com.android.tools.r8.naming.retrace.Main.mainPC(Main.java:42)",
"<OR> Exception in thread \"main\" java.lang.NullPointerException",
"\tat com.android.tools.r8.naming.retrace.Main.main(Main.java:3)",
- "\tat com.android.tools.r8.naming.retrace.Main.overload1(Main.java:7)",
- "\tat com.android.tools.r8.naming.retrace.Main.definedOverload(Main.java:11)",
- "\tat com.android.tools.r8.naming.retrace.Main.mainPC(Main.java:42)",
- "<OR> Exception in thread \"main\" java.lang.NullPointerException",
- "\tat com.android.tools.r8.naming.retrace.Main.main(Main.java:3)",
- "\tat com.android.tools.r8.naming.retrace.Main.overload2(Main.java:11)",
- "\tat com.android.tools.r8.naming.retrace.Main.definedOverload(Main.java:7)",
- "\tat com.android.tools.r8.naming.retrace.Main.mainPC(Main.java:42)",
- "<OR> Exception in thread \"main\" java.lang.NullPointerException",
- "\tat com.android.tools.r8.naming.retrace.Main.main(Main.java:3)",
- "\tat com.android.tools.r8.naming.retrace.Main.overload2(Main.java:11)",
- "\tat com.android.tools.r8.naming.retrace.Main.definedOverload(Main.java:11)",
+ "\tat com.android.tools.r8.naming.retrace.Main.overload2(Main.java)",
+ "\tat com.android.tools.r8.naming.retrace.Main.definedOverload(Main.java)",
"\tat com.android.tools.r8.naming.retrace.Main.mainPC(Main.java:42)");
}
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/NoObfuscationRangeMappingWithStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/NoObfuscationRangeMappingWithStackTrace.java
index 579541f..8ec36a8 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/NoObfuscationRangeMappingWithStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/NoObfuscationRangeMappingWithStackTrace.java
@@ -26,8 +26,8 @@
"Exception in thread \"main\" java.lang.NullPointerException",
"\tat com.android.tools.r8.naming.retrace.Main.foo(Main.java:1)",
"\tat com.android.tools.r8.naming.retrace.Main.bar(Main.java:3)",
- "\tat com.android.tools.r8.naming.retrace.Main.baz(Main.java:8)",
- "\tat com.android.tools.r8.naming.retrace.Main.main(Main.java:7)");
+ "\tat com.android.tools.r8.naming.retrace.Main.baz(Main.java:0)",
+ "\tat com.android.tools.r8.naming.retrace.Main.main(Main.java:0)");
}
@Override
@@ -36,8 +36,8 @@
"Exception in thread \"main\" java.lang.NullPointerException",
"\tat com.android.tools.r8.naming.retrace.Main.void foo(long)(Main.java:1)",
"\tat com.android.tools.r8.naming.retrace.Main.void bar(int)(Main.java:3)",
- "\tat com.android.tools.r8.naming.retrace.Main.void baz()(Main.java:8)",
- "\tat com.android.tools.r8.naming.retrace.Main.void main(java.lang.String[])(Main.java:7)");
+ "\tat com.android.tools.r8.naming.retrace.Main.void baz()(Main.java:0)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void main(java.lang.String[])(Main.java:0)");
}
@Override
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/OutlineInOutlineStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/OutlineInOutlineStackTrace.java
new file mode 100644
index 0000000..ae8b52b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/OutlineInOutlineStackTrace.java
@@ -0,0 +1,55 @@
+// Copyright (c) 2021, 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.retrace.stacktraces;
+
+import com.android.tools.r8.utils.StringUtils;
+import java.util.Arrays;
+import java.util.List;
+
+public class OutlineInOutlineStackTrace implements StackTraceForTest {
+
+ @Override
+ public List<String> obfuscatedStackTrace() {
+ return Arrays.asList(
+ "java.io.IOException: INVALID_SENDER", "\tat a.a(:4)", "\tat b.a(:6)", "\tat c.a(:28)");
+ }
+
+ @Override
+ public String mapping() {
+ return StringUtils.lines(
+ "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }",
+ "outline1.Class -> a:",
+ " 4:4:int outline():0:0 -> a",
+ "# { 'id':'com.android.tools.r8.outline' }",
+ "outline2.Class -> b:",
+ " 6:6:int outline():0:0 -> a",
+ "# { 'id':'com.android.tools.r8.outlineCallsite', 'positions': { '4': 43 } }",
+ " 42:43:int outline():0:0 -> a",
+ "# { 'id':'com.android.tools.r8.outline' }",
+ "some.Class -> c:",
+ " 1:1:void foo.bar.Baz.qux():42:42 -> a",
+ " 10:11:int outlineCaller(int):98:98 -> a",
+ " 28:28:int outlineCaller(int):0:0 -> a",
+ "# { 'id':'com.android.tools.r8.outlineCallsite', 'positions': { '42': 10, '43': 11 } }");
+ }
+
+ @Override
+ public List<String> retracedStackTrace() {
+ return Arrays.asList(
+ "java.io.IOException: INVALID_SENDER", "\tat some.Class.outlineCaller(Class.java:98)");
+ }
+
+ @Override
+ public List<String> retraceVerboseStackTrace() {
+ return Arrays.asList(
+ "java.io.IOException: INVALID_SENDER",
+ "\tat some.Class.int outlineCaller(int)(Class.java:98)");
+ }
+
+ @Override
+ public int expectedWarnings() {
+ return 0;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/OutlineSimpleStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/OutlineSimpleStackTrace.java
new file mode 100644
index 0000000..ad0dddc
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/OutlineSimpleStackTrace.java
@@ -0,0 +1,49 @@
+// Copyright (c) 2021, 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.retrace.stacktraces;
+
+import com.android.tools.r8.utils.StringUtils;
+import java.util.Arrays;
+import java.util.List;
+
+public class OutlineSimpleStackTrace implements StackTraceForTest {
+
+ @Override
+ public List<String> obfuscatedStackTrace() {
+ return Arrays.asList("java.io.IOException: INVALID_SENDER", "\tat a.a(:1)", "\tat b.s(:27)");
+ }
+
+ @Override
+ public String mapping() {
+ return StringUtils.lines(
+ "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }",
+ "outline.Class -> a:",
+ " 1:2:int outline() -> a",
+ "# { 'id':'com.android.tools.r8.outline' }",
+ "some.Class -> b:",
+ " 1:1:void foo.bar.Baz.qux():42:42 -> s",
+ " 4:4:int outlineCaller(int):98:98 -> s",
+ " 27:27:int outlineCaller(int):0:0 -> s",
+ "# { 'id':'com.android.tools.r8.outlineCallsite', 'positions': { '1': 4, '2': 5 } }");
+ }
+
+ @Override
+ public List<String> retracedStackTrace() {
+ return Arrays.asList(
+ "java.io.IOException: INVALID_SENDER", "\tat some.Class.outlineCaller(Class.java:98)");
+ }
+
+ @Override
+ public List<String> retraceVerboseStackTrace() {
+ return Arrays.asList(
+ "java.io.IOException: INVALID_SENDER",
+ "\tat some.Class.int outlineCaller(int)(Class.java:98)");
+ }
+
+ @Override
+ public int expectedWarnings() {
+ return 0;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/OutlineWithInliningStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/OutlineWithInliningStackTrace.java
new file mode 100644
index 0000000..a8198a2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/OutlineWithInliningStackTrace.java
@@ -0,0 +1,53 @@
+// Copyright (c) 2021, 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.retrace.stacktraces;
+
+import com.android.tools.r8.utils.StringUtils;
+import java.util.Arrays;
+import java.util.List;
+
+public class OutlineWithInliningStackTrace implements StackTraceForTest {
+
+ @Override
+ public List<String> obfuscatedStackTrace() {
+ return Arrays.asList("java.io.IOException: INVALID_SENDER", "\tat a.a(:2)", "\tat b.s(:27)");
+ }
+
+ @Override
+ public String mapping() {
+ return StringUtils.lines(
+ "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }",
+ "outline.Class -> a:",
+ " 1:2:int outline():0 -> a",
+ "# { 'id':'com.android.tools.r8.outline' }",
+ "some.Class -> b:",
+ " 1:1:void foo.bar.Baz.qux():42:42 -> s",
+ " 5:5:int foo.bar.baz.outlineCaller(int):98:98 -> s",
+ " 5:5:int outlineCaller(int):24 -> s",
+ " 27:27:int outlineCaller(int):0:0 -> s",
+ "# { 'id':'com.android.tools.r8.outlineCallsite', 'positions': { '1': 4, '2': 5 } }");
+ }
+
+ @Override
+ public List<String> retracedStackTrace() {
+ return Arrays.asList(
+ "java.io.IOException: INVALID_SENDER",
+ "\tat foo.bar.baz.outlineCaller(baz.java:98)",
+ "\tat some.Class.outlineCaller(Class.java:24)");
+ }
+
+ @Override
+ public List<String> retraceVerboseStackTrace() {
+ return Arrays.asList(
+ "java.io.IOException: INVALID_SENDER",
+ "\tat foo.bar.baz.int outlineCaller(int)(baz.java:98)",
+ "\tat some.Class.int outlineCaller(int)(Class.java:24)");
+ }
+
+ @Override
+ public int expectedWarnings() {
+ return 0;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/OutsideLineRangeStackTraceTest.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/OutsideLineRangeStackTraceTest.java
new file mode 100644
index 0000000..81587cf
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/OutsideLineRangeStackTraceTest.java
@@ -0,0 +1,64 @@
+// Copyright (c) 2021, 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.retrace.stacktraces;
+
+import com.android.tools.r8.utils.StringUtils;
+import java.util.Arrays;
+import java.util.List;
+
+public class OutsideLineRangeStackTraceTest implements StackTraceForTest {
+
+ @Override
+ public List<String> obfuscatedStackTrace() {
+ return Arrays.asList(
+ "java.io.IOException: INVALID_SENDER",
+ "\tat a.a(:2)",
+ "\tat a.a(Unknown Source)",
+ "\tat b.a(:27)",
+ "\tat b.a(Unknown Source)");
+ }
+
+ @Override
+ public String mapping() {
+ return StringUtils.lines(
+ "some.other.Class -> a:",
+ " void method1():42:42 -> a",
+ "some.Class -> b:",
+ " 1:3:void method2():11:13 -> a",
+ " 4:4:void method2():10:10 -> a");
+ }
+
+ @Override
+ public List<String> retracedStackTrace() {
+ return Arrays.asList(
+ "java.io.IOException: INVALID_SENDER",
+ "\tat some.other.Class.method1(Class.java:42)",
+ "\tat some.other.Class.method1(Class.java:42)",
+ "\tat some.Class.a(Class.java:27)",
+ "\tat some.Class.method2(Class.java)");
+ }
+
+ @Override
+ public List<String> retraceVerboseStackTrace() {
+ return Arrays.asList(
+ "There are 2 ambiguous stack traces.",
+ "java.io.IOException: INVALID_SENDER",
+ "\tat some.other.Class.void method1()(Class.java:42)",
+ "\tat some.other.Class.void method1()(Class.java:42)",
+ "\tat some.Class.a(Class.java:27)",
+ // TODO(b/202055473): Could emit range 11-13.
+ "\tat some.Class.void method2()(Class.java)",
+ "<OR> java.io.IOException: INVALID_SENDER",
+ "\tat some.other.Class.void method1()(Class.java:42)",
+ "\tat some.other.Class.void method1()(Class.java:42)",
+ "\tat some.Class.a(Class.java:27)",
+ "\tat some.Class.void method2()(Class.java:10)");
+ }
+
+ @Override
+ public int expectedWarnings() {
+ return 0;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/SingleLineNoLineNumberStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/SingleLineNoLineNumberStackTrace.java
index 8f6e183..c30fdbf 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/SingleLineNoLineNumberStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/SingleLineNoLineNumberStackTrace.java
@@ -26,7 +26,7 @@
"com.android.tools.r8.naming.retrace.Main -> foo.a:",
" 0:0:void method1(java.lang.String):42:42 -> a",
" 0:0:void main(java.lang.String[]):28 -> a",
- " 0:0:void method2(java.lang.String):42:48 -> b",
+ " 0:0:void method2(java.lang.String):42:44 -> b",
" 0:0:void main2(java.lang.String[]):29 -> b",
" void method3(java.lang.String):72:72 -> c",
" void main3(java.lang.String[]):30 -> c",
@@ -39,23 +39,23 @@
"Exception in thread \"main\" java.lang.NullPointerException",
"\tat com.android.tools.r8.naming.retrace.Main.method1(Main.java:42)",
"\tat com.android.tools.r8.naming.retrace.Main.main(Main.java:28)",
- "\tat com.android.tools.r8.naming.retrace.Main.method2(Main.java:42)",
- "\tat com.android.tools.r8.naming.retrace.Main.main2(Main.java:29)",
- "\tat com.android.tools.r8.naming.retrace.Main.main3(Main.java:30)",
+ "\tat com.android.tools.r8.naming.retrace.Main.method2(Main.java)",
+ "\tat com.android.tools.r8.naming.retrace.Main.main2(Main.java)",
+ "\tat com.android.tools.r8.naming.retrace.Main.main3(Main.java)",
"\tat com.android.tools.r8.naming.retrace.Main.main4(Main.java:153)",
"<OR> Exception in thread \"main\" java.lang.NullPointerException",
"\tat com.android.tools.r8.naming.retrace.Main.method1(Main.java:42)",
"\tat com.android.tools.r8.naming.retrace.Main.main(Main.java:28)",
- "\tat com.android.tools.r8.naming.retrace.Main.method2(Main.java:42)",
- "\tat com.android.tools.r8.naming.retrace.Main.main2(Main.java:29)",
- "\tat com.android.tools.r8.naming.retrace.Main.method3(Main.java:72)",
+ "\tat com.android.tools.r8.naming.retrace.Main.method2(Main.java)",
+ "\tat com.android.tools.r8.naming.retrace.Main.main2(Main.java)",
+ "\tat com.android.tools.r8.naming.retrace.Main.method3(Main.java)",
"\tat com.android.tools.r8.naming.retrace.Main.main4(Main.java:153)");
}
@Override
public List<String> retraceVerboseStackTrace() {
return Arrays.asList(
- "There are 2 ambiguous stack traces.",
+ "There are 6 ambiguous stack traces.",
"Exception in thread \"main\" java.lang.NullPointerException",
"\tat com.android.tools.r8.naming.retrace.Main.void"
+ " method1(java.lang.String)(Main.java:42)",
@@ -79,6 +79,54 @@
"\tat com.android.tools.r8.naming.retrace.Main.void"
+ " method3(java.lang.String)(Main.java:72)",
"\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " main4(java.lang.String[])(Main.java:153)",
+ "<OR> Exception in thread \"main\" java.lang.NullPointerException",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " method1(java.lang.String)(Main.java:42)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void main(java.lang.String[])(Main.java:28)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " method2(java.lang.String)(Main.java:43)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " main2(java.lang.String[])(Main.java:29)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " main3(java.lang.String[])(Main.java:30)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " main4(java.lang.String[])(Main.java:153)",
+ "<OR> Exception in thread \"main\" java.lang.NullPointerException",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " method1(java.lang.String)(Main.java:42)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void main(java.lang.String[])(Main.java:28)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " method2(java.lang.String)(Main.java:43)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " main2(java.lang.String[])(Main.java:29)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " method3(java.lang.String)(Main.java:72)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " main4(java.lang.String[])(Main.java:153)",
+ "<OR> Exception in thread \"main\" java.lang.NullPointerException",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " method1(java.lang.String)(Main.java:42)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void main(java.lang.String[])(Main.java:28)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " method2(java.lang.String)(Main.java:44)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " main2(java.lang.String[])(Main.java:29)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " main3(java.lang.String[])(Main.java:30)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " main4(java.lang.String[])(Main.java:153)",
+ "<OR> Exception in thread \"main\" java.lang.NullPointerException",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " method1(java.lang.String)(Main.java:42)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void main(java.lang.String[])(Main.java:28)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " method2(java.lang.String)(Main.java:44)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " main2(java.lang.String[])(Main.java:29)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ + " method3(java.lang.String)(Main.java:72)",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ " main4(java.lang.String[])(Main.java:153)");
}
diff --git a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
index a38f6f2..5e37647 100644
--- a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
+++ b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
@@ -587,6 +587,18 @@
});
}
+ public ClassFileTransformer rewriteEnclosingMethod(
+ String newOwner, String newName, String newDescriptor) {
+ return addClassTransformer(
+ new ClassTransformer() {
+
+ @Override
+ public void visitOuterClass(String owner, String name, String descriptor) {
+ super.visitOuterClass(newOwner, newName, newDescriptor);
+ }
+ });
+ }
+
public ClassFileTransformer removeMethods(MethodPredicate predicate) {
return addClassTransformer(
new ClassTransformer() {
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
index 4e2b27d..cf9ce0a 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.retrace.RetraceMethodResult;
import com.android.tools.r8.retrace.RetraceStackTraceContext;
import com.android.tools.r8.retrace.Retracer;
+import java.util.OptionalInt;
public interface InstructionSubject {
@@ -163,11 +164,13 @@
}
default RetraceFrameResult retraceLinePosition(Retracer retracer) {
- return retrace(retracer).narrowByPosition(RetraceStackTraceContext.empty(), getLineNumber());
+ return retrace(retracer)
+ .narrowByPosition(RetraceStackTraceContext.empty(), OptionalInt.of(getLineNumber()));
}
default RetraceFrameResult retracePcPosition(Retracer retracer, MethodSubject methodSubject) {
return retrace(retracer)
- .narrowByPosition(RetraceStackTraceContext.empty(), getOffset(methodSubject).offset);
+ .narrowByPosition(
+ RetraceStackTraceContext.empty(), OptionalInt.of(getOffset(methodSubject).offset));
}
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java b/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java
index 8b54ae2..7a78ed0 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java
@@ -8,7 +8,7 @@
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
-import com.android.tools.r8.Collectors;
+import com.android.tools.r8.CollectorsUtils;
import com.android.tools.r8.Diagnostic;
import com.android.tools.r8.DiagnosticsMatcher;
import com.android.tools.r8.errors.Unreachable;
@@ -586,7 +586,7 @@
return new TypeSafeMatcher<RetraceFrameResult>() {
@Override
protected boolean matchesSafely(RetraceFrameResult item) {
- RetraceFrameElement single = item.stream().collect(Collectors.toSingle());
+ RetraceFrameElement single = item.stream().collect(CollectorsUtils.toSingle());
Box<LinePosition> currentPosition = new Box<>(startPosition);
Box<Boolean> returnValue = new Box<>();
single.stream()
@@ -627,7 +627,7 @@
return new TypeSafeMatcher<RetraceFrameResult>() {
@Override
protected boolean matchesSafely(RetraceFrameResult item) {
- RetraceFrameElement single = item.stream().collect(Collectors.toSingle());
+ RetraceFrameElement single = item.stream().collect(CollectorsUtils.toSingle());
return !single.stream()
.anyMatch(
frame -> {
diff --git a/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1 b/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1
new file mode 100644
index 0000000..759844b
--- /dev/null
+++ b/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1
@@ -0,0 +1 @@
+8ddcb2b3cd52273413a538b22438e996e5c0dfcb
\ No newline at end of file
diff --git a/third_party/dart-sdk.tar.gz.sha1 b/third_party/dart-sdk.tar.gz.sha1
index f8b4a60..2c16136 100644
--- a/third_party/dart-sdk.tar.gz.sha1
+++ b/third_party/dart-sdk.tar.gz.sha1
@@ -1 +1 @@
-0f15c6a81827ce4979b6fcf6183ef35df335d9dc
\ No newline at end of file
+5dfd3e8a9eabac7c138a3cc80e6bbd8b7dafd5ae
\ No newline at end of file
diff --git a/third_party/retrace/binary_compatibility.tar.gz.sha1 b/third_party/retrace/binary_compatibility.tar.gz.sha1
index 6b09100..f81f5fc 100644
--- a/third_party/retrace/binary_compatibility.tar.gz.sha1
+++ b/third_party/retrace/binary_compatibility.tar.gz.sha1
@@ -1 +1 @@
-e7ea0fbb97ccfb2faa89b58d60f8b54f5bca0130
\ No newline at end of file
+239b7652dc8282715373a1871987c3919df029d6
\ No newline at end of file
diff --git a/tools/archive.py b/tools/archive.py
index 24e8e0a..5207e5c 100755
--- a/tools/archive.py
+++ b/tools/archive.py
@@ -145,8 +145,6 @@
utils.D8,
utils.R8LIB,
utils.R8LIB_NO_DEPS,
- utils.R8RETRACE,
- utils.R8RETRACE_NO_DEPS,
utils.LIBRARY_DESUGAR_CONVERSIONS,
'-Pno_internal'
])
@@ -193,8 +191,6 @@
utils.R8_FULL_EXCLUDE_DEPS_JAR,
utils.R8LIB_EXCLUDE_DEPS_JAR,
utils.R8LIB_EXCLUDE_DEPS_JAR + '.map',
- utils.R8RETRACE_JAR,
- utils.R8RETRACE_EXCLUDE_DEPS_JAR,
utils.MAVEN_ZIP,
utils.MAVEN_ZIP_LIB,
utils.DESUGAR_CONFIGURATION,
diff --git a/tools/fmt-diff.py b/tools/fmt-diff.py
index 4e97f3a..fc08c80 100755
--- a/tools/fmt-diff.py
+++ b/tools/fmt-diff.py
@@ -22,7 +22,7 @@
upstream = subprocess.check_output(['git', 'cl', 'upstream']).strip()
git_diff_process = Popen(['git', 'diff', '-U0', upstream], stdout=PIPE)
fmt_process = Popen(
- ['python', GOOGLE_JAVA_FORMAT_DIFF, '-p1', '-i'],
+ [sys.executable, GOOGLE_JAVA_FORMAT_DIFF, '-p1', '-i'],
stdin=git_diff_process.stdout)
git_diff_process.stdout.close()
fmt_process.communicate()
diff --git a/tools/r8_release.py b/tools/r8_release.py
index f9d14f9..a0ed999 100755
--- a/tools/r8_release.py
+++ b/tools/r8_release.py
@@ -363,7 +363,6 @@
g4_open('src.jar')
g4_open('lib.jar')
g4_open('lib.jar.map')
- g4_open('retrace_lib.jar')
g4_open('desugar_jdk_libs_configuration.jar')
download_file(options.version, 'r8-full-exclude-deps.jar', 'full.jar')
download_file(options.version, 'r8-src.jar', 'src.jar')
@@ -372,7 +371,6 @@
options.version, 'r8lib-exclude-deps.jar.map', 'lib.jar.map')
download_file(options.version, 'desugar_jdk_libs_configuration.jar',
'desugar_jdk_libs_configuration.jar')
- download_file(options.version, 'r8retrace-exclude-deps.jar', 'retrace_lib.jar')
g4_open('METADATA')
sed(r'[1-9]\.[0-9]{1,2}\.[0-9]{1,3}-dev',
options.version,
diff --git a/tools/test.py b/tools/test.py
index 6f27a56..071036c 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -318,7 +318,6 @@
# Force gradle to build a version of r8lib without dependencies for
# BootstrapCurrentEqualityTest.
gradle_args.append('R8LibNoDeps')
- gradle_args.append('R8Retrace')
if options.r8lib_no_deps:
gradle_args.append('-Pr8lib_no_deps')
if options.worktree:
diff --git a/tools/utils.py b/tools/utils.py
index 641e352..53aac35 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -41,8 +41,6 @@
R8 = 'r8'
R8LIB = 'r8lib'
R8LIB_NO_DEPS = 'r8LibNoDeps'
-R8RETRACE = 'R8Retrace'
-R8RETRACE_NO_DEPS = 'R8RetraceNoDeps'
R8_SRC = 'sourceJar'
LIBRARY_DESUGAR_CONVERSIONS = 'buildLibraryDesugarConversions'
@@ -54,8 +52,6 @@
R8_SRC_JAR = os.path.join(LIBS, 'r8-src.jar')
R8LIB_EXCLUDE_DEPS_JAR = os.path.join(LIBS, 'r8lib-exclude-deps.jar')
R8_FULL_EXCLUDE_DEPS_JAR = os.path.join(LIBS, 'r8-full-exclude-deps.jar')
-R8RETRACE_JAR = os.path.join(LIBS, 'r8retrace.jar')
-R8RETRACE_EXCLUDE_DEPS_JAR = os.path.join(LIBS, 'r8retrace-exclude-deps.jar')
MAVEN_ZIP = os.path.join(LIBS, 'r8.zip')
MAVEN_ZIP_LIB = os.path.join(LIBS, 'r8lib.zip')
LIBRARY_DESUGAR_CONVERSIONS_ZIP = os.path.join(LIBS, 'library_desugar_conversions.zip')