Merge "Add a class merging test for use of -keepparameternames"
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveScheduler.java b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveScheduler.java
index d1fe04c..031d161 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveScheduler.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveScheduler.java
@@ -14,6 +14,8 @@
import com.android.tools.r8.ir.code.Move;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Value;
+import it.unimi.dsi.fastutil.ints.IntArraySet;
+import it.unimi.dsi.fastutil.ints.IntSet;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
@@ -59,6 +61,8 @@
}
public void schedule() {
+ assert everyDestinationOnlyWrittenOnce();
+
// Worklist of moves that are ready to be inserted.
Deque<RegisterMove> worklist = new LinkedList<>();
@@ -196,4 +200,13 @@
iterator.remove();
return move;
}
+
+ private boolean everyDestinationOnlyWrittenOnce() {
+ IntSet destinations = new IntArraySet(moveSet.size());
+ for (RegisterMove move : moveSet) {
+ boolean changed = destinations.add(move.dst);
+ assert changed;
+ }
+ return true;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java b/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java
index 1ea788d..cebcc8c 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java
@@ -61,7 +61,46 @@
assert to.getSplitParent() == from.getSplitParent();
BasicBlock atEntryToBlock = blockStartMap.get(i + 1);
if (atEntryToBlock == null) {
- addInMove(i, to, from);
+ Value value = from.getValue();
+ if (value.definition != null
+ && value.definition.isMoveException()
+ && to.getStart() == value.definition.asMoveException().getNumber() + 1) {
+ // Consider the following IR code.
+ // 40: ...
+ // 42: v0 <- move-exception
+ // 44: ...
+ // ...
+ // 50: ... v0 ... // 4-bit constrained use of v0
+ //
+ // Initially, the liveness interval of v0 is [42; 50[. If the method has overlapping move-
+ // exception intervals (and the register allocator needs more than 16 registers), then the
+ // intervals of v0 will be split immediately after its definition. Therefore, v0 will have
+ // two liveness intervals: I1=[42; 43[ and I2=[43;50[.
+ //
+ // When allocating a register for the interval I2, we may need to spill an existing value v1
+ // that is currently active. As a result, we will split the liveness interval of v1 before
+ // the start of I2 (i.e., at position 43). The live intervals of v1 after the split
+ // therefore becomes J1=[x, y[, J2=[41, 43[, J3=[43, z[.
+ //
+ // If the registers assigned to J1 and J2 are different, we will create an in-move at
+ // position 43 in resolveControlFlow() (not position 41, since the first instruction of the
+ // target block is a move-exception instruction). If the the registers assigned to I1 and I2
+ // are also different, then an in-move will also be created at position 43 by the call to
+ // addSpillOrRestoreMove() in insertMoves().
+ //
+ // If the registers of I2 and J2 are the same (which is a valid assignment), then we will
+ // do parallel move scheduling for the following two in-moves:
+ // move X, reg(I2)
+ // move X, reg(J2)
+ //
+ // Therefore, there is a risk that we end up with the value that has been spilled instead of
+ // the exception object in register X at position 44. To avoid this situation, we schedule
+ // the move of the exception object (in this case, "move X, reg(I2)") as an out-move, such
+ // that it always gets inserted *after* the resolution moves of the current block.
+ addOutMove(i, to, from);
+ } else {
+ addInMove(i, to, from);
+ }
}
}
diff --git a/tools/build_sample_apk.py b/tools/build_sample_apk.py
index fca92ca..b31ade4 100755
--- a/tools/build_sample_apk.py
+++ b/tools/build_sample_apk.py
@@ -43,6 +43,9 @@
result.add_option('--split',
help='Split the app using the split.spec file',
default=False, action='store_true')
+ result.add_option('--install',
+ help='Install the app (including featuresplit)',
+ default=False, action='store_true')
result.add_option('--app',
help='Which app to build',
default='simple',
@@ -140,6 +143,20 @@
utils.PrintCmd(command)
subprocess.check_call(command)
+def run_adb(args):
+ command = ['adb']
+ command.extend(args)
+ utils.PrintCmd(command)
+ subprocess.check_call(command)
+
+def adb_install(apks):
+ args = [
+ 'install-multiple' if len(apks) > 1 else 'install',
+ '-r',
+ '-d']
+ args.extend(apks)
+ run_adb(args)
+
def create_temp_apk(app, prefix):
temp_apk_path = os.path.join(get_bin_path(app), '%s.ap_' % app)
shutil.copyfile(os.path.join(get_bin_path(app), '%sresources.ap_' % prefix),
@@ -154,6 +171,7 @@
def Main():
(options, args) = parse_options()
+ apks = []
is_split = options.split
run_aapt_pack(options.aapt, options.api, options.app)
if is_split:
@@ -170,17 +188,20 @@
aapt_add_dex(options.aapt, dex_path, temp_apk_path)
apk_path = os.path.join(get_bin_path(options.app), '%s.apk' % options.app)
apk_utils.sign(temp_apk_path, apk_path, options.keystore)
- print('Apk available at: %s' % apk_path)
+ apks.append(apk_path)
- if split:
+ if is_split:
split_temp_apk_path = create_temp_apk(options.app, 'split_')
aapt_add_dex(options.aapt,
get_split_path(options.app, 'split'),
temp_apk_path)
split_apk_path = os.path.join(get_bin_path(options.app), 'featuresplit.apk')
apk_utils.sign(temp_apk_path, split_apk_path, options.keystore)
- print('Feature split available at: %s' % split_apk_path)
+ apks.append(split_apk_path)
+ print('Generated apks available at: %s' % ' '.join(apks))
+ if options.install:
+ adb_install(apks)
if __name__ == '__main__':