Avoid IR processing of throw null methods
Change-Id: Ia60eb6f42a5ea642f0bb6aa85214606004a65e6f
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index dcc55b1..0263c5f 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -979,9 +979,10 @@
}
if (code.isCfCode()) {
assert verifyOriginalMethodInPosition(code.asCfCode(), originalMethod);
- } else {
- assert code.isDexCode();
+ } else if (code.isDexCode()) {
assert verifyOriginalMethodInDebugInfo(code.asDexCode(), originalMethod);
+ } else {
+ assert code.isThrowNullCode();
}
}
}));
diff --git a/src/main/java/com/android/tools/r8/code/Instruction.java b/src/main/java/com/android/tools/r8/code/Instruction.java
index 1a594e9..8671b68 100644
--- a/src/main/java/com/android/tools/r8/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/code/Instruction.java
@@ -133,6 +133,10 @@
write32BitValue(item.getOffset(mapping), dest);
}
+ public boolean hasOffset() {
+ return offset >= 0;
+ }
+
public int getOffset() {
return offset;
}
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index dab9181..10e78f3 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -15,7 +15,6 @@
import com.android.tools.r8.ProgramConsumer;
import com.android.tools.r8.ResourceException;
import com.android.tools.r8.SourceFileEnvironment;
-import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.dex.FileWriter.ByteBufferResult;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.features.FeatureSplitConfiguration.DataResourceProvidersAndConsumer;
@@ -25,8 +24,6 @@
import com.android.tools.r8.graph.DexAnnotationDirectory;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.graph.DexCallSite;
-import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexDebugInfo;
import com.android.tools.r8.graph.DexEncodedArray;
import com.android.tools.r8.graph.DexEncodedField;
@@ -36,6 +33,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.DexValue;
+import com.android.tools.r8.graph.DexWritableCode;
import com.android.tools.r8.graph.EnclosingMethodAttribute;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
@@ -127,7 +125,7 @@
}
@Override
- public boolean add(DexCode dexCode) {
+ public boolean add(DexEncodedMethod method, DexWritableCode dexCode) {
return true;
}
@@ -642,18 +640,9 @@
}
private void setCallSiteContexts(DexProgramClass clazz) {
- for (DexEncodedMethod method : clazz.methods()) {
- if (method.hasCode()) {
- DexCode code = method.getCode().asDexCode();
- assert code != null;
- for (Instruction instruction : code.instructions) {
- DexCallSite callSite = instruction.getCallSite();
- if (callSite != null) {
- callSite.setContext(method.getReference(), instruction.getOffset());
- }
- }
- }
- }
+ clazz.forEachProgramMethodMatching(
+ DexEncodedMethod::hasCode,
+ method -> method.getDefinition().getCode().asDexWritableCode().setCallSiteContexts(method));
}
/**
@@ -683,20 +672,23 @@
// for all code objects and write the processed results into that map.
// TODO(b/181636450): Reconsider the code mapping setup now that synthetics are never duplicated
// in outputs.
- Map<DexEncodedMethod, DexCode> codeMapping = new IdentityHashMap<>();
+ Map<DexEncodedMethod, DexWritableCode> codeMapping = new IdentityHashMap<>();
for (DexProgramClass clazz : classes) {
- clazz.forEachMethod(
+ clazz.forEachProgramMethodMatching(
+ DexEncodedMethod::hasCode,
method -> {
- DexCode code =
- method.rewriteCodeWithJumboStrings(
+ DexWritableCode code = method.getDefinition().getCode().asDexWritableCode();
+ DexWritableCode rewrittenCode =
+ code.rewriteCodeWithJumboStrings(
+ method,
mapping,
application.dexItemFactory,
options.testing.forceJumboStringProcessing);
- codeMapping.put(method, code);
+ codeMapping.put(method.getDefinition(), rewrittenCode);
// The mapping now has ownership of the methods code object. This ensures freeing of
// code resources once the map entry is cleared and also ensures that we don't end up
// using the incorrect code pointer again later!
- method.removeCode();
+ method.getDefinition().unsetCode();
});
}
return MethodToCodeObjectMapping.fromMapBacking(codeMapping);
diff --git a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
index 0e1edc9..44affb4 100644
--- a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
+++ b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
@@ -33,11 +33,11 @@
return new DesugaredLibraryCodeToKeep(namingLens, options);
}
- abstract void recordMethod(DexMethod method);
+ public abstract void recordMethod(DexMethod method);
- abstract void recordField(DexField field);
+ public abstract void recordField(DexField field);
- abstract void recordClass(DexType type);
+ public abstract void recordClass(DexType type);
abstract void recordClassAllAccesses(DexType type);
@@ -82,7 +82,7 @@
}
@Override
- void recordMethod(DexMethod method) {
+ public void recordMethod(DexMethod method) {
DexType baseType = method.holder.toBaseType(options.dexItemFactory());
if (shouldKeep(baseType)) {
keepClass(baseType);
@@ -101,7 +101,7 @@
}
@Override
- void recordField(DexField field) {
+ public void recordField(DexField field) {
DexType baseType = field.holder.toBaseType(options.dexItemFactory());
if (shouldKeep(baseType)) {
keepClass(baseType);
@@ -115,7 +115,7 @@
}
@Override
- void recordClass(DexType type) {
+ public void recordClass(DexType type) {
if (shouldKeep(type)) {
keepClass(type);
}
@@ -218,13 +218,13 @@
public static class NopCodeToKeep extends CodeToKeep {
@Override
- void recordMethod(DexMethod method) {}
+ public void recordMethod(DexMethod method) {}
@Override
- void recordField(DexField field) {}
+ public void recordField(DexField field) {}
@Override
- void recordClass(DexType type) {}
+ public void recordClass(DexType type) {}
@Override
void recordClassAllAccesses(DexType type) {}
diff --git a/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java b/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java
index b193e73..08f8cad 100644
--- a/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java
+++ b/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java
@@ -4,11 +4,8 @@
package com.android.tools.r8.dex;
import com.android.tools.r8.ByteBufferProvider;
-import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.graph.DexCode;
-import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexWritableCode;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.utils.EncodedValueUtils;
@@ -95,37 +92,17 @@
}
public void putInstructions(
- DexCode code,
+ DexWritableCode code,
ProgramMethod context,
ObjectToOffsetMapping mapping,
CodeToKeep desugaredLibraryCodeToKeep) {
- int size = 0;
- Instruction[] instructions = code.instructions;
- for (Instruction instruction : instructions) {
- size += instruction.getSize();
- }
+ int size = code.codeSizeInBytes();
ensureSpaceFor(size * Short.BYTES);
assert byteBuffer.position() % 2 == 0;
ShortBuffer shortBuffer = byteBuffer.asShortBuffer();
- for (int i = 0; i < instructions.length; i++) {
- Instruction insn = instructions[i];
- DexMethod method = insn.getMethod();
- DexField field = insn.getField();
- if (field != null) {
- assert method == null;
- desugaredLibraryCodeToKeep.recordField(field);
- } else if (method != null) {
- desugaredLibraryCodeToKeep.recordMethod(method);
- } else if (insn.isConstClass()) {
- desugaredLibraryCodeToKeep.recordClass(insn.asConstClass().getType());
- } else if (insn.isInstanceOf()) {
- desugaredLibraryCodeToKeep.recordClass(insn.asInstanceOf().getType());
- } else if (insn.isCheckCast()) {
- desugaredLibraryCodeToKeep.recordClass(insn.asCheckCast().getType());
- }
- insn.write(
- shortBuffer, context, mapping.getGraphLens(), mapping, mapping.getLensCodeRewriter());
- }
+ code.writeDex(
+ shortBuffer, context, mapping.getGraphLens(), mapping.getLensCodeRewriter(), mapping);
+ code.writeKeepRulesForDesugaredLibrary(desugaredLibraryCodeToKeep);
byteBuffer.position(byteBuffer.position() + shortBuffer.position() * Short.BYTES);
}
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java
index dc93c37..079d0d6 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -6,7 +6,6 @@
import static com.android.tools.r8.utils.LebUtils.sizeAsUleb128;
import com.android.tools.r8.ByteBufferProvider;
-import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.DefaultInterfaceMethodDiagnostic;
import com.android.tools.r8.errors.InvokeCustomDiagnostic;
@@ -20,7 +19,6 @@
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexCode.Try;
import com.android.tools.r8.graph.DexCode.TryHandler;
import com.android.tools.r8.graph.DexCode.TryHandler.TypeAddrPair;
@@ -43,6 +41,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.DexValue;
+import com.android.tools.r8.graph.DexWritableCode;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.IndexedDexItem;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -341,7 +340,7 @@
for (DexProgramClass clazz : mapping.getClasses()) {
clazz.forEachProgramMethod(
method -> {
- DexCode code = codeMapping.getCode(method.getDefinition());
+ DexWritableCode code = codeMapping.getCode(method.getDefinition());
assert code != null || method.getDefinition().shouldNotHaveCode();
if (code != null) {
ProgramDexCode programCode = new ProgramDexCode(code, method);
@@ -409,18 +408,15 @@
return size;
}
- private int sizeOfCodeItem(DexCode code) {
+ private int sizeOfCodeItem(DexWritableCode code) {
int result = 16;
- int insnSize = 0;
- for (Instruction insn : code.instructions) {
- insnSize += insn.getSize();
- }
+ int insnSize = code.codeSizeInBytes();
result += insnSize * 2;
- result += code.tries.length * 8;
- if (code.handlers.length > 0) {
+ result += code.getTries().length * 8;
+ if (code.getHandlers().length > 0) {
result = alignSize(4, result);
- result += LebUtils.sizeAsUleb128(code.handlers.length);
- for (TryHandler handler : code.handlers) {
+ result += LebUtils.sizeAsUleb128(code.getHandlers().length);
+ for (TryHandler handler : code.getHandlers()) {
boolean hasCatchAll = handler.catchAllAddr != TryHandler.NO_HANDLER;
result += LebUtils
.sizeAsSleb128(hasCatchAll ? -handler.pairs.length : handler.pairs.length);
@@ -501,13 +497,13 @@
writeCodeItem(code.getCode(), code.getMethod());
}
- private void writeCodeItem(DexCode code, ProgramMethod method) {
- mixedSectionOffsets.setOffsetFor(code, dest.align(4));
+ private void writeCodeItem(DexWritableCode code, ProgramMethod method) {
+ mixedSectionOffsets.setOffsetFor(method.getDefinition(), code, dest.align(4));
// Fixed size header information.
- dest.putShort((short) code.registerSize);
- dest.putShort((short) code.incomingRegisterSize);
- dest.putShort((short) code.outgoingRegisterSize);
- dest.putShort((short) code.tries.length);
+ dest.putShort((short) code.getRegisterSize(method));
+ dest.putShort((short) code.getIncomingRegisterSize(method));
+ dest.putShort((short) code.getOutgoingRegisterSize());
+ dest.putShort((short) code.getTries().length);
dest.putInt(mixedSectionOffsets.getOffsetFor(code.getDebugInfoForWriting()));
// Jump over the size.
int insnSizeOffset = dest.position();
@@ -519,16 +515,16 @@
dest.rewind(insnSize + 4);
dest.putInt(insnSize / 2);
dest.forward(insnSize);
- if (code.tries.length > 0) {
+ if (code.getTries().length > 0) {
// The tries need to be 4 byte aligned.
int beginOfTriesOffset = dest.align(4);
// First write the handlers, so that we know their mixedSectionOffsets.
- dest.forward(code.tries.length * 8);
+ dest.forward(code.getTries().length * 8);
int beginOfHandlersOffset = dest.position();
- dest.putUleb128(code.handlers.length);
- short[] offsets = new short[code.handlers.length];
+ dest.putUleb128(code.getHandlers().length);
+ short[] offsets = new short[code.getHandlers().length];
int i = 0;
- for (TryHandler handler : code.handlers) {
+ for (TryHandler handler : code.getHandlers()) {
offsets[i++] = (short) (dest.position() - beginOfHandlersOffset);
boolean hasCatchAll = handler.catchAllAddr != TryHandler.NO_HANDLER;
dest.putSleb128(hasCatchAll ? -handler.pairs.length : handler.pairs.length);
@@ -544,7 +540,7 @@
int endOfCodeOffset = dest.position();
// Now write the tries.
dest.moveTo(beginOfTriesOffset);
- for (Try aTry : code.tries) {
+ for (Try aTry : code.getTries()) {
dest.putInt(aTry.startAddress);
dest.putShort((short) aTry.instructionCount);
dest.putShort(offsets[aTry.handlerIndex]);
@@ -665,13 +661,13 @@
dest.putUleb128(nextOffset - currentOffset);
currentOffset = nextOffset;
dest.putUleb128(method.accessFlags.getAsDexAccessFlags());
- DexCode code = codeMapping.getCode(method);
+ DexWritableCode code = codeMapping.getCode(method);
desugaredLibraryCodeToKeep.recordMethod(method.getReference());
if (code == null) {
assert method.shouldNotHaveCode();
dest.putUleb128(0);
} else {
- dest.putUleb128(mixedSectionOffsets.getOffsetFor(code));
+ dest.putUleb128(mixedSectionOffsets.getOffsetFor(method, code));
// Writing the methods starts to take up memory so we are going to flush the
// code objects since they are no longer necessary after this.
codeMapping.clearCode(method);
@@ -867,7 +863,7 @@
dest.putInt((int) adler.getValue());
}
- private int alignSize(int bytes, int value) {
+ private static int alignSize(int bytes, int value) {
int mask = bytes - 1;
return (value + mask) & ~mask;
}
@@ -1083,7 +1079,7 @@
private final MethodToCodeObjectMapping codeMapping;
- private final Reference2IntMap<DexCode> codes = createReference2IntMap();
+ private final Reference2IntMap<DexEncodedMethod> codes = createReference2IntMap();
private final Object2IntMap<DexDebugInfo> debugInfos = createObject2IntMap();
private final Object2IntMap<DexTypeList> typeLists = createObject2IntMap();
private final Reference2IntMap<DexString> stringData = createReference2IntMap();
@@ -1159,8 +1155,8 @@
}
@Override
- public boolean add(DexCode code) {
- return add(codes, code);
+ public boolean add(DexEncodedMethod method, DexWritableCode code) {
+ return add(codes, method);
}
@Override
@@ -1201,7 +1197,7 @@
return add(stringData, string);
}
- public Collection<DexCode> getCodes() {
+ public Collection<DexEncodedMethod> getCodes() {
return codes.keySet();
}
@@ -1312,8 +1308,8 @@
return lookup(annotationSetRefList, annotationSetRefLists);
}
- public int getOffsetFor(DexCode code) {
- return lookup(code, codes);
+ public int getOffsetFor(DexEncodedMethod method, DexWritableCode code) {
+ return lookup(method, codes);
}
private <T> void setOffsetFor(T item, int offset, Object2IntMap<T> map) {
@@ -1330,8 +1326,8 @@
setOffsetFor(debugInfo, offset, debugInfos);
}
- void setOffsetFor(DexCode code, int offset) {
- setOffsetFor(code, offset, codes);
+ void setOffsetFor(DexEncodedMethod method, DexWritableCode code, int offset) {
+ setOffsetFor(method, offset, codes);
}
void setOffsetFor(DexTypeList typeList, int offset) {
diff --git a/src/main/java/com/android/tools/r8/dex/MethodToCodeObjectMapping.java b/src/main/java/com/android/tools/r8/dex/MethodToCodeObjectMapping.java
index 5541398..dfdb07a 100644
--- a/src/main/java/com/android/tools/r8/dex/MethodToCodeObjectMapping.java
+++ b/src/main/java/com/android/tools/r8/dex/MethodToCodeObjectMapping.java
@@ -4,24 +4,27 @@
package com.android.tools.r8.dex;
import com.android.tools.r8.graph.Code;
-import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexWritableCode;
import java.util.Collection;
+import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
public abstract class MethodToCodeObjectMapping {
- public abstract DexCode getCode(DexEncodedMethod method);
+ public abstract DexWritableCode getCode(DexEncodedMethod method);
public abstract void clearCode(DexEncodedMethod method);
- public abstract boolean verifyCodeObjects(Collection<DexCode> codes);
+ public abstract boolean verifyCodeObjects(Collection<DexEncodedMethod> codes);
public static MethodToCodeObjectMapping fromMethodBacking() {
return MethodBacking.INSTANCE;
}
- public static MethodToCodeObjectMapping fromMapBacking(Map<DexEncodedMethod, DexCode> map) {
+ public static MethodToCodeObjectMapping fromMapBacking(
+ Map<DexEncodedMethod, DexWritableCode> map) {
return new MapBacking(map);
}
@@ -30,33 +33,33 @@
private static final MethodBacking INSTANCE = new MethodBacking();
@Override
- public DexCode getCode(DexEncodedMethod method) {
+ public DexWritableCode getCode(DexEncodedMethod method) {
Code code = method.getCode();
- assert code == null || code.isDexCode();
- return code == null ? null : code.asDexCode();
+ assert code == null || code.isDexWritableCode();
+ return code == null ? null : code.asDexWritableCode();
}
@Override
public void clearCode(DexEncodedMethod method) {
- method.removeCode();
+ method.unsetCode();
}
@Override
- public boolean verifyCodeObjects(Collection<DexCode> codes) {
+ public boolean verifyCodeObjects(Collection<DexEncodedMethod> codes) {
return true;
}
}
private static class MapBacking extends MethodToCodeObjectMapping {
- private final Map<DexEncodedMethod, DexCode> codes;
+ private final Map<DexEncodedMethod, DexWritableCode> codes;
- public MapBacking(Map<DexEncodedMethod, DexCode> codes) {
+ public MapBacking(Map<DexEncodedMethod, DexWritableCode> codes) {
this.codes = codes;
}
@Override
- public DexCode getCode(DexEncodedMethod method) {
+ public DexWritableCode getCode(DexEncodedMethod method) {
return codes.get(method);
}
@@ -67,7 +70,10 @@
}
@Override
- public boolean verifyCodeObjects(Collection<DexCode> codes) {
+ public boolean verifyCodeObjects(Collection<DexEncodedMethod> methods) {
+ // TODO(b/204056443): Convert to a Set<DexWritableCode> when DexCode#hashCode() works.
+ List<DexWritableCode> codes =
+ methods.stream().map(this::getCode).collect(Collectors.toList());
assert this.codes.values().containsAll(codes);
return true;
}
diff --git a/src/main/java/com/android/tools/r8/dex/MixedSectionCollection.java b/src/main/java/com/android/tools/r8/dex/MixedSectionCollection.java
index 2cedf5c..0ca695e 100644
--- a/src/main/java/com/android/tools/r8/dex/MixedSectionCollection.java
+++ b/src/main/java/com/android/tools/r8/dex/MixedSectionCollection.java
@@ -6,13 +6,13 @@
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexAnnotationDirectory;
import com.android.tools.r8.graph.DexAnnotationSet;
-import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexDebugInfo;
import com.android.tools.r8.graph.DexEncodedArray;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItem;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.graph.DexWritableCode;
import com.android.tools.r8.graph.ParameterAnnotationsList;
/**
@@ -66,11 +66,11 @@
/**
* Adds the given code item to the collection.
*
- * Does not add any dependencies.
+ * <p>Does not add any dependencies.
*
* @return true if the item was not added before
*/
- public abstract boolean add(DexCode dexCode);
+ public abstract boolean add(DexEncodedMethod method, DexWritableCode dexCode);
/**
* Adds the given debug info to the collection.
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 4589a49..455d586 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -62,7 +62,7 @@
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
-public class CfCode extends Code implements StructuralItem<CfCode> {
+public class CfCode extends Code implements CfWritableCode, StructuralItem<CfCode> {
public enum StackMapStatus {
NOT_VERIFIED,
@@ -261,11 +261,21 @@
}
@Override
+ public boolean isCfWritableCode() {
+ return true;
+ }
+
+ @Override
public CfCode asCfCode() {
return this;
}
@Override
+ public CfWritableCode asCfWritableCode() {
+ return this;
+ }
+
+ @Override
public void acceptHashing(HashingVisitor visitor) {
// Rather than hash the entire content, hash the sizes and each instruction "type" which
// should provide a fast yet reasonably distinct key.
@@ -316,7 +326,8 @@
return true;
}
- public void write(
+ @Override
+ public void writeCf(
ProgramMethod method,
CfVersion classFileVersion,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/graph/CfWritableCode.java b/src/main/java/com/android/tools/r8/graph/CfWritableCode.java
new file mode 100644
index 0000000..fd23726
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/CfWritableCode.java
@@ -0,0 +1,21 @@
+// 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.graph;
+
+import com.android.tools.r8.cf.CfVersion;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.naming.NamingLens;
+import org.objectweb.asm.MethodVisitor;
+
+public interface CfWritableCode {
+
+ void writeCf(
+ ProgramMethod method,
+ CfVersion classFileVersion,
+ AppView<?> appView,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor);
+}
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 0d6c31e..ba7a9c9 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
-import com.android.tools.r8.ir.optimize.OutlinerImpl.OutlineCode;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
@@ -59,10 +58,18 @@
return false;
}
+ public boolean isCfWritableCode() {
+ return false;
+ }
+
public boolean isDexCode() {
return false;
}
+ public boolean isDexWritableCode() {
+ return false;
+ }
+
public boolean isHorizontalClassMergingCode() {
return false;
}
@@ -71,6 +78,17 @@
return false;
}
+ public boolean isSharedCodeObject() {
+ return false;
+ }
+
+ public boolean isThrowNullCode() {
+ return false;
+ }
+
+ public ThrowNullCode asThrowNullCode() {
+ return null;
+ }
/** Estimate the number of IR instructions emitted by buildIR(). */
public int estimatedSizeForInlining() {
@@ -88,6 +106,10 @@
throw new Unreachable(getClass().getCanonicalName() + ".asCfCode()");
}
+ public CfWritableCode asCfWritableCode() {
+ throw new Unreachable(getClass().getCanonicalName() + ".asCfWritableCode()");
+ }
+
public LazyCfCode asLazyCfCode() {
throw new Unreachable(getClass().getCanonicalName() + ".asLazyCfCode()");
}
@@ -96,8 +118,8 @@
throw new Unreachable(getClass().getCanonicalName() + ".asDexCode()");
}
- public OutlineCode asOutlineCode() {
- throw new Unreachable(getClass().getCanonicalName() + ".asOutlineCode()");
+ public DexWritableCode asDexWritableCode() {
+ throw new Unreachable(getClass().getCanonicalName() + ".asDexWritableCode()");
}
@Override
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 af3bcde..c23bf18 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -7,7 +7,10 @@
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.code.ReturnVoid;
import com.android.tools.r8.code.SwitchPayload;
+import com.android.tools.r8.dex.CodeToKeep;
+import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.dex.JumboStringRewriter;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexCode.TryHandler.TypeAddrPair;
@@ -32,6 +35,7 @@
import com.android.tools.r8.utils.structural.StructuralSpecification;
import com.google.common.base.Strings;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
+import java.nio.ShortBuffer;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
@@ -41,7 +45,7 @@
import java.util.Set;
// DexCode corresponds to code item in dalvik/dex-format.html
-public class DexCode extends Code implements StructuralItem<DexCode> {
+public class DexCode extends Code implements DexWritableCode, StructuralItem<DexCode> {
public static final String FAKE_THIS_PREFIX = "_";
public static final String FAKE_THIS_SUFFIX = "this";
@@ -130,6 +134,36 @@
return DexCode::specify;
}
+ @Override
+ public DexWritableCode rewriteCodeWithJumboStrings(
+ ProgramMethod method, ObjectToOffsetMapping mapping, DexItemFactory factory, boolean force) {
+ DexString firstJumboString = null;
+ if (force) {
+ firstJumboString = mapping.getFirstString();
+ } else {
+ assert highestSortingString != null
+ || Arrays.stream(instructions).noneMatch(Instruction::isConstString);
+ assert Arrays.stream(instructions).noneMatch(Instruction::isDexItemBasedConstString);
+ if (highestSortingString != null
+ && mapping.getOffsetFor(highestSortingString) > Constants.MAX_NON_JUMBO_INDEX) {
+ firstJumboString = mapping.getFirstJumboString();
+ }
+ }
+ return firstJumboString != null
+ ? new JumboStringRewriter(method.getDefinition(), firstJumboString, factory).rewrite()
+ : this;
+ }
+
+ @Override
+ public void setCallSiteContexts(ProgramMethod method) {
+ for (Instruction instruction : instructions) {
+ DexCallSite callSite = instruction.getCallSite();
+ if (callSite != null) {
+ callSite.setContext(method.getReference(), instruction.getOffset());
+ }
+ }
+ }
+
public DexCode withoutThisParameter() {
// Note that we assume the original code has a register associated with 'this'
// argument of the (former) instance method. We also assume (but do not check)
@@ -153,6 +187,16 @@
}
@Override
+ public boolean isDexWritableCode() {
+ return true;
+ }
+
+ @Override
+ public DexWritableCode asDexWritableCode() {
+ return this;
+ }
+
+ @Override
public int estimatedSizeForInlining() {
return codeSizeInBytes();
}
@@ -510,6 +554,7 @@
}
}
+ @Override
public DexDebugInfoForWriting getDebugInfoForWriting() {
if (debugInfo == null) {
return null;
@@ -521,6 +566,36 @@
return debugInfoForWriting;
}
+ @Override
+ public TryHandler[] getHandlers() {
+ return handlers;
+ }
+
+ @Override
+ public DexString getHighestSortingString() {
+ return highestSortingString;
+ }
+
+ @Override
+ public Try[] getTries() {
+ return tries;
+ }
+
+ @Override
+ public int getRegisterSize(ProgramMethod method) {
+ return registerSize;
+ }
+
+ @Override
+ public int getIncomingRegisterSize(ProgramMethod method) {
+ return incomingRegisterSize;
+ }
+
+ @Override
+ public int getOutgoingRegisterSize() {
+ return outgoingRegisterSize;
+ }
+
private void updateHighestSortingString(DexString candidate) {
assert candidate != null;
if (highestSortingString == null || highestSortingString.compareTo(candidate) < 0) {
@@ -533,17 +608,59 @@
}
@Override
- void collectMixedSectionItems(MixedSectionCollection mixedItems) {
- if (mixedItems.add(this)) {
- if (debugInfo != null) {
- getDebugInfoForWriting().collectMixedSectionItems(mixedItems);
+ public void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ if (debugInfo != null) {
+ getDebugInfoForWriting().collectMixedSectionItems(mixedItems);
+ }
+ }
+
+ @Override
+ public int codeSizeInBytes() {
+ Instruction last = instructions[instructions.length - 1];
+ assert last.hasOffset();
+ int result = last.getOffset() + last.getSize();
+ assert result == computeCodeSizeInBytes();
+ return result;
+ }
+
+ private int computeCodeSizeInBytes() {
+ int size = 0;
+ for (Instruction insn : instructions) {
+ size += insn.getSize();
+ }
+ return size;
+ }
+
+ @Override
+ public void writeKeepRulesForDesugaredLibrary(CodeToKeep desugaredLibraryCodeToKeep) {
+ for (Instruction instruction : instructions) {
+ DexMethod method = instruction.getMethod();
+ DexField field = instruction.getField();
+ if (field != null) {
+ assert method == null;
+ desugaredLibraryCodeToKeep.recordField(field);
+ } else if (method != null) {
+ desugaredLibraryCodeToKeep.recordMethod(method);
+ } else if (instruction.isConstClass()) {
+ desugaredLibraryCodeToKeep.recordClass(instruction.asConstClass().getType());
+ } else if (instruction.isInstanceOf()) {
+ desugaredLibraryCodeToKeep.recordClass(instruction.asInstanceOf().getType());
+ } else if (instruction.isCheckCast()) {
+ desugaredLibraryCodeToKeep.recordClass(instruction.asCheckCast().getType());
}
}
}
- public int codeSizeInBytes() {
- Instruction last = instructions[instructions.length - 1];
- return last.getOffset() + last.getSize();
+ @Override
+ public void writeDex(
+ ShortBuffer shortBuffer,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils lensCodeRewriter,
+ ObjectToOffsetMapping mapping) {
+ for (Instruction instruction : instructions) {
+ instruction.write(shortBuffer, context, graphLens, mapping, lensCodeRewriter);
+ }
}
public static class Try extends DexItem implements StructuralItem<Try> {
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 14a7ff5..afdef0a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -40,8 +40,6 @@
import com.android.tools.r8.code.Return;
import com.android.tools.r8.code.Throw;
import com.android.tools.r8.code.XorIntLit8;
-import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.dex.JumboStringRewriter;
import com.android.tools.r8.dex.MethodToCodeObjectMapping;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.InternalCompilerError;
@@ -776,8 +774,8 @@
public void collectMixedSectionItemsWithCodeMapping(
MixedSectionCollection mixedItems, MethodToCodeObjectMapping mapping) {
- DexCode code = mapping.getCode(this);
- if (code != null) {
+ DexWritableCode code = mapping.getCode(this);
+ if (code != null && mixedItems.add(this, code)) {
code.collectMixedSectionItems(mixedItems);
}
annotations().collectMixedSectionItems(mixedItems);
@@ -797,11 +795,6 @@
return code;
}
- public void removeCode() {
- checkIfObsolete();
- code = null;
- }
-
public CfVersion getClassFileVersion() {
checkIfObsolete();
assert classFileVersion != null;
@@ -1298,34 +1291,6 @@
return method;
}
- /** Rewrites the code in this method to have JumboString bytecode if required by mapping. */
- public DexCode rewriteCodeWithJumboStrings(
- ObjectToOffsetMapping mapping, DexItemFactory factory, boolean force) {
- checkIfObsolete();
- assert code == null || code.isDexCode();
- if (code == null) {
- return null;
- }
- DexCode code = this.code.asDexCode();
- DexString firstJumboString = null;
- if (force) {
- firstJumboString = mapping.getFirstString();
- } else {
- assert code.highestSortingString != null
- || Arrays.stream(code.instructions).noneMatch(Instruction::isConstString);
- assert Arrays.stream(code.instructions).noneMatch(Instruction::isDexItemBasedConstString);
- if (code.highestSortingString != null
- && mapping.getOffsetFor(code.highestSortingString) > Constants.MAX_NON_JUMBO_INDEX) {
- firstJumboString = mapping.getFirstJumboString();
- }
- }
- if (firstJumboString != null) {
- JumboStringRewriter rewriter = new JumboStringRewriter(this, firstJumboString, factory);
- return rewriter.rewrite();
- }
- return code;
- }
-
public String codeToString() {
checkIfObsolete();
return code == null ? "<no code>" : code.toString(this, null);
diff --git a/src/main/java/com/android/tools/r8/graph/DexWritableCode.java b/src/main/java/com/android/tools/r8/graph/DexWritableCode.java
new file mode 100644
index 0000000..9aea5e4
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/DexWritableCode.java
@@ -0,0 +1,48 @@
+// 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.graph;
+
+import com.android.tools.r8.dex.CodeToKeep;
+import com.android.tools.r8.dex.MixedSectionCollection;
+import com.android.tools.r8.graph.DexCode.Try;
+import com.android.tools.r8.graph.DexCode.TryHandler;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import java.nio.ShortBuffer;
+
+public interface DexWritableCode {
+
+ int codeSizeInBytes();
+
+ void collectMixedSectionItems(MixedSectionCollection mixedItems);
+
+ void writeKeepRulesForDesugaredLibrary(CodeToKeep codeToKeep);
+
+ DexDebugInfoForWriting getDebugInfoForWriting();
+
+ DexString getHighestSortingString();
+
+ TryHandler[] getHandlers();
+
+ Try[] getTries();
+
+ int getRegisterSize(ProgramMethod method);
+
+ int getIncomingRegisterSize(ProgramMethod method);
+
+ int getOutgoingRegisterSize();
+
+ /** Rewrites the code to have JumboString bytecode if required by mapping. */
+ DexWritableCode rewriteCodeWithJumboStrings(
+ ProgramMethod method, ObjectToOffsetMapping mapping, DexItemFactory factory, boolean force);
+
+ void setCallSiteContexts(ProgramMethod method);
+
+ void writeDex(
+ ShortBuffer shortBuffer,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils lensCodeRewriter,
+ ObjectToOffsetMapping mapping);
+}
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 f222dbf..9589d1e 100644
--- a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
@@ -168,6 +168,8 @@
// If code is (lazy) CF code, then use the CF code object rather than the lazy wrapper.
if (code.isCfCode()) {
code = code.asCfCode();
+ } else if (code.isSharedCodeObject()) {
+ continue;
}
DexEncodedMethod otherMethod = codeOwners.put(code, method);
assert otherMethod == null;
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 ba5faec..2403804 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -121,6 +121,11 @@
}
@Override
+ public boolean isCfWritableCode() {
+ return true;
+ }
+
+ @Override
public LazyCfCode asLazyCfCode() {
return this;
}
@@ -134,6 +139,11 @@
return code;
}
+ @Override
+ public CfWritableCode asCfWritableCode() {
+ return asCfCode();
+ }
+
private void internalParseCode() {
ReparseContext context = this.context;
JarApplicationReader application = this.application;
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramDexCode.java b/src/main/java/com/android/tools/r8/graph/ProgramDexCode.java
index 93e42d1..4e15eac 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramDexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramDexCode.java
@@ -6,15 +6,15 @@
public class ProgramDexCode {
- private final DexCode code;
+ private final DexWritableCode code;
private final ProgramMethod method;
- public ProgramDexCode(DexCode code, ProgramMethod method) {
+ public ProgramDexCode(DexWritableCode code, ProgramMethod method) {
this.code = code;
this.method = method;
}
- public DexCode getCode() {
+ public DexWritableCode getCode() {
return code;
}
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
index 146e33f..90278d0 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
@@ -61,11 +61,14 @@
IndexedItemCollection indexedItems, GraphLens graphLens, LensCodeRewriterUtils rewriter) {
DexEncodedMethod definition = getDefinition();
assert !definition.isObsolete();
- assert !definition.hasCode() || definition.getCode().isDexCode();
getReference().collectIndexedItems(indexedItems);
- Code code = definition.getCode();
- if (code != null && code.isDexCode()) {
- code.asDexCode().collectIndexedItems(indexedItems, this, graphLens, rewriter);
+ if (definition.hasCode()) {
+ Code code = definition.getCode();
+ if (code.isDexCode()) {
+ code.asDexCode().collectIndexedItems(indexedItems, this, graphLens, rewriter);
+ } else {
+ assert code.isThrowNullCode();
+ }
}
definition.annotations().collectIndexedItems(indexedItems);
definition.parameterAnnotationsList.collectIndexedItems(indexedItems);
@@ -106,9 +109,8 @@
public void convertToThrowNullMethod(AppView<?> appView) {
MethodAccessFlags accessFlags = getAccessFlags();
accessFlags.demoteFromAbstract();
- Code emptyThrowingCode = getDefinition().buildEmptyThrowingCode(appView.options());
getDefinition().setApiLevelForCode(AndroidApiLevel.minApiLevelIfEnabledOrUnknown(appView));
- getDefinition().setCode(emptyThrowingCode, appView);
+ getDefinition().setCode(ThrowNullCode.get(), appView);
getSimpleFeedback().markProcessed(getDefinition(), ConstraintWithTarget.ALWAYS);
getSimpleFeedback().unsetOptimizationInfoForThrowNullMethod(this);
}
diff --git a/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java b/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
new file mode 100644
index 0000000..c9d875a
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
@@ -0,0 +1,377 @@
+// 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.graph;
+
+import com.android.tools.r8.cf.CfVersion;
+import com.android.tools.r8.code.Const4;
+import com.android.tools.r8.code.Throw;
+import com.android.tools.r8.dex.CodeToKeep;
+import com.android.tools.r8.dex.MixedSectionCollection;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexCode.Try;
+import com.android.tools.r8.graph.DexCode.TryHandler;
+import com.android.tools.r8.ir.code.CatchHandlers;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.NumberGenerator;
+import com.android.tools.r8.ir.code.Position;
+import com.android.tools.r8.ir.code.Position.SyntheticPosition;
+import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.ir.conversion.SourceCode;
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.ConsumerUtils;
+import com.google.common.collect.ImmutableList;
+import java.nio.ShortBuffer;
+import java.util.List;
+import java.util.function.Consumer;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+public class ThrowNullCode extends Code implements CfWritableCode, DexWritableCode {
+
+ private static final ThrowNullCode INSTANCE = new ThrowNullCode();
+
+ private ThrowNullCode() {}
+
+ public static ThrowNullCode get() {
+ return INSTANCE;
+ }
+
+ @Override
+ public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ ThrowNullSourceCode source = new ThrowNullSourceCode(method);
+ return IRBuilder.create(method, appView, source, origin).build(method);
+ }
+
+ @Override
+ public IRCode buildInliningIR(
+ ProgramMethod context,
+ ProgramMethod method,
+ AppView<?> appView,
+ GraphLens codeLens,
+ NumberGenerator valueNumberGenerator,
+ Position callerPosition,
+ Origin origin,
+ RewrittenPrototypeDescription protoChanges) {
+ ThrowNullSourceCode source = new ThrowNullSourceCode(method, callerPosition);
+ return IRBuilder.createForInlining(
+ method, appView, codeLens, source, origin, valueNumberGenerator, protoChanges)
+ .build(context);
+ }
+
+ @Override
+ public int codeSizeInBytes() {
+ return Const4.SIZE + Throw.SIZE;
+ }
+
+ @Override
+ public void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ // Intentionally empty.
+ }
+
+ @Override
+ protected int computeHashCode() {
+ return System.identityHashCode(this);
+ }
+
+ @Override
+ protected boolean computeEquals(Object other) {
+ return this == other;
+ }
+
+ @Override
+ public int estimatedDexCodeSizeUpperBoundInBytes() {
+ return codeSizeInBytes();
+ }
+
+ @Override
+ public DexDebugInfoForWriting getDebugInfoForWriting() {
+ return null;
+ }
+
+ @Override
+ public TryHandler[] getHandlers() {
+ return new TryHandler[0];
+ }
+
+ @Override
+ public DexString getHighestSortingString() {
+ return null;
+ }
+
+ @Override
+ public int getIncomingRegisterSize(ProgramMethod method) {
+ return getMaxLocals(method);
+ }
+
+ private int getMaxLocals(ProgramMethod method) {
+ int maxLocals = method.getAccessFlags().isStatic() ? 0 : 1;
+ for (DexType parameter : method.getParameters()) {
+ maxLocals += parameter.getRequiredRegisters();
+ }
+ return maxLocals;
+ }
+
+ @Override
+ public int getOutgoingRegisterSize() {
+ return 0;
+ }
+
+ @Override
+ public int getRegisterSize(ProgramMethod method) {
+ return Math.max(getIncomingRegisterSize(method), 1);
+ }
+
+ @Override
+ public Try[] getTries() {
+ return new Try[0];
+ }
+
+ @Override
+ public boolean isCfWritableCode() {
+ return true;
+ }
+
+ @Override
+ public CfWritableCode asCfWritableCode() {
+ return this;
+ }
+
+ @Override
+ public boolean isDexWritableCode() {
+ return true;
+ }
+
+ @Override
+ public DexWritableCode asDexWritableCode() {
+ return this;
+ }
+
+ @Override
+ public boolean isEmptyVoidMethod() {
+ return false;
+ }
+
+ @Override
+ public boolean isSharedCodeObject() {
+ return true;
+ }
+
+ @Override
+ public boolean isThrowNullCode() {
+ return true;
+ }
+
+ @Override
+ public ThrowNullCode asThrowNullCode() {
+ return this;
+ }
+
+ @Override
+ public void registerCodeReferences(ProgramMethod method, UseRegistry registry) {
+ // Intentionally empty.
+ }
+
+ @Override
+ public void registerCodeReferencesForDesugaring(ClasspathMethod method, UseRegistry registry) {
+ // Intentionally empty.
+ }
+
+ @Override
+ public DexWritableCode rewriteCodeWithJumboStrings(
+ ProgramMethod method, ObjectToOffsetMapping mapping, DexItemFactory factory, boolean force) {
+ // Intentionally empty. This piece of code does not have any const-string instructions.
+ return this;
+ }
+
+ @Override
+ public void setCallSiteContexts(ProgramMethod method) {
+ // Intentionally empty. This piece of code does not have any call sites.
+ }
+
+ @Override
+ public void writeCf(
+ ProgramMethod method,
+ CfVersion classFileVersion,
+ AppView<?> appView,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
+ int maxStack = 1;
+ visitor.visitInsn(Opcodes.ACONST_NULL);
+ visitor.visitInsn(Opcodes.ATHROW);
+ visitor.visitEnd();
+ visitor.visitMaxs(maxStack, getMaxLocals(method));
+ }
+
+ @Override
+ public void writeDex(
+ ShortBuffer shortBuffer,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils lensCodeRewriter,
+ ObjectToOffsetMapping mapping) {
+ int register = 0;
+ new Const4(register, 0).write(shortBuffer, context, graphLens, mapping, lensCodeRewriter);
+ new Throw(register).write(shortBuffer, context, graphLens, mapping, lensCodeRewriter);
+ }
+
+ @Override
+ public void writeKeepRulesForDesugaredLibrary(CodeToKeep codeToKeep) {
+ // Intentionally empty.
+ }
+
+ @Override
+ public String toString() {
+ return "ThrowNullCode";
+ }
+
+ @Override
+ public String toString(DexEncodedMethod method, ClassNameMapper naming) {
+ return "ThrowNullCode";
+ }
+
+ static class ThrowNullSourceCode implements SourceCode {
+
+ private static final List<Consumer<IRBuilder>> instructionBuilders =
+ ImmutableList.of(builder -> builder.addNullConst(0), builder -> builder.addThrow(0));
+
+ private final ProgramMethod method;
+ private final Position position;
+
+ ThrowNullSourceCode(ProgramMethod method) {
+ this(method, null);
+ }
+
+ ThrowNullSourceCode(ProgramMethod method, Position callerPosition) {
+ this.method = method;
+ this.position =
+ SyntheticPosition.builder()
+ .setLine(0)
+ .setMethod(method.getReference())
+ .setCallerPosition(callerPosition)
+ .build();
+ }
+
+ @Override
+ public int instructionCount() {
+ return instructionBuilders.size();
+ }
+
+ @Override
+ public int instructionIndex(int instructionOffset) {
+ return instructionOffset;
+ }
+
+ @Override
+ public int instructionOffset(int instructionIndex) {
+ return instructionIndex;
+ }
+
+ @Override
+ public void buildPrelude(IRBuilder builder) {
+ int firstArgumentRegister = 0;
+ builder.buildArgumentsWithRewrittenPrototypeChanges(
+ firstArgumentRegister, method.getDefinition(), ConsumerUtils.emptyBiConsumer());
+ }
+
+ @Override
+ public void buildInstruction(
+ IRBuilder builder, int instructionIndex, boolean firstBlockInstruction) {
+ instructionBuilders.get(instructionIndex).accept(builder);
+ }
+
+ @Override
+ public void buildPostlude(IRBuilder builder) {
+ // Intentionally empty.
+ }
+
+ @Override
+ public void clear() {
+ // Intentionally empty.
+ }
+
+ @Override
+ public Position getCanonicalDebugPositionAtOffset(int offset) {
+ return null;
+ }
+
+ @Override
+ public CatchHandlers<Integer> getCurrentCatchHandlers(IRBuilder builder) {
+ return null;
+ }
+
+ @Override
+ public Position getCurrentPosition() {
+ return position;
+ }
+
+ @Override
+ public DebugLocalInfo getIncomingLocal(int register) {
+ return null;
+ }
+
+ @Override
+ public DebugLocalInfo getIncomingLocalAtBlock(int register, int blockOffset) {
+ return null;
+ }
+
+ @Override
+ public DebugLocalInfo getOutgoingLocal(int register) {
+ return null;
+ }
+
+ @Override
+ public void setUp() {
+ // Intentionally empty.
+ }
+
+ @Override
+ public int traceInstruction(int instructionIndex, IRBuilder builder) {
+ // This instruction does not close the block.
+ return -1;
+ }
+
+ @Override
+ public boolean verifyCurrentInstructionCanThrow() {
+ return true;
+ }
+
+ @Override
+ public boolean verifyRegister(int register) {
+ return true;
+ }
+
+ @Override
+ public void buildBlockTransfer(
+ IRBuilder builder, int predecessorOffset, int successorOffset, boolean isExceptional) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public int getMoveExceptionRegister(int instructionIndex) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public void resolveAndBuildNewArrayFilledData(
+ int arrayRef, int payloadOffset, IRBuilder builder) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public void resolveAndBuildSwitch(
+ int value, int fallthroughOffset, int payloadOffset, IRBuilder builder) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public boolean verifyLocalInScope(DebugLocalInfo local) {
+ throw new Unreachable();
+ }
+ }
+}
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 3aefd80..eb30bd3 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
@@ -561,7 +561,10 @@
}
}
- private boolean needsIRConversion() {
+ private boolean needsIRConversion(ProgramMethod method) {
+ if (method.getDefinition().getCode().isThrowNullCode()) {
+ return false;
+ }
if (appView.enableWholeProgramOptimizations()) {
return true;
}
@@ -1062,7 +1065,7 @@
options.testing.hookInIrConversion.run();
}
- if (!needsIRConversion() || options.skipIR) {
+ if (!needsIRConversion(method) || options.skipIR) {
feedback.markProcessed(method.getDefinition(), ConstraintWithTarget.NEVER);
return Timing.empty();
}
@@ -1683,7 +1686,9 @@
}
private synchronized void updateHighestSortingStrings(DexEncodedMethod method) {
- DexString highestSortingReferencedString = method.getCode().asDexCode().highestSortingString;
+ Code code = method.getCode();
+ assert code.isDexWritableCode();
+ DexString highestSortingReferencedString = code.asDexWritableCode().getHighestSortingString();
if (highestSortingReferencedString != null) {
if (highestSortingString == null
|| highestSortingReferencedString.compareTo(highestSortingString) > 0) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
index 7513257..c89f90c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
@@ -267,7 +267,7 @@
assert InvalidCode.isInvalidCode(defaultMethod.getCode());
assert !InvalidCode.isInvalidCode(companionMethod.getCode());
defaultMethod.accessFlags.setAbstract();
- defaultMethod.removeCode();
+ defaultMethod.unsetCode();
graphLensBuilder.recordCodeMovedToCompanionClass(
defaultMethod.getReference(), companionMethod.getReference());
});
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java
index 68111d4..921bc7f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java
@@ -1773,11 +1773,6 @@
}
@Override
- public OutlineCode asOutlineCode() {
- return this;
- }
-
- @Override
public boolean isEmptyVoidMethod() {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
index 7b8da09..b10c36a 100644
--- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -15,7 +15,7 @@
import com.android.tools.r8.errors.ConstantPoolOverflowDiagnostic;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexAnnotationElement;
import com.android.tools.r8.graph.DexAnnotationSet;
@@ -591,8 +591,10 @@
NamingLens namingLens,
LensCodeRewriterUtils rewriter,
MethodVisitor visitor) {
- CfCode code = method.getDefinition().getCode().asCfCode();
- code.write(method, classFileVersion, appView, namingLens, rewriter, visitor);
+ Code code = method.getDefinition().getCode();
+ assert code.isCfWritableCode();
+ code.asCfWritableCode()
+ .writeCf(method, classFileVersion, appView, namingLens, rewriter, visitor);
}
public static String printCf(byte[] result) {
diff --git a/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java b/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java
index a22a766..f00e19c 100644
--- a/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java
@@ -156,8 +156,7 @@
instructions[i] = constString;
}
}
- } else {
- assert code.isCfCode();
+ } else if (code.isCfCode()) {
List<CfInstruction> instructions = code.asCfCode().getInstructions();
List<CfInstruction> newInstructions =
ListUtils.mapOrElse(
@@ -176,6 +175,8 @@
},
instructions);
code.asCfCode().setInstructions(newInstructions);
+ } else {
+ assert code.isThrowNullCode();
}
}
}