Merge "Remove clean-jack/dex-files from jack mk" into ub-jack
diff --git a/build.xml b/build.xml
index 4e1a062..6bc4411 100644
--- a/build.xml
+++ b/build.xml
@@ -1019,6 +1019,7 @@
       <exclude name="com/android/jack/optimizations/lambdas/test008/**"/>
       <exclude name="com/android/jack/sourcepath/test002/jack/Sourcepath002.java"/>
       <exclude name="com/android/jack/shrob/test062/jack/**"/>
+      <exclude name="com/android/jack/shrob/test066/jack/**"/>
       <classpath>
         <filelist dir="/">
           <file name="${jill-api.dist.dir}/${jill-api.lib.name}" />
diff --git a/jack-coverage/tests/com/android/jack/coverage/CoverageTests.java b/jack-coverage/tests/com/android/jack/coverage/CoverageTests.java
index 2efffb3..9b1afb2 100644
--- a/jack-coverage/tests/com/android/jack/coverage/CoverageTests.java
+++ b/jack-coverage/tests/com/android/jack/coverage/CoverageTests.java
@@ -25,6 +25,7 @@
 import com.google.gson.JsonParser;
 
 import com.android.jack.test.TestsProperties;
+import com.android.jack.test.junit.KnownIssue;
 import com.android.jack.test.toolchain.AbstractTestTools;
 import com.android.jack.test.toolchain.JackApiV03Toolchain;
 import com.android.jack.test.toolchain.JackApiV04Toolchain;
@@ -246,6 +247,7 @@
   }
 
   @Test
+  @KnownIssue  // flaky due to non-determinism
   public void testClassId_005() throws Exception {
     String testPackageName = getTestPackageName("test005");
     File testRootDir = getTestRootDir(testPackageName);
diff --git a/jack-tests/.classpath b/jack-tests/.classpath
index bb0538ba..fc20cfd 100644
--- a/jack-tests/.classpath
+++ b/jack-tests/.classpath
@@ -2,7 +2,7 @@
 <classpath>
 	<classpathentry kind="src" path="src"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
-	<classpathentry excluding="com/android/jack/annotation/test014/jack/|com/android/jack/annotation/test015/jack/|com/android/jack/annotation/test016/jack/|com/android/jack/annotation/test017/jack/|com/android/jack/classpath/test002/lib1override/|com/android/jack/compiletime/test*/**|com/android/jack/enums/test003/link/Other.java|com/android/jack/enums/test003/link/Values.java|com/android/jack/error/test001/jack/A.java|com/android/jack/error/test002/jack/A.java|com/android/jack/frontend/test002/jack/PackageName/ClassInConflictingPackage.java|com/android/jack/frontend/test005/jack/|com/android/jack/frontend/test006/jack/|com/android/jack/frontend/test007/jack/|com/android/jack/frontend/test007/jackduplicate/|com/android/jack/frontend/test008/jack/NoOuterContext.java|com/android/jack/frontend/test010/jack/UnusedLocalVar.java|com/android/jack/frontend/test013/jack/ExtendingInnerOnly.java|com/android/jack/frontend/test014/jack/ExtendingInnerInStaticContext.java|com/android/jack/frontend/test015/jack/WithOuterContextButStatic.java|com/android/jack/frontend/test016/jack/WithDuplicated.java|com/android/jack/frontend/test017/jack/InvalidQualification.java|com/android/jack/jarjar/test003/dontcompile/|com/android/jack/jarjar/test004/dontcompile/|com/android/jack/java8/annotation/|com/android/jack/java8/defaultmethod/|com/android/jack/java8/gwt/|com/android/jack/java8/inference/|com/android/jack/java8/intersectiontype/|com/android/jack/java8/lambda/|com/android/jack/java8/methodref/|com/android/jack/java8/retrolambda/|com/android/jack/java8/staticmethod/|com/android/jack/java8/variable/|com/android/jack/lookup/test001/liboverride/|com/android/jack/nopackage/test*/**|com/android/jack/optimizations/lambdas/test*/**|com/android/jack/jarjar/test006/dontcompile/|com/android/jack/java8/bridges/|com/android/jack/jill/test001/|com/android/jack/jill/test002/|com/android/jack/jill/test003/|com/android/jack/jill/test004/|com/android/jack/sourcepath/test002/jack/Sourcepath002.java|com/android/jack/annotation/test019/jack/|com/android/jack/frontend/test018/jack/|com/android/jack/annotation/test020/jack/|com/android/jack/assign/test002/jack/|com/android/jack/annotation/processor/sample2/src/|com/android/jack/shrob/test062/jack/Tests.java|com/android/jack/shrob/test062/jack/A.java|com/android/jack/coverage/test006_v1/jack/|com/android/jack/coverage/test006_v2/jack/|com/android/jack/multidex/test004/jack/" kind="src" path="tests"/>
+	<classpathentry excluding="com/android/jack/annotation/test014/jack/|com/android/jack/annotation/test015/jack/|com/android/jack/annotation/test016/jack/|com/android/jack/annotation/test017/jack/|com/android/jack/classpath/test002/lib1override/|com/android/jack/compiletime/test*/**|com/android/jack/enums/test003/link/Other.java|com/android/jack/enums/test003/link/Values.java|com/android/jack/error/test001/jack/A.java|com/android/jack/error/test002/jack/A.java|com/android/jack/frontend/test002/jack/PackageName/ClassInConflictingPackage.java|com/android/jack/frontend/test005/jack/|com/android/jack/frontend/test006/jack/|com/android/jack/frontend/test007/jack/|com/android/jack/frontend/test007/jackduplicate/|com/android/jack/frontend/test008/jack/NoOuterContext.java|com/android/jack/frontend/test010/jack/UnusedLocalVar.java|com/android/jack/frontend/test013/jack/ExtendingInnerOnly.java|com/android/jack/frontend/test014/jack/ExtendingInnerInStaticContext.java|com/android/jack/frontend/test015/jack/WithOuterContextButStatic.java|com/android/jack/frontend/test016/jack/WithDuplicated.java|com/android/jack/frontend/test017/jack/InvalidQualification.java|com/android/jack/jarjar/test003/dontcompile/|com/android/jack/jarjar/test004/dontcompile/|com/android/jack/java8/annotation/|com/android/jack/java8/defaultmethod/|com/android/jack/java8/gwt/|com/android/jack/java8/inference/|com/android/jack/java8/intersectiontype/|com/android/jack/java8/lambda/|com/android/jack/java8/methodref/|com/android/jack/java8/retrolambda/|com/android/jack/java8/staticmethod/|com/android/jack/java8/variable/|com/android/jack/lookup/test001/liboverride/|com/android/jack/nopackage/test*/**|com/android/jack/optimizations/lambdas/test*/**|com/android/jack/jarjar/test006/dontcompile/|com/android/jack/java8/bridges/|com/android/jack/jill/test001/|com/android/jack/jill/test002/|com/android/jack/jill/test003/|com/android/jack/jill/test004/|com/android/jack/sourcepath/test002/jack/Sourcepath002.java|com/android/jack/annotation/test019/jack/|com/android/jack/frontend/test018/jack/|com/android/jack/annotation/test020/jack/|com/android/jack/assign/test002/jack/|com/android/jack/annotation/processor/sample2/src/|com/android/jack/shrob/test062/jack/Tests.java|com/android/jack/shrob/test062/jack/A.java|com/android/jack/coverage/test006_v1/jack/|com/android/jack/coverage/test006_v2/jack/|com/android/jack/multidex/test004/jack/|com/android/jack/shrob/test066/jack/MySuperInterfaceWithDefaultMethod.java|com/android/jack/shrob/test066/jack/MyClass.java" kind="src" path="tests"/>
 	<classpathentry kind="lib" path="libs/junit4.jar"/>
 	<classpathentry kind="lib" path="libs/antlr-runtime-lib.jar"/>
 	<classpathentry kind="lib" path="libs/dx-ref.jar"/>
diff --git a/jack-tests/prebuilts/jack-test-annotations-lib.jack b/jack-tests/prebuilts/jack-test-annotations-lib.jack
index 2057e01..f728d45 100644
--- a/jack-tests/prebuilts/jack-test-annotations-lib.jack
+++ b/jack-tests/prebuilts/jack-test-annotations-lib.jack
Binary files differ
diff --git a/jack-tests/src/com/android/jack/annotations/CalledByInvokeCustom.java b/jack-tests/src/com/android/jack/annotations/CalledByInvokeCustom.java
index 52066f1..1357815 100644
--- a/jack-tests/src/com/android/jack/annotations/CalledByInvokeCustom.java
+++ b/jack-tests/src/com/android/jack/annotations/CalledByInvokeCustom.java
@@ -33,4 +33,5 @@
   String name();
   Class<?> returnType() default void.class;
   Class<?>[] argumentTypes() default {};
+  Constant[] methodHandleExtraArgs() default {};
 }
