Merge "Minor refactoring of class initialization analysis"
diff --git a/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java b/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java
index 8c79ea1..c5cb84e 100644
--- a/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java
+++ b/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java
@@ -26,6 +26,7 @@
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
+import java.util.ListIterator;
import java.util.Map;
public class LoadStoreHelper {
@@ -35,7 +36,7 @@
private final AppInfo appInfo;
private Map<Value, ConstInstruction> clonableConstants = null;
- private BasicBlock block = null;
+ private ListIterator<BasicBlock> blockIterator = null;
public LoadStoreHelper(IRCode code, TypeVerificationHelper typesHelper, AppInfo appInfo) {
this.code = code;
@@ -96,16 +97,16 @@
public void insertLoadsAndStores() {
clonableConstants = new IdentityHashMap<>();
- for (BasicBlock block : code.blocks) {
- this.block = block;
- InstructionListIterator it = block.listIterator();
+ blockIterator = code.blocks.listIterator();
+ while (blockIterator.hasNext()) {
+ InstructionListIterator it = blockIterator.next().listIterator();
while (it.hasNext()) {
it.next().insertLoadAndStores(it, this);
}
clonableConstants.clear();
}
clonableConstants = null;
- block = null;
+ blockIterator = null;
}
public void insertPhiMoves(CfRegisterAllocator allocator) {
@@ -170,8 +171,7 @@
assert !(instruction.outValue() instanceof StackValue);
if (instruction.isConstInstruction()) {
ConstInstruction constInstruction = instruction.asConstInstruction();
- assert block != null;
- if (canRemoveConstInstruction(constInstruction, block)) {
+ if (canRemoveConstInstruction(constInstruction, instruction.getBlock())) {
assert !constInstruction.isDexItemBasedConstString()
|| constInstruction.outValue().numberOfUsers() == 1;
clonableConstants.put(instruction.outValue(), constInstruction);
@@ -180,7 +180,8 @@
return;
}
assert instruction.outValue().isUsed(); // Should have removed it above.
- } else if (!instruction.outValue().isUsed()) {
+ }
+ if (!instruction.outValue().isUsed()) {
popOutValue(instruction.outValue(), instruction, it);
return;
}
@@ -189,19 +190,40 @@
Store store = new Store(oldOutValue, newOutValue);
// Move the debugging-locals liveness pertaining to the instruction to the store.
instruction.moveDebugValues(store);
- add(store, instruction, it);
- }
-
- public void popOutValue(Value value, Instruction instruction, InstructionListIterator it) {
- StackValue newOutValue = createStackValue(value, 0);
- instruction.swapOutValue(newOutValue);
- add(new Pop(newOutValue), instruction, it);
+ BasicBlock storeBlock = instruction.getBlock();
+ // If the block has catch-handlers we are not allowed to modify the locals of the block. If the
+ // instruction is throwing, the action should be moved to a new block - otherwise, the store
+ // should be inserted and the remaining instructions should be moved along with the handlers to
+ // the new block.
+ boolean hasCatchHandlers = instruction.getBlock().hasCatchHandlers();
+ if (hasCatchHandlers && instruction.instructionTypeCanThrow()) {
+ storeBlock = it.split(this.code, this.blockIterator);
+ it = storeBlock.listIterator();
+ }
+ add(store, storeBlock, instruction.getPosition(), it);
+ if (hasCatchHandlers && !instruction.instructionTypeCanThrow()) {
+ it.split(this.code, this.blockIterator);
+ this.blockIterator.previous();
+ }
}
public void popOutType(DexType type, Instruction instruction, InstructionListIterator it) {
- StackValue newOutValue = createStackValue(type, 0);
+ popOutValue(createStackValue(type, 0), instruction, it);
+ }
+
+ private void popOutValue(Value value, Instruction instruction, InstructionListIterator it) {
+ popOutValue(createStackValue(value, 0), instruction, it);
+ }
+
+ private void popOutValue(
+ StackValue newOutValue, Instruction instruction, InstructionListIterator it) {
+ BasicBlock insertBlock = instruction.getBlock();
+ if (insertBlock.hasCatchHandlers() && instruction.instructionTypeCanThrow()) {
+ insertBlock = it.split(this.code, this.blockIterator);
+ it = insertBlock.listIterator();
+ }
instruction.swapOutValue(newOutValue);
- add(new Pop(newOutValue), instruction, it);
+ add(new Pop(newOutValue), insertBlock, instruction.getPosition(), it);
}
private static class PhiMove {
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCode.java b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
index 3b33879..870ae6f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCode.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
@@ -665,15 +665,8 @@
}
// After the throwing instruction only debug instructions and the final jump
// instruction is allowed.
- // TODO(mkroghj) Temporarily allow stack-operations to be after throwing instructions.
if (seenThrowing) {
- assert instruction.isDebugInstruction()
- || instruction.isJumpInstruction()
- || instruction.isStore()
- || instruction.isPop()
- || instruction.isDup()
- || instruction.isDup2()
- || instruction.isSwap();
+ assert instruction.isDebugInstruction() || instruction.isGoto();
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Store.java b/src/main/java/com/android/tools/r8/ir/code/Store.java
index 21cb146..202bac6 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Store.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Store.java
@@ -75,7 +75,7 @@
@Override
public void insertLoadAndStores(InstructionListIterator it, LoadStoreHelper helper) {
- // Nothing to do. This is only hit because loads and stores are insert for phis.
+ throw new Unreachable("This IR must not be inserted before load and store insertion.");
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
index 6b5f6c4..8a46e1e 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
@@ -149,9 +149,6 @@
computeInitializers();
typeVerificationHelper = new TypeVerificationHelper(code, factory, appInfo);
typeVerificationHelper.computeVerificationTypes();
- if (!options.testing.noSplittingExceptionalEdges) {
- splitExceptionalBlocks();
- }
rewriter.converter.deadCodeRemover.run(code);
rewriteNots();
LoadStoreHelper loadStoreHelper = new LoadStoreHelper(code, typeVerificationHelper, appInfo);
@@ -223,38 +220,6 @@
return initializers;
}
- // Split all blocks with throwing instructions and exceptional edges such that any non-throwing
- // instructions that might define values prior to the throwing exception are excluded from the
- // try-catch range. Failure to do so will result in code that does not verify on the JVM.
- private void splitExceptionalBlocks() {
- ListIterator<BasicBlock> it = code.listIterator();
- while (it.hasNext()) {
- BasicBlock block = it.next();
- if (!block.hasCatchHandlers()) {
- continue;
- }
- int size = block.getInstructions().size();
- boolean isThrow = block.exit().isThrow();
- if ((isThrow && size == 1) || (!isThrow && size == 2)) {
- // Fast-path to avoid processing blocks with just a single throwing instruction.
- continue;
- }
- InstructionListIterator instructions = block.listIterator();
- boolean hasOutValues = false;
- while (instructions.hasNext()) {
- Instruction instruction = instructions.next();
- if (instruction.instructionTypeCanThrow()) {
- break;
- }
- hasOutValues |= instruction.outValue() != null;
- }
- if (hasOutValues) {
- instructions.previous();
- instructions.split(code, it);
- }
- }
- }
-
private void rewriteNots() {
for (BasicBlock block : code.blocks) {
InstructionListIterator it = block.listIterator();
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 3997982..7f4fbe1 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -539,7 +539,6 @@
public boolean forceNameReflectionOptimization = false;
public boolean disallowLoadStoreOptimization = false;
public Consumer<IRCode> irModifier = null;
- public boolean noSplittingExceptionalEdges = false;
}
private boolean hasMinApi(AndroidApiLevel level) {
diff --git a/src/test/java/com/android/tools/r8/cf/TryRangeTestRunner.java b/src/test/java/com/android/tools/r8/cf/TryRangeTestRunner.java
index e4c7098..926a22d 100644
--- a/src/test/java/com/android/tools/r8/cf/TryRangeTestRunner.java
+++ b/src/test/java/com/android/tools/r8/cf/TryRangeTestRunner.java
@@ -8,9 +8,19 @@
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfLabel;
+import com.android.tools.r8.cf.code.CfLoad;
+import com.android.tools.r8.cf.code.CfStackInstruction;
+import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.util.List;
import java.util.ListIterator;
import org.junit.Test;
@@ -18,8 +28,7 @@
* This tests that we produce valid code when having normal-flow with exceptional edges in blocks.
* We might perform optimizations that add operations (dup, swap, etc.) before and after
* instructions that lie on the boundary of the exception table that is generated for a basic block.
- * If live-ranges are minimized this could produce VerifyErrors. TODO(b/119771771) Will fail if
- * shorten live ranges without shorten exception table range.
+ * If live-ranges are minimized this could produce VerifyErrors.
*/
public class TryRangeTestRunner extends TestBase {
@@ -37,27 +46,45 @@
o.testing.disallowLoadStoreOptimization = true;
})
.run(TryRangeTest.class)
- .assertSuccess();
+ .assertSuccessWithOutput(StringUtils.lines("10", "7.0"));
}
@Test
public void testRegisterAllocationLimitLeadingRange() throws Exception {
- testForR8(Backend.CF)
- .addProgramClasses(TryRangeTestLimitRange.class)
- .addKeepMainRule(TryRangeTestLimitRange.class)
- .setMode(CompilationMode.RELEASE)
- .minification(false)
- .noTreeShaking()
- .enableInliningAnnotations()
- .addOptionsModification(
- o -> {
- o.testing.disallowLoadStoreOptimization = true;
- o.testing.irModifier = this::processIR;
- // TODO(mkroghj) Remove this option entirely when splittingExceptionalEdges is moved.
- o.testing.noSplittingExceptionalEdges = true;
- })
- .run(TryRangeTestLimitRange.class)
- .assertFailure();
+ CodeInspector inspector =
+ testForR8(Backend.CF)
+ .addProgramClasses(TryRangeTestLimitRange.class)
+ .addKeepMainRule(TryRangeTestLimitRange.class)
+ .setMode(CompilationMode.RELEASE)
+ .minification(false)
+ .noTreeShaking()
+ .enableInliningAnnotations()
+ .addOptionsModification(
+ o -> {
+ o.testing.disallowLoadStoreOptimization = true;
+ o.testing.irModifier = this::processIR;
+ })
+ .run(TryRangeTestLimitRange.class)
+ .assertSuccessWithOutput("")
+ .inspector();
+ // Assert that we do not have any register-modifying instructions in the throwing block:
+ // L0: ; locals:
+ // iload 1;
+ // invokestatic com.android.tools.r8.cf.TryRangeTestLimitRange.doSomething(I)F
+ // L1: ; locals:
+ // 11: pop
+ ClassSubject clazz = inspector.clazz("com.android.tools.r8.cf.TryRangeTestLimitRange");
+ CfCode cfCode = clazz.uniqueMethodWithName("main").getMethod().getCode().asCfCode();
+ List<CfInstruction> instructions = cfCode.getInstructions();
+ CfLabel startLabel = cfCode.getTryCatchRanges().get(0).start;
+ int index = 0;
+ while (instructions.get(index) != startLabel) {
+ index++;
+ }
+ assert instructions.get(index + 1) instanceof CfLoad;
+ assert instructions.get(index + 2) instanceof CfInvoke;
+ assert instructions.get(index + 3) == cfCode.getTryCatchRanges().get(0).end;
+ assert instructions.get(index + 4) instanceof CfStackInstruction;
}
private void processIR(IRCode code) {
diff --git a/tools/as_utils.py b/tools/as_utils.py
index 10fb29f..5f224a6 100644
--- a/tools/as_utils.py
+++ b/tools/as_utils.py
@@ -126,6 +126,9 @@
for line in lines:
if '-printconfiguration' not in line:
f.write(line)
+ # Check that there is a line-break at the end of the file or insert one.
+ if lines[-1].strip():
+ f.write('\n')
f.write('-printconfiguration {}\n'.format(destination))
def FindProguardConfigurationFile(app, config, checkout_dir):
diff --git a/tools/run_on_as_app.py b/tools/run_on_as_app.py
index aacfbe9..3a9bf8c 100755
--- a/tools/run_on_as_app.py
+++ b/tools/run_on_as_app.py
@@ -113,6 +113,10 @@
'git_repo': 'https://github.com/mkj-gram/Tusky.git',
'flavor': 'blue'
},
+ 'Vungle-Android-SDK': {
+ 'app_id': 'com.publisher.vungle.sample',
+ 'git_repo': 'https://github.com/mkj-gram/Vungle-Android-SDK.git',
+ },
# This does not build yet.
'muzei': {
'git_repo': 'https://github.com/sgjesse/muzei.git',
diff --git a/tools/test.py b/tools/test.py
index f4cee88..bb6a98a 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -121,6 +121,8 @@
def Main():
(options, args) = ParseOptions()
if utils.is_bot():
+ print "Result of 'java -version':"
+ print subprocess.check_output(['java', '-version'])
gradle.RunGradle(['clean'])
gradle_args = ['--stacktrace']