Merge "Removed dex markers when performing incremental builds."
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index ce38bc9..5718ec2 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -236,10 +236,7 @@
       }
       if (innerClassAnnotation != null) {
         if (enclosingAnnotation == null) {
-          System.out.println("InnerClass annotation is missing a corresponding EnclosingMember " +
-              "annotation. This is typically a sign of using an outdated Java toolchain. To fix, " +
-              "recompile the source with an updated toolchain. The InnerClass annotation will be " +
-              "ignored.");
+          application.options.warningMissingEnclosingMember = true;
         } else {
           addAnnotation(innerClassAnnotation);
           addAnnotation(enclosingAnnotation);
diff --git a/src/main/java/com/android/tools/r8/ir/code/Cmp.java b/src/main/java/com/android/tools/r8/ir/code/Cmp.java
index 3d20415..9b54353 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Cmp.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Cmp.java
@@ -143,7 +143,7 @@
 
   @Override
   public boolean canBeFolded() {
-    return (leftValue().isConstant() && rightValue().isConstant()) || nonOverlapingRanges();
+    return (leftValue().isConstNumber() && rightValue().isConstNumber()) || nonOverlapingRanges();
   }
 
   @Override
@@ -151,7 +151,7 @@
     assert canBeFolded();
     int result;
     if (type == NumericType.LONG) {
-      if (leftValue().isConstant() && rightValue().isConstant()) {
+      if (leftValue().isConstNumber() && rightValue().isConstNumber()) {
         long left = leftValue().getConstInstruction().asConstNumber().getLongValue();
         long right = rightValue().getConstInstruction().asConstNumber().getLongValue();
         result = Integer.signum(Long.compare(left, right));
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstString.java b/src/main/java/com/android/tools/r8/ir/code/ConstString.java
index bb1ff32..124ff54 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstString.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstString.java
@@ -64,6 +64,11 @@
   }
 
   @Override
+  public boolean isOutConstant() {
+    return true;
+  }
+
+  @Override
   public boolean isConstString() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java
index 035bf95..2ffb5a1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Value.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Value.java
@@ -354,7 +354,7 @@
   }
 
   public boolean internalComputeNeedsRegister() {
-    if (!isConstant()) {
+    if (!isConstNumber()) {
       return true;
     }
     if (numberOfPhiUsers() > 0) {
@@ -422,6 +422,10 @@
     return definition.getOutConstantConstInstruction();
   }
 
+  public boolean isConstNumber() {
+    return isConstant() && getConstInstruction().isConstNumber();
+  }
+
   public boolean isConstant() {
     return definition.isOutConstant() && getLocalInfo() == null;
   }
@@ -481,11 +485,11 @@
   }
 
   public boolean hasValueRange() {
-    return valueRange != null || isConstant();
+    return valueRange != null || isConstNumber();
   }
 
   public boolean isValueInRange(int value) {
-    if (isConstant()) {
+    if (isConstNumber()) {
       return value == getConstInstruction().asConstNumber().getIntValue();
     } else {
       return valueRange != null && valueRange.containsValue(value);
@@ -493,7 +497,7 @@
   }
 
   public LongInterval getValueRange() {
-    if (isConstant()) {
+    if (isConstNumber()) {
       if (type == MoveType.SINGLE) {
         int value = getConstInstruction().asConstNumber().getIntValue();
         return new LongInterval(value, value);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 809e3ac..a718da2 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -1394,7 +1394,8 @@
     Value in2 = readNumericRegister(right, type);
     Value out = writeNumericRegister(dest, type, ThrowingInfo.NO_THROW);
     Instruction instruction;
-    if (in2.isConstant() && in2.getConstInstruction().asConstNumber().isIntegerNegativeOne(type)) {
+    if (in2.isConstNumber() &&
+        in2.getConstInstruction().asConstNumber().isIntegerNegativeOne(type)) {
       instruction = new Not(type, out, in1);
     } else {
       instruction = new Xor(type, out, in1, in2);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 981f673..e1c0ccb 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -20,6 +20,7 @@
 import com.android.tools.r8.ir.code.CheckCast;
 import com.android.tools.r8.ir.code.Cmp;
 import com.android.tools.r8.ir.code.Cmp.Bias;
+import com.android.tools.r8.ir.code.ConstInstruction;
 import com.android.tools.r8.ir.code.ConstNumber;
 import com.android.tools.r8.ir.code.ConstString;
 import com.android.tools.r8.ir.code.DominatorTree;
@@ -32,6 +33,7 @@
 import com.android.tools.r8.ir.code.InstructionListIterator;
 import com.android.tools.r8.ir.code.Invoke;
 import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.InvokeNewArray;
 import com.android.tools.r8.ir.code.InvokeVirtual;
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.code.MoveType;
@@ -675,7 +677,7 @@
         Map<ConstNumber, ConstNumber> oldToNew = new HashMap<>();
         for (int i = 0; i < invoke.inValues().size(); i++) {
           Value value = invoke.inValues().get(i);
-          if (value.isConstant() && value.numberOfUsers() > 1) {
+          if (value.isConstNumber() && value.numberOfUsers() > 1) {
             ConstNumber definition = value.getConstInstruction().asConstNumber();
             Value originalValue = definition.outValue();
             ConstNumber newNumber = oldToNew.get(definition);
@@ -700,7 +702,7 @@
       BasicBlock predecessor = block.getPredecessors().get(i);
       for (Phi phi : block.getPhis()) {
         Value operand = phi.getOperand(i);
-        if (!operand.isPhi() && operand.isConstant()) {
+        if (!operand.isPhi() && operand.isConstNumber()) {
           ConstNumber definition = operand.getConstInstruction().asConstNumber();
           ConstNumber newNumber = oldToNew.get(definition);
           Value originalValue = definition.outValue();
@@ -814,18 +816,16 @@
     insertAt.add(instruction);
   }
 
-  private short[] computeArrayFilledData(
-      NewArrayEmpty newArray, int size, BasicBlock block, int elementSize) {
-    ConstNumber[] values = computeConstantArrayValues(newArray, block, size);
+  private short[] computeArrayFilledData(ConstInstruction[] values, int size, int elementSize) {
     if (values == null) {
       return null;
     }
     if (elementSize == 1) {
       short[] result = new short[(size + 1) / 2];
       for (int i = 0; i < size; i += 2) {
-        short value = (short) (values[i].getIntValue() & 0xFF);
+        short value = (short) (values[i].asConstNumber().getIntValue() & 0xFF);
         if (i + 1 < size) {
-          value |= (short) ((values[i + 1].getIntValue() & 0xFF) << 8);
+          value |= (short) ((values[i + 1].asConstNumber().getIntValue() & 0xFF) << 8);
         }
         result[i / 2] = value;
       }
@@ -835,7 +835,7 @@
     int shortsPerConstant = elementSize / 2;
     short[] result = new short[size * shortsPerConstant];
     for (int i = 0; i < size; i++) {
-      long value = values[i].getRawValue();
+      long value = values[i].asConstNumber().getRawValue();
       for (int part = 0; part < shortsPerConstant; part++) {
         result[i * shortsPerConstant + part] = (short) ((value >> (16 * part)) & 0xFFFFL);
       }
@@ -843,12 +843,12 @@
     return result;
   }
 
-  private ConstNumber[] computeConstantArrayValues(
+  private ConstInstruction[] computeConstantArrayValues(
       NewArrayEmpty newArray, BasicBlock block, int size) {
     if (size > MAX_FILL_ARRAY_SIZE) {
       return null;
     }
-    ConstNumber[] values = new ConstNumber[size];
+    ConstInstruction[] values = new ConstInstruction[size];
     int remaining = size;
     Set<Instruction> users = newArray.outValue().uniqueUsers();
     // We allow the array instantiations to cross block boundaries as long as it hasn't encountered
@@ -860,8 +860,9 @@
         Instruction instruction = it.next();
         // If we encounter an instruction that can throw an exception we need to bail out of the
         // optimization so that we do not transform half-initialized arrays into fully initialized
-        // arrays on exceptional edges.
-        if (instruction.instructionInstanceCanThrow()) {
+        // arrays on exceptional edges. If the block has no handlers it is not observable so
+        // we perform the rewriting.
+        if (block.hasCatchHandlers() && instruction.instructionInstanceCanThrow()) {
           return null;
         }
         if (!users.contains(instruction)) {
@@ -873,16 +874,15 @@
           return null;
         }
         ArrayPut arrayPut = instruction.asArrayPut();
-        if (!arrayPut.source().isConstant()) {
+        if (!(arrayPut.source().isConstant() && arrayPut.index().isConstNumber())) {
           return null;
         }
-        assert arrayPut.index().isConstant();
         int index = arrayPut.index().getConstInstruction().asConstNumber().getIntValue();
         assert index >= 0 && index < values.length;
         if (values[index] != null) {
           return null;
         }
-        ConstNumber value = arrayPut.source().getConstInstruction().asConstNumber();
+        ConstInstruction value = arrayPut.source().getConstInstruction();
         values[index] = value;
         --remaining;
         if (remaining == 0) {
@@ -895,7 +895,7 @@
     return null;
   }
 
-  private boolean isPrimitiveNewArrayWithConstantPositiveSize(Instruction instruction) {
+  private boolean isPrimitiveOrStringNewArrayWithPositiveSize(Instruction instruction) {
     if (!(instruction instanceof NewArrayEmpty)) {
       return false;
     }
@@ -903,48 +903,69 @@
     if (!newArray.size().isConstant()) {
       return false;
     }
+    assert newArray.size().isConstNumber();
     int size = newArray.size().getConstInstruction().asConstNumber().getIntValue();
     if (size < 1) {
       return false;
     }
-    if (!newArray.type.isPrimitiveArrayType()) {
-      return false;
-    }
-    return true;
+    return newArray.type.isPrimitiveArrayType() || newArray.type == dexItemFactory.stringArrayType;
   }
 
   /**
-   * Replace NewArrayEmpty followed by stores of constants to all entries with NewArrayEmpty
-   * and FillArrayData.
+   * Replace new-array followed by stores of constants to all entries with new-array
+   * and fill-array-data / filled-new-array.
    */
   public void simplifyArrayConstruction(IRCode code) {
     for (BasicBlock block : code.blocks) {
       // Map from the array value to the number of array put instruction to remove for that value.
+      Map<Value, Instruction> instructionToInsertForArray = new HashMap<>();
       Map<Value, Integer> storesToRemoveForArray = new HashMap<>();
       // First pass: identify candidates and insert fill array data instruction.
       InstructionListIterator it = block.listIterator();
       while (it.hasNext()) {
         Instruction instruction = it.next();
-        if (!isPrimitiveNewArrayWithConstantPositiveSize(instruction)) {
+        if (!isPrimitiveOrStringNewArrayWithPositiveSize(instruction)) {
           continue;
         }
         NewArrayEmpty newArray = instruction.asNewArrayEmpty();
         int size = newArray.size().getConstInstruction().asConstNumber().getIntValue();
-        // If there is only one element it is typically smaller to generate the array put
-        // instruction instead of fill array data.
-        if (size == 1) {
+        ConstInstruction[] values = computeConstantArrayValues(newArray, block, size);
+        if (values == null) {
           continue;
         }
-        int elementSize = newArray.type.elementSizeForPrimitiveArrayType();
-        short[] contents = computeArrayFilledData(newArray, size, block, elementSize);
-        if (contents == null) {
-          continue;
+        if (newArray.type == dexItemFactory.stringArrayType) {
+          // Don't replace with filled-new-array if it requires more than 200 consecutive registers.
+          if (size > 200) {
+            continue;
+          }
+          List<Value> stringValues = new ArrayList<>(size);
+          for (ConstInstruction value : values) {
+            stringValues.add(value.outValue());
+          }
+          InvokeNewArray invoke = new InvokeNewArray(
+              dexItemFactory.stringArrayType, newArray.outValue(), stringValues);
+          it.detach();
+          for (Value value : newArray.inValues()) {
+            value.removeUser(newArray);
+          }
+          instructionToInsertForArray.put(newArray.outValue(), invoke);
+        } else {
+          // If there is only one element it is typically smaller to generate the array put
+          // instruction instead of fill array data.
+          if (size == 1) {
+            continue;
+          }
+          int elementSize = newArray.type.elementSizeForPrimitiveArrayType();
+          short[] contents = computeArrayFilledData(values, size, elementSize);
+          if (contents == null) {
+            continue;
+          }
+          int arraySize = newArray.size().getConstInstruction().asConstNumber().getIntValue();
+          NewArrayFilledData fillArray = new NewArrayFilledData(
+              newArray.outValue(), elementSize, arraySize, contents);
+          it.add(fillArray);
         }
         storesToRemoveForArray.put(newArray.outValue(), size);
-        int arraySize = newArray.size().getConstInstruction().asConstNumber().getIntValue();
-        NewArrayFilledData fillArray = new NewArrayFilledData(
-            newArray.outValue(), elementSize, arraySize, contents);
-        it.add(fillArray);
       }
       // Second pass: remove all the array put instructions for the array for which we have
       // inserted a fill array data instruction instead.
@@ -956,9 +977,18 @@
             if (instruction.isArrayPut()) {
               Value array = instruction.asArrayPut().array();
               Integer toRemoveCount = storesToRemoveForArray.get(array);
-              if (toRemoveCount != null && toRemoveCount > 0) {
-                storesToRemoveForArray.put(array, toRemoveCount - 1);
-                it.remove();
+              if (toRemoveCount != null) {
+                if (toRemoveCount > 0) {
+                  storesToRemoveForArray.put(array, --toRemoveCount);
+                  it.remove();
+                }
+                if (toRemoveCount == 0) {
+                  storesToRemoveForArray.put(array, --toRemoveCount);
+                  Instruction construction = instructionToInsertForArray.get(array);
+                  if (construction != null) {
+                    it.add(construction);
+                  }
+                }
               }
             }
           }
@@ -1082,8 +1112,8 @@
         If theIf = block.exit().asIf();
         List<Value> inValues = theIf.inValues();
         int cond;
-        if (inValues.get(0).isConstant()
-            && (theIf.isZeroTest() || inValues.get(1).isConstant())) {
+        if (inValues.get(0).isConstNumber()
+            && (theIf.isZeroTest() || inValues.get(1).isConstNumber())) {
           // Zero test with a constant of comparison between between two constants.
           if (theIf.isZeroTest()) {
             cond = inValues.get(0).getConstInstruction().asConstNumber().getIntValue();
@@ -1143,8 +1173,8 @@
     List<Value> inValues = theIf.inValues();
     Value leftValue = inValues.get(0);
     Value rightValue = inValues.get(1);
-    if (leftValue.isConstant() || rightValue.isConstant()) {
-      if (leftValue.isConstant()) {
+    if (leftValue.isConstNumber() || rightValue.isConstNumber()) {
+      if (leftValue.isConstNumber()) {
         int left = leftValue.getConstInstruction().asConstNumber().getIntValue();
         if (left == 0) {
           If ifz = new If(theIf.getType().forSwappedOperands(), rightValue);
@@ -1152,7 +1182,6 @@
           assert block.exit() == ifz;
         }
       } else {
-        assert rightValue.isConstant();
         int right = rightValue.getConstInstruction().asConstNumber().getIntValue();
         if (right == 0) {
           If ifz = new If(theIf.getType(), leftValue);
@@ -1231,7 +1260,7 @@
             iterator.previous();
             iterator.add(zero);
 
-            // Then replace the invoke instruction with NewArrayEmpty instruction.
+            // Then replace the invoke instruction with new-array instruction.
             Instruction next = iterator.next();
             assert current == next;
             NewArrayEmpty newArray = new NewArrayEmpty(destValue, zero.outValue(),
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index 38cdb29..7b7e5e7 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -1587,7 +1587,7 @@
         newActive.add(splitChild);
         // If the constant is split before its first actual use, mark the constant as being
         // spilled. That will allows us to remove it afterwards if it is rematerializable.
-        if (intervals.getValue().isConstant()
+        if (intervals.getValue().isConstNumber()
             && intervals.getStart() == intervals.getValue().definition.getNumber()
             && intervals.getUses().size() == 1) {
           intervals.setSpilled(true);
@@ -1598,7 +1598,9 @@
             LiveIntervals splitOfSplit = splitChild.splitBefore(splitChild.getFirstUse());
             splitOfSplit.setRegister(intervals.getRegister());
             inactive.add(splitOfSplit);
-          } else if (intervals.getValue().isConstant()) {
+          } else if (intervals.getValue().isConstNumber()) {
+            // TODO(ager): Do this for all constants. Currently we only rematerialize const
+            // number and therefore we only do it for numbers at this point.
             splitRangesForSpilledConstant(splitChild, registerNumber);
           } else if (intervals.isArgumentInterval()) {
             splitRangesForSpilledArgument(splitChild);
@@ -1627,7 +1629,7 @@
     // Spilling a non-pinned, non-rematerializable value. We use the value in the spill
     // register for as long as possible to avoid further moves.
     assert spilled.isSpilled();
-    assert !spilled.getValue().isConstant();
+    assert !spilled.getValue().isConstNumber();
     assert !spilled.isLinked() || spilled.isArgumentInterval();
     if (spilled.isArgumentInterval()) {
       registerNumber = Constants.U16BIT_MAX;
@@ -1658,7 +1660,7 @@
     // spill we are running low on registers and this constant should get out of the way
     // as much as possible.
     assert spilled.isSpilled();
-    assert spilled.getValue().isConstant();
+    assert spilled.getValue().isConstNumber();
     assert !spilled.isLinked() || spilled.isArgumentInterval();
     // Do not split range if constant is reused by one of the eleven following instruction.
     int maxGapSize = 11 * INSTRUCTION_NUMBER_DELTA;
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
index 06b33f4..12db3d9 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
@@ -85,7 +85,8 @@
   }
 
   public boolean isRematerializable(LinearScanRegisterAllocator registerAllocator) {
-    if (!value.isConstant()) {
+    // TODO(ager): rematerialize const string as well.
+    if (!value.isConstNumber()) {
       return false;
     }
     // If one of the non-spilled splits uses a register that is higher than U8BIT_MAX we cannot
@@ -420,7 +421,7 @@
   }
 
   public boolean isConstantNumberInterval() {
-    return value.definition != null && value.isConstant();
+    return value.definition != null && value.isConstNumber();
   }
 
   public int numberOfUsesWithConstraint() {
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 5477d4d..30472f9 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -117,12 +117,27 @@
 
   public String warningInvalidParameterAnnotations = null;
 
+  public boolean warningMissingEnclosingMember = false;
+
   public boolean printWarnings() {
     boolean printed = false;
+    boolean printOutdatedToolchain = false;
     if (warningInvalidParameterAnnotations != null) {
       System.out.println("Warning: " + warningInvalidParameterAnnotations);
       printed = true;
     }
+    if (warningMissingEnclosingMember) {
+      System.out.println(
+          "Warning: InnerClass annotations are missing corresponding EnclosingMember annotations."
+              + " Such InnerClass annotations are ignored.");
+      printed = true;
+      printOutdatedToolchain = true;
+    }
+    if (printOutdatedToolchain) {
+      System.out.println(
+          "Some warnings are typically a sign of using an outdated Java toolchain."
+              + " To fix, recompile the source with an updated toolchain.");
+    }
     return printed;
   }
 
diff --git a/tools/create_jctf_tests.py b/tools/create_jctf_tests.py
index ff9d797..b7b449d 100755
--- a/tools/create_jctf_tests.py
+++ b/tools/create_jctf_tests.py
@@ -16,10 +16,12 @@
 
 import utils
 
-JCTFROOT = 'third_party/jctf'
-DESTINATION_DIR = 'build/generated/test/java/com/android/tools/r8/jctf'
+JCTFROOT = join(utils.REPO_ROOT, 'third_party', 'jctf')
+DESTINATION_DIR = join(utils.REPO_ROOT, 'build', 'generated', 'test', 'java',
+    'com', 'android', 'tools', 'r8', 'jctf')
 PACKAGE_PREFIX = 'com.google.jctf.test.lib.java.'
-RELATIVE_TESTDIR = 'LibTests/src/com/google/jctf/test/lib/java'
+RELATIVE_TESTDIR = join('LibTests', 'src', 'com', 'google', 'jctf', 'test',
+    'lib', 'java')
 TESTDIR = join(JCTFROOT, RELATIVE_TESTDIR)
 TEMPLATE = Template(
 """// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
@@ -58,12 +60,17 @@
 EXIT_FAILURE = 1
 RE_PACKAGE = re.compile('package\\s+(com[^\\s;]*)')
 
+def fix_long_path(p):
+  if os.name == 'nt':
+    p = ('\\\\?\\' + p).decode('utf-8')
+  return p
+
 def file_contains_string(filepath, search_string):
-  with open(filepath) as f:
+  with open(fix_long_path(filepath)) as f:
     return search_string in f.read()
 
 def read_package_from_java_file(filepath):
-  with open(filepath) as f:
+  with open(fix_long_path(filepath)) as f:
     for line in f:
       m = RE_PACKAGE.search(line)
       if m:
@@ -74,7 +81,7 @@
 def generate_test(class_name, compiler_under_test, compiler_under_test_enum,
     relative_package):
   filename = join(DESTINATION_DIR, compiler_under_test,
-      relative_package.replace('.', '/'), class_name + '.java')
+      relative_package.replace('.', os.sep), class_name + '.java')
   utils.makedirs_if_needed(dirname(filename))
 
   full_class_name = '{}{}.{}'.format(PACKAGE_PREFIX, relative_package,
@@ -88,7 +95,7 @@
       classFile = full_class_name.replace('.', '/') + '.class',
       nameWithoutPackagePrefix = '{}.{}'.format(relative_package, class_name))
 
-  with open(filename, 'w') as f:
+  with open(fix_long_path(filename), 'w') as f:
     f.write(contents)
 
 def Main():
@@ -98,7 +105,7 @@
     return EXIT_FAILURE
 
   for tool in ['d8', 'r8']:
-    p = join(DESTINATION_DIR, tool)
+    p = fix_long_path(join(DESTINATION_DIR, tool))
     if exists(p):
       rmtree(p)
     makedirs(p)