diff --git a/jack-tests/src/com/android/jack/annotations/Constant.java b/jack-tests/src/com/android/jack/annotations/Constant.java
new file mode 100644
index 0000000..f8df17d
--- /dev/null
+++ b/jack-tests/src/com/android/jack/annotations/Constant.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Describes an annotation that allows passing a constant extra argument to a linker method.
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.ANNOTATION_TYPE)
+public @interface Constant {
+  boolean[] booleanValue() default {};
+  byte[] byteValue() default {};
+  char[] charValue() default {};
+  short[] shortValue() default {};
+  int[] intValue() default {};
+  float[] floatValue() default {};
+  double[] doubleValue() default {};
+  long[] longValue() default {};
+  Class<?>[] classValue() default {};
+  String[] stringValue() default {};
+}
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/java7/InvokeCustomTests.java b/jack-tests/tests/com/android/jack/java7/InvokeCustomTests.java
index 80ef256..c912652 100644
--- a/jack-tests/tests/com/android/jack/java7/InvokeCustomTests.java
+++ b/jack-tests/tests/com/android/jack/java7/InvokeCustomTests.java
@@ -56,6 +56,10 @@
       AbstractTestTools.getTestRootDir("com.android.jack.java7.invokecustom.test003"),
       "com.android.jack.java7.invokecustom.test003.Tests").setSrcDirName("");
 
+  private RuntimeTestInfo INVOKE_CUSTOM_004 = new RuntimeTestInfo(
+      AbstractTestTools.getTestRootDir("com.android.jack.java7.invokecustom.test004"),
+      "com.android.jack.java7.invokecustom.test004.Tests").setSrcDirName("");
+
   @Test
   @Runtime
   @KnownIssue
@@ -77,6 +81,13 @@
     run(INVOKE_CUSTOM_003);
   }
 
+  @Test
+  @Runtime
+  @KnownIssue
+  public void testInvokeCustom004() throws Exception {
+    run(INVOKE_CUSTOM_004);
+  }
+
   private void run(@Nonnull RuntimeTestInfo rti) throws Exception {
     List<Class<? extends IToolchain>> excludeClazz = new ArrayList<Class<? extends IToolchain>>(1);
     excludeClazz.add(JillBasedToolchain.class);
diff --git a/jack-tests/tests/com/android/jack/java7/InvokePolymorphicTests.java b/jack-tests/tests/com/android/jack/java7/InvokePolymorphicTests.java
index b6d1cf7..349cddf 100644
--- a/jack-tests/tests/com/android/jack/java7/InvokePolymorphicTests.java
+++ b/jack-tests/tests/com/android/jack/java7/InvokePolymorphicTests.java
@@ -20,6 +20,13 @@
 
 import com.android.jack.JackAbortException;
 import com.android.jack.Options;
+import com.android.jack.dx.io.ClassData;
+import com.android.jack.dx.io.ClassData.Method;
+import com.android.jack.dx.io.ClassDef;
+import com.android.jack.dx.io.Code;
+import com.android.jack.dx.io.DexBuffer;
+import com.android.jack.dx.io.MethodId;
+import com.android.jack.test.helper.FileChecker;
 import com.android.jack.test.helper.RuntimeTestHelper;
 import com.android.jack.test.junit.KnownIssue;
 import com.android.jack.test.junit.Runtime;
@@ -35,6 +42,7 @@
 import org.junit.Test;
 
 import java.io.ByteArrayOutputStream;
+import java.io.File;
 
 import javax.annotation.Nonnegative;
 import javax.annotation.Nonnull;
@@ -74,6 +82,30 @@
       AbstractTestTools.getTestRootDir("com.android.jack.java7.invokepolymorphic.test006"),
       "com.android.jack.java7.invokepolymorphic.test006.Tests").setSrcDirName("");
 
