Extend inlining to allow invokes.
Also extend the oracle to hand package private and protected access modifiers
correctly.
Bug:
Change-Id: I1b592660842d4d81dd508e69f7c5641860f11633
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 84d6d5d..54f9470 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -33,6 +33,10 @@
return false;
}
+ public int estimatedSizeForInlining() {
+ return Integer.MAX_VALUE;
+ }
+
public DexCode asDexCode() {
throw new Unreachable(getClass().getCanonicalName() + ".asDexCode()");
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index aedb6df..04c61a4 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -7,9 +7,7 @@
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unreachable;
-
import com.google.common.base.MoreObjects;
-
import java.util.Arrays;
import java.util.function.Consumer;
@@ -204,4 +202,9 @@
// For non-dex code we don't try to check the code.
return true;
}
+
+ public boolean defaultValuesForStaticFieldsMayTriggerAllocation() {
+ return Arrays.stream(staticFields())
+ .anyMatch(field -> !field.staticValue.mayTriggerAllocation());
+ }
}
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 d939868..dc3ae37 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -64,6 +64,11 @@
}
@Override
+ public int estimatedSizeForInlining() {
+ return instructions.length;
+ }
+
+ @Override
public DexCode asDexCode() {
return this;
}
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 400b42f..ef6a96c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -3,9 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
-import static com.android.tools.r8.graph.DexEncodedMethod.CompilationState.PROCESSED_INLINING_CANDIDATE_PACKAGE_PRIVATE;
-import static com.android.tools.r8.graph.DexEncodedMethod.CompilationState.PROCESSED_INLINING_CANDIDATE_PRIVATE;
-import static com.android.tools.r8.graph.DexEncodedMethod.CompilationState.PROCESSED_INLINING_CANDIDATE_PUBLIC;
+import static com.android.tools.r8.graph.DexEncodedMethod.CompilationState.PROCESSED_INLINING_CANDIDATE_ANY;
+import static com.android.tools.r8.graph.DexEncodedMethod.CompilationState.PROCESSED_INLINING_CANDIDATE_SAME_CLASS;
+import static com.android.tools.r8.graph.DexEncodedMethod.CompilationState.PROCESSED_INLINING_CANDIDATE_SAME_PACKAGE;
+import static com.android.tools.r8.graph.DexEncodedMethod.CompilationState.PROCESSED_INLINING_CANDIDATE_SUBCLASS;
import static com.android.tools.r8.graph.DexEncodedMethod.CompilationState.PROCESSED_NOT_INLINING_CANDIDATE;
import com.android.tools.r8.code.Const;
@@ -35,17 +36,40 @@
public class DexEncodedMethod extends KeyedDexItem<DexMethod> {
- public enum CompilationState
-
- {
+ /**
+ * Encodes the processing state of a method.
+ * <p>
+ * We also use this enum to encode whether and if under what constraints a method may be
+ * inlined.
+ */
+ public enum CompilationState {
+ /**
+ * Has not been processed, yet.
+ */
NOT_PROCESSED,
+ /**
+ * Has been processed but cannot be inlined due to instructions that are not supported.
+ */
PROCESSED_NOT_INLINING_CANDIDATE,
- // Code only contains instructions that access public entities.
- PROCESSED_INLINING_CANDIDATE_PUBLIC,
- // Code only contains instructions that access public and package private entities.
- PROCESSED_INLINING_CANDIDATE_PACKAGE_PRIVATE,
- // Code also contains instructions that access public entities.
- PROCESSED_INLINING_CANDIDATE_PRIVATE,
+ /**
+ * Code only contains instructions that access public entities and can this be inlined
+ * into any context.
+ */
+ PROCESSED_INLINING_CANDIDATE_ANY,
+ /**
+ * Code also contains instructions that access protected entities that reside in a differnt
+ * package and hence require subclass relationship to be visible.
+ */
+ PROCESSED_INLINING_CANDIDATE_SUBCLASS,
+ /**
+ * Code contains instructions that reference package private entities or protected entities
+ * from the same package.
+ */
+ PROCESSED_INLINING_CANDIDATE_SAME_PACKAGE,
+ /**
+ * Code contains instructions that reference private entities.
+ */
+ PROCESSED_INLINING_CANDIDATE_SAME_CLASS,
}
public static final DexEncodedMethod[] EMPTY_ARRAY = new DexEncodedMethod[]{};
@@ -79,7 +103,8 @@
|| compilationState == CompilationState.PROCESSED_NOT_INLINING_CANDIDATE;
}
- public boolean isInliningCandidate(DexEncodedMethod container, boolean alwaysInline) {
+ public boolean isInliningCandidate(DexEncodedMethod container, boolean alwaysInline,
+ AppInfoWithSubtyping appInfo) {
if (container.accessFlags.isStatic() && container.accessFlags.isConstructor()) {
// This will probably never happen but never inline a class initializer.
return false;
@@ -92,33 +117,33 @@
return true;
}
switch (compilationState) {
- case PROCESSED_INLINING_CANDIDATE_PUBLIC:
+ case PROCESSED_INLINING_CANDIDATE_ANY:
return true;
- case PROCESSED_INLINING_CANDIDATE_PACKAGE_PRIVATE:
+ case PROCESSED_INLINING_CANDIDATE_SUBCLASS:
+ return container.method.getHolder().isSubtypeOf(method.getHolder(), appInfo);
+ case PROCESSED_INLINING_CANDIDATE_SAME_PACKAGE:
return container.method.getHolder().isSamePackage(method.getHolder());
- // TODO(bak): Expand check for package private access:
- case PROCESSED_INLINING_CANDIDATE_PRIVATE:
+ case PROCESSED_INLINING_CANDIDATE_SAME_CLASS:
return container.method.getHolder() == method.getHolder();
default:
return false;
}
}
- public boolean isPublicInlining() {
- return compilationState == PROCESSED_INLINING_CANDIDATE_PUBLIC;
- }
-
public boolean markProcessed(Constraint state) {
CompilationState prevCompilationState = compilationState;
switch (state) {
case ALWAYS:
- compilationState = PROCESSED_INLINING_CANDIDATE_PUBLIC;
+ compilationState = PROCESSED_INLINING_CANDIDATE_ANY;
+ break;
+ case SUBCLASS:
+ compilationState = PROCESSED_INLINING_CANDIDATE_SUBCLASS;
break;
case PACKAGE:
- compilationState = PROCESSED_INLINING_CANDIDATE_PACKAGE_PRIVATE;
+ compilationState = PROCESSED_INLINING_CANDIDATE_SAME_PACKAGE;
break;
- case PRIVATE:
- compilationState = PROCESSED_INLINING_CANDIDATE_PRIVATE;
+ case SAMECLASS:
+ compilationState = PROCESSED_INLINING_CANDIDATE_SAME_CLASS;
break;
case NEVER:
compilationState = PROCESSED_NOT_INLINING_CANDIDATE;
diff --git a/src/main/java/com/android/tools/r8/graph/DexValue.java b/src/main/java/com/android/tools/r8/graph/DexValue.java
index 29f59e5..08c8a1c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexValue.java
+++ b/src/main/java/com/android/tools/r8/graph/DexValue.java
@@ -99,6 +99,15 @@
return this == defaultForType(type, factory);
}
+ /**
+ * Whether creating this value as a default value for a field might trigger an allocation.
+ * <p>
+ * This is conservative.
+ */
+ public boolean mayTriggerAllocation() {
+ return true;
+ }
+
static private abstract class SimpleDexValue extends DexValue {
@Override
@@ -111,6 +120,11 @@
// Intentionally empty
}
+ @Override
+ public boolean mayTriggerAllocation() {
+ return false;
+ }
+
protected static void writeIntegerTo(byte type, long value, int expected,
DexOutputBuffer dest) {
// Leave space for header.
diff --git a/src/main/java/com/android/tools/r8/ir/code/Argument.java b/src/main/java/com/android/tools/r8/ir/code/Argument.java
index d624990..c7b55d5 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Argument.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Argument.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.ir.code;
import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.Constraint;
@@ -67,7 +67,7 @@
}
@Override
- public Constraint inliningConstraint(AppInfo info, DexType holder) {
+ public Constraint inliningConstraint(AppInfoWithSubtyping info, DexType holder) {
return Constraint.ALWAYS;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Binop.java b/src/main/java/com/android/tools/r8/ir/code/Binop.java
index 899516a..bcdfc22 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Binop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Binop.java
@@ -7,7 +7,7 @@
import static com.android.tools.r8.dex.Constants.U8BIT_MAX;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.Constraint;
@@ -112,7 +112,7 @@
}
@Override
- public Constraint inliningConstraint(AppInfo info, DexType holder) {
+ public Constraint inliningConstraint(AppInfoWithSubtyping info, DexType holder) {
return Constraint.ALWAYS;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstInstruction.java b/src/main/java/com/android/tools/r8/ir/code/ConstInstruction.java
index 657faf7..8259926 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstInstruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstInstruction.java
@@ -3,6 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.code;
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+
public abstract class ConstInstruction extends Instruction {
public ConstInstruction(Value out) {
@@ -23,4 +27,9 @@
public ConstInstruction asConstInstruction() {
return this;
}
+
+ @Override
+ public Constraint inliningConstraint(AppInfoWithSubtyping info, DexType holder) {
+ return Constraint.ALWAYS;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
index 0da5b43..d53c577 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
@@ -12,10 +12,7 @@
import com.android.tools.r8.code.ConstWide32;
import com.android.tools.r8.code.ConstWideHigh16;
import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.graph.AppInfo;
-import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
import com.android.tools.r8.utils.NumberUtils;
public class ConstNumber extends ConstInstruction {
@@ -186,9 +183,4 @@
public ConstNumber asConstNumber() {
return this;
}
-
- @Override
- public Constraint inliningConstraint(AppInfo info, DexType holder) {
- return Constraint.ALWAYS;
- }
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
index 065d3df..ca18978 100644
--- a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.ir.code;
import com.android.tools.r8.graph.AppInfo;
-import com.android.tools.r8.graph.DexAccessFlags;
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexField;
@@ -44,22 +44,17 @@
abstract DexEncodedField lookupTarget(DexType type, AppInfo appInfo);
@Override
- public Constraint inliningConstraint(AppInfo info, DexType holder) {
+ public Constraint inliningConstraint(AppInfoWithSubtyping info, DexType holder) {
// Resolve the field if possible and decide whether the instruction can inlined.
DexType fieldHolder = field.getHolder();
DexEncodedField target = lookupTarget(fieldHolder, info);
DexClass fieldClass = info.definitionFor(fieldHolder);
- if ((target != null) && (fieldClass != null) && !fieldClass.isLibraryClass()) {
- DexAccessFlags flags = target.accessFlags;
- if (flags.isPublic()) {
- return Constraint.ALWAYS;
- }
- if (flags.isPrivate() && (fieldHolder == holder)) {
- return Constraint.PRIVATE;
- }
- if (flags.isProtected() && (fieldHolder.isSamePackage(holder))) {
- return Constraint.PACKAGE;
- }
+ if ((target != null) && (fieldClass != null)) {
+ Constraint fieldConstraint = Constraint
+ .deriveConstraint(holder, fieldHolder, target.accessFlags, info);
+ Constraint classConstraint = Constraint
+ .deriveConstraint(holder, fieldHolder, fieldClass.accessFlags, info);
+ return Constraint.min(fieldConstraint, classConstraint);
}
return Constraint.NEVER;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java b/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
index 1126299..955a6cc 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.ir.code;
import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.conversion.DexBuilder;
@@ -75,14 +75,11 @@
}
@Override
- public Constraint inliningConstraint(AppInfo info, DexType holder) {
+ public Constraint inliningConstraint(AppInfoWithSubtyping info, DexType holder) {
DexClass targetClass = info.definitionFor(type());
if (targetClass == null) {
return Constraint.NEVER;
}
- if (targetClass.accessFlags.isPublic()) {
- return Constraint.ALWAYS;
- }
- return Constraint.NEVER;
+ return Constraint.deriveConstraint(holder, type(), targetClass.accessFlags, info);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
index 083100b..e6ba6c0 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.ir.code;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.code.Value.DebugInfo;
@@ -839,7 +839,7 @@
}
// Returns the inlining constraint for this instruction.
- public Constraint inliningConstraint(AppInfo info, DexType holder) {
+ public Constraint inliningConstraint(AppInfoWithSubtyping info, DexType holder) {
return Constraint.NEVER;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
index f11d62f..cc23ef5 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
@@ -5,12 +5,11 @@
import com.android.tools.r8.code.InvokeDirectRange;
import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.InlineAction;
-import com.android.tools.r8.ir.optimize.InliningOracle;
import java.util.List;
public class InvokeDirect extends InvokeMethodWithReceiver {
@@ -89,7 +88,7 @@
}
@Override
- public InlineAction computeInlining(InliningOracle decider) {
- return decider.computeForInvokeDirect(this);
+ DexEncodedMethod lookupTarget(AppInfo appInfo) {
+ return appInfo.lookupDirectTarget(getInvokedMethod());
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java b/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
index 9d0c01f..a639ba1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
@@ -4,12 +4,11 @@
package com.android.tools.r8.ir.code;
import com.android.tools.r8.code.InvokeInterfaceRange;
+import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.InlineAction;
-import com.android.tools.r8.ir.optimize.InliningOracle;
import java.util.List;
public class InvokeInterface extends InvokeMethodWithReceiver {
@@ -76,7 +75,8 @@
}
@Override
- public InlineAction computeInlining(InliningOracle decider) {
- return decider.computeForInvokeInterface(this);
+ DexEncodedMethod lookupTarget(AppInfo appInfo) {
+ DexMethod method = getInvokedMethod();
+ return appInfo.lookupVirtualDefinition(method.holder, method);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
index 950e31f..70201f0 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
@@ -3,7 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.code;
+import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.optimize.Inliner.Constraint;
import com.android.tools.r8.ir.optimize.Inliner.InlineAction;
import com.android.tools.r8.ir.optimize.InliningOracle;
import java.util.List;
@@ -46,5 +52,28 @@
return this;
}
+ abstract DexEncodedMethod lookupTarget(AppInfo appInfo);
+
+ @Override
+ public Constraint inliningConstraint(AppInfoWithSubtyping info, DexType holder) {
+ if (method.holder.isArrayType()) {
+ return Constraint.ALWAYS;
+ }
+ DexEncodedMethod target = lookupTarget(info);
+ if (target != null) {
+ DexType methodHolder = target.method.holder;
+ DexClass methodClass = info.definitionFor(methodHolder);
+ if ((methodClass != null)) {
+ Constraint methodConstrain = Constraint
+ .deriveConstraint(holder, methodHolder, target.accessFlags, info);
+ // We also have to take the constraint of the enclosing class into account.
+ Constraint classConstraint = Constraint
+ .deriveConstraint(holder, methodHolder, methodClass.accessFlags, info);
+ return Constraint.min(methodConstrain, classConstraint);
+ }
+ }
+ return Constraint.NEVER;
+ }
+
public abstract InlineAction computeInlining(InliningOracle decider);
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
index c83b1d2..cdc8644 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.ir.code;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.ir.optimize.Inliner.InlineAction;
+import com.android.tools.r8.ir.optimize.InliningOracle;
import java.util.List;
public abstract class InvokeMethodWithReceiver extends InvokeMethod {
@@ -31,4 +33,10 @@
public InvokeMethodWithReceiver asInvokeMethodWithReceiver() {
return this;
}
+
+
+ @Override
+ public final InlineAction computeInlining(InliningOracle decider) {
+ return decider.computeForInvokeWithReceiver(this);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java b/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
index efc12db..5eacaa9 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.code;
import com.android.tools.r8.code.InvokePolymorphicRange;
+import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
@@ -87,6 +88,12 @@
}
@Override
+ DexEncodedMethod lookupTarget(AppInfo appInfo) {
+ // TODO(herhut): Implement lookup target for invokePolymorphic.
+ return null;
+ }
+
+ @Override
public InlineAction computeInlining(InliningOracle decider) {
return decider.computeForInvokePolymorpic(this);
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
index dc22e2e..6654c16 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.code;
import com.android.tools.r8.code.InvokeStaticRange;
+import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
@@ -76,6 +77,12 @@
}
@Override
+ DexEncodedMethod lookupTarget(AppInfo appInfo) {
+ DexMethod method = getInvokedMethod();
+ return appInfo.lookupStaticTarget(method);
+ }
+
+ @Override
public InlineAction computeInlining(InliningOracle decider) {
return decider.computeForInvokeStatic(this);
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java b/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
index fc79c11..b3d5fe4 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
@@ -4,15 +4,16 @@
package com.android.tools.r8.ir.code;
import com.android.tools.r8.code.InvokeSuperRange;
+import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.InlineAction;
-import com.android.tools.r8.ir.optimize.InliningOracle;
+import com.android.tools.r8.ir.optimize.Inliner.Constraint;
import java.util.List;
-public class InvokeSuper extends InvokeMethod {
+public class InvokeSuper extends InvokeMethodWithReceiver {
public InvokeSuper(DexMethod target, Value result, List<Value> arguments) {
super(target, result, arguments);
@@ -75,7 +76,14 @@
}
@Override
- public InlineAction computeInlining(InliningOracle decider) {
- return decider.computeForInvokeSuper(this);
+ DexEncodedMethod lookupTarget(AppInfo appInfo) {
+ DexMethod method = getInvokedMethod();
+ return appInfo.lookupVirtualDefinition(method.holder, method);
+ }
+
+ @Override
+ public Constraint inliningConstraint(AppInfoWithSubtyping info, DexType holder) {
+ // The semantics of invoke super depend on the context.
+ return Constraint.SAMECLASS;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
index 3988980..34793c2 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
@@ -4,12 +4,11 @@
package com.android.tools.r8.ir.code;
import com.android.tools.r8.code.InvokeVirtualRange;
+import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.InlineAction;
-import com.android.tools.r8.ir.optimize.InliningOracle;
import java.util.List;
public class InvokeVirtual extends InvokeMethodWithReceiver {
@@ -76,7 +75,8 @@
}
@Override
- public InlineAction computeInlining(InliningOracle decider) {
- return decider.computeForInvokeVirtual(this);
+ DexEncodedMethod lookupTarget(AppInfo appInfo) {
+ DexMethod method = getInvokedMethod();
+ return appInfo.lookupVirtualTarget(method.holder, method);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java b/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java
index ec9c12f..9d35ce2 100644
--- a/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.code;
-import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.optimize.Inliner.Constraint;
import com.android.tools.r8.utils.InternalOptions;
@@ -47,7 +47,7 @@
}
@Override
- public Constraint inliningConstraint(AppInfo info, DexType holder) {
+ public Constraint inliningConstraint(AppInfoWithSubtyping info, DexType holder) {
return Constraint.ALWAYS;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Move.java b/src/main/java/com/android/tools/r8/ir/code/Move.java
index 91e19f0..277c63c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Move.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Move.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.ir.code;
import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.Constraint;
@@ -81,7 +81,7 @@
}
@Override
- public Constraint inliningConstraint(AppInfo info, DexType holder) {
+ public Constraint inliningConstraint(AppInfoWithSubtyping info, DexType holder) {
return Constraint.ALWAYS;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Return.java b/src/main/java/com/android/tools/r8/ir/code/Return.java
index 142206c..337ed71 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Return.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Return.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.code.ReturnWide;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.Constraint;
@@ -110,7 +110,7 @@
}
@Override
- public Constraint inliningConstraint(AppInfo info, DexType holder) {
+ public Constraint inliningConstraint(AppInfoWithSubtyping info, DexType holder) {
return Constraint.ALWAYS;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Throw.java b/src/main/java/com/android/tools/r8/ir/code/Throw.java
index 9bd6a81..2f9f9f7 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Throw.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Throw.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.ir.code;
import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.Constraint;
@@ -63,7 +63,7 @@
}
@Override
- public Constraint inliningConstraint(AppInfo info, DexType holder) {
+ public Constraint inliningConstraint(AppInfoWithSubtyping info, DexType holder) {
return Constraint.ALWAYS;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Unop.java b/src/main/java/com/android/tools/r8/ir/code/Unop.java
index 174b7b6..a534420 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Unop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Unop.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.ir.code;
import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.optimize.Inliner.Constraint;
@@ -43,7 +43,7 @@
}
@Override
- public Constraint inliningConstraint(AppInfo info, DexType holder) {
+ public Constraint inliningConstraint(AppInfoWithSubtyping info, DexType holder) {
return Constraint.ALWAYS;
}
}
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 51aa284..e6b592d 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
@@ -6,8 +6,6 @@
import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor.ExcludeDexResources;
import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor.IncludeAllResources;
-import com.google.common.collect.ImmutableSet;
-
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
@@ -39,7 +37,7 @@
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
-
+import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -511,7 +509,7 @@
if (!options.inlineAccessors || inliner == null) {
state = Constraint.NEVER;
} else {
- state = inliner.identifySimpleMethods(code, method);
+ state = inliner.computeInliningConstraint(code, method);
}
feedback.markProcessed(method, state);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index a2b3ba2..876c83b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -4,8 +4,12 @@
package com.android.tools.r8.ir.optimize;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
-import com.android.tools.r8.graph.DexCode;
+import com.android.tools.r8.graph.DexAccessFlags;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.ir.code.BasicBlock;
@@ -34,8 +38,6 @@
public class Inliner {
- private static final int INLINING_INSTRUCTION_LIMIT = 5;
-
protected final AppInfoWithSubtyping appInfo;
private final GraphLense graphLense;
private final InternalOptions options;
@@ -61,50 +63,43 @@
return result;
}
- public Constraint identifySimpleMethods(IRCode code, DexEncodedMethod method) {
- DexCode dex = method.getCode().asDexCode();
- // We have generated code for a method and we want to figure out whether the method is a
- // candidate for inlining. The code is the final IR after optimizations.
- if (dex.instructions.length > INLINING_INSTRUCTION_LIMIT) {
- return Constraint.NEVER;
- }
+ public Constraint computeInliningConstraint(IRCode code, DexEncodedMethod method) {
Constraint result = Constraint.ALWAYS;
- ListIterator<BasicBlock> iterator = code.listIterator();
- assert iterator.hasNext();
- BasicBlock block = iterator.next();
- BasicBlock nextBlock;
- do {
- nextBlock = iterator.hasNext() ? iterator.next() : null;
- InstructionListIterator it = block.listIterator();
- while (it.hasNext()) {
- Instruction instruction = it.next();
- Constraint state = instructionAllowedForInlining(method, instruction);
- if (state == Constraint.NEVER) {
- return Constraint.NEVER;
- }
- if (state.ordinal() < result.ordinal()) {
- result = state;
- }
+ InstructionIterator it = code.instructionIterator();
+ while (it.hasNext()) {
+ Instruction instruction = it.next();
+ Constraint state = instructionAllowedForInlining(method, instruction);
+ if (state == Constraint.NEVER) {
+ return Constraint.NEVER;
}
- block = nextBlock;
- } while (block != null);
+ if (state.ordinal() < result.ordinal()) {
+ result = state;
+ }
+ }
return result;
}
boolean hasInliningAccess(DexEncodedMethod method, DexEncodedMethod target) {
- if (target.accessFlags.isPublic()) {
+ if (!isVisibleWithFlags(target.method.holder, method.method.holder, target.accessFlags)) {
+ return false;
+ }
+ // The class needs also to be visible for us to have access.
+ DexClass targetClass = appInfo.definitionFor(target.method.holder);
+ return isVisibleWithFlags(target.method.holder, method.method.holder, targetClass.accessFlags);
+ }
+
+ private boolean isVisibleWithFlags(DexType target, DexType context, DexAccessFlags flags) {
+ if (flags.isPublic()) {
return true;
}
- DexType methodHolder = method.method.getHolder();
- DexType targetHolder = target.method.getHolder();
- if (target.accessFlags.isPrivate()) {
- return methodHolder == targetHolder;
+ if (flags.isPrivate()) {
+ return target == context;
}
- if (target.accessFlags.isProtected() &&
- methodHolder.isSubtypeOf(targetHolder, appInfo)) {
- return true;
+ if (flags.isProtected()) {
+ return context.isSubtypeOf(target, appInfo) || target.isSamePackage(context);
}
- return methodHolder.isSamePackage(targetHolder);
+ // package-private
+ return target.isSamePackage(context);
}
synchronized DexEncodedMethod doubleInlining(DexEncodedMethod method,
@@ -141,14 +136,59 @@
}
}
+ /**
+ * Encodes the constraints for inlining a method's instructions into a different context.
+ * <p>
+ * This only takes the instructions into account and not whether a method should be inlined
+ * or what reason for inlining it might have. Also, it does not take the visibility of the
+ * method itself into account.
+ */
public enum Constraint {
// The ordinal values are important so please do not reorder.
- NEVER, // Never inline this.
- PRIVATE, // Only inline this into methods with same holder.
- PACKAGE, // Only inline this into methods with holders from same package.
- ALWAYS, // No restrictions for inlining this.
+ NEVER, // Never inline this.
+ SAMECLASS, // Only inline this into methods with same holder.
+ PACKAGE, // Only inline this into methods with holders from same package.
+ SUBCLASS, // Only inline this into methods with holders from a subclass.
+ ALWAYS; // No restrictions for inlining this.
+
+ static {
+ assert NEVER.ordinal() < SAMECLASS.ordinal();
+ assert SAMECLASS.ordinal() < PACKAGE.ordinal();
+ assert PACKAGE.ordinal() < SUBCLASS.ordinal();
+ assert SUBCLASS.ordinal() < ALWAYS.ordinal();
+ }
+
+ public static Constraint deriveConstraint(DexType contextHolder, DexType targetHolder,
+ DexAccessFlags flags, AppInfoWithSubtyping appInfo) {
+ if (flags.isPublic()) {
+ return ALWAYS;
+ } else if (flags.isPrivate()) {
+ return targetHolder == contextHolder ? SAMECLASS : NEVER;
+ } else if (flags.isProtected()) {
+ if (targetHolder.isSamePackage(contextHolder)) {
+ // Even though protected, this is visible via the same package from the context.
+ return PACKAGE;
+ } else if (contextHolder.isSubtypeOf(targetHolder, appInfo)) {
+ return SUBCLASS;
+ }
+ return NEVER;
+ } else {
+ /* package-private */
+ return targetHolder.isSamePackage(contextHolder) ? PACKAGE : NEVER;
+ }
+ }
+
+ public static Constraint min(Constraint one, Constraint other) {
+ return one.ordinal() < other.ordinal() ? one : other;
+ }
}
+ /**
+ * Encodes the reason why a method should be inlined.
+ * <p>
+ * This is independent of determining whether a method can be inlined, except for the FORCE
+ * state, that will inline a method irrespective of visibility and instruction checks.
+ */
public enum Reason {
FORCE, // Inlinee is marked for forced inlining (bridge method or renamed constructor).
SINGLE_CALLER, // Inlinee has precisely one caller.
@@ -199,7 +239,8 @@
return numOfInstructions;
}
- private boolean legalConstructorInline(DexEncodedMethod method, IRCode code) {
+ private boolean legalConstructorInline(DexEncodedMethod method,
+ InvokeMethod invoke, IRCode code) {
// In the Java VM Specification section "4.10.2.4. Instance Initialization Methods and
// Newly Created Objects" it says:
//
@@ -208,29 +249,43 @@
// declared within myClass.
//
- // Allow inlining a constructor into a constructor, as the constructor code is expected to
- // adhere to the VM specification.
- if (method.accessFlags.isConstructor()) {
+ // Allow inlining a constructor into a constructor of the same class, as the constructor code
+ // is expected to adhere to the VM specification.
+ if (method.accessFlags.isConstructor()
+ && method.method.holder == invoke.getInvokedMethod().holder) {
return true;
}
// Don't allow inlining a constructor into a non-constructor if the first use of the
// un-initialized object is not an argument of an invoke of <init>.
+ // Also, we cannot inline a constructor if it initializes final fields, as such is only allowed
+ // from within a constructor of the corresponding class.
InstructionIterator iterator = code.instructionIterator();
Instruction instruction = iterator.next();
// A constructor always has the un-initialized object as the first argument.
assert instruction.isArgument();
Value unInitializedObject = instruction.outValue();
+ boolean seenSuperInvoke = false;
while (iterator.hasNext()) {
instruction = iterator.next();
if (instruction.inValues().contains(unInitializedObject)) {
- return instruction.isInvokeDirect()
- && appInfo.dexItemFactory
- .isConstructor(instruction.asInvokeDirect().getInvokedMethod());
+ if (instruction.isInvokeDirect() && !seenSuperInvoke) {
+ DexMethod target = instruction.asInvokeDirect().getInvokedMethod();
+ seenSuperInvoke = appInfo.dexItemFactory.isConstructor(target);
+ }
+ if (!seenSuperInvoke) {
+ return false;
+ }
+ }
+ if (instruction.isInstancePut()) {
+ DexField field = instruction.asInstancePut().getField();
+ DexEncodedField target = appInfo.lookupInstanceTarget(field.getHolder(), field);
+ if (target != null && target.accessFlags.isFinal()) {
+ return false;
+ }
}
}
- assert false : "Execution should never reach this point";
- return false;
+ return true;
}
/// Computer the receiver value for the holder method.
@@ -250,8 +305,7 @@
return;
}
computeReceiverMustBeNonNull(code);
- Value receiver = receiverValue(method, code);
- InliningOracle oracle = new InliningOracle(this, method, receiver, callGraph);
+ InliningOracle oracle = new InliningOracle(this, method, callGraph);
List<BasicBlock> blocksToRemove = new ArrayList<>();
ListIterator<BasicBlock> blockIterator = code.listIterator();
@@ -272,8 +326,7 @@
// The declared target cannot be found so skip inlining.
continue;
}
- boolean forceInline = result.reason == Reason.FORCE;
- if (!target.isProcessed() && !forceInline) {
+ if (!(target.isProcessed() || result.reason == Reason.FORCE)) {
// Do not inline code that was not processed unless we have to force inline.
continue;
}
@@ -291,20 +344,16 @@
// If this code did not go through the full pipeline, apply inlining to make sure
// that force inline targets get processed.
if (!target.isProcessed()) {
- assert forceInline;
+ assert result.reason == Reason.FORCE;
if (Log.ENABLED) {
Log.verbose(getClass(), "Forcing extra inline on " + target.toSourceString());
}
performInlining(target, inlinee, callGraph);
}
// Make sure constructor inlining is legal.
- if (target.accessFlags.isConstructor() && !legalConstructorInline(method, inlinee)) {
- continue;
- }
- // Ensure the container is compatible with the target.
- if (!forceInline
- && !result.target.isPublicInlining()
- && (method.method.getHolder() != result.target.method.getHolder())) {
+ if (target.accessFlags.isConstructor()
+ && !target.accessFlags.isStatic()
+ && !legalConstructorInline(method, invoke, inlinee)) {
continue;
}
DexType downcast = null;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
index 446b75a..fb6c2eb 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
@@ -3,18 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.optimize;
+import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.code.InvokeDirect;
-import com.android.tools.r8.ir.code.InvokeInterface;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.InvokeMethodWithReceiver;
import com.android.tools.r8.ir.code.InvokePolymorphic;
import com.android.tools.r8.ir.code.InvokeStatic;
-import com.android.tools.r8.ir.code.InvokeSuper;
-import com.android.tools.r8.ir.code.InvokeVirtual;
-import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.conversion.CallGraph;
import com.android.tools.r8.ir.optimize.Inliner.InlineAction;
import com.android.tools.r8.ir.optimize.Inliner.Reason;
@@ -26,20 +22,19 @@
*/
public class InliningOracle {
- final Inliner inliner;
- final DexEncodedMethod method;
- final Value receiver;
- final CallGraph callGraph;
- final private InliningInfo info;
+ private static final int INLINING_INSTRUCTION_LIMIT = 5;
+
+ private final Inliner inliner;
+ private final DexEncodedMethod method;
+ private final CallGraph callGraph;
+ private final InliningInfo info;
public InliningOracle(
Inliner inliner,
DexEncodedMethod method,
- Value receiver,
CallGraph callGraph) {
this.inliner = inliner;
this.method = method;
- this.receiver = receiver;
this.callGraph = callGraph;
info = Log.ENABLED ? new InliningInfo(method) : null;
}
@@ -50,7 +45,7 @@
}
}
- DexEncodedMethod validateCandidate(InvokeMethod invoke) {
+ private DexEncodedMethod validateCandidate(InvokeMethod invoke) {
DexEncodedMethod candidate = invoke.computeSingleTarget(inliner.appInfo);
if ((candidate == null)
|| (candidate.getCode() == null)
@@ -60,32 +55,6 @@
}
return null;
}
- if (method == candidate) {
- // Cannot handle recursive inlining at this point.
- // Bridge methods should never have recursive calls.
- assert !candidate.getOptimizationInfo().forceInline();
- return null;
- }
-
- if (candidate.accessFlags.isSynchronized()) {
- // Don't inline if target is synchronized.
- if (info != null) {
- info.exclude(invoke, "Inlinee candidate is synchronized");
- }
- return null;
- }
-
- if (callGraph.isBreaker(method, candidate)) {
- // Cycle breaker so abort to preserve compilation order.
- return null;
- }
-
- if (!inliner.hasInliningAccess(method, candidate)) {
- if (info != null) {
- info.exclude(invoke, "Inlinee candidate does not have right access flags");
- }
- return null;
- }
return candidate;
}
@@ -102,104 +71,6 @@
return Reason.SIMPLE;
}
- public InlineAction computeForInvokeWithReceiver(InvokeMethodWithReceiver invoke) {
- boolean receiverIsNeverNull = invoke.receiverIsNeverNull();
- if (!receiverIsNeverNull) {
- if (info != null) {
- info.exclude(invoke, "receiver for candidate can be null");
- }
- return null;
- }
- DexEncodedMethod target = invoke.computeSingleTarget(inliner.appInfo);
- if (target == null) {
- // Abort inlining attempt if we cannot find single target.
- if (info != null) {
- info.exclude(invoke, "could not find single target");
- }
- return null;
- }
-
- if (target == method) {
- // Bridge methods should never have recursive calls.
- assert !target.getOptimizationInfo().forceInline();
- return null;
- }
-
- if (target.getCode() == null) {
- return null;
- }
-
- DexClass holder = inliner.appInfo.definitionFor(target.method.getHolder());
- if (holder.isInterface()) {
- // Art978_virtual_interfaceTest correctly expects an IncompatibleClassChangeError exception at runtime.
- if (info != null) {
- info.exclude(invoke, "Do not inline target if method holder is an interface class");
- }
- return null;
- }
-
- if (holder.isLibraryClass()) {
- // Library functions should not be inlined.
- return null;
- }
-
- // Don't inline if target is synchronized.
- if (target.accessFlags.isSynchronized()) {
- if (info != null) {
- info.exclude(invoke, "target is synchronized");
- }
- return null;
- }
-
- Reason reason = computeInliningReason(target);
- // Determine if this should be inlined no matter how big it is.
- if (!target.isInliningCandidate(method, reason != Reason.SIMPLE)) {
- // Abort inlining attempt if the single target is not an inlining candidate.
- if (info != null) {
- info.exclude(invoke, "target is not identified for inlining");
- }
- return null;
- }
-
- if (callGraph.isBreaker(method, target)) {
- // Cycle breaker so abort to preserve compilation order.
- return null;
- }
-
- // Abort inlining attempt if method -> target access is not right.
- if (!inliner.hasInliningAccess(method, target)) {
- if (info != null) {
- info.exclude(invoke, "target does not have right access");
- }
- return null;
- }
-
- // Attempt to inline a candidate that is only called twice.
- if ((reason == Reason.DUAL_CALLER) && (inliner.doubleInlining(method, target) == null)) {
- if (info != null) {
- info.exclude(invoke, "target is not ready for double inlining");
- }
- return null;
- }
-
- if (info != null) {
- info.include(invoke.getType(), target);
- }
- return new InlineAction(target, invoke, reason);
- }
-
- public InlineAction computeForInvokeVirtual(InvokeVirtual invoke) {
- return computeForInvokeWithReceiver(invoke);
- }
-
- public InlineAction computeForInvokeInterface(InvokeInterface invoke) {
- return computeForInvokeWithReceiver(invoke);
- }
-
- public InlineAction computeForInvokeDirect(InvokeDirect invoke) {
- return computeForInvokeWithReceiver(invoke);
- }
-
private boolean canInlineStaticInvoke(DexEncodedMethod method, DexEncodedMethod target) {
// Only proceed with inlining a static invoke if:
// - the holder for the target equals the holder for the method, or
@@ -209,7 +80,9 @@
return true;
}
DexClass clazz = inliner.appInfo.definitionFor(targetHolder);
- return (clazz != null) && (!clazz.hasNonTrivialClassInitializer());
+ return (clazz != null)
+ && (!clazz.hasNonTrivialClassInitializer())
+ && (!clazz.defaultValuesForStaticFieldsMayTriggerAllocation());
}
private synchronized boolean isDoubleInliningTarget(DexEncodedMethod candidate) {
@@ -219,14 +92,113 @@
&& (candidate.getCode().asDexCode().instructions.length <= 10);
}
+ private boolean passesInliningConstraints(InvokeMethod invoke, DexEncodedMethod candidate,
+ Reason reason) {
+ if (callGraph.isBreaker(method, candidate)) {
+ // Cycle breaker so abort to preserve compilation order.
+ return false;
+ }
+
+ if (method == candidate) {
+ // Cannot handle recursive inlining at this point.
+ // Force inlined method should never be recursive.
+ assert !candidate.getOptimizationInfo().forceInline();
+ if (info != null) {
+ info.exclude(invoke, "direct recursion");
+ }
+ return false;
+ }
+
+ // Abort inlining attempt if method -> target access is not right.
+ if (!inliner.hasInliningAccess(method, candidate)) {
+ if (info != null) {
+ info.exclude(invoke, "target does not have right access");
+ }
+ return false;
+ }
+
+ DexClass holder = inliner.appInfo.definitionFor(candidate.method.getHolder());
+ if (holder.isInterface()) {
+ // Art978_virtual_interfaceTest correctly expects an IncompatibleClassChangeError exception at
+ // runtime.
+ if (info != null) {
+ info.exclude(invoke, "Do not inline target if method holder is an interface class");
+ }
+ return false;
+ }
+
+ if (holder.isLibraryClass()) {
+ // Library functions should not be inlined.
+ return false;
+ }
+
+ // Don't inline if target is synchronized.
+ if (candidate.accessFlags.isSynchronized()) {
+ if (info != null) {
+ info.exclude(invoke, "target is synchronized");
+ }
+ return false;
+ }
+
+ // Attempt to inline a candidate that is only called twice.
+ if ((reason == Reason.DUAL_CALLER) && (inliner.doubleInlining(method, candidate) == null)) {
+ if (info != null) {
+ info.exclude(invoke, "target is not ready for double inlining");
+ }
+ return false;
+ }
+
+ if (reason == Reason.SIMPLE) {
+ // If we are looking for a simple method, only inline if actually simple.
+ Code code = candidate.getCode();
+ if (code.estimatedSizeForInlining() > INLINING_INSTRUCTION_LIMIT) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public InlineAction computeForInvokeWithReceiver(InvokeMethodWithReceiver invoke) {
+ boolean receiverIsNeverNull = invoke.receiverIsNeverNull();
+ if (!receiverIsNeverNull) {
+ if (info != null) {
+ info.exclude(invoke, "receiver for candidate can be null");
+ }
+ return null;
+ }
+ DexEncodedMethod candidate = validateCandidate(invoke);
+ if (candidate == null) {
+ return null;
+ }
+
+ Reason reason = computeInliningReason(candidate);
+ if (!candidate.isInliningCandidate(method, reason == Reason.FORCE, inliner.appInfo)) {
+ // Abort inlining attempt if the single target is not an inlining candidate.
+ if (info != null) {
+ info.exclude(invoke, "target is not identified for inlining");
+ }
+ return null;
+ }
+
+ if (!passesInliningConstraints(invoke, candidate, reason)) {
+ return null;
+ }
+
+ if (info != null) {
+ info.include(invoke.getType(), candidate);
+ }
+ return new InlineAction(candidate, invoke, reason);
+ }
+
public InlineAction computeForInvokeStatic(InvokeStatic invoke) {
DexEncodedMethod candidate = validateCandidate(invoke);
if (candidate == null) {
return null;
}
+
Reason reason = computeInliningReason(candidate);
// Determine if this should be inlined no matter how big it is.
- if (!candidate.isInliningCandidate(method, reason != Reason.SIMPLE)) {
+ if (!candidate.isInliningCandidate(method, reason == Reason.FORCE, inliner.appInfo)) {
// Abort inlining attempt if the single target is not an inlining candidate.
if (info != null) {
info.exclude(invoke, "target is not identified for inlining");
@@ -242,11 +214,7 @@
return null;
}
- // Attempt to inline a candidate that is only called twice.
- if ((reason == Reason.DUAL_CALLER) && (inliner.doubleInlining(method, candidate) == null)) {
- if (info != null) {
- info.exclude(invoke, "target is not ready for double inlining");
- }
+ if (!passesInliningConstraints(invoke, candidate, reason)) {
return null;
}
@@ -256,20 +224,6 @@
return new InlineAction(candidate, invoke, reason);
}
- public InlineAction computeForInvokeSuper(InvokeSuper invoke) {
- DexEncodedMethod candidate = validateCandidate(invoke);
- if (candidate == null) {
- if (info != null) {
- info.exclude(invoke, "not a valid inlining target");
- }
- return null;
- }
- if (info != null) {
- info.include(invoke.getType(), candidate);
- }
- return new InlineAction(candidate, invoke, Reason.SIMPLE);
- }
-
public InlineAction computeForInvokePolymorpic(InvokePolymorphic invoke) {
// TODO: No inlining of invoke polymorphic for now.
if (info != null) {
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 c2e804e..8cc8ec4 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
@@ -958,6 +958,12 @@
}
@Override
+ public int estimatedSizeForInlining() {
+ // We just onlined this, so do not inline it again.
+ return Integer.MAX_VALUE;
+ }
+
+ @Override
public OutlineCode asOutlineCode() {
return this;
}
diff --git a/src/test/examples/inlining/InlineConstructorFinalField.java b/src/test/examples/inlining/InlineConstructorFinalField.java
new file mode 100644
index 0000000..093a2ac
--- /dev/null
+++ b/src/test/examples/inlining/InlineConstructorFinalField.java
@@ -0,0 +1,23 @@
+// Copyright (c) 2017, 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 inlining;
+
+public class InlineConstructorFinalField {
+
+ public final int number;
+
+ @CheckDiscarded
+ InlineConstructorFinalField(int value) {
+ number = value;
+ }
+
+ // This will not be inlined, as it sets a final field.
+ InlineConstructorFinalField() {
+ this(42);
+ }
+
+ public String toString() {
+ return "value: " + number;
+ }
+}
diff --git a/src/test/examples/inlining/Inlining.java b/src/test/examples/inlining/Inlining.java
index e013655..bd8870f 100644
--- a/src/test/examples/inlining/Inlining.java
+++ b/src/test/examples/inlining/Inlining.java
@@ -3,6 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
package inlining;
+import inlining.pkg.OtherPublicClass;
+import inlining.pkg.PublicClass;
+import inlining.pkg.Subclass;
+
class A {
int a;
@@ -14,6 +18,14 @@
int a() {
return a;
}
+
+ int cannotInline(int v) {
+ // Cannot inline due to recursion.
+ if (v > 0) {
+ return cannotInline(v - 1);
+ }
+ return 42;
+ }
}
class B extends A {
@@ -21,6 +33,14 @@
B(int a) {
super(a);
}
+
+ int cannotInline(int v) {
+ return -1;
+ }
+
+ int callMethodInSuper() {
+ return super.cannotInline(10);
+ }
}
class InlineConstructor {
@@ -134,6 +154,21 @@
Assert(ic != null);
InlineConstructorOfInner icoi = new InlineConstructorOfInner();
Assert(icoi != null);
+
+ // Check that super calls are processed correctly.
+ new B(123).callMethodInSuper();
+
+ // Inline calls to package private methods
+ PublicClass.alsoCallsPackagePrivateMethod();
+ OtherPublicClass.callsMethodThatCallsPackagePrivateMethod();
+ // Inline calls to protected methods.
+ PublicClass.callsProtectedMethod3();
+ PublicClass.alsoReadsPackagePrivateField();
+ OtherPublicClass.callsMethodThatCallsProtectedMethod();
+ OtherPublicClass.callsMethodThatReadsFieldInPackagePrivateClass();
+ Subclass.callsMethodThatCallsProtectedMethod();
+ // Do not inline constructors which set final field.
+ System.out.println(new InlineConstructorFinalField());
}
private static boolean intCmpExpression(A a, A b) {
@@ -180,6 +215,7 @@
return 21.21F == floatConstantInline();
}
+ @CheckDiscarded
private static String stringConstantInline() {
return "Fisk er godt";
}
diff --git a/src/test/examples/inlining/keep-rules-discard.txt b/src/test/examples/inlining/keep-rules-discard.txt
index 66be962..ea5e143 100644
--- a/src/test/examples/inlining/keep-rules-discard.txt
+++ b/src/test/examples/inlining/keep-rules-discard.txt
@@ -8,9 +8,6 @@
public static void main(...);
}
-# allow access modification to enable minifcation
--allowaccessmodification
-
# check that methods have been inlined
-checkdiscard class * {
@inlining.CheckDiscarded *;
diff --git a/src/test/examples/inlining/keep-rules.txt b/src/test/examples/inlining/keep-rules.txt
index dd713bb..d60f1dc 100644
--- a/src/test/examples/inlining/keep-rules.txt
+++ b/src/test/examples/inlining/keep-rules.txt
@@ -7,6 +7,3 @@
-keep public class inlining.Inlining {
public static void main(...);
}
-
-# allow access modification to enable minifcation
--allowaccessmodification
diff --git a/src/test/examples/inlining/pkg/OtherPublicClass.java b/src/test/examples/inlining/pkg/OtherPublicClass.java
new file mode 100644
index 0000000..4d781d9
--- /dev/null
+++ b/src/test/examples/inlining/pkg/OtherPublicClass.java
@@ -0,0 +1,20 @@
+// Copyright (c) 2017, 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 inlining.pkg;
+
+public class OtherPublicClass {
+
+ public static String callsMethodThatCallsPackagePrivateMethod() {
+ return PublicClass.callsPackagePrivateMethod();
+ }
+
+ public static String callsMethodThatCallsProtectedMethod() {
+ return PublicClass.callsProtectedMethod();
+ }
+
+ public static int callsMethodThatReadsFieldInPackagePrivateClass() {
+ return PublicClass.readsPackagePrivateField();
+ }
+
+}
diff --git a/src/test/examples/inlining/pkg/PackagePrivateClass.java b/src/test/examples/inlining/pkg/PackagePrivateClass.java
new file mode 100644
index 0000000..ae05e8b
--- /dev/null
+++ b/src/test/examples/inlining/pkg/PackagePrivateClass.java
@@ -0,0 +1,9 @@
+// Copyright (c) 2017, 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 inlining.pkg;
+
+class PackagePrivateClass {
+
+ public static int aField = 42;
+}
diff --git a/src/test/examples/inlining/pkg/PublicClass.java b/src/test/examples/inlining/pkg/PublicClass.java
new file mode 100644
index 0000000..17cdea4
--- /dev/null
+++ b/src/test/examples/inlining/pkg/PublicClass.java
@@ -0,0 +1,59 @@
+// Copyright (c) 2017, 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 inlining.pkg;
+
+import inlining.CheckDiscarded;
+
+public class PublicClass {
+
+ protected static String protectedMethod() {
+ return "Hello";
+ }
+
+ @CheckDiscarded
+ static String callsProtectedMethod() {
+ return protectedMethod();
+ }
+
+ @CheckDiscarded
+ static String callsProtectedMethod2() {
+ return protectedMethod();
+ }
+
+ public static String callsProtectedMethod3() {
+ return protectedMethod();
+ }
+
+ static String packagePrivateMethod() {
+ return "World";
+ }
+
+ @CheckDiscarded
+ static int readsPackagePrivateField() {
+ return PackagePrivateClass.aField;
+ }
+
+ public static int alsoReadsPackagePrivateField() {
+ return PackagePrivateClass.aField;
+ }
+
+ @CheckDiscarded
+ public static String callsPackagePrivateMethod() {
+ return packagePrivateMethod();
+ }
+
+ public static String alsoCallsPackagePrivateMethod() {
+ return packagePrivateMethod();
+ }
+
+ public static void callMeToPreventInling() {
+ // Call it three times so it does not get inlined.
+ packagePrivateMethod();
+ packagePrivateMethod();
+ packagePrivateMethod();
+ protectedMethod();
+ protectedMethod();
+ protectedMethod();
+ }
+}
diff --git a/src/test/examples/inlining/pkg/Subclass.java b/src/test/examples/inlining/pkg/Subclass.java
new file mode 100644
index 0000000..f917697
--- /dev/null
+++ b/src/test/examples/inlining/pkg/Subclass.java
@@ -0,0 +1,11 @@
+// Copyright (c) 2017, 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 inlining.pkg;
+
+public class Subclass extends PublicClass {
+
+ public static String callsMethodThatCallsProtectedMethod() {
+ return PublicClass.callsProtectedMethod2();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
index 22278e2..b83b193 100644
--- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -743,6 +743,18 @@
DexVm.ART_4_4_4, DexVm.ART_5_1_1, DexVm.ART_6_0_1, DexVm.ART_7_0_0)))
.build();
+ public static List<String> requireInliningToBeDisabled = ImmutableList.of(
+ // Test for a specific stack trace that gets destroyed by inlining.
+ "492-checker-inline-invoke-interface",
+ "493-checker-inline-invoke-interface",
+ "488-checker-inline-recursive-calls",
+ "487-checker-inline-calls",
+ "122-npe",
+
+ // Calls some internal art methods that cannot tolerate inlining.
+ "466-get-live-vreg"
+ );
+
private static List<String> failuresToTriage = ImmutableList.of(
// This is flaky.
"104-growth-limit",
@@ -812,11 +824,14 @@
private final boolean failsWithArtOriginalOnly;
// Test might produce different outputs.
private final boolean outputMayDiffer;
+ // Whether to disable inlining
+ private final boolean disableInlining;
TestSpecification(String name, DexTool dexTool,
File directory, boolean skipArt, boolean skipTest, boolean failsWithX8,
boolean failsWithArt, boolean failsWithArtOutput, boolean failsWithArtOriginalOnly,
- String nativeLibrary, boolean expectedToFailWithX8, boolean outputMayDiffer) {
+ String nativeLibrary, boolean expectedToFailWithX8, boolean outputMayDiffer,
+ boolean disableInlining) {
this.name = name;
this.dexTool = dexTool;
this.nativeLibrary = nativeLibrary;
@@ -829,12 +844,13 @@
this.failsWithArtOriginalOnly = failsWithArtOriginalOnly;
this.expectedToFailWithX8 = expectedToFailWithX8;
this.outputMayDiffer = outputMayDiffer;
+ this.disableInlining = disableInlining;
}
TestSpecification(String name, DexTool dexTool, File directory, boolean skipArt,
boolean failsWithArt) {
this(name, dexTool, directory, skipArt,
- false, false, failsWithArt, false, false, null, false, false);
+ false, false, failsWithArt, false, false, null, false, false, false);
}
public File resolveFile(String name) {
@@ -980,7 +996,8 @@
failsRunWithArtOriginalOnly.contains(name),
useNativeLibrary.contains(name) ? "arttest" : null,
expectedToFailWithCompilerSet.contains(name),
- outputMayDiffer.contains(name)));
+ outputMayDiffer.contains(name),
+ requireInliningToBeDisabled.contains(name)));
}
}
return data;
@@ -1049,9 +1066,11 @@
CompilerUnderTest compilerUnderTest,
Collection<String> fileNames,
String resultPath,
- CompilationMode compilationMode)
+ CompilationMode compilationMode,
+ boolean disableInlining)
throws IOException, ProguardRuleParserException, ExecutionException, CompilationException {
- executeCompilerUnderTest(compilerUnderTest, fileNames, resultPath, compilationMode, null);
+ executeCompilerUnderTest(compilerUnderTest, fileNames, resultPath, compilationMode, null,
+ disableInlining);
}
private void executeCompilerUnderTest(
@@ -1059,7 +1078,8 @@
Collection<String> fileNames,
String resultPath,
CompilationMode mode,
- String keepRulesFile)
+ String keepRulesFile,
+ boolean disableInlining)
throws IOException, ProguardRuleParserException, ExecutionException, CompilationException {
assert mode != null;
switch (compilerUnderTest) {
@@ -1100,6 +1120,9 @@
if (enableInterfaceMethodDesugaring.contains(name)) {
options.interfaceMethodDesugaring = OffOrAuto.Auto;
}
+ if (disableInlining) {
+ options.inlineAccessors = false;
+ }
});
break;
}
@@ -1292,7 +1315,8 @@
DexVm dexVm,
File resultDir)
throws IOException, ProguardRuleParserException, ExecutionException, CompilationException {
- executeCompilerUnderTest(compilerUnderTest, fileNames, resultDir.getAbsolutePath(), mode);
+ executeCompilerUnderTest(compilerUnderTest, fileNames, resultDir.getAbsolutePath(), mode,
+ specification.disableInlining);
if (!ToolHelper.artSupported()) {
return;
@@ -1445,7 +1469,8 @@
thrown.expect(CompilationError.class);
try {
executeCompilerUnderTest(
- compilerUnderTest, fileNames, resultDir.getCanonicalPath(), compilationMode, null);
+ compilerUnderTest, fileNames, resultDir.getCanonicalPath(), compilationMode,
+ specification.disableInlining);
} catch (CompilationException e) {
throw new CompilationError(e.getMessage(), e);
} catch (ExecutionException e) {
@@ -1456,12 +1481,14 @@
} else if (specification.failsWithX8) {
thrown.expect(Throwable.class);
executeCompilerUnderTest(
- compilerUnderTest, fileNames, resultDir.getCanonicalPath(), compilationMode);
+ compilerUnderTest, fileNames, resultDir.getCanonicalPath(), compilationMode,
+ specification.disableInlining);
System.err.println("Should have failed R8/D8 compilation with an exception.");
return;
} else {
executeCompilerUnderTest(
- compilerUnderTest, fileNames, resultDir.getCanonicalPath(), compilationMode);
+ compilerUnderTest, fileNames, resultDir.getCanonicalPath(), compilationMode,
+ specification.disableInlining);
}
if (!specification.skipArt && ToolHelper.artSupported()) {
diff --git a/src/test/java/com/android/tools/r8/shaking/PrintUsageTest.java b/src/test/java/com/android/tools/r8/shaking/PrintUsageTest.java
index 47c6330..c9b476a 100644
--- a/src/test/java/com/android/tools/r8/shaking/PrintUsageTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/PrintUsageTest.java
@@ -151,10 +151,13 @@
}
private static void inspectShaking9(PrintUsageInspector inspector) {
- assertFalse(inspector.clazz("shaking9.Superclass").isPresent());
+ Optional<ClassSubject> superClass = inspector.clazz("shaking9.Superclass");
+ assertTrue(superClass.isPresent());
+ assertTrue(superClass.get().method("void", "<init>", Collections.emptyList()));
Optional<ClassSubject> subClass = inspector.clazz("shaking9.Subclass");
assertTrue(subClass.isPresent());
assertTrue(subClass.get().method("void", "aMethod", Collections.emptyList()));
+ assertTrue(subClass.get().method("void", "<init>", Collections.emptyList()));
}
private static void inspectShaking12(PrintUsageInspector inspector) {
diff --git a/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java b/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
index 5b94e6b..3435577 100644
--- a/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
@@ -73,8 +73,12 @@
"minifygeneric:keep-rules.txt:DEX:false",
"minifygeneric:keep-rules.txt:JAR:false",
"minifygenericwithinner:keep-rules.txt:DEX:false",
- "minifygenericwithinner:keep-rules.txt:JAR:false"
-
+ "minifygenericwithinner:keep-rules.txt:JAR:false",
+ // TODO(62048823): Inlining tests don't use allowaccessmodification.
+ "inlining:keep-rules.txt:DEX:true",
+ "inlining:keep-rules.txt:JAR:true",
+ "inlining:keep-rules-discard.txt:DEX:true",
+ "inlining:keep-rules-discard.txt:JAR:true"
);
private final boolean minify;
diff --git a/src/test/java/com/android/tools/r8/smali/OutlineTest.java b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
index 4808f33..4656cd6 100644
--- a/src/test/java/com/android/tools/r8/smali/OutlineTest.java
+++ b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
@@ -43,6 +43,13 @@
public class OutlineTest extends SmaliTestBase {
+ private InternalOptions createInternalOptions() {
+ InternalOptions result = new InternalOptions();
+ // Disable inlining to make sure that code looks as expected.
+ result.inlineAccessors = false;
+ return result;
+ }
+
DexEncodedMethod getInvokedMethod(DexApplication application, InvokeStatic invoke) {
DexInspector inspector = new DexInspector(application);
ClassSubject clazz = inspector.clazz(invoke.getMethod().holder.toSourceString());
@@ -118,7 +125,7 @@
);
for (int i = 2; i < 6; i++) {
- InternalOptions options = new InternalOptions();
+ InternalOptions options = createInternalOptions();
options.outline.threshold = 1;
options.outline.minSize = i;
options.outline.maxSize = i;
@@ -183,7 +190,7 @@
);
for (int i = 2; i < 6; i++) {
- InternalOptions options = new InternalOptions();
+ InternalOptions options = createInternalOptions();
options.outline.threshold = 1;
options.outline.minSize = i;
options.outline.maxSize = i;
@@ -249,7 +256,7 @@
" return-void"
);
- InternalOptions options = new InternalOptions();
+ InternalOptions options = createInternalOptions();
options.outline.threshold = 1;
DexApplication originalApplication = buildApplication(builder, options);
DexApplication processedApplication = processApplication(originalApplication, options);
@@ -313,7 +320,7 @@
" return-void"
);
- InternalOptions options = new InternalOptions();
+ InternalOptions options = createInternalOptions();
options.outline.threshold = 1;
DexApplication originalApplication = buildApplication(builder, options);
DexApplication processedApplication = processApplication(originalApplication, options);
@@ -372,7 +379,7 @@
);
for (int i = 2; i < 4; i++) {
- InternalOptions options = new InternalOptions();
+ InternalOptions options = createInternalOptions();
options.outline.threshold = 1;
options.outline.minSize = i;
options.outline.maxSize = i;
@@ -446,7 +453,7 @@
);
for (int i = 2; i < 4; i++) {
- InternalOptions options = new InternalOptions();
+ InternalOptions options = createInternalOptions();
options.outline.threshold = 1;
options.outline.minSize = i;
options.outline.maxSize = i;
@@ -516,7 +523,7 @@
);
for (int i = 2; i < 6; i++) {
- InternalOptions options = new InternalOptions();
+ InternalOptions options = createInternalOptions();
options.outline.threshold = 1;
options.outline.minSize = i;
options.outline.maxSize = i;
@@ -614,7 +621,7 @@
" return-void"
);
- InternalOptions options = new InternalOptions();
+ InternalOptions options = createInternalOptions();
options.outline.threshold = 1;
options.outline.minSize = 7;
options.outline.maxSize = 7;
@@ -678,7 +685,7 @@
);
for (int i = 2; i < 8; i++) {
- InternalOptions options = new InternalOptions();
+ InternalOptions options = createInternalOptions();
options.outline.threshold = 1;
options.outline.minSize = i;
options.outline.maxSize = i;
@@ -735,7 +742,7 @@
" return-void"
);
- InternalOptions options = new InternalOptions();
+ InternalOptions options = createInternalOptions();
options.outline.threshold = 1;
options.outline.minSize = 3;
options.outline.maxSize = 3;
@@ -808,7 +815,7 @@
" return-void"
);
- InternalOptions options = new InternalOptions();
+ InternalOptions options = createInternalOptions();
options.outline.threshold = 1;
options.outline.minSize = 3;
options.outline.maxSize = 3;
@@ -879,7 +886,7 @@
" return-void"
);
- InternalOptions options = new InternalOptions();
+ InternalOptions options = createInternalOptions();
options.outline.threshold = 1;
options.outline.minSize = 3;
options.outline.maxSize = 3;
@@ -943,7 +950,7 @@
" return-void"
);
- InternalOptions options = new InternalOptions();
+ InternalOptions options = createInternalOptions();
options.outline.threshold = 1;
options.outline.minSize = 5;
options.outline.maxSize = 5;
@@ -1003,7 +1010,7 @@
" return-void"
);
- InternalOptions options = new InternalOptions();
+ InternalOptions options = createInternalOptions();
options.outline.threshold = 1;
options.outline.minSize = 4;
options.outline.maxSize = 4;
@@ -1077,7 +1084,7 @@
" return-void"
);
- InternalOptions options = new InternalOptions();
+ InternalOptions options = createInternalOptions();
options.outline.threshold = 1;
options.outline.minSize = 4;
options.outline.maxSize = 4;
@@ -1152,7 +1159,7 @@
" return-void"
);
- InternalOptions options = new InternalOptions();
+ InternalOptions options = createInternalOptions();
options.outline.threshold = 1;
options.outline.minSize = 3; // Outline add, sub and mul.
options.outline.maxSize = 3;
@@ -1204,7 +1211,7 @@
" return-void"
);
- InternalOptions options = new InternalOptions();
+ InternalOptions options = createInternalOptions();
options.outline.threshold = 1;
options.outline.minSize = 3;
options.outline.maxSize = 3;
@@ -1249,7 +1256,7 @@
" return-void"
);
- InternalOptions options = new InternalOptions();
+ InternalOptions options = createInternalOptions();
options.outline.threshold = 1;
options.outline.minSize = 3;
options.outline.maxSize = 3;
@@ -1455,7 +1462,7 @@
" return-void"
);
- InternalOptions options = new InternalOptions();
+ InternalOptions options = createInternalOptions();
options.outline.threshold = 2;
DexApplication originalApplication = buildApplicationWithAndroidJar(builder, options);
diff --git a/src/test/java/com/android/tools/r8/utils/R8InliningTest.java b/src/test/java/com/android/tools/r8/utils/R8InliningTest.java
index 50db347..7f3c3e1 100644
--- a/src/test/java/com/android/tools/r8/utils/R8InliningTest.java
+++ b/src/test/java/com/android/tools/r8/utils/R8InliningTest.java
@@ -85,7 +85,10 @@
.setOutputPath(out)
.addProguardConfigurationFiles(Paths.get(keepRulesFile))
.build();
- ToolHelper.runR8(command);
+ // TODO(62048823): Enable minification.
+ ToolHelper.runR8(command, o -> {
+ o.skipMinification = true;
+ });
ToolHelper.runArtNoVerificationErrors(out + "/classes.dex", "inlining.Inlining");
}