Merge "Return an invalid StackMap when none can be found." into mnc-dev
diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk
index e0c0b0c..b9a449c 100644
--- a/build/Android.common_path.mk
+++ b/build/Android.common_path.mk
@@ -88,4 +88,8 @@
 
 HOST_CORE_DEX_FILES   := $(foreach jar,$(HOST_CORE_JARS),  $(call intermediates-dir-for,JAVA_LIBRARIES,$(jar),t,COMMON)/javalib.jar)
 TARGET_CORE_DEX_FILES := $(foreach jar,$(TARGET_CORE_JARS),$(call intermediates-dir-for,JAVA_LIBRARIES,$(jar), ,COMMON)/javalib.jar)
+
+# Classpath for Jack compilation: we only need core-libart.
+HOST_JACK_CLASSPATH   := $(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart-hostdex,t,COMMON)/classes.jack)
+TARGET_JACK_CLASSPATH := $(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart, ,COMMON)/classes.jack)
 endif # ART_ANDROID_COMMON_PATH_MK
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 7ca03cf..c50246d 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -193,7 +193,8 @@
   }
 
   if (!reg_arg.Valid()) {
-    LoadBaseDisp(TargetPtrReg(kSp), offset, rl_dest.reg, rl_dest.wide ? k64 : k32, kNotVolatile);
+    OpSize op_size = rl_dest.wide ? k64 : (rl_dest.ref ? kReference : k32);
+    LoadBaseDisp(TargetPtrReg(kSp), offset, rl_dest.reg, op_size, kNotVolatile);
   } else {
     if (rl_dest.wide) {
       OpRegCopyWide(rl_dest.reg, reg_arg);
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index d993d93..d1fe167 100755
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -1336,9 +1336,24 @@
     }
     OpRegReg(kOpRev, rl_result.reg.GetLow(), rl_i.reg.GetHigh());
     OpRegReg(kOpRev, rl_result.reg.GetHigh(), r_i_low);
+    // Free up at least one input register if it was a temp. Otherwise we may be in the bad
+    // situation of not having a temp available for SwapBits. Make sure it's not overlapping
+    // with the output, though.
     if (rl_i.reg.GetLowReg() == rl_result.reg.GetLowReg()) {
+      // There's definitely a free temp after this.
       FreeTemp(r_i_low);
+    } else {
+      // We opportunistically release both here. That saves duplication of the register state
+      // lookup (to see if it's actually a temp).
+      if (rl_i.reg.GetLowReg() != rl_result.reg.GetHighReg()) {
+        FreeTemp(rl_i.reg.GetLow());
+      }
+      if (rl_i.reg.GetHighReg() != rl_result.reg.GetLowReg() &&
+          rl_i.reg.GetHighReg() != rl_result.reg.GetHighReg()) {
+        FreeTemp(rl_i.reg.GetHigh());
+      }
     }
+
     SwapBits(rl_result.reg.GetLow(), 1, 0x55555555);
     SwapBits(rl_result.reg.GetLow(), 2, 0x33333333);
     SwapBits(rl_result.reg.GetLow(), 4, 0x0f0f0f0f);
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index f0b7bfd..5bd6583 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -471,7 +471,8 @@
 ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, const StringPiece& signature,
                                             size_t pointer_size) {
   for (auto& method : GetVirtualMethods(pointer_size)) {
-    if (name == method.GetName() && method.GetSignature() == signature) {
+    ArtMethod* const np_method = method.GetInterfaceMethodIfProxy(pointer_size);
+    if (name == np_method->GetName() && np_method->GetSignature() == signature) {
       return &method;
     }
   }
@@ -481,7 +482,8 @@
 ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, const Signature& signature,
                                             size_t pointer_size) {
   for (auto& method : GetVirtualMethods(pointer_size)) {
-    if (name == method.GetName() && signature == method.GetSignature()) {
+    ArtMethod* const np_method = method.GetInterfaceMethodIfProxy(pointer_size);
+    if (name == np_method->GetName() && signature == np_method->GetSignature()) {
       return &method;
     }
   }
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 085f741..e3999c1 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -4061,7 +4061,9 @@
                     << " to be compatible with type '" << insn_type
                     << "' but found type '" << *field_type
                     << "' in get-object";
-        work_line_->SetRegisterType(this, vregA, reg_types_.Conflict());
+        if (error != VERIFY_ERROR_BAD_CLASS_HARD) {
+          work_line_->SetRegisterType(this, vregA, reg_types_.Conflict());
+        }
         return;
       }
     }
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index c8aa4fd..1435607 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -585,7 +585,15 @@
   DCHECK(!Equals(incoming_type));  // Trivial equality handled by caller
   // Perform pointer equality tests for conflict to avoid virtual method dispatch.
   const ConflictType& conflict = reg_types->Conflict();
-  if (this == &conflict) {
+  if (IsUndefined() || incoming_type.IsUndefined()) {
+    // There is a difference between undefined and conflict. Conflicts may be copied around, but
+    // not used. Undefined registers must not be copied. So any merge with undefined should return
+    // undefined.
+    if (IsUndefined()) {
+      return *this;
+    }
+    return incoming_type;
+  } else if (this == &conflict) {
     DCHECK(IsConflict());
     return *this;  // Conflict MERGE * => Conflict
   } else if (&incoming_type == &conflict) {
diff --git a/runtime/verifier/register_line-inl.h b/runtime/verifier/register_line-inl.h
index 244deed..9cd2bdf 100644
--- a/runtime/verifier/register_line-inl.h
+++ b/runtime/verifier/register_line-inl.h
@@ -38,10 +38,9 @@
     verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Expected category1 register type not '"
         << new_type << "'";
     return false;
-  } else if (new_type.IsConflict()) {  // should only be set during a merge
-    verifier->Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "Set register to unknown type " << new_type;
-    return false;
   } else {
+    // Note: previously we failed when asked to set a conflict. However, conflicts are OK as long
+    //       as they are not accessed, and our backends can handle this nowadays.
     line_[vdst] = new_type.GetId();
   }
   // Clear the monitor entry bits for this register.
@@ -93,8 +92,9 @@
   if (!SetRegisterType(verifier, vdst, type)) {
     return;
   }
-  if ((cat == kTypeCategory1nr && !type.IsCategory1Types()) ||
-      (cat == kTypeCategoryRef && !type.IsReferenceTypes())) {
+  if (!type.IsConflict() &&                                  // Allow conflicts to be copied around.
+      ((cat == kTypeCategory1nr && !type.IsCategory1Types()) ||
+       (cat == kTypeCategoryRef && !type.IsReferenceTypes()))) {
     verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "copy1 v" << vdst << "<-v" << vsrc << " type=" << type
                                                  << " cat=" << static_cast<int>(cat);
   } else if (cat == kTypeCategoryRef) {
diff --git a/test/003-omnibus-opcodes/build b/test/003-omnibus-opcodes/build
index f909fb2..faa2983 100644
--- a/test/003-omnibus-opcodes/build
+++ b/test/003-omnibus-opcodes/build
@@ -22,5 +22,10 @@
 rm classes/UnresClass.class
 ${JAVAC} -d classes `find src2 -name '*.java'`
 
-${DX} -JXmx256m --debug --dex --output=classes.dex classes
+if [ ${USE_JACK} = "true" ]; then
+  ${JILL} classes --output classes.jack
+  ${JACK} --import classes.jack --output-dex .
+else
+  ${DX} -JXmx256m --debug --dex --output=classes.dex classes
+  fi
 zip $TEST_NAME.jar classes.dex
diff --git a/test/004-JniTest/jni_test.cc b/test/004-JniTest/jni_test.cc
index ca256ec..db0dd32 100644
--- a/test/004-JniTest/jni_test.cc
+++ b/test/004-JniTest/jni_test.cc
@@ -626,3 +626,7 @@
   assert(strcmp(test_array, chars6) == 0);
   env->ReleaseStringUTFChars(s6, chars6);
 }
+
+extern "C" JNIEXPORT jlong JNICALL Java_Main_testGetMethodID(JNIEnv* env, jclass, jclass c) {
+  return reinterpret_cast<jlong>(env->GetMethodID(c, "a", "()V"));
+}
diff --git a/test/004-JniTest/src/Main.java b/test/004-JniTest/src/Main.java
index a81ec6d..decefac 100644
--- a/test/004-JniTest/src/Main.java
+++ b/test/004-JniTest/src/Main.java
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
+import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
 
 public class Main {
     public static void main(String[] args) {
@@ -35,6 +37,7 @@
         testCallNonvirtual();
         testNewStringObject();
         testRemoveLocalObject();
+        testProxyGetMethodID();
     }
 
     private static native void testFindClassOnAttachedNativeThread();
@@ -194,6 +197,31 @@
     private static native void testCallNonvirtual();
 
     private static native void testNewStringObject();
+
+    private interface SimpleInterface {
+        void a();
+    }
+
+    private static class DummyInvocationHandler implements InvocationHandler {
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            return null;
+        }
+    }
+
+    private static void testProxyGetMethodID() {
+        InvocationHandler handler = new DummyInvocationHandler();
+        SimpleInterface proxy =
+                (SimpleInterface) Proxy.newProxyInstance(SimpleInterface.class.getClassLoader(),
+                        new Class[] {SimpleInterface.class}, handler);
+        if (testGetMethodID(SimpleInterface.class) == 0) {
+            throw new AssertionError();
+        }
+        if (testGetMethodID(proxy.getClass()) == 0) {
+            throw new AssertionError();
+        }
+    }
+
+    private static native long testGetMethodID(Class<?> c);
 }
 
 class JniCallNonvirtualTest {
diff --git a/test/004-ReferenceMap/build b/test/004-ReferenceMap/build
new file mode 100644
index 0000000..08987b5
--- /dev/null
+++ b/test/004-ReferenceMap/build
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+# Copyright (C) 2015 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.
+
+# Stop if something fails.
+set -e
+
+# The test relies on DEX file produced by javac+dx so keep building with them for now
+# (see b/19467889)
+mkdir classes
+${JAVAC} -d classes `find src -name '*.java'`
+${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
+  --dump-width=1000 ${DX_FLAGS} classes
+zip $TEST_NAME.jar classes.dex
diff --git a/test/004-StackWalk/build b/test/004-StackWalk/build
new file mode 100644
index 0000000..08987b5
--- /dev/null
+++ b/test/004-StackWalk/build
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+# Copyright (C) 2015 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.
+
+# Stop if something fails.
+set -e
+
+# The test relies on DEX file produced by javac+dx so keep building with them for now
+# (see b/19467889)
+mkdir classes
+${JAVAC} -d classes `find src -name '*.java'`
+${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
+  --dump-width=1000 ${DX_FLAGS} classes
+zip $TEST_NAME.jar classes.dex
diff --git a/test/005-annotations/build b/test/005-annotations/build
index 2474055..3f00a1a 100644
--- a/test/005-annotations/build
+++ b/test/005-annotations/build
@@ -25,4 +25,12 @@
 # ...but not at run time.
 rm 'classes/android/test/anno/MissingAnnotation.class'
 rm 'classes/android/test/anno/ClassWithInnerAnnotationClass$MissingInnerAnnotationClass.class'
-${DX} -JXmx256m --debug --dex --output=$TEST_NAME.jar classes
+
+if [ ${USE_JACK} = "true" ]; then
+  ${JILL} classes --output classes.jack
+  ${JACK} --import classes.jack --output-dex .
+else
+  ${DX} -JXmx256m --debug --dex --output=classes.dex classes
+fi
+
+zip $TEST_NAME.jar classes.dex
diff --git a/test/022-interface/build b/test/022-interface/build
index c86b1dc..3f8915c 100644
--- a/test/022-interface/build
+++ b/test/022-interface/build
@@ -19,5 +19,11 @@
 
 # Use classes that are compiled with ecj that exposes an invokeinterface
 # issue when interfaces override methods in Object
-${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+if [ ${USE_JACK} = "true" ]; then
+  ${JILL} classes --output classes.jack
+  ${JACK} --import classes.jack --output-dex .
+else
+  ${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+fi
+
 zip $TEST_NAME.jar classes.dex
diff --git a/test/023-many-interfaces/build b/test/023-many-interfaces/build
index ad42a2d..b4381f4 100644
--- a/test/023-many-interfaces/build
+++ b/test/023-many-interfaces/build
@@ -21,8 +21,14 @@
 gcc -Wall -Werror -o iface-gen iface-gen.c
 ./iface-gen
 
-mkdir classes
-${JAVAC} -d classes src/*.java
+if [ ${USE_JACK} = "true" ]; then
+  ${JACK} --output-dex . src
+else
+  mkdir classes
+  ${JAVAC} -d classes src/*.java
 
-${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+  # dx needs more memory for that test so do not pass Xmx option here.
+  ${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+fi
+
 zip $TEST_NAME.jar classes.dex
diff --git a/test/036-finalizer/src/Main.java b/test/036-finalizer/src/Main.java
index e3cf4ee..cac034e 100644
--- a/test/036-finalizer/src/Main.java
+++ b/test/036-finalizer/src/Main.java
@@ -89,10 +89,15 @@
         return s[0];
     }
 
+    private static void printWeakReference(WeakReference<FinalizerTest> wimp) {
+        // Reference ft so we are sure the WeakReference cannot be cleared.
+        FinalizerTest keepLive = wimp.get();
+        System.out.println("wimp: " + wimpString(wimp));
+    }
+
     public static void main(String[] args) {
         WeakReference<FinalizerTest> wimp = makeRef();
-
-        System.out.println("wimp: " + wimpString(wimp));
+        printWeakReference(wimp);
 
         /* this will try to collect and finalize ft */
         System.out.println("gc");
diff --git a/test/056-const-string-jumbo/build b/test/056-const-string-jumbo/build
index ef286d1..ae42519 100644
--- a/test/056-const-string-jumbo/build
+++ b/test/056-const-string-jumbo/build
@@ -39,8 +39,13 @@
     printf("}\n") > fileName;
 }'
 
-mkdir classes
-${JAVAC} -d classes src/*.java
+if [ ${USE_JACK} = "true" ]; then
+  ${JACK} --output-dex . src
+else
+  mkdir classes
+  ${JAVAC} -d classes src/*.java
 
-${DX} -JXmx500m --debug --dex --no-optimize --positions=none --no-locals --output=classes.dex classes
+  ${DX} -JXmx500m --debug --dex --no-optimize --positions=none --no-locals --output=classes.dex classes
+fi
+
 zip $TEST_NAME.jar classes.dex
diff --git a/test/074-gc-thrash/src/Main.java b/test/074-gc-thrash/src/Main.java
index 238e73a..f947d0b 100644
--- a/test/074-gc-thrash/src/Main.java
+++ b/test/074-gc-thrash/src/Main.java
@@ -218,17 +218,7 @@
             return;
         }
 
-        /*
-         * Check the results of the last trip through.  Everything in
-         * "weak" should be matched in "strong", and the two should be
-         * equivalent (object-wise, not just string-equality-wise).
-         */
-        for (int i = 0; i < MAX_DEPTH; i++) {
-            if (strong[i] != weak[i].get()) {
-                System.err.println("Deep: " + i + " strong=" + strong[i] +
-                    ", weak=" + weak[i].get());
-            }
-        }
+        checkStringReferences();
 
         /*
          * Wipe "strong", do a GC, see if "weak" got collected.
@@ -248,6 +238,26 @@
             System.out.println("Deep: iters=" + iter / MAX_DEPTH);
     }
 
+
+    /**
+     * Check the results of the last trip through.  Everything in
+     * "weak" should be matched in "strong", and the two should be
+     * equivalent (object-wise, not just string-equality-wise).
+     *
+     * We do that check in a separate method to avoid retaining these
+     * String references in local DEX registers. In interpreter mode,
+     * they would retain these references until the end of the method
+     * or until they are updated to another value.
+     */
+    private static void checkStringReferences() {
+      for (int i = 0; i < MAX_DEPTH; i++) {
+          if (strong[i] != weak[i].get()) {
+              System.err.println("Deep: " + i + " strong=" + strong[i] +
+                  ", weak=" + weak[i].get());
+          }
+      }
+    }
+
     /**
      * Recursively dive down, setting one or more local variables.
      *
diff --git a/test/082-inline-execute/src/Main.java b/test/082-inline-execute/src/Main.java
index 4dfa73c..177c5a4 100644
--- a/test/082-inline-execute/src/Main.java
+++ b/test/082-inline-execute/src/Main.java
@@ -1000,6 +1000,45 @@
     Assert.assertEquals(Long.reverse(0x8765432187654321L), 0x84c2a6e184c2a6e1L);
     Assert.assertEquals(Long.reverse(Long.MAX_VALUE), 0xfffffffffffffffeL);
     Assert.assertEquals(Long.reverse(Long.MIN_VALUE), 1L);
+
+    Assert.assertEquals(test_Long_reverse_b22324327(0xaaaaaaaaaaaaaaaaL, 0x5555555555555555L),
+            157472205507277347L);
+  }
+
+  // A bit more complicated than the above. Use local variables to stress register allocation.
+  private static long test_Long_reverse_b22324327(long l1, long l2) {
+    // A couple of local integers. Use them in a loop, so they get promoted.
+    int i1 = 0, i2 = 1, i3 = 2, i4 = 3, i5 = 4, i6 = 5, i7 = 6, i8 = 7;
+    for (int k = 0; k < 10; k++) {
+      i1 += 1;
+      i2 += 2;
+      i3 += 3;
+      i4 += 4;
+      i5 += 5;
+      i6 += 6;
+      i7 += 7;
+      i8 += 8;
+    }
+
+    // Do the Long.reverse() calls, save the results.
+    long r1 = Long.reverse(l1);
+    long r2 = Long.reverse(l2);
+
+    // Some more looping with the ints.
+    for (int k = 0; k < 10; k++) {
+      i1 += 1;
+      i2 += 2;
+      i3 += 3;
+      i4 += 4;
+      i5 += 5;
+      i6 += 6;
+      i7 += 7;
+      i8 += 8;
+    }
+
+    // Include everything in the result, so things are kept live. Try to be a little bit clever to
+    // avoid things being folded somewhere.
+    return (r1 / i1) + (r2 / i2) + i3 + i4 + i5 + i6 + i7 + i8;
   }
 
   static Object runtime;
diff --git a/test/085-old-style-inner-class/build b/test/085-old-style-inner-class/build
index 963d6b3..6f50a76 100644
--- a/test/085-old-style-inner-class/build
+++ b/test/085-old-style-inner-class/build
@@ -22,7 +22,12 @@
 mkdir classes
 ${JAVAC} -source 1.4 -target 1.4 -d classes `find src -name '*.java'`
 
-# Suppress stderr to keep the inner class warnings out of the expected output.
-${DX} --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes 2>/dev/null
+if [ ${USE_JACK} = "true" ]; then
+  ${JILL} classes --output classes.jack
+  ${JACK} --import classes.jack --output-dex .
+else
+  # Suppress stderr to keep the inner class warnings out of the expected output.
+  ${DX} --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes 2>/dev/null
+fi
 
 zip $TEST_NAME.jar classes.dex
diff --git a/test/089-many-methods/build b/test/089-many-methods/build
index 7ede759..ff77c60 100644
--- a/test/089-many-methods/build
+++ b/test/089-many-methods/build
@@ -43,7 +43,8 @@
     printf("}\n") > fileName;
 }'
 
+# The test relies on the error message produced by dx, not jack, so keep building with dx for now
+# (b/19467889).
 mkdir classes
 ${JAVAC} -d classes `find src -name '*.java'`
 ${DX} -JXmx1024m --dex --no-optimize classes
-
diff --git a/test/097-duplicate-method/build b/test/097-duplicate-method/build
index 6576779..a855873 100644
--- a/test/097-duplicate-method/build
+++ b/test/097-duplicate-method/build
@@ -18,8 +18,19 @@
 set -e
 
 mkdir classes
-${JAVAC} -d classes src/*.java
-${JASMIN} -d classes src/*.j
 
-${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+if [ ${USE_JACK} = "true" ]; then
+  ${JACK} --output-jack src.jack src
+
+  ${JASMIN} -d classes src/*.j
+  ${JILL} classes --output jasmin.jack
+
+  # We set jack.import.type.policy=keep-first to consider class definitions from jasmin first.
+  ${JACK} --import jasmin.jack --import src.jack -D jack.import.type.policy=keep-first --output-dex .
+else
+  ${JAVAC} -d classes src/*.java
+  ${JASMIN} -d classes src/*.j
+
+  ${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+fi
 zip $TEST_NAME.jar classes.dex
diff --git a/test/111-unresolvable-exception/build b/test/111-unresolvable-exception/build
index c21a9ef..e772fb8 100644
--- a/test/111-unresolvable-exception/build
+++ b/test/111-unresolvable-exception/build
@@ -21,5 +21,10 @@
 ${JAVAC} -d classes `find src -name '*.java'`
 rm classes/TestException.class
 
-${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+if [ ${USE_JACK} = "true" ]; then
+  ${JILL} classes --output classes.jack
+  ${JACK} --import classes.jack --output-dex .
+else
+  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+fi
 zip $TEST_NAME.jar classes.dex
diff --git a/test/113-multidex/build b/test/113-multidex/build
index ec8706e..8ef5c0e 100644
--- a/test/113-multidex/build
+++ b/test/113-multidex/build
@@ -17,16 +17,32 @@
 # Stop if something fails.
 set -e
 
-mkdir classes
-
 # All except Main
+mkdir classes
 ${JAVAC} -d classes `find src -name '*.java'`
 rm classes/Main.class
-${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
 
 # Only Main
-${JAVAC} -d classes `find src -name '*.java'`
-rm classes/Second.class classes/FillerA.class classes/FillerB.class classes/Inf*.class
-${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes
+mkdir classes2
+${JAVAC} -d classes2 `find src -name '*.java'`
+rm classes2/Second.class classes2/FillerA.class classes2/FillerB.class classes2/Inf*.class
 
+if [ ${USE_JACK} = "true" ]; then
+  # Create .jack files from classes generated with javac.
+  ${JILL} classes --output classes.jack
+  ${JILL} classes2 --output classes2.jack
+
+  # Create DEX files from .jack files.
+  ${JACK} --import classes.jack --output-dex .
+  mv classes.dex classes-1.dex
+  ${JACK} --import classes2.jack --output-dex .
+  mv classes.dex classes2.dex
+  mv classes-1.dex classes.dex
+else
+  # All except Main
+  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+
+  # Only Main
+  ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes2
+fi
 zip $TEST_NAME.jar classes.dex classes2.dex
diff --git a/test/114-ParallelGC/src/Main.java b/test/114-ParallelGC/src/Main.java
index 46029cf..159dd5c 100644
--- a/test/114-ParallelGC/src/Main.java
+++ b/test/114-ParallelGC/src/Main.java
@@ -53,20 +53,21 @@
         }
 
         // Allocate objects to definitely run GC before quitting.
-        ArrayList<Object> l = new ArrayList<Object>();
-        try {
-            for (int i = 0; i < 100000; i++) {
-                l.add(new ArrayList<Object>(i));
-            }
-        } catch (OutOfMemoryError oom) {
-        }
-        // Make the (outer) ArrayList unreachable. Note it may still
-        // be reachable under an interpreter or a compiler without a
-        // liveness analysis.
-        l = null;
+        allocateObjectsToRunGc();
+
         new ArrayList<Object>(50);
     }
 
+    private static void allocateObjectsToRunGc() {
+      ArrayList<Object> l = new ArrayList<Object>();
+      try {
+          for (int i = 0; i < 100000; i++) {
+              l.add(new ArrayList<Object>(i));
+          }
+      } catch (OutOfMemoryError oom) {
+      }
+    }
+
     private Main(CyclicBarrier startBarrier) {
         this.startBarrier = startBarrier;
     }
diff --git a/test/121-modifiers/build b/test/121-modifiers/build
index d73be86..85b69e9 100644
--- a/test/121-modifiers/build
+++ b/test/121-modifiers/build
@@ -30,5 +30,11 @@
 # mv NonInf.out classes/NonInf.class
 # mv Main.class A.class A\$B.class A\$C.class classes/
 
-${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+if [ ${USE_JACK} = "true" ]; then
+  ${JILL} classes --output classes.jack
+  # Workaround b/19561685: disable sanity checks to produce a DEX file with invalid modifiers.
+  ${JACK} --sanity-checks off --import classes.jack --output-dex .
+else
+  ${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+fi
 zip $TEST_NAME.jar classes.dex
diff --git a/test/124-missing-classes/build b/test/124-missing-classes/build
index 62e57c8..b92ecf9 100644
--- a/test/124-missing-classes/build
+++ b/test/124-missing-classes/build
@@ -25,4 +25,11 @@
 # ...but not at run time.
 rm 'classes/MissingClass.class'
 rm 'classes/Main$MissingInnerClass.class'
-${DX} -JXmx256m --debug --dex --output=$TEST_NAME.jar classes
+
+if [ ${USE_JACK} = "true" ]; then
+  ${JILL} classes --output classes.jack
+  ${JACK} --import classes.jack --output-dex .
+else
+  ${DX} -JXmx256m --debug --dex --output=classes.dex classes
+fi
+zip $TEST_NAME.jar classes.dex
diff --git a/test/126-miranda-multidex/build b/test/126-miranda-multidex/build
index 4c30f3f..b7f2118 100644
--- a/test/126-miranda-multidex/build
+++ b/test/126-miranda-multidex/build
@@ -17,16 +17,32 @@
 # Stop if something fails.
 set -e
 
+# All except MirandaInterface
 mkdir classes
-
-# All except Main
 ${JAVAC} -d classes `find src -name '*.java'`
 rm classes/MirandaInterface.class
-${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
 
-# Only Main
-${JAVAC} -d classes `find src -name '*.java'`
-rm classes/Main.class classes/MirandaAbstract.class classes/MirandaClass*.class classes/MirandaInterface2*.class
-${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes
+# Only MirandaInterface
+mkdir classes2
+${JAVAC} -d classes2 `find src -name '*.java'`
+rm classes2/Main.class classes2/MirandaAbstract.class classes2/MirandaClass*.class classes2/MirandaInterface2*.class
 
+if [ ${USE_JACK} = "true" ]; then
+  # Create .jack files from classes generated with javac.
+  ${JILL} classes --output classes.jack
+  ${JILL} classes2 --output classes2.jack
+
+  # Create DEX files from .jack files.
+  ${JACK} --import classes.jack --output-dex .
+  mv classes.dex classes-1.dex
+  ${JACK} --import classes2.jack --output-dex .
+  mv classes.dex classes2.dex
+  mv classes-1.dex classes.dex
+else
+  # All except Main
+  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+
+  # Only Main
+  ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes2
+fi
 zip $TEST_NAME.jar classes.dex classes2.dex
diff --git a/test/127-secondarydex/build b/test/127-secondarydex/build
index 712774f..0d9f4d6 100755
--- a/test/127-secondarydex/build
+++ b/test/127-secondarydex/build
@@ -23,9 +23,21 @@
 mkdir classes-ex
 mv classes/Super.class classes-ex
 
-if [ ${NEED_DEX} = "true" ]; then
-  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
+if [ ${USE_JACK} = "true" ]; then
+  # Create .jack files from classes generated with javac.
+  ${JILL} classes --output classes.jack
+  ${JILL} classes-ex --output classes-ex.jack
+
+  # Create DEX files from .jack files.
+  ${JACK} --import classes.jack --output-dex .
   zip $TEST_NAME.jar classes.dex
-  ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+  ${JACK} --import classes-ex.jack --output-dex .
   zip ${TEST_NAME}-ex.jar classes.dex
+else
+  if [ ${NEED_DEX} = "true" ]; then
+    ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
+    zip $TEST_NAME.jar classes.dex
+    ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+    zip ${TEST_NAME}-ex.jar classes.dex
+  fi
 fi
diff --git a/test/131-structural-change/build b/test/131-structural-change/build
index 7ddc81d..ff0da20 100755
--- a/test/131-structural-change/build
+++ b/test/131-structural-change/build
@@ -17,15 +17,23 @@
 # Stop if something fails.
 set -e
 
-mkdir classes
-${JAVAC} -d classes `find src -name '*.java'`
-
-mkdir classes-ex
-${JAVAC} -d classes-ex `find src-ex -name '*.java'`
-
-if [ ${NEED_DEX} = "true" ]; then
-  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
+if [ ${USE_JACK} = "true" ]; then
+  ${JACK} --output-dex . src
   zip $TEST_NAME.jar classes.dex
-  ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+
+  ${JACK} --output-dex . src-ex
   zip ${TEST_NAME}-ex.jar classes.dex
+else
+  mkdir classes
+  ${JAVAC} -d classes `find src -name '*.java'`
+
+  mkdir classes-ex
+  ${JAVAC} -d classes-ex `find src-ex -name '*.java'`
+
+  if [ ${NEED_DEX} = "true" ]; then
+    ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
+    zip $TEST_NAME.jar classes.dex
+    ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+    zip ${TEST_NAME}-ex.jar classes.dex
+  fi
 fi
diff --git a/test/303-verification-stress/build b/test/303-verification-stress/build
index 789d38e..9d19809 100644
--- a/test/303-verification-stress/build
+++ b/test/303-verification-stress/build
@@ -21,8 +21,14 @@
 gcc -Wall -Werror -o classes-gen classes-gen.c
 ./classes-gen
 
-mkdir classes
-${JAVAC} -d classes src/*.java
+if [ ${USE_JACK} = "true" ]; then
+  ${JACK} --output-dex . src
+else
+  mkdir classes
+  ${JAVAC} -d classes src/*.java
 
-${DX} --debug --dex --output=classes.dex classes
+  # dx needs more memory for that test so do not pass Xmx option here.
+  ${DX} --debug --dex --output=classes.dex classes
+fi
+
 zip $TEST_NAME.jar classes.dex
diff --git a/test/454-get-vreg/build b/test/454-get-vreg/build
new file mode 100644
index 0000000..08987b5
--- /dev/null
+++ b/test/454-get-vreg/build
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+# Copyright (C) 2015 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.
+
+# Stop if something fails.
+set -e
+
+# The test relies on DEX file produced by javac+dx so keep building with them for now
+# (see b/19467889)
+mkdir classes
+${JAVAC} -d classes `find src -name '*.java'`
+${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
+  --dump-width=1000 ${DX_FLAGS} classes
+zip $TEST_NAME.jar classes.dex
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index 2196a88..659f104 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -23,4 +23,8 @@
 b/21886894
 b/22080519
 b/21645819
+b/22244733
+b/22331663
+b/22331663 (pass)
+b/22331663 (fail)
 Done!
diff --git a/test/800-smali/smali/b_22244733.smali b/test/800-smali/smali/b_22244733.smali
new file mode 100644
index 0000000..1b62ad9
--- /dev/null
+++ b/test/800-smali/smali/b_22244733.smali
@@ -0,0 +1,7 @@
+.class public LB22244733;
+.super Ljava/lang/Object;
+
+.method public static run(Ljava/lang/String;)Ljava/lang/String;
+.registers 2             # One local and one parameter.
+       return-object p0  # Simple return, use the special-method path in Quick.
+.end method
diff --git a/test/800-smali/smali/b_22331663.smali b/test/800-smali/smali/b_22331663.smali
new file mode 100644
index 0000000..057fc7f
--- /dev/null
+++ b/test/800-smali/smali/b_22331663.smali
@@ -0,0 +1,38 @@
+.class public LB22331663;
+.super Ljava/lang/Object;
+
+
+.method public static run(Z)V
+.registers 6
+       # Make v4 defined, just use null.
+       const v4, 0
+
+       if-eqz v5, :Label2
+
+:Label1
+       # Construct a java.lang.Object completely, and throw a new exception.
+       new-instance v4, Ljava/lang/Object;
+       invoke-direct {v4}, Ljava/lang/Object;-><init>()V
+
+       new-instance v3, Ljava/lang/RuntimeException;
+       invoke-direct {v3}, Ljava/lang/RuntimeException;-><init>()V
+       throw v3
+
+:Label2
+       # Allocate a java.lang.Object (do not initialize), and throw a new exception.
+       new-instance v4, Ljava/lang/Object;
+
+       new-instance v3, Ljava/lang/RuntimeException;
+       invoke-direct {v3}, Ljava/lang/RuntimeException;-><init>()V
+       throw v3
+
+:Label3
+       # Catch handler. Here we had to merge the uninitialized with the initialized reference,
+       # which creates a conflict. Copy the conflict, and then return. This should not make the
+       # verifier fail the method.
+       move-object v0, v4
+
+       return-void
+
+.catchall {:Label1 .. :Label3} :Label3
+.end method
diff --git a/test/800-smali/smali/b_22331663_fail.smali b/test/800-smali/smali/b_22331663_fail.smali
new file mode 100644
index 0000000..0c25e30
--- /dev/null
+++ b/test/800-smali/smali/b_22331663_fail.smali
@@ -0,0 +1,20 @@
+.class public LB22331663Fail;
+.super Ljava/lang/Object;
+
+
+.method public static run(Z)V
+.registers 6
+       if-eqz v5, :Label1
+
+       # Construct a java.lang.Object completely. This makes v4 of reference type.
+       new-instance v4, Ljava/lang/Object;
+       invoke-direct {v4}, Ljava/lang/Object;-><init>()V
+
+:Label1
+       # At this point, v4 is the merge of Undefined and ReferenceType. The verifier should
+       # reject any use of this, even a copy. Previously this was a conflict. Conflicts must
+       # be movable now, so ensure that we do not get a conflict (and then allow the move).
+       move-object v0, v4
+
+       return-void
+.end method
diff --git a/test/800-smali/smali/b_22331663_pass.smali b/test/800-smali/smali/b_22331663_pass.smali
new file mode 100644
index 0000000..1b54180
--- /dev/null
+++ b/test/800-smali/smali/b_22331663_pass.smali
@@ -0,0 +1,22 @@
+.class public LB22331663Pass;
+.super Ljava/lang/Object;
+
+
+.method public static run(Z)V
+.registers 6
+       if-eqz v5, :Label1
+
+       # Construct a java.lang.Object completely. This makes v4 of reference type.
+       new-instance v4, Ljava/lang/Object;
+       invoke-direct {v4}, Ljava/lang/Object;-><init>()V
+
+:Label1
+       # At this point, v4 is the merge of Undefined and ReferenceType. The verifier should not
+       # reject this if it is unused.
+
+       # Do an allocation here. This will force heap checking in gcstress mode.
+       new-instance v0, Ljava/lang/Object;
+       invoke-direct {v0}, Ljava/lang/Object;-><init>()V
+
+       return-void
+.end method
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index e6f065e..709c7f6 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -93,6 +93,14 @@
                 new NullPointerException(), null));
         testCases.add(new TestCase("b/21645819", "B21645819", "run", new Object[] { null },
                 null, null));
+        testCases.add(new TestCase("b/22244733", "B22244733", "run", new Object[] { "abc" },
+                null, "abc"));
+        testCases.add(new TestCase("b/22331663", "B22331663", "run", new Object[] { false },
+                null, null));
+        testCases.add(new TestCase("b/22331663 (pass)", "B22331663Pass", "run",
+                new Object[] { false }, null, null));
+        testCases.add(new TestCase("b/22331663 (fail)", "B22331663Fail", "run",
+                new Object[] { false }, new VerifyError(), null));
     }
 
     public void runTests() {
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index b043d46..b1edc3b 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -32,20 +32,47 @@
 # an empty file touched in the intermediate directory.
 TEST_ART_RUN_TEST_BUILD_RULES :=
 
+# Dependencies for actually running a run-test.
+TEST_ART_RUN_TEST_DEPENDENCIES := \
+  $(DX) \
+  $(HOST_OUT_EXECUTABLES)/jasmin \
+  $(HOST_OUT_EXECUTABLES)/smali \
+  $(HOST_OUT_EXECUTABLES)/dexmerger
+
+ifeq ($(ANDROID_COMPILE_WITH_JACK),true)
+  TEST_ART_RUN_TEST_DEPENDENCIES += \
+    $(JACK_JAR) \
+    $(JACK_LAUNCHER_JAR) \
+    $(JILL_JAR)
+endif
+
 # Helper to create individual build targets for tests. Must be called with $(eval).
 # $(1): the test number
 define define-build-art-run-test
   dmart_target := $(art_run_tests_dir)/art-run-tests/$(1)/touch
-$$(dmart_target): $(DX) $(HOST_OUT_EXECUTABLES)/jasmin $(HOST_OUT_EXECUTABLES)/smali $(HOST_OUT_EXECUTABLES)/dexmerger
+  run_test_options = --build-only
+  ifeq ($(ANDROID_COMPILE_WITH_JACK),true)
+    run_test_options += --build-with-jack
+  else
+    run_test_options += --build-with-javac-dx
+  endif
+$$(dmart_target): PRIVATE_RUN_TEST_OPTIONS := $$(run_test_options)
+$$(dmart_target): $(TEST_ART_RUN_TEST_DEPENDENCIES)
 	$(hide) rm -rf $$(dir $$@) && mkdir -p $$(dir $$@)
 	$(hide) DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) \
 	  SMALI=$(abspath $(HOST_OUT_EXECUTABLES)/smali) \
 	  DXMERGER=$(abspath $(HOST_OUT_EXECUTABLES)/dexmerger) \
-	  $(LOCAL_PATH)/run-test --build-only --output-path $$(abspath $$(dir $$@)) $(1)
+	  JACK=$(abspath $(JACK)) \
+	  JACK_VM_COMMAND="$(JACK_VM) $(DEFAULT_JACK_VM_ARGS) $(JAVA_TMPDIR_ARG) -jar $(abspath $(JACK_LAUNCHER_JAR)) " \
+	  JACK_CLASSPATH=$(TARGET_JACK_CLASSPATH) \
+	  JACK_JAR=$(abspath $(JACK_JAR)) \
+	  JILL_JAR=$(abspath $(JILL_JAR)) \
+	  $(LOCAL_PATH)/run-test $$(PRIVATE_RUN_TEST_OPTIONS) --output-path $$(abspath $$(dir $$@)) $(1)
 	$(hide) touch $$@
 
   TEST_ART_RUN_TEST_BUILD_RULES += $$(dmart_target)
   dmart_target :=
+  run_test_options :=
 endef
 $(foreach test, $(TEST_ART_RUN_TESTS), $(eval $(call define-build-art-run-test,$(test))))
 
@@ -590,6 +617,12 @@
   prereq_rule :=
   test_groups :=
   uc_host_or_target :=
+  jack_classpath :=
+  ifeq ($(ANDROID_COMPILE_WITH_JACK),true)
+    run_test_options += --build-with-jack
+  else
+    run_test_options += --build-with-javac-dx
+  endif
   ifeq ($(ART_TEST_RUN_TEST_ALWAYS_CLEAN),true)
     run_test_options += --always-clean
   endif
@@ -598,11 +631,13 @@
     test_groups := ART_RUN_TEST_HOST_RULES
     run_test_options += --host
     prereq_rule := $(ART_TEST_HOST_RUN_TEST_DEPENDENCIES)
+    jack_classpath := $(HOST_JACK_CLASSPATH)
   else
     ifeq ($(1),target)
       uc_host_or_target := TARGET
       test_groups := ART_RUN_TEST_TARGET_RULES
       prereq_rule := test-art-target-sync
+      jack_classpath := $(TARGET_JACK_CLASSPATH)
     else
       $$(error found $(1) expected $(TARGET_TYPES))
     endif
@@ -797,12 +832,19 @@
     run_test_options := --android-root $(ART_TEST_ANDROID_ROOT) $$(run_test_options)
   endif
 $$(run_test_rule_name): PRIVATE_RUN_TEST_OPTIONS := $$(run_test_options)
+$$(run_test_rule_name): PRIVATE_JACK_CLASSPATH := $$(jack_classpath)
 .PHONY: $$(run_test_rule_name)
-$$(run_test_rule_name): $(DX) $(HOST_OUT_EXECUTABLES)/jasmin $(HOST_OUT_EXECUTABLES)/smali $(HOST_OUT_EXECUTABLES)/dexmerger $(HOST_OUT_EXECUTABLES)/hprof-conv $$(prereq_rule)
+$$(run_test_rule_name): $(TEST_ART_RUN_TEST_DEPENDENCIES) $(HOST_OUT_EXECUTABLES)/hprof-conv $$(prereq_rule)
 	$(hide) $$(call ART_TEST_SKIP,$$@) && \
-	  DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) \
+	  DX=$(abspath $(DX)) \
+	    JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) \
 	    SMALI=$(abspath $(HOST_OUT_EXECUTABLES)/smali) \
 	    DXMERGER=$(abspath $(HOST_OUT_EXECUTABLES)/dexmerger) \
+	    JACK=$(abspath $(JACK)) \
+	    JACK_VM_COMMAND="$(JACK_VM) $(DEFAULT_JACK_VM_ARGS) $(JAVA_TMPDIR_ARG) -jar $(abspath $(JACK_LAUNCHER_JAR)) " \
+	    JACK_CLASSPATH=$$(PRIVATE_JACK_CLASSPATH) \
+	    JACK_JAR=$(abspath $(JACK_JAR)) \
+	    JILL_JAR=$(abspath $(JILL_JAR)) \
 	    art/test/run-test $$(PRIVATE_RUN_TEST_OPTIONS) $(12) \
 	      && $$(call ART_TEST_PASSED,$$@) || $$(call ART_TEST_FAILED,$$@)
 	$$(hide) (echo $(MAKECMDGOALS) | grep -q $$@ && \
@@ -817,6 +859,7 @@
   run_test_options :=
   run_test_rule_name :=
   prereq_rule :=
+  jack_classpath :=
 endef  # define-test-art-run-test
 
 $(foreach target, $(TARGET_TYPES), \
diff --git a/test/etc/default-build b/test/etc/default-build
index fbe97f9..7995bd5 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -38,16 +38,52 @@
   exit 0
 fi
 
-mkdir classes
-${JAVAC} -implicit:none -classpath src-multidex -d classes `find src -name '*.java'`
-
-if [ -d src2 ]; then
-  ${JAVAC} -d classes `find src2 -name '*.java'`
+if [ -d src-multidex ]; then
+  # Jack does not support this configuration unless we specify how to partition the DEX file
+  # with a .jpp file.
+  USE_JACK="false"
 fi
 
-if [ ${NEED_DEX} = "true" ]; then
-  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
-    --dump-width=1000 ${DX_FLAGS} classes
+if [ ${USE_JACK} = "true" ]; then
+  # Jack toolchain
+  if [ -d src ]; then
+    ${JACK} --output-jack src.jack src
+    imported_jack_files="--import src.jack"
+  fi
+
+  if [ -d src2 ]; then
+    ${JACK} --output-jack src2.jack src2
+    imported_jack_files="--import src2.jack ${imported_jack_files}"
+  fi
+
+  # Compile jack files into a DEX file. We set jack.import.type.policy=keep-first to consider
+  # class definitions from src2 first.
+  ${JACK} ${imported_jack_files} -D jack.import.type.policy=keep-first --output-dex .
+else
+  # Legacy toolchain with javac+dx
+  if [ -d src ]; then
+    mkdir classes
+    ${JAVAC} -implicit:none -classpath src-multidex -d classes `find src -name '*.java'`
+  fi
+
+  if [ -d src-multidex ]; then
+    mkdir classes2
+    ${JAVAC} -implicit:none -classpath src -d classes2 `find src-multidex -name '*.java'`
+    if [ ${NEED_DEX} = "true" ]; then
+      ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex \
+        --dump-width=1000 ${DX_FLAGS} classes2
+    fi
+  fi
+
+  if [ -d src2 ]; then
+    mkdir -p classes
+    ${JAVAC} -d classes `find src2 -name '*.java'`
+  fi
+
+  if [ ${NEED_DEX} = "true" ]; then
+    ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
+      --dump-width=1000 ${DX_FLAGS} classes
+  fi
 fi
 
 if [ -d smali ]; then
@@ -57,30 +93,34 @@
 fi
 
 if [ -d src-ex ]; then
-  mkdir classes-ex
-  ${JAVAC} -d classes-ex -cp classes `find src-ex -name '*.java'`
-  if [ ${NEED_DEX} = "true" ]; then
-    ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes-ex.dex \
-      --dump-width=1000 ${DX_FLAGS} classes-ex
+  if [ ${USE_JACK} = "true" ]; then
+      # Rename previous "classes.dex" so it is not overwritten.
+      mv classes.dex classes-1.dex
+      #TODO find another way to append src.jack to the jack classpath
+      ${JACK}:src.jack --output-dex . src-ex
+      zip $TEST_NAME-ex.jar classes.dex
+      # Restore previous "classes.dex" so it can be zipped.
+      mv classes-1.dex classes.dex
+  else
+    mkdir classes-ex
+    ${JAVAC} -d classes-ex -cp classes `find src-ex -name '*.java'`
+    if [ ${NEED_DEX} = "true" ]; then
+      ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes-ex.dex \
+        --dump-width=1000 ${DX_FLAGS} classes-ex
 
-    # quick shuffle so that the stored name is "classes.dex"
-    mv classes.dex classes-1.dex
-    mv classes-ex.dex classes.dex
-    zip $TEST_NAME-ex.jar classes.dex
-    mv classes.dex classes-ex.dex
-    mv classes-1.dex classes.dex
+      # quick shuffle so that the stored name is "classes.dex"
+      mv classes.dex classes-1.dex
+      mv classes-ex.dex classes.dex
+      zip $TEST_NAME-ex.jar classes.dex
+      mv classes.dex classes-ex.dex
+      mv classes-1.dex classes.dex
+    fi
   fi
 fi
 
 # Create a single jar with two dex files for multidex.
 if [ -d src-multidex ]; then
-  mkdir classes2
-  ${JAVAC} -implicit:none -classpath src -d classes2 `find src-multidex -name '*.java'`
-  if [ ${NEED_DEX} = "true" ]; then
-    ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex \
-      --dump-width=1000 ${DX_FLAGS} classes2
-    zip $TEST_NAME.jar classes.dex classes2.dex
-  fi
+  zip $TEST_NAME.jar classes.dex classes2.dex
 elif [ ${NEED_DEX} = "true" ]; then
   zip $TEST_NAME.jar classes.dex
 fi
diff --git a/test/run-test b/test/run-test
index 3f17861..8410387 100755
--- a/test/run-test
+++ b/test/run-test
@@ -46,6 +46,7 @@
 export RUN="${progdir}/etc/run-test-jar"
 export DEX_LOCATION=/data/run-test/${test_dir}
 export NEED_DEX="true"
+export USE_JACK="false"
 
 # If dx was not set by the environment variable, assume it is in the path.
 if [ -z "$DX" ]; then
@@ -67,6 +68,46 @@
   export DXMERGER="dexmerger"
 fi
 
+# If jack was not set by the environment variable, assume it is in the path.
+if [ -z "$JACK" ]; then
+  export JACK="jack"
+fi
+
+# If the tree is compiled with Jack, build test with Jack by default.
+if [ "$ANDROID_COMPILE_WITH_JACK" = "true" ]; then
+  USE_JACK="true"
+fi
+
+# ANDROID_BUILD_TOP is not set in a build environment.
+if [ -z "$ANDROID_BUILD_TOP" ]; then
+    export ANDROID_BUILD_TOP=$oldwd
+fi
+
+# If JACK_VM_COMMAND is not set, assume it launches the prebuilt jack-launcher.
+if [ -z "$JACK_VM_COMMAND" ]; then
+  if [ ! -z "$TMPDIR" ]; then
+    jack_temp_dir="-Djava.io.tmpdir=$TMPDIR"
+  fi
+  export JACK_VM_COMMAND="java -Dfile.encoding=UTF-8 -Xms2560m -XX:+TieredCompilation $jack_temp_dir -jar $ANDROID_BUILD_TOP/prebuilts/sdk/tools/jack-launcher.jar"
+fi
+
+# If JACK_CLASSPATH is not set, assume it only contains core-libart.
+if [ -z "$JACK_CLASSPATH" ]; then
+  export JACK_CLASSPATH="$ANDROID_BUILD_TOP/out/host/common/obj/JAVA_LIBRARIES/core-libart-hostdex_intermediates/classes.jack"
+fi
+
+# If JACK_JAR is not set, assume it is located in the prebuilts directory.
+if [ -z "$JACK_JAR" ]; then
+  export JACK_JAR="$ANDROID_BUILD_TOP/prebuilts/sdk/tools/jack.jar"
+fi
+
+# If JILL_JAR is not set, assume it is located in the prebuilts directory.
+if [ -z "$JILL_JAR" ]; then
+  export JILL_JAR="$ANDROID_BUILD_TOP/prebuilts/sdk/tools/jill.jar"
+fi
+
+export JACK="$JACK -g -cp $JACK_CLASSPATH"
+export JILL="java -jar $JILL_JAR"
 
 info="info.txt"
 build="build"
@@ -115,6 +156,7 @@
         runtime="jvm"
         prebuild_mode="no"
         NEED_DEX="false"
+        USE_JACK="false"
         run_args="${run_args} --jvm"
         shift
     elif [ "x$1" = "x-O" ]; then
@@ -236,6 +278,12 @@
     elif [ "x$1" = "x--build-only" ]; then
         build_only="yes"
         shift
+    elif [ "x$1" = "x--build-with-javac-dx" ]; then
+        USE_JACK="false"
+        shift
+    elif [ "x$1" = "x--build-with-jack" ]; then
+        USE_JACK="true"
+        shift
     elif [ "x$1" = "x--output-path" ]; then
         shift
         tmp_dir=$1
@@ -365,10 +413,7 @@
     fi
 elif [ "$runtime" = "art" ]; then
     if [ "$target_mode" = "no" ]; then
-        # ANDROID_BUILD_TOP and ANDROID_HOST_OUT are not set in a build environment.
-        if [ -z "$ANDROID_BUILD_TOP" ]; then
-            export ANDROID_BUILD_TOP=$oldwd
-        fi
+        # ANDROID_HOST_OUT is not set in a build environment.
         if [ -z "$ANDROID_HOST_OUT" ]; then
             export ANDROID_HOST_OUT=$ANDROID_BUILD_TOP/out/host/linux-x86
         fi
@@ -458,6 +503,8 @@
         echo "    --debuggable          Whether to compile Java code for a debugger."
         echo "    --gdb                 Run under gdb; incompatible with some tests."
         echo "    --build-only          Build test files only (off by default)."
+        echo "    --build-with-javac-dx Build test files with javac and dx (on by default)."
+        echo "    --build-with-jack     Build test files with jack and jill (off by default)."
         echo "    --interpreter         Enable interpreter only mode (off by default)."
         echo "    --jit                 Enable jit (off by default)."
         echo "    --optimizing          Enable optimizing compiler (default)."
@@ -545,6 +592,10 @@
   # if Checker is not invoked and the test only runs the program.
   build_args="${build_args} --dx-option --no-optimize"
 
+  # Jack does not necessarily generate the same DEX output than dx. Because these tests depend
+  # on a particular DEX output, keep building them with dx for now (b/19467889).
+  USE_JACK="false"
+
   if [ "$runtime" = "art" -a "$image_suffix" = "-optimizing" -a "$target_mode" = "no" -a "$debuggable" = "no" ]; then
     run_checker="yes"
     run_args="${run_args} -Xcompiler-option --dump-cfg=$tmp_dir/$cfg_output \
@@ -553,14 +604,20 @@
 fi
 
 # To cause tests to fail fast, limit the file sizes created by dx, dex2oat and ART output to 2MB.
-file_size_limit=2048
+build_file_size_limit=2048
+run_file_size_limit=2048
 if echo "$test_dir" | grep 089; then
-  file_size_limit=5120
+  build_file_size_limit=5120
+  run_file_size_limit=5120
 elif echo "$test_dir" | grep 083; then
-  file_size_limit=5120
+  build_file_size_limit=5120
+  run_file_size_limit=5120
 fi
-if ! ulimit -S "$file_size_limit"; then
-   echo "ulimit file size setting failed"
+if [ ${USE_JACK} = "false" ]; then
+  # Set ulimit if we build with dx only, Jack can generate big temp files.
+  if ! ulimit -S "$build_file_size_limit"; then
+    echo "ulimit file size setting failed"
+  fi
 fi
 
 good="no"
@@ -571,6 +628,9 @@
     build_exit="$?"
     echo "build exit status: $build_exit" 1>&2
     if [ "$build_exit" = '0' ]; then
+        if ! ulimit -S "$run_file_size_limit"; then
+          echo "ulimit file size setting failed"
+        fi
         echo "${test_dir}: running..." 1>&2
         "./${run}" $run_args "$@" 2>&1
         run_exit="$?"
@@ -593,6 +653,9 @@
     "./${build}" $build_args >"$build_output" 2>&1
     build_exit="$?"
     if [ "$build_exit" = '0' ]; then
+        if ! ulimit -S "$run_file_size_limit"; then
+          echo "ulimit file size setting failed"
+        fi
         echo "${test_dir}: running..." 1>&2
         "./${run}" $run_args "$@" >"$output" 2>&1
         if [ "$run_checker" = "yes" ]; then
@@ -624,6 +687,9 @@
     "./${build}" $build_args >"$build_output" 2>&1
     build_exit="$?"
     if [ "$build_exit" = '0' ]; then
+        if ! ulimit -S "$run_file_size_limit"; then
+          echo "ulimit file size setting failed"
+        fi
         echo "${test_dir}: running..." 1>&2
         "./${run}" $run_args "$@" >"$output" 2>&1
         run_exit="$?"
diff --git a/tools/symbolize.sh b/tools/symbolize.sh
index 7365a9b..f5686e6 100755
--- a/tools/symbolize.sh
+++ b/tools/symbolize.sh
@@ -22,6 +22,7 @@
 INTERACTIVE="no"
 if [ "x$1" = "x--interactive" ] ; then
   INTERACTIVE="yes"
+  shift
 fi
 
 # Pull the file from the device and symbolize it.
@@ -57,4 +58,15 @@
   done
 }
 
-all
+if [ "x$1" = "x" ] ; then
+  # No further arguments, iterate over all oat files on device.
+  all
+else
+  # Take the parameters as a list of paths on device.
+  while (($#)); do
+    DIR=$(dirname $1)
+    NAME=$(basename $1)
+    one $DIR $NAME
+    shift
+  done
+fi