+  private RuntimeTestInfo INVOKE_POLYMORPHIC_007 = new RuntimeTestInfo(
+      AbstractTestTools.getTestRootDir("com.android.jack.java7.invokepolymorphic.test007"),
+      "com.android.jack.java7.invokepolymorphic.test007.Tests").setSrcDirName("")
+          .addFileChecker(new FileChecker() {
+            @Override
+            public void check(@Nonnull File file) throws Exception {
+              DexBuffer dexBuffer = new DexBuffer(file);
+              for (ClassDef classDef : dexBuffer.classDefs()) {
+                if (classDef.getTypeName()
+                    .equals("Lcom/android/jack/java7/invokepolymorphic/test007/Tests;")) {
+                  Assert.assertTrue(classDef.getClassDataOffset() != 0);
+                  ClassData classData = dexBuffer.readClassData(classDef);
+                  for (Method method : classData.getVirtualMethods()) {
+                    MethodId methodId = dexBuffer.methodIds().get(method.getMethodIndex());
+                    if (dexBuffer.strings().get(methodId.getNameIndex()).equals("testDummy")) {
+                      Code code = dexBuffer.readCode(method);
+                      Assert.assertEquals(5, code.getOutsSize());
+                    }
+                  }
+                }
+              }
+            }
+          });
+
   @Test
   @Runtime
   @KnownIssue
@@ -165,6 +197,13 @@
     Assert.assertTrue(errOut.toString().isEmpty());
   }
 
+  @Test
+  @Runtime
+  @KnownIssue
+  public void testInvokePolymorphic007() throws Exception {
+    run(INVOKE_POLYMORPHIC_007);
+  }
+
   private void run(@Nonnull RuntimeTestInfo rti) throws Exception {
     new RuntimeTestHelper(rti).setSourceLevel(SourceLevel.JAVA_7)
         .addProperty(Options.ANDROID_MIN_API_LEVEL.getName(), Options.ANDROID_MIN_API_LEVEL
diff --git a/jack-tests/tests/com/android/jack/java7/invokecustom/test001/Tests.java b/jack-tests/tests/com/android/jack/java7/invokecustom/test001/Tests.java
index 3bd66dc..1cc9e10 100644
--- a/jack-tests/tests/com/android/jack/java7/invokecustom/test001/Tests.java
+++ b/jack-tests/tests/com/android/jack/java7/invokecustom/test001/Tests.java
@@ -16,7 +16,6 @@
 package com.android.jack.java7.invokecustom.test001;
 
 import static java.lang.invoke.MethodHandles.lookup;
-import static java.lang.invoke.MethodType.methodType;
 
 import com.android.jack.annotations.CalledByInvokeCustom;
 import com.android.jack.annotations.LinkerMethodHandle;
@@ -29,6 +28,8 @@
 import java.lang.invoke.CallSite;
 import java.lang.invoke.ConstantCallSite;
 import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
 
 public class Tests {
 
@@ -36,7 +37,9 @@
 
   @CalledByInvokeCustom(
       invokeMethodHandle = @LinkerMethodHandle(kind = MethodHandleKind.INVOKE_STATIC,
-          enclosingType = Tests.class, name = "linkerMethod"),
+          enclosingType = Tests.class,
+          name = "linkerMethod",
+          argumentTypes = {MethodHandles.Lookup.class, String.class, MethodType.class}),
       name = "add",
       returnType = int.class,
       argumentTypes = {int.class, int.class})
@@ -45,14 +48,14 @@
   }
 
   @SuppressWarnings("unused")
-  private static CallSite linkerMethod() throws Throwable {
-    MethodHandle mh_add =
-        lookup().findStatic(Tests.class, "add", methodType(int.class, int.class, int.class));
+  private static CallSite linkerMethod(MethodHandles.Lookup caller, String name,
+      MethodType methodType) throws Throwable {
+    MethodHandle mh_add = lookup().findStatic(Tests.class, name, methodType);
     return new ConstantCallSite(mh_add);
   }
 
   @Test
   public void test() throws Throwable {
-    Assert.assertEquals(5, add(2,3));
+    Assert.assertEquals(5, Tests.add(2,3));
   }
 }
diff --git a/jack-tests/tests/com/android/jack/java7/invokecustom/test002/Tests.java b/jack-tests/tests/com/android/jack/java7/invokecustom/test002/Tests.java
index 3f3bd5d..3289499 100644
--- a/jack-tests/tests/com/android/jack/java7/invokecustom/test002/Tests.java
+++ b/jack-tests/tests/com/android/jack/java7/invokecustom/test002/Tests.java
@@ -57,6 +57,6 @@
 
   @Test
   public void test() throws Throwable {
-    Assert.assertEquals(5, add(2,3));
+    Assert.assertEquals(5, Tests.add(2,3));
   }
 }
diff --git a/jack-tests/tests/com/android/jack/java7/invokecustom/test003/Tests.java b/jack-tests/tests/com/android/jack/java7/invokecustom/test003/Tests.java
index 4791946..211e040 100644
--- a/jack-tests/tests/com/android/jack/java7/invokecustom/test003/Tests.java
+++ b/jack-tests/tests/com/android/jack/java7/invokecustom/test003/Tests.java
@@ -16,7 +16,6 @@
 package com.android.jack.java7.invokecustom.test003;
 
 import static java.lang.invoke.MethodHandles.lookup;
-import static java.lang.invoke.MethodType.methodType;
 
 import com.android.jack.annotations.CalledByInvokeCustom;
 import com.android.jack.annotations.LinkerMethodHandle;
@@ -29,6 +28,8 @@
 import java.lang.invoke.CallSite;
 import java.lang.invoke.ConstantCallSite;
 import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
 
 public class Tests {
 
@@ -36,7 +37,9 @@
 
   @CalledByInvokeCustom(
       invokeMethodHandle = @LinkerMethodHandle(kind = MethodHandleKind.INVOKE_STATIC,
-          enclosingType = Tests.class, name = "linkerMethod"),
+          enclosingType = Tests.class,
+          name = "linkerMethod",
+          argumentTypes = {MethodHandles.Lookup.class, String.class, MethodType.class}),
       name = "add",
       returnType = int.class,
       argumentTypes = {int.class, int.class, int.class, int.class, int.class, int.class})
@@ -45,14 +48,14 @@
   }
 
   @SuppressWarnings("unused")
-  private static CallSite linkerMethod() throws Throwable {
-    MethodHandle mh_add = lookup().findStatic(Tests.class, "add",
-        methodType(int.class, int.class, int.class, int.class, int.class, int.class, int.class));
+  private static CallSite linkerMethod(MethodHandles.Lookup caller, String name,
+      MethodType methodType) throws Throwable {
+    MethodHandle mh_add = lookup().findStatic(Tests.class, name, methodType);
     return new ConstantCallSite(mh_add);
   }
 
   @Test
   public void test() throws Throwable {
-    Assert.assertEquals(21, add(1, 2, 3, 4, 5, 6));
+    Assert.assertEquals(21, Tests.add(1, 2, 3, 4, 5, 6));
   }
 }
