Remove ownership pointer from code objects.
Change-Id: I8571a4fa764dc69a3152d770173372375069d3af
diff --git a/src/main/java/com/android/tools/r8/cf/CfPrinter.java b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
index 97a9aaf..4378118 100644
--- a/src/main/java/com/android/tools/r8/cf/CfPrinter.java
+++ b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
@@ -50,6 +50,7 @@
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCode.LocalVariableInfo;
import com.android.tools.r8.graph.DebugLocalInfo;
+import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
@@ -115,7 +116,12 @@
}
/** Entry for printing a complete code object. */
- public CfPrinter(CfCode code, ClassNameMapper mapper) {
+ public CfPrinter(CfCode code) {
+ this(code, null, null);
+ }
+
+ /** Entry for printing a complete method object. */
+ public CfPrinter(CfCode code, DexEncodedMethod method, ClassNameMapper mapper) {
this.mapper = mapper;
indent = " ";
instructionIndexSpace = ("" + code.getInstructions().size()).length();
@@ -127,9 +133,11 @@
sortedLabels.add((CfLabel) instruction);
}
}
- builder.append(".method ");
- appendMethod(code.getMethod());
- newline();
+ if (method != null) {
+ builder.append(".method ");
+ appendMethod(method.method);
+ newline();
+ }
builder.append(".limit stack ").append(code.getMaxStack());
newline();
builder.append(".limit locals ").append(code.getMaxLocals());
@@ -175,8 +183,10 @@
instruction.print(this);
}
newline();
- builder.append(".end method");
- newline();
+ if (method != null) {
+ builder.append(".end method");
+ newline();
+ }
}
private List<List<LocalVariableInfo>> computeLocalsAtLabels(
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index bdb28f8..7339bb3 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -72,7 +72,6 @@
}
}
- private final DexMethod method;
private final int maxStack;
private final int maxLocals;
public final List<CfInstruction> instructions;
@@ -80,13 +79,11 @@
private final List<LocalVariableInfo> localVariables;
public CfCode(
- DexMethod method,
int maxStack,
int maxLocals,
List<CfInstruction> instructions,
List<CfTryCatch> tryCatchRanges,
List<LocalVariableInfo> localVariables) {
- this.method = method;
this.maxStack = maxStack;
this.maxLocals = maxLocals;
this.instructions = instructions;
@@ -94,10 +91,6 @@
this.localVariables = localVariables;
}
- public DexMethod getMethod() {
- return method;
- }
-
public int getMaxStack() {
return maxStack;
}
@@ -215,7 +208,6 @@
@Override
public IRCode buildIR(DexEncodedMethod encodedMethod, AppView<?> appView, Origin origin) {
- assert getOwner() == encodedMethod;
return internalBuild(encodedMethod, encodedMethod, appView, null, null, origin);
}
@@ -227,7 +219,6 @@
ValueNumberGenerator valueNumberGenerator,
Position callerPosition,
Origin origin) {
- assert getOwner() == encodedMethod;
assert valueNumberGenerator != null;
assert callerPosition != null;
return internalBuild(
@@ -258,9 +249,9 @@
}
@Override
- public void registerCodeReferences(UseRegistry registry) {
+ public void registerCodeReferences(DexEncodedMethod method, UseRegistry registry) {
for (CfInstruction instruction : instructions) {
- instruction.registerUse(registry, method.holder);
+ instruction.registerUse(registry, method.method.holder);
}
for (CfTryCatch tryCatch : tryCatchRanges) {
for (DexType guard : tryCatch.guards) {
@@ -271,11 +262,11 @@
@Override
public String toString() {
- return new CfPrinter(this, null).toString();
+ return new CfPrinter(this).toString();
}
@Override
public String toString(DexEncodedMethod method, ClassNameMapper naming) {
- return new CfPrinter(this, naming).toString();
+ return new CfPrinter(this, method, naming).toString();
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/Code.java b/src/main/java/com/android/tools/r8/graph/Code.java
index ca71f6e..82c50c8 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -15,18 +15,6 @@
public abstract class Code extends CachedHashValueDexItem {
- private DexEncodedMethod owner;
-
- public void setOwner(DexEncodedMethod encodedMethod) {
- // When this Code is un/linked to DexEncodedMethod, the ownership should be updated accordingly.
- owner = encodedMethod;
- }
-
- public DexEncodedMethod getOwner() {
- // build*IR() will check if the current Code belongs to the given DexEncodedMethod.
- return owner;
- }
-
public abstract IRCode buildIR(DexEncodedMethod encodedMethod, AppView<?> appView, Origin origin);
public IRCode buildInliningIR(
@@ -40,9 +28,9 @@
+ getClass().getCanonicalName());
}
- public abstract void registerCodeReferences(UseRegistry registry);
+ public abstract void registerCodeReferences(DexEncodedMethod method, UseRegistry registry);
- public void registerArgumentReferences(ArgumentUse registry) {
+ public void registerArgumentReferences(DexEncodedMethod method, ArgumentUse registry) {
throw new Unreachable();
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexCode.java b/src/main/java/com/android/tools/r8/graph/DexCode.java
index 6f1f727..a5b1097 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -214,7 +214,6 @@
@Override
public IRCode buildIR(DexEncodedMethod encodedMethod, AppView<?> appView, Origin origin) {
- assert getOwner() == encodedMethod;
DexSourceCode source =
new DexSourceCode(
this,
@@ -234,7 +233,6 @@
ValueNumberGenerator valueNumberGenerator,
Position callerPosition,
Origin origin) {
- assert getOwner() == encodedMethod;
DexSourceCode source =
new DexSourceCode(
this,
@@ -246,7 +244,7 @@
}
@Override
- public void registerCodeReferences(UseRegistry registry) {
+ public void registerCodeReferences(DexEncodedMethod method, UseRegistry registry) {
for (Instruction insn : instructions) {
insn.registerUse(registry);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 00b927a..b7bfbd4 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -157,11 +157,8 @@
assert implementation != null;
assert code != null;
assert code == implementation.getCode();
- assert code.getOwner() == implementation;
accessFlags.setAbstract();
removeCode();
- // Reset the code ownership to the implementation method as the above removeCode cleared it.
- implementation.setCodeOwnership();
defaultInterfaceMethodImplementation = implementation;
}
@@ -190,7 +187,6 @@
this.parameterAnnotationsList = parameterAnnotationsList;
this.code = code;
assert code == null || !shouldNotHaveCode();
- setCodeOwnership();
}
public DexEncodedMethod(
@@ -267,6 +263,11 @@
return isVirtualMethod() && !accessFlags.isAbstract();
}
+ public boolean isNonAbstractNonNativeMethod() {
+ checkIfObsolete();
+ return !accessFlags.isAbstract() && !accessFlags.isNative();
+ }
+
public boolean isPublicized() {
checkIfObsolete();
return accessFlags.isPromotedToPublic();
@@ -393,9 +394,7 @@
public void setCode(Code code) {
checkIfObsolete();
- voidCodeOwnership();
this.code = code;
- setCodeOwnership();
}
public void setCode(IRCode ir, RegisterAllocator registerAllocator, InternalOptions options) {
@@ -452,22 +451,9 @@
public void removeCode() {
checkIfObsolete();
- voidCodeOwnership();
code = null;
}
- private void setCodeOwnership() {
- if (code != null) {
- code.setOwner(this);
- }
- }
-
- public void voidCodeOwnership() {
- if (code != null) {
- code.setOwner(null);
- }
- }
-
public int getClassFileVersion() {
checkIfObsolete();
assert classFileVersion >= 0;
@@ -540,14 +526,12 @@
// a subtype, i.e., self contradict.
assert !accessFlags.isFinal();
accessFlags.setAbstract();
- voidCodeOwnership();
this.code = null;
return this;
}
public IRCode buildEmptyThrowingIRCode(AppView<?> appView, Origin origin) {
DexCode emptyThrowingDexCode = buildEmptyThrowingDexCode();
- emptyThrowingDexCode.setOwner(this);
return emptyThrowingDexCode.buildIR(this, appView, origin);
}
@@ -596,7 +580,6 @@
public CfCode buildEmptyThrowingCfCode() {
CfInstruction insn[] = {new CfConstNull(), new CfThrow()};
return new CfCode(
- method,
1,
method.proto.parameters.size() + 1,
Arrays.asList(insn),
@@ -700,7 +683,6 @@
.add(new CfThrow());
CfCode code =
new CfCode(
- method,
3,
locals,
instructionBuilder.build(),
@@ -957,7 +939,7 @@
if (Log.ENABLED) {
Log.verbose(getClass(), "Registering definitions reachable from `%s`.", method);
}
- code.registerCodeReferences(registry);
+ code.registerCodeReferences(this, registry);
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
index fbfb968..9538a2b 100644
--- a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
@@ -21,6 +21,10 @@
public class DirectMappedDexApplication extends DexApplication {
+ // Mapping from code objects to their encoded-method owner. Used for asserting unique ownership
+ // and debugging purposes.
+ private final Map<Code, DexEncodedMethod> codeOwners = new IdentityHashMap<>();
+
// Unmodifiable mapping of all types to their definitions.
private final Map<DexType, DexClass> allClasses;
// Collections of the three different types for iteration.
@@ -103,6 +107,7 @@
// As a side effect, this will rebuild the program classes and library classes maps.
DirectMappedDexApplication rewrittenApplication = this.builder().build().asDirect();
assert rewrittenApplication.mappingIsValid(graphLense, allClasses.keySet());
+ assert rewrittenApplication.verifyCodeObjectsOwners();
return rewrittenApplication;
}
@@ -122,6 +127,36 @@
return true;
}
+ // Debugging helper to compute the code-object owner map.
+ public Map<Code, DexEncodedMethod> computeCodeObjectOwnersForDebugging() {
+ // Call the verification method without assert to ensure owners are computed.
+ verifyCodeObjectsOwners();
+ return codeOwners;
+ }
+
+ // Debugging helper to find the method a code object belongs to.
+ public DexEncodedMethod getCodeOwnerForDebugging(Code code) {
+ return computeCodeObjectOwnersForDebugging().get(code);
+ }
+
+ private boolean verifyCodeObjectsOwners() {
+ codeOwners.clear();
+ for (DexProgramClass clazz : programClasses) {
+ for (DexEncodedMethod method :
+ clazz.methods(DexEncodedMethod::isNonAbstractNonNativeMethod)) {
+ Code code = method.getCode();
+ assert code != null;
+ // If code is (lazy) CF code, then use the CF code object rather than the lazy wrapper.
+ if (code.isCfCode()) {
+ code = code.asCfCode();
+ }
+ DexEncodedMethod otherMethod = codeOwners.put(code, method);
+ assert otherMethod == null;
+ }
+ }
+ return true;
+ }
+
public static class Builder extends DexApplication.Builder<Builder> {
private final ImmutableList<DexLibraryClass> libraryClasses;
diff --git a/src/main/java/com/android/tools/r8/graph/JarCode.java b/src/main/java/com/android/tools/r8/graph/JarCode.java
index d91a050..f1f3eca 100644
--- a/src/main/java/com/android/tools/r8/graph/JarCode.java
+++ b/src/main/java/com/android/tools/r8/graph/JarCode.java
@@ -146,7 +146,6 @@
AppView<?> appView,
ValueNumberGenerator generator,
Position callerPosition) {
- assert getOwner() == encodedMethod;
triggerDelayedParsingIfNeccessary();
if (!keepLocals(encodedMethod, appView.options())) {
// We strip locals here because we will not be able to recover from invalid info.
@@ -201,10 +200,10 @@
}
@Override
- public void registerCodeReferences(UseRegistry registry) {
+ public void registerCodeReferences(DexEncodedMethod method, UseRegistry registry) {
triggerDelayedParsingIfNeccessary();
node.instructions.accept(
- new JarRegisterEffectsVisitor(method.holder, registry, application));
+ new JarRegisterEffectsVisitor(method.method.holder, registry, application));
for (TryCatchBlockNode tryCatchBlockNode : node.tryCatchBlocks) {
// Exception type can be null for "catch all" used for try/finally.
if (tryCatchBlockNode.type != null) {
@@ -215,9 +214,9 @@
}
@Override
- public void registerArgumentReferences(ArgumentUse registry) {
+ public void registerArgumentReferences(DexEncodedMethod method, ArgumentUse registry) {
triggerDelayedParsingIfNeccessary();
- node.instructions.accept(new JarArgumentUseVisitor(getOwner(), registry));
+ node.instructions.accept(new JarArgumentUseVisitor(method, registry));
}
public ConstraintWithTarget computeInliningConstraint(
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 212d380..43745d6 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -86,14 +86,12 @@
public LazyCfCode(
DexMethod method, Origin origin, ReparseContext context, JarApplicationReader application) {
- this.method = method;
this.origin = origin;
this.context = context;
this.application = application;
context.codeList.add(this);
}
- private final DexMethod method;
private final Origin origin;
private final JarApplicationReader application;
private CfCode code;
@@ -145,8 +143,6 @@
assert this.context != null;
this.code = code;
this.context = null;
- // Propagate the ownership of LazyCfCode to CfCode.
- code.setOwner(this.getOwner());
}
@Override
@@ -176,7 +172,6 @@
@Override
public IRCode buildIR(DexEncodedMethod encodedMethod, AppView<?> appView, Origin origin) {
- assert getOwner() == encodedMethod;
return asCfCode().buildIR(encodedMethod, appView, origin);
}
@@ -188,15 +183,14 @@
ValueNumberGenerator valueNumberGenerator,
Position callerPosition,
Origin origin) {
- assert getOwner() == encodedMethod;
return asCfCode()
.buildInliningIR(
context, encodedMethod, appView, valueNumberGenerator, callerPosition, origin);
}
@Override
- public void registerCodeReferences(UseRegistry registry) {
- asCfCode().registerCodeReferences(registry);
+ public void registerCodeReferences(DexEncodedMethod method, UseRegistry registry) {
+ asCfCode().registerCodeReferences(method, registry);
}
@Override
@@ -231,8 +225,7 @@
if (!flags.isAbstract() && !flags.isNative()) {
LazyCfCode code = context.codeList.get(methodIndex++).asLazyCfCode();
DexMethod method = application.getMethod(context.owner.type, name, desc);
- assert code.method == method;
- MethodCodeVisitor methodVisitor = new MethodCodeVisitor(application, code);
+ MethodCodeVisitor methodVisitor = new MethodCodeVisitor(application, method, code);
if (!usrJsrInliner) {
return methodVisitor;
}
@@ -253,14 +246,14 @@
private final Map<DebugLocalInfo, DebugLocalInfo> canonicalDebugLocalInfo = new HashMap<>();
private Map<Label, CfLabel> labelMap;
private final LazyCfCode code;
- private DexMethod method;
+ private final DexMethod method;
- MethodCodeVisitor(JarApplicationReader application, LazyCfCode code) {
+ MethodCodeVisitor(JarApplicationReader application, DexMethod method, LazyCfCode code) {
super(InternalOptions.ASM_VERSION);
this.application = application;
this.factory = application.getFactory();
- this.method = code.method;
this.code = code;
+ this.method = method;
}
@Override
@@ -275,8 +268,7 @@
@Override
public void visitEnd() {
- code.setCode(
- new CfCode(method, maxStack, maxLocals, instructions, tryCatchRanges, localVariables));
+ code.setCode(new CfCode(maxStack, maxLocals, instructions, tryCatchRanges, localVariables));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
index 2764c93..bfc8352 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
@@ -321,7 +321,6 @@
}
}
return new CfCode(
- method.method,
stackHeightTracker.maxHeight,
registerAllocator.registersUsed(),
instructions,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
index 3487de2..7d5618b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
@@ -1514,7 +1514,6 @@
@Override
public IRCode buildIR(DexEncodedMethod encodedMethod, AppView<?> appView, Origin origin) {
- assert getOwner() == encodedMethod;
OutlineSourceCode source = new OutlineSourceCode(outline, encodedMethod.method);
return new IRBuilder(encodedMethod, appView, source, origin).build(encodedMethod);
}
@@ -1525,7 +1524,7 @@
}
@Override
- public void registerCodeReferences(UseRegistry registry) {
+ public void registerCodeReferences(DexEncodedMethod method, UseRegistry registry) {
throw new Unreachable();
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
index 168a216..166ec88 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
@@ -292,7 +292,6 @@
return null;
}
}
- assert method.getCode().getOwner() == method;
int offset = method.accessFlags.isStatic() ? 0 : 1;
int argumentCount = method.method.proto.parameters.size() + offset;
CollectUsedArguments collector = new CollectUsedArguments();
@@ -301,7 +300,7 @@
// static.
collector.register(0);
}
- method.getCode().registerArgumentReferences(collector);
+ method.getCode().registerArgumentReferences(method, collector);
BitSet used = collector.getUsedArguments();
if (used.cardinality() < argumentCount) {
List<RemovedArgumentInfo> unused = new ArrayList<>();
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
index 5c489ac..25a35ad 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
@@ -35,7 +35,6 @@
@Override
public final IRCode buildIR(DexEncodedMethod encodedMethod, AppView<?> appView, Origin origin) {
- assert getOwner() == encodedMethod;
IRBuilder builder =
new IRBuilder(
encodedMethod,
@@ -54,7 +53,6 @@
ValueNumberGenerator valueNumberGenerator,
Position callerPosition,
Origin origin) {
- assert getOwner() == encodedMethod;
IRBuilder builder =
new IRBuilder(
encodedMethod,
@@ -71,7 +69,7 @@
}
@Override
- public void registerCodeReferences(UseRegistry registry) {
+ public void registerCodeReferences(DexEncodedMethod method, UseRegistry registry) {
getRegistryCallback().accept(registry);
}
diff --git a/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java b/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
index 88260d4..8101b6b 100644
--- a/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
+++ b/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
@@ -75,7 +75,7 @@
}
InvokeSingleTargetExtractor targetExtractor =
new InvokeSingleTargetExtractor(appView.dexItemFactory());
- method.getCode().registerCodeReferences(targetExtractor);
+ method.getCode().registerCodeReferences(method, targetExtractor);
DexMethod target = targetExtractor.getTarget();
InvokeKind kind = targetExtractor.getKind();
// javac-generated visibility forward bridge method has same descriptor (name, signature and
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 575a774..b71e9e1 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -1062,7 +1062,6 @@
toBeDiscarded.forEach(
method -> {
assert !method.isObsolete();
- method.voidCodeOwnership();
method.setObsolete();
});
source.forEachMethod(
@@ -1070,15 +1069,9 @@
if (method.isObsolete()) {
method.unsetObsolete();
}
- if (method.hasCode()) {
- method.getCode().setOwner(method);
- }
});
assert Streams.concat(Streams.stream(source.methods()), Streams.stream(target.methods()))
- .allMatch(
- method ->
- !method.isObsolete()
- && (!method.hasCode() || method.getCode().getOwner() == method));
+ .allMatch(method -> !method.isObsolete());
return true;
}
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 bddb2e2..bd913c5 100644
--- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -563,7 +563,6 @@
}
method.setCode(
new CfCode(
- oldCode.getMethod(),
oldCode.getMaxStack(),
oldCode.getMaxLocals(),
newInstructions,