diff --git a/jack-tests/tests/com/android/jack/java7/invokecustom/test004/Tests.java b/jack-tests/tests/com/android/jack/java7/invokecustom/test004/Tests.java
new file mode 100644
index 0000000..cab44a5
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/java7/invokecustom/test004/Tests.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.jack.java7.invokecustom.test004;
+
+import static java.lang.invoke.MethodHandles.lookup;
+
+import com.android.jack.annotations.CalledByInvokeCustom;
+import com.android.jack.annotations.Constant;
+import com.android.jack.annotations.LinkerMethodHandle;
+import com.android.jack.annotations.MethodHandleKind;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.ConstantCallSite;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+public class Tests {
+
+  public static CallSite fieldCallSite;
+
+  @CalledByInvokeCustom(
+      invokeMethodHandle = @LinkerMethodHandle(kind = MethodHandleKind.INVOKE_STATIC,
+          enclosingType = Tests.class,
+          name = "linkerMethod",
+          argumentTypes = {MethodHandles.Lookup.class, String.class, MethodType.class,
+                           boolean.class, byte.class, char.class, short.class, int.class,
+                           float.class, double.class, String.class, Class.class, long.class}),
+      methodHandleExtraArgs = {@Constant(booleanValue = true), @Constant(byteValue = 1),
+                         @Constant(charValue = 'a'), @Constant(shortValue = 1024),
+                         @Constant(intValue = 1), @Constant(floatValue = 11.1f),
+                         @Constant(doubleValue = 2.2), @Constant(stringValue = "Hello"),
+                         @Constant(classValue = Tests.class), @Constant(longValue = 123456789L)},
+      name = "add",
+      returnType = int.class,
+      argumentTypes = {int.class, int.class})
+  private static int add(int a, int b) {
+    return a + b;
+  }
+
+  @SuppressWarnings("unused")
+  private static CallSite linkerMethod(MethodHandles.Lookup caller, String name,
+      MethodType methodType, boolean v1, byte v2, char v3, short v4, int v5, float v6, double v7,
+      String v8, Class<?> v9, long v10) throws Throwable {
+    Assert.assertTrue(v1);
+    Assert.assertEquals(1, v2);
+    Assert.assertEquals('a', v3);
+    Assert.assertEquals(1024, v4);
+    Assert.assertEquals(1, v5);
+    Assert.assertEquals(11.1f, v6, 0);
+    Assert.assertEquals(2.2, v7, 0);
+    Assert.assertEquals("Hello", v8);
+    Assert.assertEquals(Tests.class, v9);
+    Assert.assertEquals(123456789L, v10);
+    MethodHandle mh_add = lookup().findStatic(Tests.class, name, methodType);
+    return new ConstantCallSite(mh_add);
+  }
+
+  @Test
+  public void test() throws Throwable {
+    Assert.assertEquals(5, add(2,3));
+  }
+}
diff --git a/jack-tests/tests/com/android/jack/java7/invokepolymorphic/test007/Tests.java b/jack-tests/tests/com/android/jack/java7/invokepolymorphic/test007/Tests.java
new file mode 100644
index 0000000..09ac89d
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/java7/invokepolymorphic/test007/Tests.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.java7.invokepolymorphic.test007;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+import java.lang.invoke.MethodHandle;
+
+public class Tests {
+  @SuppressWarnings("null")
+  @Test
+  public void testDummy() throws Throwable {
+    MethodHandle mh = null;
+    try {
+      mh.invokeExact(new Integer(1), new Integer(1), 1, 2);
+      Assert.fail();
+    } catch (NullPointerException npe) {
+      // OK
+    }
+  }
+}
diff --git a/jack-tests/tests/com/android/jack/shrob/ShrinkTests.java b/jack-tests/tests/com/android/jack/shrob/ShrinkTests.java
index 88a3dd2..4cd3540 100644
--- a/jack-tests/tests/com/android/jack/shrob/ShrinkTests.java
+++ b/jack-tests/tests/com/android/jack/shrob/ShrinkTests.java
@@ -18,6 +18,7 @@
 
 import com.android.jack.Options;
 import com.android.jack.ProguardFlags;
+import com.android.jack.backend.dex.compatibility.AndroidCompatibilityChecker;
 import com.android.jack.shrob.shrink.ShrinkStructurePrinter;
 import com.android.jack.test.category.SlowTests;
 import com.android.jack.test.comparator.ComparatorMapping;
@@ -30,6 +31,8 @@
 import com.android.jack.test.toolchain.DummyToolchain;
 import com.android.jack.test.toolchain.JackApiToolchainBase;
 import com.android.jack.test.toolchain.JackBasedToolchain;
+import com.android.jack.test.toolchain.Toolchain.SourceLevel;
+import com.android.jack.util.AndroidApiLevel;
 
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
@@ -496,4 +499,47 @@
     new RuntimeTestHelper(runtimeTestInfo).compileAndRunTest(/* checkStructure = */ false);
   }
 
+  @Test
+  @KnownIssue
+  public void test66_001() throws Exception {
+    File testFolder = new File(shrobTestsDir, "test066");
+
+    JackBasedToolchain toolchain =
+        AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class);
+    File lib = AbstractTestTools.createTempFile("lib", toolchain.getLibraryExtension());
+    toolchain.addToClasspath(toolchain.getDefaultBootClasspath());
+    toolchain.srcToLib(lib, true /* zipFiles */ , new File(testFolder, "lib"));
+
+    toolchain = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class);
+    toolchain.addToClasspath(toolchain.getDefaultBootClasspath()).addToClasspath(lib);
+
+    File refFolder = new File(testFolder, "refsShrinking");
+
+    File candidateNodeListing = AbstractTestTools.createTempFile("nodeListing", ".txt");
+    toolchain.addProperty(ShrinkStructurePrinter.STRUCTURE_PRINTING.getName(), "true");
+    toolchain.addProperty(ShrinkStructurePrinter.STRUCTURE_PRINTING_FILE.getName(),
+        candidateNodeListing.getPath());
+    toolchain.addProperty(Options.METHOD_FILTER.getName(), "supported-methods");
+    toolchain
+        .addProperty(Options.ANDROID_MIN_API_LEVEL.getName(),
+            String.valueOf(AndroidApiLevel.ReleasedLevel.N.getLevel()))
+        .setSourceLevel(SourceLevel.JAVA_8);
+    toolchain.disableDxOptimizations();
+
+    File outFolder = AbstractTestTools.createTempDir();
+
+    SourceToDexComparisonTestHelper env =
+        new SourceToDexComparisonTestHelper(new File(testFolder, "jack"));
+
+    env.setWithDebugInfo(true);
+    env.setCandidateTestTools(toolchain);
+    env.setReferenceTestTools(new DummyToolchain());
+    env.setProguardFlags(dontObfuscateFlagFile,
+        new ProguardFlags(shrobTestsDir, "keepAllAttributes.flags"),
+        new ProguardFlags(testFolder, "proguard.flags001"));
+    env.setSourceLevel(SourceLevel.JAVA_8);
+
+    env.runTest(
+        new ComparatorMapping(new File(refFolder, "expected-001.txt"), candidateNodeListing));
+  }
 }
diff --git a/jack-tests/tests/com/android/jack/shrob/test066/info.txt b/jack-tests/tests/com/android/jack/shrob/test066/info.txt
new file mode 100644
index 0000000..f05f107
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test066/info.txt
@@ -0,0 +1,2 @@
+This tests contains an Interface with a default method which should be kept if
+the overridden method is kept as well or is in the classpath.
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test066/jack/MySuperInterfaceWithDefaultMethod.java b/jack-tests/tests/com/android/jack/shrob/test066/jack/MySuperInterfaceWithDefaultMethod.java
new file mode 100644
index 0000000..700150f
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test066/jack/MySuperInterfaceWithDefaultMethod.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.jack.shrob.test066.jack;
+
+import com.android.jack.shrob.test066.lib.MySuperInterface;
+
+public interface MySuperInterfaceWithDefaultMethod extends MySuperInterface {
+  @Override
+  default void m() {
+  }
+}
diff --git a/jack-tests/tests/com/android/jack/shrob/test066/lib/MySuperInterface.java b/jack-tests/tests/com/android/jack/shrob/test066/lib/MySuperInterface.java
new file mode 100644
index 0000000..e5a8188
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test066/lib/MySuperInterface.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.shrob.test066.lib;
+
+public interface MySuperInterface {
+  void m();
+}
diff --git a/jack-tests/tests/com/android/jack/shrob/test066/proguard.flags001 b/jack-tests/tests/com/android/jack/shrob/test066/proguard.flags001
new file mode 100644
index 0000000..a3ed85a
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test066/proguard.flags001
@@ -0,0 +1 @@
+-keep class **.MySuperInterfaceWithDefaultMethod
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test066/refsShrinking/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test066/refsShrinking/expected-001.txt
new file mode 100644
index 0000000..f4ba26f
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test066/refsShrinking/expected-001.txt
@@ -0,0 +1,2 @@
+Lcom/android/jack/shrob/test066/jack/MySuperInterfaceWithDefaultMethod;:
+m()V
\ No newline at end of file
diff --git a/jack/src/com/android/jack/backend/dex/DexWritingTool.java b/jack/src/com/android/jack/backend/dex/DexWritingTool.java
index 86828dd..af6e5cb 100644
--- a/jack/src/com/android/jack/backend/dex/DexWritingTool.java
+++ b/jack/src/com/android/jack/backend/dex/DexWritingTool.java
@@ -157,8 +157,10 @@
     try {
       inputStream = inputDex.getInputStream();
       merger.addDexFile(new DexBuffer(inputStream));
-    } catch (IOException | WrongPermissionException e) {
+    } catch (IOException e) {
       throw new DexWritingException(new CannotReadException(inputDex, e));
+    } catch (WrongPermissionException e) {
+      throw new DexWritingException(e);
     } finally {
       if (inputStream != null) {
         try {
diff --git a/jack/src/com/android/jack/backend/dex/invokecustom/InvokeCustomHelper.java b/jack/src/com/android/jack/backend/dex/invokecustom/InvokeCustomHelper.java
index 69cefa2..5e4917a 100644
--- a/jack/src/com/android/jack/backend/dex/invokecustom/InvokeCustomHelper.java
+++ b/jack/src/com/android/jack/backend/dex/invokecustom/InvokeCustomHelper.java
@@ -19,25 +19,39 @@
 import com.android.jack.Jack;
 import com.android.jack.backend.dex.DexAnnotations;
 import com.android.jack.backend.dex.rop.RopHelper;
+import com.android.jack.dx.rop.cst.CstArray;
 import com.android.jack.dx.rop.cst.CstCallSiteRef;
+import com.android.jack.dx.rop.cst.CstDouble;
 import com.android.jack.dx.rop.cst.CstFieldRef;
+import com.android.jack.dx.rop.cst.CstFloat;
+import com.android.jack.dx.rop.cst.CstInteger;
+import com.android.jack.dx.rop.cst.CstLong;
 import com.android.jack.dx.rop.cst.CstMethodHandleRef;
 import com.android.jack.dx.rop.cst.CstMethodHandleRef.MethodHandleKind;
 import com.android.jack.dx.rop.cst.CstMethodRef;
 import com.android.jack.dx.rop.cst.CstNat;
 import com.android.jack.dx.rop.cst.CstPrototypeRef;
 import com.android.jack.dx.rop.cst.CstString;
+import com.android.jack.dx.rop.cst.TypedConstant;
 import com.android.jack.dx.rop.type.Prototype;
 import com.android.jack.ir.ast.JAbstractMethodCall;
 import com.android.jack.ir.ast.JAnnotation;
 import com.android.jack.ir.ast.JAnnotationMethod;
 import com.android.jack.ir.ast.JArrayLiteral;
+import com.android.jack.ir.ast.JBooleanLiteral;
+import com.android.jack.ir.ast.JByteLiteral;
+import com.android.jack.ir.ast.JCharLiteral;
 import com.android.jack.ir.ast.JClassLiteral;
 import com.android.jack.ir.ast.JDefinedAnnotationType;
+import com.android.jack.ir.ast.JDoubleLiteral;
 import com.android.jack.ir.ast.JEnumLiteral;
+import com.android.jack.ir.ast.JFloatLiteral;
+import com.android.jack.ir.ast.JIntLiteral;
 import com.android.jack.ir.ast.JLiteral;
+import com.android.jack.ir.ast.JLongLiteral;
 import com.android.jack.ir.ast.JMethod;
 import com.android.jack.ir.ast.JNameValuePair;
+import com.android.jack.ir.ast.JShortLiteral;
 import com.android.jack.ir.ast.JStringLiteral;
 import com.android.jack.ir.formatter.BinarySignatureFormatter;
 
@@ -77,21 +91,37 @@
     JStringLiteral callSiteMethodName = null;
     JClassLiteral callSiteReturnType = null;
     JArrayLiteral callSiteArgumentTypes = null;
+    CstArray extraArgs = null;
     for (JNameValuePair nameValuePair : invokeCustomCallSite.getNameValuePairs()) {
-      if (nameValuePair.getName().equals("invokeMethodHandle")) {
-        JArrayLiteral arrayLiteral = (JArrayLiteral) nameValuePair.getValue();
-        assert arrayLiteral.getValues().size() == 1;
-        methodHandle = readLinkerMethodHandle((JAnnotation) arrayLiteral.getValues().get(0));
-      } else if (nameValuePair.getName().equals("fieldMethodHandle")) {
-        JArrayLiteral arrayLiteral = (JArrayLiteral) nameValuePair.getValue();
-        assert arrayLiteral.getValues().size() == 1;
-        methodHandle = readLinkerFieldHandle((JAnnotation) arrayLiteral.getValues().get(0));
-      } else if (nameValuePair.getName().equals("name")) {
-        callSiteMethodName = (JStringLiteral) (nameValuePair.getValue());
-      } else if (nameValuePair.getName().equals("returnType")) {
-        callSiteReturnType = (JClassLiteral) (nameValuePair.getValue());
-      } else if (nameValuePair.getName().equals("argumentTypes")) {
-        callSiteArgumentTypes = (JArrayLiteral) (nameValuePair.getValue());
+      switch (nameValuePair.getName()) {
+        case "invokeMethodHandle": {
+          JArrayLiteral arrayLiteral = (JArrayLiteral) nameValuePair.getValue();
+          assert arrayLiteral.getValues().size() == 1;
+          methodHandle = readLinkerMethodHandle((JAnnotation) arrayLiteral.getValues().get(0));
+          break;
+        }
+        case "fieldMethodHandle": {
+          JArrayLiteral arrayLiteral = (JArrayLiteral) nameValuePair.getValue();
+          assert arrayLiteral.getValues().size() == 1;
+          methodHandle = readLinkerFieldHandle((JAnnotation) arrayLiteral.getValues().get(0));
+          break;
+        }
+        case "methodHandleExtraArgs": {
+          extraArgs = readExtraArgs((JArrayLiteral) nameValuePair.getValue());
+          break;
+        }
+        case "name": {
+          callSiteMethodName = (JStringLiteral) (nameValuePair.getValue());
+          break;
+        }
+        case "returnType": {
+          callSiteReturnType = (JClassLiteral) (nameValuePair.getValue());
+          break;
+        }
+        case "argumentTypes": {
+          callSiteArgumentTypes = (JArrayLiteral) (nameValuePair.getValue());
+          break;
+        }
       }
     }
     assert methodHandle != null;
@@ -103,7 +133,7 @@
         Prototype.intern(buildSignature(callSiteArgumentTypes, callSiteReturnType));
 
     return new CstCallSiteRef(methodHandle, callSiteMethodName.getValue(),
-        new CstPrototypeRef(callSitePrototype));
+        new CstPrototypeRef(callSitePrototype), extraArgs);
   }
 
   @CheckForNull
@@ -117,6 +147,73 @@
   }
 
   @Nonnull
+  private static CstArray readExtraArgs(@Nonnull JArrayLiteral extraArgs) {
+    CstArray.List list = new CstArray.List(extraArgs.getValues().size());
+    int idx = 0;
+    for (JLiteral extraArg : extraArgs.getValues()) {
+      assert extraArg instanceof JAnnotation;
+      JAnnotation extrArgAnnot = (JAnnotation) extraArg;
+      for (JNameValuePair nameValuePair : extrArgAnnot.getNameValuePairs()) {
+        JArrayLiteral value = (JArrayLiteral) nameValuePair.getValue();
+        assert value.getValues().size() == 1;
+        TypedConstant cst = null;
+        JLiteral jLiteral = value.getValues().get(0);
+        switch (nameValuePair.getName()) {
+          case "booleanValue" : {
+            cst = CstInteger.make(((JBooleanLiteral) jLiteral).getValue() ? 1 : 0);
+            break;
+          }
+          case "byteValue" : {
+            cst = CstInteger.make(((JByteLiteral) jLiteral).getValue());
+            break;
+          }
+          case "charValue" : {
+            cst = CstInteger.make(((JCharLiteral) jLiteral).getValue());
+            break;
+          }
+          case "shortValue" : {
+            cst = CstInteger.make(((JShortLiteral) jLiteral).getValue());
+            break;
+          }
+          case "intValue" : {
+            cst = CstInteger.make(((JIntLiteral) jLiteral).getValue());
+            break;
+          }
+          case "floatValue" : {
+            cst = CstFloat
+                .make(Float.floatToIntBits(((JFloatLiteral) jLiteral).getValue()));
+            break;
+          }
+          case "doubleValue" : {
+            cst = CstDouble.make(
+                Double.doubleToLongBits(((JDoubleLiteral) jLiteral).getValue()));
+            break;
+          }
+          case "longValue" : {
+            cst = CstLong.make(((JLongLiteral) jLiteral).getValue());
+            break;
+          }
+          case "stringValue" : {
+            cst = new CstString(((JStringLiteral) jLiteral).getValue());
+            break;
+          }
+          case "classValue" : {
+            cst = RopHelper.getCstType(((JClassLiteral) jLiteral).getRefType());
+            break;
+          }
+          default: {
+            throw new AssertionError();
+          }
+        }
+        list.set(idx++, cst);
+      }
+    }
+
+    list.setImmutable();
+    return new CstArray(list);
+  }
+
+  @Nonnull
   private static CstMethodHandleRef readLinkerFieldHandle(@Nonnull JAnnotation linkerFieldHandle) {
     JNameValuePair kindValuePair = linkerFieldHandle.getNameValuePair("kind");
     assert kindValuePair != null;
diff --git a/jack/src/com/android/jack/dx/dex/code/DalvInsnList.java b/jack/src/com/android/jack/dx/dex/code/DalvInsnList.java
index 1d453d9..b29c7a8 100644
--- a/jack/src/com/android/jack/dx/dex/code/DalvInsnList.java
+++ b/jack/src/com/android/jack/dx/dex/code/DalvInsnList.java
@@ -30,6 +30,8 @@
 import java.io.Writer;
 import java.util.ArrayList;
 
+import javax.annotation.Nonnull;
+
 /**
  * List of {@link DalvInsn} instances.
  */
@@ -188,27 +190,32 @@
     for (int i = 0; i < sz; i++) {
       DalvInsn insn = (DalvInsn) get0(i);
 
-      if (!(insn instanceof CstInsn)) {
-        continue;
-      }
-
-      Constant cst = ((CstInsn) insn).getConstant();
-
-      if (!(cst instanceof CstBaseMethodRef)) {
-        continue;
-      }
-
-      boolean isStatic = (insn.getOpcode().getFamily() == Opcodes.INVOKE_STATIC);
-      int count = ((CstBaseMethodRef) cst).getParameterWordCount(isStatic);
-
-      if (count > result) {
-        result = count;
+      if (isCallInstruction(insn)) {
+        int count = insn.getRegisters().getWordCount();
+        if (count > result) {
+          result = count;
+        }
       }
     }
 
     return result;
   }
 
+  private boolean isCallInstruction(@Nonnull DalvInsn insn) {
+    if (insn instanceof CstInsn) {
+      Constant cst = ((CstInsn) insn).getConstant();
+      if (cst instanceof CstBaseMethodRef) {
+        return true;
+      }
+    } else if (insn instanceof DualCstInsn) {
+      assert insn.getOpcode().getOpcode() == Opcodes.INVOKE_POLYMORPHIC
+          || insn.getOpcode().getOpcode() == Opcodes.INVOKE_POLYMORPHIC_RANGE;
+      return true;
+    }
+
+    return false;
+  }
+
   /**
    * Does a human-friendly dump of this instance.
    *
diff --git a/jack/src/com/android/jack/dx/dex/file/CallSiteIdItem.java b/jack/src/com/android/jack/dx/dex/file/CallSiteIdItem.java
index 8b678a7..a538a17 100644
--- a/jack/src/com/android/jack/dx/dex/file/CallSiteIdItem.java
+++ b/jack/src/com/android/jack/dx/dex/file/CallSiteIdItem.java
@@ -30,7 +30,7 @@
 public final class CallSiteIdItem extends IndexedItem {
 
   @Nonnull
-  private CstCallSiteRef callSiteRef;
+  private final CstCallSiteRef callSiteRef;
   @Nonnull
   private EncodedArrayItem encodedArray;
 
@@ -73,14 +73,18 @@
     if (out.annotates()) {
       out.annotate(0, indexString());
       out.annotate(4, "  encoded_array_absolute_offset: " + encodedArray.getAbsoluteOffset());
-      out.annotate(0, "  method_handle_idx:             "
-          + Hex.u2(file.findItemOrNull(callSiteRef.getMethodHandle()).getIndex()));
+      MethodHandleIdItem methodHandle =
+          (MethodHandleIdItem) file.findItemOrNull(callSiteRef.getMethodHandle());
+      out.annotate(0, "  method_handle_idx:             " + Hex.u2(methodHandle.getIndex()) + " // "
+          + methodHandle.getCstMethodHandleRef().toHuman());
       out.annotate(0,
           "  target_method_name:            " + callSiteRef.getTargetMethodName().getString());
       ProtoIdItem methodType =
           (ProtoIdItem) file.findItemOrNull(callSiteRef.getCallSitePrototype());
       out.annotate(0, "  method_type_idx:               " + Hex.u2(methodType.getIndex()) + " // "
           + methodType.toHuman());
+      out.annotate(0, "  extra_args:                    "
+          + callSiteRef.getExtraArgs().getList().toHuman("{", ",", "}"));
     }
 
     out.writeInt(encodedArray.getAbsoluteOffset());
diff --git a/jack/src/com/android/jack/dx/dex/file/MethodHandleIdItem.java b/jack/src/com/android/jack/dx/dex/file/MethodHandleIdItem.java
index 46e6717..bb495f1 100644
--- a/jack/src/com/android/jack/dx/dex/file/MethodHandleIdItem.java
+++ b/jack/src/com/android/jack/dx/dex/file/MethodHandleIdItem.java
@@ -30,7 +30,7 @@
 public final class MethodHandleIdItem extends IndexedItem {
 
   @Nonnull
-  private CstMethodHandleRef cstMethodHandleRef;
+  private final CstMethodHandleRef cstMethodHandleRef;
 
   /**
    * Constructs an instance.
@@ -62,6 +62,11 @@
     file.internIfAppropriate(cstMethodHandleRef.getMemberRef());
   }
 
+  @Nonnull
+  public CstMethodHandleRef getCstMethodHandleRef() {
+    return cstMethodHandleRef;
+  }
+
   /** {@inheritDoc} */
   @Override
   public void writeTo(@Nonnull DexFile file, @Nonnull AnnotatedOutput out) {
diff --git a/jack/src/com/android/jack/dx/io/DexBuffer.java b/jack/src/com/android/jack/dx/io/DexBuffer.java
index cab2ce8..bacc0a9 100644
--- a/jack/src/com/android/jack/dx/io/DexBuffer.java
+++ b/jack/src/com/android/jack/dx/io/DexBuffer.java
@@ -31,6 +31,7 @@
 import com.android.jack.dx.util.FileUtils;
 import com.android.jack.dx.util.Leb128Utils;
 import com.android.jack.dx.util.Mutf8;
+import com.android.jack.tools.merger.MergerTools;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -466,7 +467,7 @@
 
       @Override
       protected void visitPrimitive(int type, int arg, int size) {
-        throw new AssertionError("Unsupported encoded value.");
+        callSiteArrayList.set(idx++, MergerTools.createConstant(in, type, arg));
       }
 
       @Override
@@ -511,7 +512,7 @@
 
       @Override
       protected void visitType(int index) {
-        throw new AssertionError("Unsupported encoded value.");
+        callSiteArrayList.set(idx++, cstIndexMap.getCstType(index));
       }
     }
 
diff --git a/jack/src/com/android/jack/dx/rop/cst/CstCallSiteRef.java b/jack/src/com/android/jack/dx/rop/cst/CstCallSiteRef.java
index 6de8772..103e5a3 100644
--- a/jack/src/com/android/jack/dx/rop/cst/CstCallSiteRef.java
+++ b/jack/src/com/android/jack/dx/rop/cst/CstCallSiteRef.java
@@ -17,8 +17,10 @@
 package com.android.jack.dx.rop.cst;
 
 import com.android.jack.dx.dex.file.ValueEncoder.ValueType;
+import com.android.jack.dx.rop.cst.CstArray.List;
 import com.android.jack.dx.rop.type.Type;
 
+import javax.annotation.CheckForNull;
 import javax.annotation.Nonnegative;
 import javax.annotation.Nonnull;
 
@@ -33,19 +35,28 @@
   private static final int TARGET_METHOD_NAME_IDX = 1;
   @Nonnegative
   private static final int CALL_SITE_IDX = 2;
+  @Nonnegative
+  private static final int EXTRA_ARGS_IDX = 3;
   @Nonnull
-  private CstArray callSite;
+  private final CstArray callSite;
 
   public CstCallSiteRef(@Nonnull CstArray callSite) {
     this.callSite = callSite;
   }
 
   public CstCallSiteRef(@Nonnull CstMethodHandleRef methodHandle, @Nonnull String targetMethodName,
-      @Nonnull CstPrototypeRef callSitePrototype) {
-    CstArray.List list = new CstArray.List(3);
+      @Nonnull CstPrototypeRef callSitePrototype, @CheckForNull CstArray extraArgs) {
+    CstArray.List list =
+        new CstArray.List(3 + (extraArgs != null ? extraArgs.getList().size() : 0));
     list.set(METHOD_HANDLE_IDX, methodHandle);
     list.set(TARGET_METHOD_NAME_IDX, new CstString(targetMethodName));
     list.set(CALL_SITE_IDX, callSitePrototype);
+    if (extraArgs != null) {
+      List extraArgList = extraArgs.getList();
+      for (int idx = 0; idx < extraArgList.size(); idx++) {
+        list.set(EXTRA_ARGS_IDX + idx, extraArgList.get(idx));
+      }
+    }
     list.setImmutable();
     callSite = new CstArray(list);
   }
@@ -115,6 +126,17 @@
   }
 
   @Nonnull
+  public CstArray getExtraArgs() {
+    List callSiteList = callSite.getList();
+    CstArray.List list =  new CstArray.List(callSiteList.size() - EXTRA_ARGS_IDX);
+    for (int idx = EXTRA_ARGS_IDX; idx < callSiteList.size(); idx++) {
+      list.set(idx - EXTRA_ARGS_IDX, callSiteList.get(idx));
+    }
+    list.setImmutable();
+    return new CstArray(list);
+  }
+
+  @Nonnull
   public CstArray getCstArray() {
     return callSite;
   }
diff --git a/jack/src/com/android/jack/dx/rop/cst/CstMethodHandleRef.java b/jack/src/com/android/jack/dx/rop/cst/CstMethodHandleRef.java
index 400b531..612326d 100644
--- a/jack/src/com/android/jack/dx/rop/cst/CstMethodHandleRef.java
+++ b/jack/src/com/android/jack/dx/rop/cst/CstMethodHandleRef.java
@@ -86,10 +86,10 @@
   }
 
   @Nonnull
-  private MethodHandleKind kind;
+  private final MethodHandleKind kind;
 
   @Nonnull
-  private CstMemberRef memberRef;
+  private final CstMemberRef memberRef;
 
   public CstMethodHandleRef(@Nonnull MethodHandleKind kind, @Nonnull CstMemberRef memberRef) {
     this.kind = kind;
@@ -158,7 +158,7 @@
   @Override
   @Nonnull
   public String toHuman() {
-    return kind.name() + "," + memberRef.toHuman();
+    return kind.name() + ", " + memberRef.toHuman();
   }
 
   @Nonnull
diff --git a/sched/src/com/android/sched/util/codec/OrCodec.java b/sched/src/com/android/sched/util/codec/OrCodec.java
index a1ebcc6..9b96284 100644
--- a/sched/src/com/android/sched/util/codec/OrCodec.java
+++ b/sched/src/com/android/sched/util/codec/OrCodec.java
@@ -43,6 +43,8 @@
     this.codecList = codecList;
   }
 
+
+  @SafeVarargs
   public OrCodec(@Nonnull StringCodec<? extends T>... codecList) {
     assert codecList.length >= 2;
     this.codecList = Arrays.asList(codecList);
diff --git a/sched/src/com/android/sched/vfs/CachedDirectFS.java b/sched/src/com/android/sched/vfs/CachedDirectFS.java
index baef4b6..6ec09b6 100644
--- a/sched/src/com/android/sched/vfs/CachedDirectFS.java
+++ b/sched/src/com/android/sched/vfs/CachedDirectFS.java
@@ -16,14 +16,12 @@
 
 package com.android.sched.vfs;
 
-import com.android.sched.util.ConcurrentIOException;
 import com.android.sched.util.file.AbstractStreamFile;
 import com.android.sched.util.file.CannotCreateFileException;
 import com.android.sched.util.file.CannotDeleteFileException;
 import com.android.sched.util.file.CannotGetModificationTimeException;
 import com.android.sched.util.file.Directory;
 import com.android.sched.util.file.FileAlreadyExistsException;
-import com.android.sched.util.file.FileOrDirectory;
 import com.android.sched.util.file.FileOrDirectory.Permission;
 import com.android.sched.util.file.NoSuchFileException;
 import com.android.sched.util.file.NotDirectoryException;
@@ -273,8 +271,11 @@
       assert (is = trackOpenedStream(is, file)) != null;
       return is;
     } catch (FileNotFoundException e) {
-      FileOrDirectory.checkPermissions(path, file.getLocation(), Permission.READ);
-      throw new ConcurrentIOException(e);
+
+      DirectFS.checkPermissionsIfExists(path, file.getLocation(), Permission.READ);
+
+      // should not happen
+      throw new AssertionError(e);
     }
   }
 
@@ -300,8 +301,11 @@
       assert (os = trackOpenedStream(os, file)) != null;
       return os;
     } catch (FileNotFoundException e) {
-      FileOrDirectory.checkPermissions(path, file.getLocation(), Permission.WRITE);
-      throw new ConcurrentIOException(e);
+
+      DirectFS.checkPermissionsIfExists(path, file.getLocation(), Permission.WRITE);
+
+      // should not happen
+      throw new AssertionError(e);
     }
   }
 
diff --git a/sched/src/com/android/sched/vfs/DirectFS.java b/sched/src/com/android/sched/vfs/DirectFS.java
index 21e9b7f..41fa6f9 100644
--- a/sched/src/com/android/sched/vfs/DirectFS.java
+++ b/sched/src/com/android/sched/vfs/DirectFS.java
@@ -128,8 +128,11 @@
     try {
       return new FileInputStream(path);
     } catch (FileNotFoundException e) {
-      FileOrDirectory.checkPermissions(path, file.getLocation(), Permission.READ);
-      throw new ConcurrentIOException(e);
+
+      checkPermissionsIfExists(path, file.getLocation(), Permission.READ);
+
+      // should not happen
+      throw new AssertionError(e);
     }
   }
 
@@ -153,11 +156,29 @@
     try {
       return new FileOutputStream(path, append);
     } catch (FileNotFoundException e) {
-      FileOrDirectory.checkPermissions(path, file.getLocation(), Permission.WRITE);
-      throw new ConcurrentIOException(e);
+
+      checkPermissionsIfExists(path, file.getLocation(), Permission.WRITE);
+
+      // should not happen
+      throw new AssertionError(e);
     }
   }
 
+  static void checkPermissionsIfExists(
+      @Nonnull File path,
+      @Nonnull Location location,
+      int permission)
+      throws WrongPermissionException {
+    // Let's find out if the file has disappeared since we last checked or if this is a permission
+    // issue. We need to check if the file exists first.
+    try {
+      AbstractStreamFile.check(path, location);
+    } catch (NotFileException | NoSuchFileException e1) {
+      throw new ConcurrentIOException(e1);
+    }
+    FileOrDirectory.checkPermissions(path, location, permission);
+  }
+
   @Nonnull
   @Override
   Collection<? extends BaseVElement> list(@Nonnull ParentVDir dir) {