Merge "Avoid handle-less methods in ClassLinker::LinkInterfaceMethods()."
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index d55f310..0dcefea 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -157,7 +157,8 @@
   -Wno-sign-promo \
   -Wno-unused-parameter \
   -Wstrict-aliasing \
-  -fstrict-aliasing
+  -fstrict-aliasing \
+  -fvisibility=protected
 
 ART_TARGET_CLANG_CFLAGS :=
 ART_TARGET_CLANG_CFLAGS_arm :=
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index de0e3bd..0579f9b 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -61,8 +61,8 @@
 # The elf writer test has dependencies on core.oat.
 ART_GTEST_elf_writer_test_HOST_DEPS := $(HOST_CORE_OAT_OUT) $(2ND_HOST_CORE_OAT_OUT)
 ART_GTEST_elf_writer_test_TARGET_DEPS := $(TARGET_CORE_OAT_OUT) $(2ND_TARGET_CORE_OAT_OUT)
-ART_GTEST_jni_internal_test_TARGET_DEPS := $(TARGET_CORE_JARS)
-ART_GTEST_proxy_test_TARGET_DEPS := $(TARGET_CORE_JARS)
+ART_GTEST_jni_internal_test_TARGET_DEPS := $(TARGET_CORE_DEX_FILES)
+ART_GTEST_proxy_test_TARGET_DEPS := $(TARGET_CORE_DEX_FILES)
 ART_GTEST_proxy_test_HOST_DEPS := $(HOST_CORE_OAT_OUT) $(2ND_HOST_CORE_OAT_OUT)
 
 # The path for which all the source files are relative, not actually the current directory.
diff --git a/compiler/dex/compiler_enums.h b/compiler/dex/compiler_enums.h
index dcc67c3..63f3e64 100644
--- a/compiler/dex/compiler_enums.h
+++ b/compiler/dex/compiler_enums.h
@@ -528,6 +528,7 @@
   kFixupLoad,        // Mostly for immediates.
   kFixupVLoad,       // FP load which *may* be pc-relative.
   kFixupCBxZ,        // Cbz, Cbnz.
+  kFixupTBxZ,        // Tbz, Tbnz.
   kFixupPushPop,     // Not really pc relative, but changes size based on args.
   kFixupCondBranch,  // Conditional branch
   kFixupT1Branch,    // Thumb1 Unconditional branch
diff --git a/compiler/dex/quick/arm64/arm64_lir.h b/compiler/dex/quick/arm64/arm64_lir.h
index a449cbd..d001dd6 100644
--- a/compiler/dex/quick/arm64/arm64_lir.h
+++ b/compiler/dex/quick/arm64/arm64_lir.h
@@ -116,6 +116,7 @@
 #define IS_SIGNED_IMM7(value) IS_SIGNED_IMM(7, value)
 #define IS_SIGNED_IMM9(value) IS_SIGNED_IMM(9, value)
 #define IS_SIGNED_IMM12(value) IS_SIGNED_IMM(12, value)
+#define IS_SIGNED_IMM14(value) IS_SIGNED_IMM(14, value)
 #define IS_SIGNED_IMM19(value) IS_SIGNED_IMM(19, value)
 #define IS_SIGNED_IMM21(value) IS_SIGNED_IMM(21, value)
 
@@ -355,7 +356,10 @@
   kA64Sub4rrro,      // sub [s1001011000] rm[20-16] imm_6[15-10] rn[9-5] rd[4-0].
   kA64Sub4RRre,      // sub [s1001011001] rm[20-16] option[15-13] imm_3[12-10] rn[9-5] rd[4-0].
   kA64Subs3rRd,      // subs[s111000100] imm_12[21-10] rn[9-5] rd[4-0].
+  kA64Tst2rl,        // tst alias of "ands rzr, rn, #imm".
   kA64Tst3rro,       // tst alias of "ands rzr, arg1, arg2, arg3".
+  kA64Tbnz3rht,      // tbnz imm_6_b5[31] [0110111] imm_6_b40[23-19] imm_14[18-5] rt[4-0].
+  kA64Tbz3rht,       // tbz imm_6_b5[31] [0110110] imm_6_b40[23-19] imm_14[18-5] rt[4-0].
   kA64Ubfm4rrdd,     // ubfm[s10100110] N[22] imm_r[21-16] imm_s[15-10] rn[9-5] rd[4-0].
   kA64Last,
   kA64NotWide = 0,   // Flag used to select the first instruction variant.
@@ -400,23 +404,24 @@
 enum ArmEncodingKind {
   // All the formats below are encoded in the same way (as a kFmtBitBlt).
   // These are grouped together, for fast handling (e.g. "if (LIKELY(fmt <= kFmtBitBlt)) ...").
-  kFmtRegW = 0,  // Word register (w) or wzr.
-  kFmtRegX,      // Extended word register (x) or xzr.
-  kFmtRegR,      // Register with same width as the instruction or zr.
-  kFmtRegWOrSp,  // Word register (w) or wsp.
-  kFmtRegXOrSp,  // Extended word register (x) or sp.
-  kFmtRegROrSp,  // Register with same width as the instruction or sp.
-  kFmtRegS,      // Single FP reg.
-  kFmtRegD,      // Double FP reg.
-  kFmtRegF,      // Single/double FP reg depending on the instruction width.
-  kFmtBitBlt,    // Bit string using end/start.
+  kFmtRegW = 0,   // Word register (w) or wzr.
+  kFmtRegX,       // Extended word register (x) or xzr.
+  kFmtRegR,       // Register with same width as the instruction or zr.
+  kFmtRegWOrSp,   // Word register (w) or wsp.
+  kFmtRegXOrSp,   // Extended word register (x) or sp.
+  kFmtRegROrSp,   // Register with same width as the instruction or sp.
+  kFmtRegS,       // Single FP reg.
+  kFmtRegD,       // Double FP reg.
+  kFmtRegF,       // Single/double FP reg depending on the instruction width.
+  kFmtBitBlt,     // Bit string using end/start.
 
   // Less likely formats.
-  kFmtUnused,    // Unused field and marks end of formats.
-  kFmtImm21,     // Sign-extended immediate using [23..5,30..29].
-  kFmtShift,     // Register shift, 9-bit at [23..21, 15..10]..
-  kFmtExtend,    // Register extend, 9-bit at [23..21, 15..10].
-  kFmtSkip,      // Unused field, but continue to next.
+  kFmtUnused,     // Unused field and marks end of formats.
+  kFmtImm6Shift,  // Shift immediate, 6-bit at [31, 23..19].
+  kFmtImm21,      // Sign-extended immediate using [23..5,30..29].
+  kFmtShift,      // Register shift, 9-bit at [23..21, 15..10]..
+  kFmtExtend,     // Register extend, 9-bit at [23..21, 15..10].
+  kFmtSkip,       // Unused field, but continue to next.
 };
 
 // Struct used to define the snippet positions for each A64 opcode.
diff --git a/compiler/dex/quick/arm64/assemble_arm64.cc b/compiler/dex/quick/arm64/assemble_arm64.cc
index 15c89f2..5115246 100644
--- a/compiler/dex/quick/arm64/assemble_arm64.cc
+++ b/compiler/dex/quick/arm64/assemble_arm64.cc
@@ -89,6 +89,7 @@
  *     M -> 16-bit shift expression ("" or ", lsl #16" or ", lsl #32"...)
  *     B -> dmb option string (sy, st, ish, ishst, nsh, hshst)
  *     H -> operand shift
+ *     h -> 6-bit shift immediate
  *     T -> register shift (either ", lsl #0" or ", lsl #12")
  *     e -> register extend (e.g. uxtb #1)
  *     o -> register shift (e.g. lsl #1) for Word registers
@@ -614,10 +615,24 @@
                  kFmtRegR, 4, 0, kFmtRegROrSp, 9, 5, kFmtBitBlt, 21, 10,
                  kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
                  "subs", "!0r, !1R, #!2d", kFixupNone),
-    ENCODING_MAP(WIDE(kA64Tst3rro), SF_VARIANTS(0x6a000000),
+    ENCODING_MAP(WIDE(kA64Tst2rl), SF_VARIANTS(0x7200001f),
+                 kFmtRegR, 9, 5, kFmtBitBlt, 22, 10, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE0 | SETS_CCODES,
+                 "tst", "!0r, !1l", kFixupNone),
+    ENCODING_MAP(WIDE(kA64Tst3rro), SF_VARIANTS(0x6a00001f),
                  kFmtRegR, 9, 5, kFmtRegR, 20, 16, kFmtShift, -1, -1,
-                 kFmtUnused, -1, -1, IS_QUAD_OP | REG_USE01 | SETS_CCODES,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | SETS_CCODES,
                  "tst", "!0r, !1r!2o", kFixupNone),
+    // NOTE: Tbz/Tbnz does not require SETS_CCODES, but it may be replaced by some other LIRs
+    // which require SETS_CCODES in the fix-up stage.
+    ENCODING_MAP(WIDE(kA64Tbnz3rht), CUSTOM_VARIANTS(0x37000000, 0x37000000),
+                 kFmtRegR, 4, 0, kFmtImm6Shift, -1, -1, kFmtBitBlt, 18, 5, kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_USE0 | IS_BRANCH | NEEDS_FIXUP | SETS_CCODES,
+                 "tbnz", "!0r, #!1h, !2t", kFixupTBxZ),
+    ENCODING_MAP(WIDE(kA64Tbz3rht), CUSTOM_VARIANTS(0x36000000, 0x36000000),
+                 kFmtRegR, 4, 0, kFmtImm6Shift, -1, -1, kFmtBitBlt, 18, 5, kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_USE0 | IS_BRANCH | NEEDS_FIXUP | SETS_CCODES,
+                 "tbz", "!0r, #!1h, !2t", kFixupTBxZ),
     ENCODING_MAP(WIDE(kA64Ubfm4rrdd), SF_N_VARIANTS(0x53000000),
                  kFmtRegR, 4, 0, kFmtRegR, 9, 5, kFmtBitBlt, 21, 16,
                  kFmtBitBlt, 15, 10, IS_QUAD_OP | REG_DEF0_USE1,
@@ -787,6 +802,11 @@
               value |= ((operand & 0x1ffffc) >> 2) << 5;
               bits |= value;
               break;
+            case kFmtImm6Shift:
+              value = (operand & 0x1f) << 19;
+              value |= ((operand & 0x20) >> 5) << 31;
+              bits |= value;
+              break;
             default:
               LOG(FATAL) << "Bad fmt for arg. " << i << " in " << encoder->name
                          << " (" << kind << ")";
@@ -827,11 +847,6 @@
    */
   int generation = 0;
   while (true) {
-    // TODO(Arm64): check whether passes and offset adjustments are really necessary.
-    //   Currently they aren't, as - in the fixups below - LIR are never inserted.
-    //   Things can be different if jump ranges above 1 MB need to be supported.
-    //   If they are not, then we can get rid of the assembler retry logic.
-
     offset_adjustment = 0;
     AssemblerStatus res = kSuccess;  // Assume success
     generation ^= 1;
@@ -839,13 +854,9 @@
     lir = first_fixup_;
     prev_lir = NULL;
     while (lir != NULL) {
-      /*
-       * NOTE: the lir being considered here will be encoded following the switch (so long as
-       * we're not in a retry situation).  However, any new non-pc_rel instructions inserted
-       * due to retry must be explicitly encoded at the time of insertion.  Note that
-       * inserted instructions don't need use/def flags, but do need size and pc-rel status
-       * properly updated.
-       */
+      // NOTE: Any new non-pc_rel instructions inserted due to retry must be explicitly encoded at
+      // the time of insertion.  Note that inserted instructions don't need use/def flags, but do
+      // need size and pc-rel status properly updated.
       lir->offset += offset_adjustment;
       // During pass, allows us to tell whether a node has been updated with offset_adjustment yet.
       lir->flags.generation = generation;
@@ -861,7 +872,8 @@
           CodeOffset target = target_lir->offset +
               ((target_lir->flags.generation == lir->flags.generation) ? 0 : offset_adjustment);
           int32_t delta = target - pc;
-          if (!((delta & 0x3) == 0 && IS_SIGNED_IMM19(delta >> 2))) {
+          DCHECK_EQ(delta & 0x3, 0);
+          if (!IS_SIGNED_IMM19(delta >> 2)) {
             LOG(FATAL) << "Invalid jump range in kFixupT1Branch";
           }
           lir->operands[0] = delta >> 2;
@@ -876,12 +888,75 @@
           CodeOffset target = target_lir->offset +
             ((target_lir->flags.generation == lir->flags.generation) ? 0 : offset_adjustment);
           int32_t delta = target - pc;
-          if (!((delta & 0x3) == 0 && IS_SIGNED_IMM19(delta >> 2))) {
+          DCHECK_EQ(delta & 0x3, 0);
+          if (!IS_SIGNED_IMM19(delta >> 2)) {
             LOG(FATAL) << "Invalid jump range in kFixupLoad";
           }
           lir->operands[1] = delta >> 2;
           break;
         }
+        case kFixupTBxZ: {
+          int16_t opcode = lir->opcode;
+          RegStorage reg(lir->operands[0] | RegStorage::kValid);
+          int32_t imm = lir->operands[1];
+          DCHECK_EQ(IS_WIDE(opcode), reg.Is64Bit());
+          DCHECK_LT(imm, 64);
+          if (imm >= 32) {
+            DCHECK(IS_WIDE(opcode));
+          } else if (kIsDebugBuild && IS_WIDE(opcode)) {
+            // "tbz/tbnz x0, #imm(<32)" is the same with "tbz/tbnz w0, #imm(<32)", but GCC/oatdump
+            // will disassemble it as "tbz/tbnz w0, #imm(<32)". So unwide the LIR to make the
+            // compiler log behave the same with those disassembler in debug build.
+            // This will also affect tst instruction if it need to be replaced, but there is no
+            // performance difference between "tst Xt" and "tst Wt".
+            lir->opcode = UNWIDE(opcode);
+            lir->operands[0] = As32BitReg(reg).GetReg();
+          }
+
+          // Fix-up branch offset.
+          LIR *target_lir = lir->target;
+          DCHECK(target_lir);
+          CodeOffset pc = lir->offset;
+          CodeOffset target = target_lir->offset +
+              ((target_lir->flags.generation == lir->flags.generation) ? 0 : offset_adjustment);
+          int32_t delta = target - pc;
+          DCHECK_EQ(delta & 0x3, 0);
+          // Check if branch offset can be encoded in tbz/tbnz.
+          if (!IS_SIGNED_IMM14(delta >> 2)) {
+            DexOffset dalvik_offset = lir->dalvik_offset;
+            int16_t opcode = lir->opcode;
+            LIR* target = lir->target;
+            // "tbz/tbnz Rt, #imm, label" -> "tst Rt, #(1<<imm)".
+            offset_adjustment -= lir->flags.size;
+            int32_t imm = EncodeLogicalImmediate(IS_WIDE(opcode), 1 << lir->operands[1]);
+            DCHECK_NE(imm, -1);
+            lir->opcode = IS_WIDE(opcode) ? WIDE(kA64Tst2rl) : kA64Tst2rl;
+            lir->operands[1] = imm;
+            lir->target = nullptr;
+            lir->flags.fixup = EncodingMap[kA64Tst2rl].fixup;
+            lir->flags.size = EncodingMap[kA64Tst2rl].size;
+            offset_adjustment += lir->flags.size;
+            // Insert "beq/bneq label".
+            opcode = UNWIDE(opcode);
+            DCHECK(opcode == kA64Tbz3rht || opcode == kA64Tbnz3rht);
+            LIR* new_lir = RawLIR(dalvik_offset, kA64B2ct,
+                opcode == kA64Tbz3rht ? kArmCondEq : kArmCondNe, 0, 0, 0, 0, target);
+            InsertLIRAfter(lir, new_lir);
+            new_lir->offset = lir->offset + lir->flags.size;
+            new_lir->flags.generation = generation;
+            new_lir->flags.fixup = EncodingMap[kA64B2ct].fixup;
+            new_lir->flags.size = EncodingMap[kA64B2ct].size;
+            offset_adjustment += new_lir->flags.size;
+            // lir no longer pcrel, unlink and link in new_lir.
+            ReplaceFixup(prev_lir, lir, new_lir);
+            prev_lir = new_lir;  // Continue with the new instruction.
+            lir = new_lir->u.a.pcrel_next;
+            res = kRetryAll;
+            continue;
+          }
+          lir->operands[2] = delta >> 2;
+          break;
+        }
         case kFixupAdr: {
           LIR* target_lir = lir->target;
           int32_t delta;
@@ -910,6 +985,7 @@
     }
 
     if (res == kSuccess) {
+      DCHECK_EQ(offset_adjustment, 0);
       break;
     } else {
       assembler_retries++;
diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc
index d00c57d..d1b9c81 100644
--- a/compiler/dex/quick/arm64/int_arm64.cc
+++ b/compiler/dex/quick/arm64/int_arm64.cc
@@ -271,8 +271,12 @@
       ArmOpcode opcode = kA64Cbz2rt;
       ArmOpcode wide = reg.Is64Bit() ? WIDE(0) : UNWIDE(0);
       branch = NewLIR2(opcode | wide, reg.GetReg(), 0);
+    } else if (arm_cond == kArmCondLt || arm_cond == kArmCondGe) {
+      ArmOpcode opcode = (arm_cond == kArmCondLt) ? kA64Tbnz3rht : kA64Tbz3rht;
+      ArmOpcode wide = reg.Is64Bit() ? WIDE(0) : UNWIDE(0);
+      int value = reg.Is64Bit() ? 63 : 31;
+      branch = NewLIR3(opcode | wide, reg.GetReg(), value, 0);
     }
-    // TODO: Use tbz/tbnz for < 0 or >= 0.
   }
 
   if (branch == nullptr) {
@@ -856,16 +860,14 @@
   OpRegRegImm(kOpLsl, rs_length, rs_length, 1);
 
   // Copy one element.
-  OpRegRegImm(kOpAnd, rs_tmp, As32BitReg(rs_length), 2);
-  LIR* jmp_to_copy_two = OpCmpImmBranch(kCondEq, rs_tmp, 0, nullptr);
+  LIR* jmp_to_copy_two = NewLIR3(WIDE(kA64Tbz3rht), rs_length.GetReg(), 1, 0);
   OpRegImm(kOpSub, rs_length, 2);
   LoadBaseIndexed(rs_src, rs_length, rs_tmp, 0, kSignedHalf);
   StoreBaseIndexed(rs_dst, rs_length, rs_tmp, 0, kSignedHalf);
 
   // Copy two elements.
   LIR *copy_two = NewLIR0(kPseudoTargetLabel);
-  OpRegRegImm(kOpAnd, rs_tmp, As32BitReg(rs_length), 4);
-  LIR* jmp_to_copy_four = OpCmpImmBranch(kCondEq, rs_tmp, 0, nullptr);
+  LIR* jmp_to_copy_four = NewLIR3(WIDE(kA64Tbz3rht), rs_length.GetReg(), 2, 0);
   OpRegImm(kOpSub, rs_length, 4);
   LoadBaseIndexed(rs_src, rs_length, rs_tmp, 0, k32);
   StoreBaseIndexed(rs_dst, rs_length, rs_tmp, 0, k32);
diff --git a/compiler/dex/quick/arm64/target_arm64.cc b/compiler/dex/quick/arm64/target_arm64.cc
index 9b4546a..685f8d5 100644
--- a/compiler/dex/quick/arm64/target_arm64.cc
+++ b/compiler/dex/quick/arm64/target_arm64.cc
@@ -504,6 +504,9 @@
              else
                strcpy(tbuf, ", DecodeError3");
              break;
+           case 'h':
+             snprintf(tbuf, arraysize(tbuf), "%d", operand);
+             break;
            default:
              strcpy(tbuf, "DecodeError1");
              break;
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index ea56989..95c1262 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -220,9 +220,9 @@
                                    int dest_reg_class) {
   // Implement as a branch-over.
   // TODO: Conditional move?
-  LoadConstant(rs_dest, false_val);  // Favors false.
-  LIR* ne_branchover = OpCmpBranch(code, left_op, right_op, NULL);
   LoadConstant(rs_dest, true_val);
+  LIR* ne_branchover = OpCmpBranch(code, left_op, right_op, NULL);
+  LoadConstant(rs_dest, false_val);
   LIR* target_label = NewLIR0(kPseudoTargetLabel);
   ne_branchover->target = target_label;
 }
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index deefdec..a21004c 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -48,8 +48,17 @@
 
 class JniCompilerTest : public CommonCompilerTest {
  protected:
+  void SetUp() OVERRIDE {
+    CommonCompilerTest::SetUp();
+    check_generic_jni_ = false;
+  }
+
+  void SetCheckGenericJni(bool generic) {
+    check_generic_jni_ = generic;
+  }
+
   void CompileForTest(jobject class_loader, bool direct,
-                      const char* method_name, const char* method_sig, bool generic = false) {
+                      const char* method_name, const char* method_sig) {
     ScopedObjectAccess soa(Thread::Current());
     StackHandleScope<1> hs(soa.Self());
     Handle<mirror::ClassLoader> loader(
@@ -63,7 +72,7 @@
       method = c->FindVirtualMethod(method_name, method_sig);
     }
     ASSERT_TRUE(method != nullptr) << method_name << " " << method_sig;
-    if (generic) {
+    if (check_generic_jni_) {
       method->SetEntryPointFromQuickCompiledCode(class_linker_->GetQuickGenericJniTrampoline());
     } else {
       if (method->GetEntryPointFromQuickCompiledCode() == nullptr ||
@@ -78,14 +87,14 @@
   }
 
   void SetUpForTest(bool direct, const char* method_name, const char* method_sig,
-                    void* native_fnptr, bool generic = false) {
+                    void* native_fnptr) {
     // Initialize class loader and compile method when runtime not started.
     if (!runtime_->IsStarted()) {
       {
         ScopedObjectAccess soa(Thread::Current());
         class_loader_ = LoadDex("MyClassNatives");
       }
-      CompileForTest(class_loader_, direct, method_name, method_sig, generic);
+      CompileForTest(class_loader_, direct, method_name, method_sig);
       // Start runtime.
       Thread::Current()->TransitionFromSuspendedToRunnable();
       bool started = runtime_->Start();
@@ -121,16 +130,65 @@
   static jobject jobj_;
   static jobject class_loader_;
 
-
  protected:
+  // We have to list the methods here so we can share them between default and generic JNI.
+  void CompileAndRunNoArgMethodImpl();
+  void CompileAndRunIntMethodThroughStubImpl();
+  void CompileAndRunStaticIntMethodThroughStubImpl();
+  void CompileAndRunIntMethodImpl();
+  void CompileAndRunIntIntMethodImpl();
+  void CompileAndRunLongLongMethodImpl();
+  void CompileAndRunDoubleDoubleMethodImpl();
+  void CompileAndRun_fooJJ_synchronizedImpl();
+  void CompileAndRunIntObjectObjectMethodImpl();
+  void CompileAndRunStaticIntIntMethodImpl();
+  void CompileAndRunStaticDoubleDoubleMethodImpl();
+  void RunStaticLogDoubleMethodImpl();
+  void RunStaticLogFloatMethodImpl();
+  void RunStaticReturnTrueImpl();
+  void RunStaticReturnFalseImpl();
+  void RunGenericStaticReturnIntImpl();
+  void CompileAndRunStaticIntObjectObjectMethodImpl();
+  void CompileAndRunStaticSynchronizedIntObjectObjectMethodImpl();
+  void ExceptionHandlingImpl();
+  void NativeStackTraceElementImpl();
+  void ReturnGlobalRefImpl();
+  void LocalReferenceTableClearingTestImpl();
+  void JavaLangSystemArrayCopyImpl();
+  void CompareAndSwapIntImpl();
+  void GetTextImpl();
+  void GetSinkPropertiesNativeImpl();
+  void UpcallReturnTypeChecking_InstanceImpl();
+  void UpcallReturnTypeChecking_StaticImpl();
+  void UpcallArgumentTypeChecking_InstanceImpl();
+  void UpcallArgumentTypeChecking_StaticImpl();
+  void CompileAndRunFloatFloatMethodImpl();
+  void CheckParameterAlignImpl();
+  void MaxParamNumberImpl();
+  void WithoutImplementationImpl();
+  void StackArgsIntsFirstImpl();
+  void StackArgsFloatsFirstImpl();
+  void StackArgsMixedImpl();
+
   JNIEnv* env_;
   jmethodID jmethod_;
+  bool check_generic_jni_;
 };
 
 jclass JniCompilerTest::jklass_;
 jobject JniCompilerTest::jobj_;
 jobject JniCompilerTest::class_loader_;
 
+#define JNI_TEST(TestName) \
+  TEST_F(JniCompilerTest, TestName ## Default) { \
+    TestName ## Impl();                          \
+  }                                              \
+                                                 \
+  TEST_F(JniCompilerTest, TestName ## Generic) { \
+    TEST_DISABLED_FOR_MIPS();                    \
+    SetCheckGenericJni(true);                    \
+    TestName ## Impl();                          \
+  }
 
 int gJava_MyClassNatives_foo_calls = 0;
 void Java_MyClassNatives_foo(JNIEnv* env, jobject thisObj) {
@@ -145,7 +203,7 @@
   EXPECT_EQ(1U, Thread::Current()->NumStackReferences());
 }
 
-TEST_F(JniCompilerTest, CompileAndRunNoArgMethod) {
+void JniCompilerTest::CompileAndRunNoArgMethodImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "foo", "()V", reinterpret_cast<void*>(&Java_MyClassNatives_foo));
 
@@ -154,9 +212,13 @@
   EXPECT_EQ(1, gJava_MyClassNatives_foo_calls);
   env_->CallNonvirtualVoidMethod(jobj_, jklass_, jmethod_);
   EXPECT_EQ(2, gJava_MyClassNatives_foo_calls);
+
+  gJava_MyClassNatives_foo_calls = 0;
 }
 
-TEST_F(JniCompilerTest, CompileAndRunIntMethodThroughStub) {
+JNI_TEST(CompileAndRunNoArgMethod)
+
+void JniCompilerTest::CompileAndRunIntMethodThroughStubImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "bar", "(I)I", nullptr);
   // calling through stub will link with &Java_MyClassNatives_bar
@@ -169,7 +231,9 @@
   EXPECT_EQ(25, result);
 }
 
-TEST_F(JniCompilerTest, CompileAndRunStaticIntMethodThroughStub) {
+JNI_TEST(CompileAndRunIntMethodThroughStub)
+
+void JniCompilerTest::CompileAndRunStaticIntMethodThroughStubImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "sbar", "(I)I", nullptr);
   // calling through stub will link with &Java_MyClassNatives_sbar
@@ -182,6 +246,8 @@
   EXPECT_EQ(43, result);
 }
 
+JNI_TEST(CompileAndRunStaticIntMethodThroughStub)
+
 int gJava_MyClassNatives_fooI_calls = 0;
 jint Java_MyClassNatives_fooI(JNIEnv* env, jobject thisObj, jint x) {
   // 1 = thisObj
@@ -195,7 +261,7 @@
   return x;
 }
 
-TEST_F(JniCompilerTest, CompileAndRunIntMethod) {
+void JniCompilerTest::CompileAndRunIntMethodImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooI", "(I)I",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooI));
@@ -207,8 +273,12 @@
   result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 0xCAFED00D);
   EXPECT_EQ(static_cast<jint>(0xCAFED00D), result);
   EXPECT_EQ(2, gJava_MyClassNatives_fooI_calls);
+
+  gJava_MyClassNatives_fooI_calls = 0;
 }
 
+JNI_TEST(CompileAndRunIntMethod)
+
 int gJava_MyClassNatives_fooII_calls = 0;
 jint Java_MyClassNatives_fooII(JNIEnv* env, jobject thisObj, jint x, jint y) {
   // 1 = thisObj
@@ -222,7 +292,7 @@
   return x - y;  // non-commutative operator
 }
 
-TEST_F(JniCompilerTest, CompileAndRunIntIntMethod) {
+void JniCompilerTest::CompileAndRunIntIntMethodImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooII", "(II)I",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooII));
@@ -235,8 +305,12 @@
                                          0xCAFED00D);
   EXPECT_EQ(static_cast<jint>(0xCAFEBABE - 0xCAFED00D), result);
   EXPECT_EQ(2, gJava_MyClassNatives_fooII_calls);
+
+  gJava_MyClassNatives_fooII_calls = 0;
 }
 
+JNI_TEST(CompileAndRunIntIntMethod)
+
 int gJava_MyClassNatives_fooJJ_calls = 0;
 jlong Java_MyClassNatives_fooJJ(JNIEnv* env, jobject thisObj, jlong x, jlong y) {
   // 1 = thisObj
@@ -250,7 +324,7 @@
   return x - y;  // non-commutative operator
 }
 
-TEST_F(JniCompilerTest, CompileAndRunLongLongMethod) {
+void JniCompilerTest::CompileAndRunLongLongMethodImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooJJ", "(JJ)J",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooJJ));
@@ -264,8 +338,12 @@
   result = env_->CallNonvirtualLongMethod(jobj_, jklass_, jmethod_, b, a);
   EXPECT_EQ(b - a, result);
   EXPECT_EQ(2, gJava_MyClassNatives_fooJJ_calls);
+
+  gJava_MyClassNatives_fooJJ_calls = 0;
 }
 
+JNI_TEST(CompileAndRunLongLongMethod)
+
 int gJava_MyClassNatives_fooDD_calls = 0;
 jdouble Java_MyClassNatives_fooDD(JNIEnv* env, jobject thisObj, jdouble x, jdouble y) {
   // 1 = thisObj
@@ -279,7 +357,7 @@
   return x - y;  // non-commutative operator
 }
 
-TEST_F(JniCompilerTest, CompileAndRunDoubleDoubleMethod) {
+void JniCompilerTest::CompileAndRunDoubleDoubleMethodImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooDD", "(DD)D",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooDD));
@@ -294,6 +372,8 @@
   result = env_->CallNonvirtualDoubleMethod(jobj_, jklass_, jmethod_, a, b);
   EXPECT_EQ(a - b, result);
   EXPECT_EQ(2, gJava_MyClassNatives_fooDD_calls);
+
+  gJava_MyClassNatives_fooDD_calls = 0;
 }
 
 int gJava_MyClassNatives_fooJJ_synchronized_calls = 0;
@@ -309,7 +389,7 @@
   return x | y;
 }
 
-TEST_F(JniCompilerTest, CompileAndRun_fooJJ_synchronized) {
+void JniCompilerTest::CompileAndRun_fooJJ_synchronizedImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooJJ_synchronized", "(JJ)J",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooJJ_synchronized));
@@ -320,8 +400,12 @@
   jlong result = env_->CallNonvirtualLongMethod(jobj_, jklass_, jmethod_, a, b);
   EXPECT_EQ(a | b, result);
   EXPECT_EQ(1, gJava_MyClassNatives_fooJJ_synchronized_calls);
+
+  gJava_MyClassNatives_fooJJ_synchronized_calls = 0;
 }
 
+JNI_TEST(CompileAndRun_fooJJ_synchronized)
+
 int gJava_MyClassNatives_fooIOO_calls = 0;
 jobject Java_MyClassNatives_fooIOO(JNIEnv* env, jobject thisObj, jint x, jobject y,
                             jobject z) {
@@ -345,7 +429,7 @@
   }
 }
 
-TEST_F(JniCompilerTest, CompileAndRunIntObjectObjectMethod) {
+void JniCompilerTest::CompileAndRunIntObjectObjectMethodImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooIOO",
                "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
@@ -375,8 +459,12 @@
   result = env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, 2, jklass_, nullptr);
   EXPECT_TRUE(env_->IsSameObject(nullptr, result));
   EXPECT_EQ(7, gJava_MyClassNatives_fooIOO_calls);
+
+  gJava_MyClassNatives_fooIOO_calls = 0;
 }
 
+JNI_TEST(CompileAndRunIntObjectObjectMethod)
+
 int gJava_MyClassNatives_fooSII_calls = 0;
 jint Java_MyClassNatives_fooSII(JNIEnv* env, jclass klass, jint x, jint y) {
   // 1 = klass
@@ -390,7 +478,7 @@
   return x + y;
 }
 
-TEST_F(JniCompilerTest, CompileAndRunStaticIntIntMethod) {
+void JniCompilerTest::CompileAndRunStaticIntIntMethodImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "fooSII", "(II)I",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooSII));
@@ -399,8 +487,12 @@
   jint result = env_->CallStaticIntMethod(jklass_, jmethod_, 20, 30);
   EXPECT_EQ(50, result);
   EXPECT_EQ(1, gJava_MyClassNatives_fooSII_calls);
+
+  gJava_MyClassNatives_fooSII_calls = 0;
 }
 
+JNI_TEST(CompileAndRunStaticIntIntMethod)
+
 int gJava_MyClassNatives_fooSDD_calls = 0;
 jdouble Java_MyClassNatives_fooSDD(JNIEnv* env, jclass klass, jdouble x, jdouble y) {
   // 1 = klass
@@ -414,7 +506,7 @@
   return x - y;  // non-commutative operator
 }
 
-TEST_F(JniCompilerTest, CompileAndRunStaticDoubleDoubleMethod) {
+void JniCompilerTest::CompileAndRunStaticDoubleDoubleMethodImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "fooSDD", "(DD)D",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooSDD));
@@ -428,8 +520,12 @@
   result = env_->CallStaticDoubleMethod(jklass_, jmethod_, a, b);
   EXPECT_EQ(a - b, result);
   EXPECT_EQ(2, gJava_MyClassNatives_fooSDD_calls);
+
+  gJava_MyClassNatives_fooSDD_calls = 0;
 }
 
+JNI_TEST(CompileAndRunStaticDoubleDoubleMethod)
+
 // The x86 generic JNI code had a bug where it assumed a floating
 // point return value would be in xmm0. We use log, to somehow ensure
 // the compiler will use the floating point stack.
@@ -438,30 +534,30 @@
   return log(x);
 }
 
-TEST_F(JniCompilerTest, RunGenericStaticLogDoubleethod) {
+void JniCompilerTest::RunStaticLogDoubleMethodImpl() {
   TEST_DISABLED_FOR_PORTABLE();
-  TEST_DISABLED_FOR_MIPS();
-  SetUpForTest(true, "logD", "(D)D",
-               reinterpret_cast<void*>(&Java_MyClassNatives_logD), true);
+  SetUpForTest(true, "logD", "(D)D", reinterpret_cast<void*>(&Java_MyClassNatives_logD));
 
   jdouble result = env_->CallStaticDoubleMethod(jklass_, jmethod_, 2.0);
   EXPECT_EQ(log(2.0), result);
 }
 
+JNI_TEST(RunStaticLogDoubleMethod)
+
 jfloat Java_MyClassNatives_logF(JNIEnv* env, jclass klass, jfloat x) {
   return logf(x);
 }
 
-TEST_F(JniCompilerTest, RunGenericStaticLogFloatMethod) {
+void JniCompilerTest::RunStaticLogFloatMethodImpl() {
   TEST_DISABLED_FOR_PORTABLE();
-  TEST_DISABLED_FOR_MIPS();
-  SetUpForTest(true, "logF", "(F)F",
-               reinterpret_cast<void*>(&Java_MyClassNatives_logF), true);
+  SetUpForTest(true, "logF", "(F)F", reinterpret_cast<void*>(&Java_MyClassNatives_logF));
 
   jfloat result = env_->CallStaticFloatMethod(jklass_, jmethod_, 2.0);
   EXPECT_EQ(logf(2.0), result);
 }
 
+JNI_TEST(RunStaticLogFloatMethod)
+
 jboolean Java_MyClassNatives_returnTrue(JNIEnv* env, jclass klass) {
   return JNI_TRUE;
 }
@@ -474,36 +570,37 @@
   return 42;
 }
 
-TEST_F(JniCompilerTest, RunGenericStaticReturnTrue) {
+void JniCompilerTest::RunStaticReturnTrueImpl() {
   TEST_DISABLED_FOR_PORTABLE();
-  TEST_DISABLED_FOR_MIPS();
-  SetUpForTest(true, "returnTrue", "()Z",
-               reinterpret_cast<void*>(&Java_MyClassNatives_returnTrue), true);
+  SetUpForTest(true, "returnTrue", "()Z", reinterpret_cast<void*>(&Java_MyClassNatives_returnTrue));
 
   jboolean result = env_->CallStaticBooleanMethod(jklass_, jmethod_);
   EXPECT_TRUE(result);
 }
 
-TEST_F(JniCompilerTest, RunGenericStaticReturnFalse) {
+JNI_TEST(RunStaticReturnTrue)
+
+void JniCompilerTest::RunStaticReturnFalseImpl() {
   TEST_DISABLED_FOR_PORTABLE();
-  TEST_DISABLED_FOR_MIPS();
   SetUpForTest(true, "returnFalse", "()Z",
-               reinterpret_cast<void*>(&Java_MyClassNatives_returnFalse), true);
+               reinterpret_cast<void*>(&Java_MyClassNatives_returnFalse));
 
   jboolean result = env_->CallStaticBooleanMethod(jklass_, jmethod_);
   EXPECT_FALSE(result);
 }
 
-TEST_F(JniCompilerTest, RunGenericStaticReturnInt) {
+JNI_TEST(RunStaticReturnFalse)
+
+void JniCompilerTest::RunGenericStaticReturnIntImpl() {
   TEST_DISABLED_FOR_PORTABLE();
-  TEST_DISABLED_FOR_MIPS();
-  SetUpForTest(true, "returnInt", "()I",
-               reinterpret_cast<void*>(&Java_MyClassNatives_returnInt), true);
+  SetUpForTest(true, "returnInt", "()I", reinterpret_cast<void*>(&Java_MyClassNatives_returnInt));
 
   jint result = env_->CallStaticIntMethod(jklass_, jmethod_);
   EXPECT_EQ(42, result);
 }
 
+JNI_TEST(RunGenericStaticReturnInt)
+
 int gJava_MyClassNatives_fooSIOO_calls = 0;
 jobject Java_MyClassNatives_fooSIOO(JNIEnv* env, jclass klass, jint x, jobject y,
                              jobject z) {
@@ -528,7 +625,7 @@
 }
 
 
-TEST_F(JniCompilerTest, CompileAndRunStaticIntObjectObjectMethod) {
+void JniCompilerTest::CompileAndRunStaticIntObjectObjectMethodImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "fooSIOO",
                "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
@@ -558,8 +655,12 @@
   result = env_->CallStaticObjectMethod(jklass_, jmethod_, 2, jobj_, nullptr);
   EXPECT_TRUE(env_->IsSameObject(nullptr, result));
   EXPECT_EQ(7, gJava_MyClassNatives_fooSIOO_calls);
+
+  gJava_MyClassNatives_fooSIOO_calls = 0;
 }
 
+JNI_TEST(CompileAndRunStaticIntObjectObjectMethod)
+
 int gJava_MyClassNatives_fooSSIOO_calls = 0;
 jobject Java_MyClassNatives_fooSSIOO(JNIEnv* env, jclass klass, jint x, jobject y, jobject z) {
   // 3 = klass + y + z
@@ -582,7 +683,7 @@
   }
 }
 
-TEST_F(JniCompilerTest, CompileAndRunStaticSynchronizedIntObjectObjectMethod) {
+void JniCompilerTest::CompileAndRunStaticSynchronizedIntObjectObjectMethodImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "fooSSIOO",
                "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
@@ -612,14 +713,18 @@
   result = env_->CallStaticObjectMethod(jklass_, jmethod_, 2, jobj_, nullptr);
   EXPECT_TRUE(env_->IsSameObject(nullptr, result));
   EXPECT_EQ(7, gJava_MyClassNatives_fooSSIOO_calls);
+
+  gJava_MyClassNatives_fooSSIOO_calls = 0;
 }
 
+JNI_TEST(CompileAndRunStaticSynchronizedIntObjectObjectMethod)
+
 void Java_MyClassNatives_throwException(JNIEnv* env, jobject) {
   jclass c = env->FindClass("java/lang/RuntimeException");
   env->ThrowNew(c, "hello");
 }
 
-TEST_F(JniCompilerTest, ExceptionHandling) {
+void JniCompilerTest::ExceptionHandlingImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   {
     ASSERT_FALSE(runtime_->IsStarted());
@@ -660,8 +765,12 @@
   SetUpForTest(false, "foo", "()V", reinterpret_cast<void*>(&Java_MyClassNatives_foo));
   env_->CallNonvirtualVoidMethod(jobj_, jklass_, jmethod_);
   EXPECT_EQ(2, gJava_MyClassNatives_foo_calls);
+
+  gJava_MyClassNatives_foo_calls = 0;
 }
 
+JNI_TEST(ExceptionHandling)
+
 jint Java_MyClassNatives_nativeUpCall(JNIEnv* env, jobject thisObj, jint i) {
   if (i <= 0) {
     // We want to check raw Object* / Array* below
@@ -700,7 +809,7 @@
   }
 }
 
-TEST_F(JniCompilerTest, NativeStackTraceElement) {
+void JniCompilerTest::NativeStackTraceElementImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooI", "(I)I",
                reinterpret_cast<void*>(&Java_MyClassNatives_nativeUpCall));
@@ -708,11 +817,13 @@
   EXPECT_EQ(10+9+8+7+6+5+4+3+2+1, result);
 }
 
+JNI_TEST(NativeStackTraceElement)
+
 jobject Java_MyClassNatives_fooO(JNIEnv* env, jobject, jobject x) {
   return env->NewGlobalRef(x);
 }
 
-TEST_F(JniCompilerTest, ReturnGlobalRef) {
+void JniCompilerTest::ReturnGlobalRefImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooO", "(Ljava/lang/Object;)Ljava/lang/Object;",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooO));
@@ -721,6 +832,8 @@
   EXPECT_TRUE(env_->IsSameObject(result, jobj_));
 }
 
+JNI_TEST(ReturnGlobalRef)
+
 jint local_ref_test(JNIEnv* env, jobject thisObj, jint x) {
   // Add 10 local references
   ScopedObjectAccess soa(env);
@@ -730,7 +843,7 @@
   return x+1;
 }
 
-TEST_F(JniCompilerTest, LocalReferenceTableClearingTest) {
+void JniCompilerTest::LocalReferenceTableClearingTestImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooI", "(I)I", reinterpret_cast<void*>(&local_ref_test));
   // 1000 invocations of a method that adds 10 local references
@@ -740,6 +853,8 @@
   }
 }
 
+JNI_TEST(LocalReferenceTableClearingTest)
+
 void my_arraycopy(JNIEnv* env, jclass klass, jobject src, jint src_pos, jobject dst, jint dst_pos, jint length) {
   EXPECT_TRUE(env->IsSameObject(JniCompilerTest::jklass_, klass));
   EXPECT_TRUE(env->IsSameObject(JniCompilerTest::jklass_, dst));
@@ -749,13 +864,15 @@
   EXPECT_EQ(9876, length);
 }
 
-TEST_F(JniCompilerTest, JavaLangSystemArrayCopy) {
+void JniCompilerTest::JavaLangSystemArrayCopyImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V",
                reinterpret_cast<void*>(&my_arraycopy));
   env_->CallStaticVoidMethod(jklass_, jmethod_, jobj_, 1234, jklass_, 5678, 9876);
 }
 
+JNI_TEST(JavaLangSystemArrayCopy)
+
 jboolean my_casi(JNIEnv* env, jobject unsafe, jobject obj, jlong offset, jint expected, jint newval) {
   EXPECT_TRUE(env->IsSameObject(JniCompilerTest::jobj_, unsafe));
   EXPECT_TRUE(env->IsSameObject(JniCompilerTest::jobj_, obj));
@@ -765,7 +882,7 @@
   return JNI_TRUE;
 }
 
-TEST_F(JniCompilerTest, CompareAndSwapInt) {
+void JniCompilerTest::CompareAndSwapIntImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "compareAndSwapInt", "(Ljava/lang/Object;JII)Z",
                reinterpret_cast<void*>(&my_casi));
@@ -774,6 +891,8 @@
   EXPECT_EQ(result, JNI_TRUE);
 }
 
+JNI_TEST(CompareAndSwapInt)
+
 jint my_gettext(JNIEnv* env, jclass klass, jlong val1, jobject obj1, jlong val2, jobject obj2) {
   EXPECT_TRUE(env->IsInstanceOf(JniCompilerTest::jobj_, klass));
   EXPECT_TRUE(env->IsSameObject(JniCompilerTest::jobj_, obj1));
@@ -783,7 +902,7 @@
   return 42;
 }
 
-TEST_F(JniCompilerTest, GetText) {
+void JniCompilerTest::GetTextImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "getText", "(JLjava/lang/Object;JLjava/lang/Object;)I",
                reinterpret_cast<void*>(&my_gettext));
@@ -792,6 +911,8 @@
   EXPECT_EQ(result, 42);
 }
 
+JNI_TEST(GetText)
+
 int gJava_MyClassNatives_GetSinkProperties_calls = 0;
 jarray Java_MyClassNatives_GetSinkProperties(JNIEnv* env, jobject thisObj, jstring s) {
   // 1 = thisObj
@@ -809,7 +930,7 @@
   return nullptr;
 }
 
-TEST_F(JniCompilerTest, GetSinkPropertiesNative) {
+void JniCompilerTest::GetSinkPropertiesNativeImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "getSinkPropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;",
                reinterpret_cast<void*>(&Java_MyClassNatives_GetSinkProperties));
@@ -819,8 +940,12 @@
       env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, nullptr));
   EXPECT_EQ(nullptr, result);
   EXPECT_EQ(1, gJava_MyClassNatives_GetSinkProperties_calls);
+
+  gJava_MyClassNatives_GetSinkProperties_calls = 0;
 }
 
+JNI_TEST(GetSinkPropertiesNative)
+
 // This should return jclass, but we're imitating a bug pattern.
 jobject Java_MyClassNatives_instanceMethodThatShouldReturnClass(JNIEnv* env, jobject) {
   return env->NewStringUTF("not a class!");
@@ -831,7 +956,7 @@
   return env->NewStringUTF("not a class!");
 }
 
-TEST_F(JniCompilerTest, UpcallReturnTypeChecking_Instance) {
+void JniCompilerTest::UpcallReturnTypeChecking_InstanceImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "instanceMethodThatShouldReturnClass", "()Ljava/lang/Class;",
                reinterpret_cast<void*>(&Java_MyClassNatives_instanceMethodThatShouldReturnClass));
@@ -849,7 +974,9 @@
   check_jni_abort_catcher.Check("calling non-static method java.lang.Class MyClassNatives.instanceMethodThatShouldReturnClass() with CallStaticObjectMethodV");
 }
 
-TEST_F(JniCompilerTest, UpcallReturnTypeChecking_Static) {
+JNI_TEST(UpcallReturnTypeChecking_Instance)
+
+void JniCompilerTest::UpcallReturnTypeChecking_StaticImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "staticMethodThatShouldReturnClass", "()Ljava/lang/Class;",
                reinterpret_cast<void*>(&Java_MyClassNatives_staticMethodThatShouldReturnClass));
@@ -867,6 +994,8 @@
   check_jni_abort_catcher.Check("calling static method java.lang.Class MyClassNatives.staticMethodThatShouldReturnClass() with CallObjectMethodV");
 }
 
+JNI_TEST(UpcallReturnTypeChecking_Static)
+
 // This should take jclass, but we're imitating a bug pattern.
 void Java_MyClassNatives_instanceMethodThatShouldTakeClass(JNIEnv*, jobject, jclass) {
 }
@@ -875,7 +1004,7 @@
 void Java_MyClassNatives_staticMethodThatShouldTakeClass(JNIEnv*, jclass, jclass) {
 }
 
-TEST_F(JniCompilerTest, UpcallArgumentTypeChecking_Instance) {
+void JniCompilerTest::UpcallArgumentTypeChecking_InstanceImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "instanceMethodThatShouldTakeClass", "(ILjava/lang/Class;)V",
                reinterpret_cast<void*>(&Java_MyClassNatives_instanceMethodThatShouldTakeClass));
@@ -886,7 +1015,9 @@
   check_jni_abort_catcher.Check("bad arguments passed to void MyClassNatives.instanceMethodThatShouldTakeClass(int, java.lang.Class)");
 }
 
-TEST_F(JniCompilerTest, UpcallArgumentTypeChecking_Static) {
+JNI_TEST(UpcallArgumentTypeChecking_Instance)
+
+void JniCompilerTest::UpcallArgumentTypeChecking_StaticImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "staticMethodThatShouldTakeClass", "(ILjava/lang/Class;)V",
                reinterpret_cast<void*>(&Java_MyClassNatives_staticMethodThatShouldTakeClass));
@@ -897,6 +1028,8 @@
   check_jni_abort_catcher.Check("bad arguments passed to void MyClassNatives.staticMethodThatShouldTakeClass(int, java.lang.Class)");
 }
 
+JNI_TEST(UpcallArgumentTypeChecking_Static)
+
 jfloat Java_MyClassNatives_checkFloats(JNIEnv* env, jobject thisObj, jfloat f1, jfloat f2) {
   EXPECT_EQ(kNative, Thread::Current()->GetState());
   EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
@@ -907,7 +1040,7 @@
   return f1 - f2;  // non-commutative operator
 }
 
-TEST_F(JniCompilerTest, CompileAndRunFloatFloatMethod) {
+void JniCompilerTest::CompileAndRunFloatFloatMethodImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "checkFloats", "(FF)F",
                reinterpret_cast<void*>(&Java_MyClassNatives_checkFloats));
@@ -921,6 +1054,8 @@
   EXPECT_EQ(a - b, result);
 }
 
+JNI_TEST(CompileAndRunFloatFloatMethod)
+
 void Java_MyClassNatives_checkParameterAlign(JNIEnv* env, jobject thisObj, jint i1, jlong l1) {
 //  EXPECT_EQ(kNative, Thread::Current()->GetState());
 //  EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
@@ -932,7 +1067,7 @@
   EXPECT_EQ(l1, INT64_C(0x12345678ABCDEF0));
 }
 
-TEST_F(JniCompilerTest, CheckParameterAlign) {
+void JniCompilerTest::CheckParameterAlignImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "checkParameterAlign", "(IJ)V",
                reinterpret_cast<void*>(&Java_MyClassNatives_checkParameterAlign));
@@ -940,6 +1075,8 @@
   env_->CallNonvirtualVoidMethod(jobj_, jklass_, jmethod_, 1234, INT64_C(0x12345678ABCDEF0));
 }
 
+JNI_TEST(CheckParameterAlign)
+
 void Java_MyClassNatives_maxParamNumber(JNIEnv* env, jobject thisObj,
     jobject o0, jobject o1, jobject o2, jobject o3, jobject o4, jobject o5, jobject o6, jobject o7,
     jobject o8, jobject o9, jobject o10, jobject o11, jobject o12, jobject o13, jobject o14, jobject o15,
@@ -1345,7 +1482,7 @@
     "Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;"
     "Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V";
 
-TEST_F(JniCompilerTest, MaxParamNumber) {
+void JniCompilerTest::MaxParamNumberImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "maxParamNumber", longSig,
                reinterpret_cast<void*>(&Java_MyClassNatives_maxParamNumber));
@@ -1369,7 +1506,9 @@
   env_->CallNonvirtualVoidMethodA(jobj_, jklass_, jmethod_, args);
 }
 
-TEST_F(JniCompilerTest, WithoutImplementation) {
+JNI_TEST(MaxParamNumber)
+
+void JniCompilerTest::WithoutImplementationImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "withoutImplementation", "()V", nullptr);
 
@@ -1379,6 +1518,8 @@
   EXPECT_TRUE(env_->ExceptionCheck() == JNI_TRUE);
 }
 
+JNI_TEST(WithoutImplementation)
+
 void Java_MyClassNatives_stackArgsIntsFirst(JNIEnv* env, jclass klass, jint i1, jint i2, jint i3,
                                             jint i4, jint i5, jint i6, jint i7, jint i8, jint i9,
                                             jint i10, jfloat f1, jfloat f2, jfloat f3, jfloat f4,
@@ -1417,7 +1558,7 @@
   EXPECT_EQ(i20, 20);
 }
 
-TEST_F(JniCompilerTest, StackArgsIntsFirst) {
+void JniCompilerTest::StackArgsIntsFirstImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "stackArgsIntsFirst", "(IIIIIIIIIIFFFFFFFFFF)V",
                reinterpret_cast<void*>(&Java_MyClassNatives_stackArgsIntsFirst));
@@ -1448,6 +1589,8 @@
                              f3, f4, f5, f6, f7, f8, f9, f10);
 }
 
+JNI_TEST(StackArgsIntsFirst)
+
 void Java_MyClassNatives_stackArgsFloatsFirst(JNIEnv* env, jclass klass, jfloat f1, jfloat f2,
                                               jfloat f3, jfloat f4, jfloat f5, jfloat f6, jfloat f7,
                                               jfloat f8, jfloat f9, jfloat f10, jint i1, jint i2,
@@ -1486,7 +1629,7 @@
   EXPECT_EQ(i20, 20);
 }
 
-TEST_F(JniCompilerTest, StackArgsFloatsFirst) {
+void JniCompilerTest::StackArgsFloatsFirstImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "stackArgsFloatsFirst", "(FFFFFFFFFFIIIIIIIIII)V",
                reinterpret_cast<void*>(&Java_MyClassNatives_stackArgsFloatsFirst));
@@ -1517,6 +1660,8 @@
                              i4, i5, i6, i7, i8, i9, i10);
 }
 
+JNI_TEST(StackArgsFloatsFirst)
+
 void Java_MyClassNatives_stackArgsMixed(JNIEnv* env, jclass klass, jint i1, jfloat f1, jint i2,
                                         jfloat f2, jint i3, jfloat f3, jint i4, jfloat f4, jint i5,
                                         jfloat f5, jint i6, jfloat f6, jint i7, jfloat f7, jint i8,
@@ -1554,7 +1699,7 @@
   EXPECT_EQ(i20, 20);
 }
 
-TEST_F(JniCompilerTest, StackArgsMixed) {
+void JniCompilerTest::StackArgsMixedImpl() {
   TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "stackArgsMixed", "(IFIFIFIFIFIFIFIFIFIF)V",
                reinterpret_cast<void*>(&Java_MyClassNatives_stackArgsMixed));
@@ -1585,4 +1730,6 @@
                              f7, i8, f8, i9, f9, i10, f10);
 }
 
+JNI_TEST(StackArgsMixed)
+
 }  // namespace art
diff --git a/runtime/arch/arm/arm_sdiv.S b/runtime/arch/arm/arm_sdiv.S
index 925e428..babdbf5 100644
--- a/runtime/arch/arm/arm_sdiv.S
+++ b/runtime/arch/arm/arm_sdiv.S
@@ -9,7 +9,7 @@
 #include "asm_support_arm.S"
 
 .section .text
-ENTRY CheckForARMSDIVInstruction
+ENTRY_NO_HIDE CheckForARMSDIVInstruction
   mov r1,#1
   // depending on the architecture, the assembler will not allow an
   // sdiv instruction, so we will have to output the bytes directly.
diff --git a/runtime/arch/arm/asm_support_arm.S b/runtime/arch/arm/asm_support_arm.S
index e1b0ce7..a3e3b21 100644
--- a/runtime/arch/arm/asm_support_arm.S
+++ b/runtime/arch/arm/asm_support_arm.S
@@ -33,6 +33,7 @@
 .macro ENTRY name
     .thumb_func
     .type \name, #function
+    .hidden \name  // Hide this as a global symbol, so we do not incur plt calls.
     .global \name
     /* Cache alignment for function entry */
     .balign 16
@@ -41,9 +42,35 @@
     .fnstart
 .endm
 
+.macro ENTRY_NO_HIDE name
+    .thumb_func
+    .type \name, #function
+    .global \name
+    /* Cache alignment for function entry */
+    .balign 16
+\name:
+    .cfi_startproc
+    .fnstart
+.endm
+
+
 .macro ARM_ENTRY name
     .arm
     .type \name, #function
+    .hidden \name  // Hide this as a global symbol, so we do not incur plt calls.
+    .global \name
+    /* Cache alignment for function entry */
+    .balign 16
+\name:
+    .cfi_startproc
+     /* Ensure we get a sane starting CFA. */
+    .cfi_def_cfa sp,0
+    .fnstart
+.endm
+
+.macro ARM_ENTRY_NO_HIDE name
+    .arm
+    .type \name, #function
     .global \name
     /* Cache alignment for function entry */
     .balign 16
diff --git a/runtime/arch/arm/portable_entrypoints_arm.S b/runtime/arch/arm/portable_entrypoints_arm.S
index 98d17dc..3491c18 100644
--- a/runtime/arch/arm/portable_entrypoints_arm.S
+++ b/runtime/arch/arm/portable_entrypoints_arm.S
@@ -138,7 +138,7 @@
 END art_portable_resolution_trampoline
 
     .extern artPortableToInterpreterBridge
-ENTRY art_portable_to_interpreter_bridge
+ENTRY_NO_HIDE art_portable_to_interpreter_bridge
     @ Fake callee save ref and args frame set up, note portable doesn't use callee save frames.
     @ TODO: just save the registers that are needed in artPortableToInterpreterBridge.
     push {r1-r3, r5-r8, r10-r11, lr}  @ 10 words of callee saves
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 9f0db8c..1b30c9c 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -308,9 +308,12 @@
 #ifdef ARM_R4_SUSPEND_FLAG
     mov    r4, #SUSPEND_CHECK_INTERVAL     @ reset r4 to suspend check interval
 #endif
-    add    r5, r2, #16                     @ create space for method pointer in frame
-    and    r5, #0xFFFFFFF0                 @ align frame size to 16 bytes
-    sub    sp, r5                          @ reserve stack space for argument array
+    add    r5, r2, #4                      @ create space for method pointer in frame
+
+    sub    r5, sp, r5                      @ reserve & align *stack* to 16 bytes: native calling
+    and    r5, #0xFFFFFFF0                 @ convention only aligns to 8B, so we have to ensure ART
+    mov    sp, r5                          @ 16B alignment ourselves.
+
     add    r0, sp, #4                      @ pass stack pointer + method ptr as dest for memcpy
     bl     memcpy                          @ memcpy (dest, src, bytes)
     ldr    r0, [r11]                       @ restore method*
@@ -988,7 +991,7 @@
     /*
      * Called to do a generic JNI down-call
      */
-ENTRY art_quick_generic_jni_trampoline
+ENTRY_NO_HIDE art_quick_generic_jni_trampoline
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
     str r0, [sp, #0]  // Store native ArtMethod* to bottom of stack.
 
@@ -1083,7 +1086,7 @@
 END art_quick_generic_jni_trampoline
 
     .extern artQuickToInterpreterBridge
-ENTRY art_quick_to_interpreter_bridge
+ENTRY_NO_HIDE art_quick_to_interpreter_bridge
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
     mov     r1, r9                 @ pass Thread::Current
     mov     r2, sp                 @ pass SP
diff --git a/runtime/arch/arm64/asm_support_arm64.S b/runtime/arch/arm64/asm_support_arm64.S
index be167fa..fb49460 100644
--- a/runtime/arch/arm64/asm_support_arm64.S
+++ b/runtime/arch/arm64/asm_support_arm64.S
@@ -44,6 +44,16 @@
 
 .macro ENTRY name
     .type \name, #function
+    .hidden \name  // Hide this as a global symbol, so we do not incur plt calls.
+    .global \name
+    /* Cache alignment for function entry */
+    .balign 16
+\name:
+    .cfi_startproc
+.endm
+
+.macro ENTRY_NO_HIDE name
+    .type \name, #function
     .global \name
     /* Cache alignment for function entry */
     .balign 16
@@ -62,4 +72,10 @@
     END \name
 .endm
 
+.macro UNIMPLEMENTED_NO_HIDE name
+    ENTRY_NO_HIDE \name
+    brk 0
+    END \name
+.endm
+
 #endif  // ART_RUNTIME_ARCH_ARM64_ASM_SUPPORT_ARM64_S_
diff --git a/runtime/arch/arm64/portable_entrypoints_arm64.S b/runtime/arch/arm64/portable_entrypoints_arm64.S
index e136885..41711b5 100644
--- a/runtime/arch/arm64/portable_entrypoints_arm64.S
+++ b/runtime/arch/arm64/portable_entrypoints_arm64.S
@@ -25,4 +25,4 @@
 
 UNIMPLEMENTED art_portable_resolution_trampoline
 
-UNIMPLEMENTED art_portable_to_interpreter_bridge
+UNIMPLEMENTED_NO_HIDE art_portable_to_interpreter_bridge
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index ab9035a..2a19e27 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -1435,7 +1435,7 @@
     /*
      * Called to do a generic JNI down-call
      */
-ENTRY art_quick_generic_jni_trampoline
+ENTRY_NO_HIDE art_quick_generic_jni_trampoline
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
     str x0, [sp, #0]  // Store native ArtMethod* to bottom of stack.
 
@@ -1531,7 +1531,7 @@
  * x0 = method being called/to bridge to.
  * x1..x7, d0..d7 = arguments to that method.
  */
-ENTRY art_quick_to_interpreter_bridge
+ENTRY_NO_HIDE art_quick_to_interpreter_bridge
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME   // Set up frame and save arguments.
 
     //  x0 will contain mirror::ArtMethod* method.
diff --git a/runtime/arch/memcmp16.cc b/runtime/arch/memcmp16.cc
index 7928085..5a3e73e 100644
--- a/runtime/arch/memcmp16.cc
+++ b/runtime/arch/memcmp16.cc
@@ -28,4 +28,16 @@
   return 0;
 }
 
+namespace art {
+
+namespace testing {
+
+int32_t MemCmp16Testing(const uint16_t* s0, const uint16_t* s1, size_t count) {
+  return MemCmp16(s0, s1, count);
+}
+
+}
+
+}  // namespace art
+
 #pragma GCC diagnostic warning "-Wunused-function"
diff --git a/runtime/arch/memcmp16.h b/runtime/arch/memcmp16.h
index 14dc1e3..4b9fb8e 100644
--- a/runtime/arch/memcmp16.h
+++ b/runtime/arch/memcmp16.h
@@ -50,4 +50,17 @@
 extern "C" int32_t memcmp16_generic_static(const uint16_t* s0, const uint16_t* s1, size_t count);
 #endif
 
+namespace art {
+
+namespace testing {
+
+// A version that is exposed and relatively "close to the metal," so that memcmp16_test can do
+// some reasonable testing. Without this, as __memcmp16 is hidden, the test cannot access the
+// implementation.
+int32_t MemCmp16Testing(const uint16_t* s0, const uint16_t* s1, size_t count);
+
+}
+
+}  // namespace art
+
 #endif  // ART_RUNTIME_ARCH_MEMCMP16_H_
diff --git a/runtime/arch/memcmp16_test.cc b/runtime/arch/memcmp16_test.cc
index 5747c67..5ba06f8 100644
--- a/runtime/arch/memcmp16_test.cc
+++ b/runtime/arch/memcmp16_test.cc
@@ -139,7 +139,7 @@
     size_t mod_min = c1_mod < c2_mod ? c1_mod : c2_mod;
 
     int32_t expected = memcmp16_compare(s1_pot_unaligned, s2_pot_unaligned, mod_min);
-    int32_t computed = MemCmp16(s1_pot_unaligned, s2_pot_unaligned, mod_min);
+    int32_t computed = art::testing::MemCmp16Testing(s1_pot_unaligned, s2_pot_unaligned, mod_min);
 
     ASSERT_EQ(expected, computed) << "Run " << round << ", c1=" << count1 << " c2=" << count2;
 
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 25f9a5a..864e3f7 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -17,6 +17,7 @@
 #include <cstdio>
 
 #include "common_runtime_test.h"
+#include "entrypoints/quick/quick_entrypoints_enum.h"
 #include "mirror/art_field-inl.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
@@ -543,15 +544,21 @@
 #endif
   }
 
+  static uintptr_t GetEntrypoint(Thread* self, QuickEntrypointEnum entrypoint) {
+    int32_t offset;
+#ifdef __LP64__
+    offset = GetThreadOffset<8>(entrypoint).Int32Value();
+#else
+    offset = GetThreadOffset<4>(entrypoint).Int32Value();
+#endif
+    return *reinterpret_cast<uintptr_t*>(reinterpret_cast<uint8_t*>(self) + offset);
+  }
+
  protected:
   size_t fp_result;
 };
 
 
-#if defined(__i386__) || (defined(__x86_64__) && !defined(__APPLE__))
-extern "C" void art_quick_memcpy(void);
-#endif
-
 TEST_F(StubTest, Memcpy) {
 #if defined(__i386__) || (defined(__x86_64__) && !defined(__APPLE__))
   Thread* self = Thread::Current();
@@ -564,7 +571,7 @@
   }
 
   Invoke3(reinterpret_cast<size_t>(&trg[4]), reinterpret_cast<size_t>(&orig[4]),
-          10 * sizeof(uint32_t), reinterpret_cast<uintptr_t>(&art_quick_memcpy), self);
+          10 * sizeof(uint32_t), StubTest::GetEntrypoint(self, kQuickMemcpy), self);
 
   EXPECT_EQ(orig[0], trg[0]);
 
@@ -589,15 +596,14 @@
 #endif
 }
 
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
-extern "C" void art_quick_lock_object(void);
-#endif
-
 TEST_F(StubTest, LockObject) {
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
   static constexpr size_t kThinLockLoops = 100;
 
   Thread* self = Thread::Current();
+
+  const uintptr_t art_quick_lock_object = StubTest::GetEntrypoint(self, kQuickLockObject);
+
   // Create an object
   ScopedObjectAccess soa(self);
   // garbage is created during ClassLinker::Init
@@ -609,8 +615,7 @@
   LockWord::LockState old_state = lock.GetState();
   EXPECT_EQ(LockWord::LockState::kUnlocked, old_state);
 
-  Invoke3(reinterpret_cast<size_t>(obj.Get()), 0U, 0U,
-          reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
+  Invoke3(reinterpret_cast<size_t>(obj.Get()), 0U, 0U, art_quick_lock_object, self);
 
   LockWord lock_after = obj->GetLockWord(false);
   LockWord::LockState new_state = lock_after.GetState();
@@ -618,8 +623,7 @@
   EXPECT_EQ(lock_after.ThinLockCount(), 0U);  // Thin lock starts count at zero
 
   for (size_t i = 1; i < kThinLockLoops; ++i) {
-    Invoke3(reinterpret_cast<size_t>(obj.Get()), 0U, 0U,
-              reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
+    Invoke3(reinterpret_cast<size_t>(obj.Get()), 0U, 0U, art_quick_lock_object, self);
 
     // Check we're at lock count i
 
@@ -635,8 +639,7 @@
 
   obj2->IdentityHashCode();
 
-  Invoke3(reinterpret_cast<size_t>(obj2.Get()), 0U, 0U,
-          reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
+  Invoke3(reinterpret_cast<size_t>(obj2.Get()), 0U, 0U, art_quick_lock_object, self);
 
   LockWord lock_after2 = obj2->GetLockWord(false);
   LockWord::LockState new_state2 = lock_after2.GetState();
@@ -665,17 +668,15 @@
 };
 
 
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
-extern "C" void art_quick_lock_object(void);
-extern "C" void art_quick_unlock_object(void);
-#endif
-
 // NO_THREAD_SAFETY_ANALYSIS as we do not want to grab exclusive mutator lock for MonitorInfo.
 static void TestUnlockObject(StubTest* test) NO_THREAD_SAFETY_ANALYSIS {
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
   static constexpr size_t kThinLockLoops = 100;
 
   Thread* self = Thread::Current();
+
+  const uintptr_t art_quick_lock_object = StubTest::GetEntrypoint(self, kQuickLockObject);
+  const uintptr_t art_quick_unlock_object = StubTest::GetEntrypoint(self, kQuickUnlockObject);
   // Create an object
   ScopedObjectAccess soa(self);
   // garbage is created during ClassLinker::Init
@@ -687,8 +688,7 @@
   LockWord::LockState old_state = lock.GetState();
   EXPECT_EQ(LockWord::LockState::kUnlocked, old_state);
 
-  test->Invoke3(reinterpret_cast<size_t>(obj.Get()), 0U, 0U,
-                reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
+  test->Invoke3(reinterpret_cast<size_t>(obj.Get()), 0U, 0U, art_quick_unlock_object, self);
   // This should be an illegal monitor state.
   EXPECT_TRUE(self->IsExceptionPending());
   self->ClearException();
@@ -697,15 +697,13 @@
   LockWord::LockState new_state = lock_after.GetState();
   EXPECT_EQ(LockWord::LockState::kUnlocked, new_state);
 
-  test->Invoke3(reinterpret_cast<size_t>(obj.Get()), 0U, 0U,
-                reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
+  test->Invoke3(reinterpret_cast<size_t>(obj.Get()), 0U, 0U, art_quick_lock_object, self);
 
   LockWord lock_after2 = obj->GetLockWord(false);
   LockWord::LockState new_state2 = lock_after2.GetState();
   EXPECT_EQ(LockWord::LockState::kThinLocked, new_state2);
 
-  test->Invoke3(reinterpret_cast<size_t>(obj.Get()), 0U, 0U,
-                reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
+  test->Invoke3(reinterpret_cast<size_t>(obj.Get()), 0U, 0U, art_quick_unlock_object, self);
 
   LockWord lock_after3 = obj->GetLockWord(false);
   LockWord::LockState new_state3 = lock_after3.GetState();
@@ -759,12 +757,12 @@
       }
 
       if (lock) {
-        test->Invoke3(reinterpret_cast<size_t>(objects[index].Get()), 0U, 0U,
-                       reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
+        test->Invoke3(reinterpret_cast<size_t>(objects[index].Get()), 0U, 0U, art_quick_lock_object,
+                      self);
         counts[index]++;
       } else {
         test->Invoke3(reinterpret_cast<size_t>(objects[index].Get()), 0U, 0U,
-                      reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
+                      art_quick_unlock_object, self);
         counts[index]--;
       }
 
@@ -795,8 +793,8 @@
     size_t index = kNumberOfLocks - 1 - i;
     size_t count = counts[index];
     while (count > 0) {
-      test->Invoke3(reinterpret_cast<size_t>(objects[index].Get()), 0U, 0U,
-                    reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
+      test->Invoke3(reinterpret_cast<size_t>(objects[index].Get()), 0U, 0U, art_quick_unlock_object,
+                    self);
       count--;
     }
 
@@ -825,6 +823,9 @@
 TEST_F(StubTest, CheckCast) {
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
   Thread* self = Thread::Current();
+
+  const uintptr_t art_quick_check_cast = StubTest::GetEntrypoint(self, kQuickCheckCast);
+
   // Find some classes.
   ScopedObjectAccess soa(self);
   // garbage is created during ClassLinker::Init
@@ -838,24 +839,24 @@
   EXPECT_FALSE(self->IsExceptionPending());
 
   Invoke3(reinterpret_cast<size_t>(c.Get()), reinterpret_cast<size_t>(c.Get()), 0U,
-          reinterpret_cast<uintptr_t>(&art_quick_check_cast), self);
+          art_quick_check_cast, self);
 
   EXPECT_FALSE(self->IsExceptionPending());
 
   Invoke3(reinterpret_cast<size_t>(c2.Get()), reinterpret_cast<size_t>(c2.Get()), 0U,
-          reinterpret_cast<uintptr_t>(&art_quick_check_cast), self);
+          art_quick_check_cast, self);
 
   EXPECT_FALSE(self->IsExceptionPending());
 
   Invoke3(reinterpret_cast<size_t>(c.Get()), reinterpret_cast<size_t>(c2.Get()), 0U,
-          reinterpret_cast<uintptr_t>(&art_quick_check_cast), self);
+          art_quick_check_cast, self);
 
   EXPECT_FALSE(self->IsExceptionPending());
 
   // TODO: Make the following work. But that would require correct managed frames.
 
   Invoke3(reinterpret_cast<size_t>(c2.Get()), reinterpret_cast<size_t>(c.Get()), 0U,
-          reinterpret_cast<uintptr_t>(&art_quick_check_cast), self);
+          art_quick_check_cast, self);
 
   EXPECT_TRUE(self->IsExceptionPending());
   self->ClearException();
@@ -868,16 +869,16 @@
 }
 
 
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
-extern "C" void art_quick_aput_obj_with_null_and_bound_check(void);
-// Do not check non-checked ones, we'd need handlers and stuff...
-#endif
-
 TEST_F(StubTest, APutObj) {
   TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
 
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
   Thread* self = Thread::Current();
+
+  // Do not check non-checked ones, we'd need handlers and stuff...
+  const uintptr_t art_quick_aput_obj_with_null_and_bound_check =
+      StubTest::GetEntrypoint(self, kQuickAputObjectWithNullAndBoundCheck);
+
   // Create an object
   ScopedObjectAccess soa(self);
   // garbage is created during ClassLinker::Init
@@ -907,25 +908,25 @@
   EXPECT_FALSE(self->IsExceptionPending());
 
   Invoke3(reinterpret_cast<size_t>(array.Get()), 0U, reinterpret_cast<size_t>(str_obj.Get()),
-          reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
+          art_quick_aput_obj_with_null_and_bound_check, self);
 
   EXPECT_FALSE(self->IsExceptionPending());
   EXPECT_EQ(str_obj.Get(), array->Get(0));
 
   Invoke3(reinterpret_cast<size_t>(array.Get()), 1U, reinterpret_cast<size_t>(str_obj.Get()),
-          reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
+          art_quick_aput_obj_with_null_and_bound_check, self);
 
   EXPECT_FALSE(self->IsExceptionPending());
   EXPECT_EQ(str_obj.Get(), array->Get(1));
 
   Invoke3(reinterpret_cast<size_t>(array.Get()), 2U, reinterpret_cast<size_t>(str_obj.Get()),
-          reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
+          art_quick_aput_obj_with_null_and_bound_check, self);
 
   EXPECT_FALSE(self->IsExceptionPending());
   EXPECT_EQ(str_obj.Get(), array->Get(2));
 
   Invoke3(reinterpret_cast<size_t>(array.Get()), 3U, reinterpret_cast<size_t>(str_obj.Get()),
-          reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
+          art_quick_aput_obj_with_null_and_bound_check, self);
 
   EXPECT_FALSE(self->IsExceptionPending());
   EXPECT_EQ(str_obj.Get(), array->Get(3));
@@ -933,25 +934,25 @@
   // 1.2) Assign null to array[0..3]
 
   Invoke3(reinterpret_cast<size_t>(array.Get()), 0U, reinterpret_cast<size_t>(nullptr),
-          reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
+          art_quick_aput_obj_with_null_and_bound_check, self);
 
   EXPECT_FALSE(self->IsExceptionPending());
   EXPECT_EQ(nullptr, array->Get(0));
 
   Invoke3(reinterpret_cast<size_t>(array.Get()), 1U, reinterpret_cast<size_t>(nullptr),
-          reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
+          art_quick_aput_obj_with_null_and_bound_check, self);
 
   EXPECT_FALSE(self->IsExceptionPending());
   EXPECT_EQ(nullptr, array->Get(1));
 
   Invoke3(reinterpret_cast<size_t>(array.Get()), 2U, reinterpret_cast<size_t>(nullptr),
-          reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
+          art_quick_aput_obj_with_null_and_bound_check, self);
 
   EXPECT_FALSE(self->IsExceptionPending());
   EXPECT_EQ(nullptr, array->Get(2));
 
   Invoke3(reinterpret_cast<size_t>(array.Get()), 3U, reinterpret_cast<size_t>(nullptr),
-          reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
+          art_quick_aput_obj_with_null_and_bound_check, self);
 
   EXPECT_FALSE(self->IsExceptionPending());
   EXPECT_EQ(nullptr, array->Get(3));
@@ -972,7 +973,7 @@
 
   Invoke3(reinterpret_cast<size_t>(array.Get()), static_cast<size_t>(-1),
           reinterpret_cast<size_t>(str_obj.Get()),
-          reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
+          art_quick_aput_obj_with_null_and_bound_check, self);
 
   EXPECT_TRUE(self->IsExceptionPending());
   self->ClearException();
@@ -980,7 +981,7 @@
   // 2.3) Index > 0
 
   Invoke3(reinterpret_cast<size_t>(array.Get()), 10U, reinterpret_cast<size_t>(str_obj.Get()),
-          reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
+          art_quick_aput_obj_with_null_and_bound_check, self);
 
   EXPECT_TRUE(self->IsExceptionPending());
   self->ClearException();
@@ -988,7 +989,7 @@
   // 3) Failure cases (obj into str[])
 
   Invoke3(reinterpret_cast<size_t>(array.Get()), 0U, reinterpret_cast<size_t>(obj_obj.Get()),
-          reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
+          art_quick_aput_obj_with_null_and_bound_check, self);
 
   EXPECT_TRUE(self->IsExceptionPending());
   self->ClearException();
@@ -1024,7 +1025,7 @@
     size_t result = Invoke3(static_cast<size_t>(c->GetDexTypeIndex()),    // type_idx
                             reinterpret_cast<size_t>(c->GetVirtualMethod(0)),  // arbitrary
                             0U,
-                            reinterpret_cast<uintptr_t>(GetTlsPtr(self)->quick_entrypoints.pAllocObject),
+                            StubTest::GetEntrypoint(self, kQuickAllocObject),
                             self);
 
     EXPECT_FALSE(self->IsExceptionPending());
@@ -1038,7 +1039,7 @@
     // We can use nullptr in the second argument as we do not need a method here (not used in
     // resolved/initialized cases)
     size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), reinterpret_cast<size_t>(nullptr), 0U,
-                            reinterpret_cast<uintptr_t>(GetTlsPtr(self)->quick_entrypoints.pAllocObjectResolved),
+                            StubTest::GetEntrypoint(self, kQuickAllocObjectResolved),
                             self);
 
     EXPECT_FALSE(self->IsExceptionPending());
@@ -1052,7 +1053,7 @@
     // We can use nullptr in the second argument as we do not need a method here (not used in
     // resolved/initialized cases)
     size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), reinterpret_cast<size_t>(nullptr), 0U,
-                            reinterpret_cast<uintptr_t>(GetTlsPtr(self)->quick_entrypoints.pAllocObjectInitialized),
+                            StubTest::GetEntrypoint(self, kQuickAllocObjectInitialized),
                             self);
 
     EXPECT_FALSE(self->IsExceptionPending());
@@ -1108,7 +1109,7 @@
     self->ClearException();
 
     size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), reinterpret_cast<size_t>(nullptr), 0U,
-                            reinterpret_cast<uintptr_t>(GetTlsPtr(self)->quick_entrypoints.pAllocObjectInitialized),
+                            StubTest::GetEntrypoint(self, kQuickAllocObjectInitialized),
                             self);
     EXPECT_TRUE(self->IsExceptionPending());
     self->ClearException();
@@ -1154,7 +1155,7 @@
     size_t result = Invoke3(static_cast<size_t>(c->GetDexTypeIndex()),    // type_idx
                             reinterpret_cast<size_t>(c_obj->GetVirtualMethod(0)),  // arbitrary
                             10U,
-                            reinterpret_cast<uintptr_t>(GetTlsPtr(self)->quick_entrypoints.pAllocArray),
+                            StubTest::GetEntrypoint(self, kQuickAllocArray),
                             self);
 
     EXPECT_FALSE(self->IsExceptionPending());
@@ -1169,7 +1170,7 @@
     // We can use nullptr in the second argument as we do not need a method here (not used in
     // resolved/initialized cases)
     size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), reinterpret_cast<size_t>(nullptr), 10U,
-                            reinterpret_cast<uintptr_t>(GetTlsPtr(self)->quick_entrypoints.pAllocArrayResolved),
+                            StubTest::GetEntrypoint(self, kQuickAllocArrayResolved),
                             self);
     EXPECT_FALSE(self->IsExceptionPending()) << PrettyTypeOf(self->GetException(nullptr));
     EXPECT_NE(reinterpret_cast<size_t>(nullptr), result);
@@ -1188,7 +1189,7 @@
   {
     size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), reinterpret_cast<size_t>(nullptr),
                             GB,  // that should fail...
-                            reinterpret_cast<uintptr_t>(GetTlsPtr(self)->quick_entrypoints.pAllocArrayResolved),
+                            StubTest::GetEntrypoint(self, kQuickAllocArrayResolved),
                             self);
 
     EXPECT_TRUE(self->IsExceptionPending());
@@ -1205,10 +1206,6 @@
 }
 
 
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
-extern "C" void art_quick_string_compareto(void);
-#endif
-
 TEST_F(StubTest, StringCompareTo) {
   TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
 
@@ -1216,6 +1213,9 @@
   // TODO: Check the "Unresolved" allocation stubs
 
   Thread* self = Thread::Current();
+
+  const uintptr_t art_quick_string_compareto = StubTest::GetEntrypoint(self, kQuickStringCompareTo);
+
   ScopedObjectAccess soa(self);
   // garbage is created during ClassLinker::Init
 
@@ -1274,7 +1274,7 @@
       // Test string_compareto x y
       size_t result = Invoke3(reinterpret_cast<size_t>(s[x].Get()),
                               reinterpret_cast<size_t>(s[y].Get()), 0U,
-                              reinterpret_cast<uintptr_t>(&art_quick_string_compareto), self);
+                              art_quick_string_compareto, self);
 
       EXPECT_FALSE(self->IsExceptionPending());
 
@@ -1306,11 +1306,6 @@
 }
 
 
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
-extern "C" void art_quick_set32_static(void);
-extern "C" void art_quick_get32_static(void);
-#endif
-
 static void GetSet32Static(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f, Thread* self,
                            mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -1322,13 +1317,13 @@
     test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                               static_cast<size_t>(values[i]),
                               0U,
-                              reinterpret_cast<uintptr_t>(&art_quick_set32_static),
+                              StubTest::GetEntrypoint(self, kQuickSet32Static),
                               self,
                               referrer);
 
     size_t res = test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                                            0U, 0U,
-                                           reinterpret_cast<uintptr_t>(&art_quick_get32_static),
+                                           StubTest::GetEntrypoint(self, kQuickGet32Static),
                                            self,
                                            referrer);
 
@@ -1342,11 +1337,6 @@
 }
 
 
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
-extern "C" void art_quick_set32_instance(void);
-extern "C" void art_quick_get32_instance(void);
-#endif
-
 static void GetSet32Instance(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f,
                              Thread* self, mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -1358,7 +1348,7 @@
     test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                               reinterpret_cast<size_t>(obj->Get()),
                               static_cast<size_t>(values[i]),
-                              reinterpret_cast<uintptr_t>(&art_quick_set32_instance),
+                              StubTest::GetEntrypoint(self, kQuickSet32Instance),
                               self,
                               referrer);
 
@@ -1371,7 +1361,7 @@
     size_t res2 = test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                                             reinterpret_cast<size_t>(obj->Get()),
                                             0U,
-                                            reinterpret_cast<uintptr_t>(&art_quick_get32_instance),
+                                            StubTest::GetEntrypoint(self, kQuickGet32Instance),
                                             self,
                                             referrer);
     EXPECT_EQ(res, static_cast<int32_t>(res2));
@@ -1385,8 +1375,6 @@
 
 
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
-extern "C" void art_quick_set_obj_static(void);
-extern "C" void art_quick_get_obj_static(void);
 
 static void set_and_check_static(uint32_t f_idx, mirror::Object* val, Thread* self,
                                  mirror::ArtMethod* referrer, StubTest* test)
@@ -1394,13 +1382,13 @@
   test->Invoke3WithReferrer(static_cast<size_t>(f_idx),
                             reinterpret_cast<size_t>(val),
                             0U,
-                            reinterpret_cast<uintptr_t>(&art_quick_set_obj_static),
+                            StubTest::GetEntrypoint(self, kQuickSetObjStatic),
                             self,
                             referrer);
 
   size_t res = test->Invoke3WithReferrer(static_cast<size_t>(f_idx),
                                          0U, 0U,
-                                         reinterpret_cast<uintptr_t>(&art_quick_get_obj_static),
+                                         StubTest::GetEntrypoint(self, kQuickGetObjStatic),
                                          self,
                                          referrer);
 
@@ -1428,9 +1416,6 @@
 
 
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
-extern "C" void art_quick_set_obj_instance(void);
-extern "C" void art_quick_get_obj_instance(void);
-
 static void set_and_check_instance(Handle<mirror::ArtField>* f, mirror::Object* trg,
                                    mirror::Object* val, Thread* self, mirror::ArtMethod* referrer,
                                    StubTest* test)
@@ -1438,14 +1423,14 @@
   test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                             reinterpret_cast<size_t>(trg),
                             reinterpret_cast<size_t>(val),
-                            reinterpret_cast<uintptr_t>(&art_quick_set_obj_instance),
+                            StubTest::GetEntrypoint(self, kQuickSetObjInstance),
                             self,
                             referrer);
 
   size_t res = test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                                          reinterpret_cast<size_t>(trg),
                                          0U,
-                                         reinterpret_cast<uintptr_t>(&art_quick_get_obj_instance),
+                                         StubTest::GetEntrypoint(self, kQuickGetObjInstance),
                                          self,
                                          referrer);
 
@@ -1476,11 +1461,6 @@
 
 // TODO: Complete these tests for 32b architectures.
 
-#if (defined(__x86_64__) && !defined(__APPLE__)) || defined(__aarch64__)
-extern "C" void art_quick_set64_static(void);
-extern "C" void art_quick_get64_static(void);
-#endif
-
 static void GetSet64Static(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f, Thread* self,
                            mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -1491,13 +1471,13 @@
   for (size_t i = 0; i < num_values; ++i) {
     test->Invoke3UWithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                                values[i],
-                               reinterpret_cast<uintptr_t>(&art_quick_set64_static),
+                               StubTest::GetEntrypoint(self, kQuickSet64Static),
                                self,
                                referrer);
 
     size_t res = test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                                            0U, 0U,
-                                           reinterpret_cast<uintptr_t>(&art_quick_get64_static),
+                                           StubTest::GetEntrypoint(self, kQuickGet64Static),
                                            self,
                                            referrer);
 
@@ -1511,11 +1491,6 @@
 }
 
 
-#if (defined(__x86_64__) && !defined(__APPLE__)) || defined(__aarch64__)
-extern "C" void art_quick_set64_instance(void);
-extern "C" void art_quick_get64_instance(void);
-#endif
-
 static void GetSet64Instance(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f,
                              Thread* self, mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -1527,7 +1502,7 @@
     test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                               reinterpret_cast<size_t>(obj->Get()),
                               static_cast<size_t>(values[i]),
-                              reinterpret_cast<uintptr_t>(&art_quick_set64_instance),
+                              StubTest::GetEntrypoint(self, kQuickSet64Instance),
                               self,
                               referrer);
 
@@ -1540,7 +1515,7 @@
     size_t res2 = test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                                             reinterpret_cast<size_t>(obj->Get()),
                                             0U,
-                                            reinterpret_cast<uintptr_t>(&art_quick_get64_instance),
+                                            StubTest::GetEntrypoint(self, kQuickGet64Instance),
                                             self,
                                             referrer);
     EXPECT_EQ(res, static_cast<int64_t>(res2));
@@ -1683,9 +1658,6 @@
   TestFields(self, this, Primitive::Type::kPrimLong);
 }
 
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
-extern "C" void art_quick_imt_conflict_trampoline(void);
-#endif
 
 TEST_F(StubTest, IMT) {
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
@@ -1716,7 +1688,7 @@
   // Patch up ArrayList.contains.
   if (contains_amethod.Get()->GetEntryPointFromQuickCompiledCode() == nullptr) {
     contains_amethod.Get()->SetEntryPointFromQuickCompiledCode(reinterpret_cast<void*>(
-        GetTlsPtr(self)->quick_entrypoints.pQuickToInterpreterBridge));
+        StubTest::GetEntrypoint(self, kQuickQuickToInterpreterBridge)));
   }
 
   // List
@@ -1765,7 +1737,7 @@
   size_t result =
       Invoke3WithReferrerAndHidden(0U, reinterpret_cast<size_t>(array_list.Get()),
                                    reinterpret_cast<size_t>(obj.Get()),
-                                   reinterpret_cast<uintptr_t>(&art_quick_imt_conflict_trampoline),
+                                   StubTest::GetEntrypoint(self, kQuickQuickImtConflictTrampoline),
                                    self, contains_amethod.Get(),
                                    static_cast<size_t>(inf_contains.Get()->GetDexMethodIndex()));
 
@@ -1782,7 +1754,7 @@
 
   result = Invoke3WithReferrerAndHidden(0U, reinterpret_cast<size_t>(array_list.Get()),
                                         reinterpret_cast<size_t>(obj.Get()),
-                                        reinterpret_cast<uintptr_t>(&art_quick_imt_conflict_trampoline),
+                                        StubTest::GetEntrypoint(self, kQuickQuickImtConflictTrampoline),
                                         self, contains_amethod.Get(),
                                         static_cast<size_t>(inf_contains.Get()->GetDexMethodIndex()));
 
@@ -1795,10 +1767,6 @@
 #endif
 }
 
-#if defined(__arm__) || defined(__aarch64__)
-extern "C" void art_quick_indexof(void);
-#endif
-
 TEST_F(StubTest, StringIndexOf) {
 #if defined(__arm__) || defined(__aarch64__)
   TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
@@ -1848,7 +1816,7 @@
 
         // Test string_compareto x y
         size_t result = Invoke3(reinterpret_cast<size_t>(s[x].Get()), c_char[y], start,
-                                reinterpret_cast<uintptr_t>(&art_quick_indexof), self);
+                                StubTest::GetEntrypoint(self, kQuickIndexOf), self);
 
         EXPECT_FALSE(self->IsExceptionPending());
 
diff --git a/runtime/arch/x86/asm_support_x86.S b/runtime/arch/x86/asm_support_x86.S
index 96c2c05..a578023 100644
--- a/runtime/arch/x86/asm_support_x86.S
+++ b/runtime/arch/x86/asm_support_x86.S
@@ -112,6 +112,7 @@
     #define PLT_SYMBOL(name) _ ## name
 #endif
 
+// Directive to hide a function symbol.
 #if defined(__APPLE__)
     #define ASM_HIDDEN .private_extern
 #else
@@ -125,6 +126,17 @@
 
 MACRO1(DEFINE_FUNCTION, c_name)
     FUNCTION_TYPE(\c_name, 0)
+    ASM_HIDDEN VAR(c_name, 0)
+    .globl VAR(c_name, 0)
+    ALIGN_FUNCTION_ENTRY
+VAR(c_name, 0):
+    CFI_STARTPROC
+    // Ensure we get a sane starting CFA.
+    CFI_DEF_CFA(esp, 4)
+END_MACRO
+
+MACRO1(DEFINE_FUNCTION_NO_HIDE, c_name)
+    FUNCTION_TYPE(\c_name, 0)
     .globl VAR(c_name, 0)
     ALIGN_FUNCTION_ENTRY
 VAR(c_name, 0):
diff --git a/runtime/arch/x86/portable_entrypoints_x86.S b/runtime/arch/x86/portable_entrypoints_x86.S
index 5f270f8..9365795 100644
--- a/runtime/arch/x86/portable_entrypoints_x86.S
+++ b/runtime/arch/x86/portable_entrypoints_x86.S
@@ -115,7 +115,7 @@
   ret
 END_FUNCTION art_portable_resolution_trampoline
 
-DEFINE_FUNCTION art_portable_to_interpreter_bridge
+DEFINE_FUNCTION_NO_HIDE art_portable_to_interpreter_bridge
   PUSH ebp                        // Set up frame.
   movl %esp, %ebp
   CFI_DEF_CFA_REGISTER(%ebp)
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 084846a..2f3e317 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -106,7 +106,7 @@
     pushl %fs:THREAD_SELF_OFFSET             // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
     SETUP_GOT_NOSAVE                         // clobbers ebx (harmless here)
-    call PLT_SYMBOL(artDeliverPendingExceptionFromCode)  // artDeliverPendingExceptionFromCode(Thread*, SP)
+    call SYMBOL(artDeliverPendingExceptionFromCode)  // artDeliverPendingExceptionFromCode(Thread*, SP)
     int3                                     // unreached
 END_MACRO
 
@@ -121,7 +121,7 @@
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
     SETUP_GOT_NOSAVE              // clobbers ebx (harmless here)
-    call PLT_VAR(cxx_name, 1)     // cxx_name(Thread*, SP)
+    call VAR(cxx_name, 1)     // cxx_name(Thread*, SP)
     int3                          // unreached
     END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
@@ -137,7 +137,7 @@
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH eax                      // pass arg1
     SETUP_GOT_NOSAVE              // clobbers ebx (harmless here)
-    call PLT_VAR(cxx_name, 1)     // cxx_name(arg1, Thread*, SP)
+    call VAR(cxx_name, 1)     // cxx_name(arg1, Thread*, SP)
     int3                          // unreached
     END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
@@ -153,7 +153,7 @@
     PUSH ecx                      // pass arg2
     PUSH eax                      // pass arg1
     SETUP_GOT_NOSAVE              // clobbers ebx (harmless here)
-    call PLT_VAR(cxx_name, 1)     // cxx_name(arg1, arg2, Thread*, SP)
+    call VAR(cxx_name, 1)     // cxx_name(arg1, arg2, Thread*, SP)
     int3                          // unreached
     END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
@@ -161,7 +161,6 @@
     /*
      * Called by managed code to create and deliver a NullPointerException.
      */
-    ASM_HIDDEN art_quick_throw_null_pointer_exception
 NO_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception, artThrowNullPointerExceptionFromCode
 
     /*
@@ -189,7 +188,6 @@
      * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException. Arg1 holds
      * index, arg2 holds limit.
      */
-    ASM_HIDDEN art_quick_throw_array_bounds
 TWO_ARG_RUNTIME_EXCEPTION art_quick_throw_array_bounds, artThrowArrayBoundsFromCode
 
     /*
@@ -231,7 +229,7 @@
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH ecx                      // pass arg2
     PUSH eax                      // pass arg1
-    call PLT_VAR(cxx_name, 1)     // cxx_name(arg1, arg2, arg3, Thread*, SP)
+    call VAR(cxx_name, 1)     // cxx_name(arg1, arg2, arg3, Thread*, SP)
     movl %edx, %edi               // save code pointer in EDI
     addl MACRO_LITERAL(36), %esp  // Pop arguments skip eax
     CFI_ADJUST_CFA_OFFSET(-36)
@@ -253,7 +251,6 @@
     END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
 
-    ASM_HIDDEN art_quick_invoke_interface_trampoline
 INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline
 INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
 
@@ -328,7 +325,7 @@
     PUSH edx                      // pass SP
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
-    call PLT_VAR(cxx_name, 1)     // cxx_name(Thread*, SP)
+    call VAR(cxx_name, 1)     // cxx_name(Thread*, SP)
     addl MACRO_LITERAL(16), %esp  // pop arguments
     CFI_ADJUST_CFA_OFFSET(-16)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
@@ -347,7 +344,7 @@
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH eax                      // pass arg1
-    call PLT_VAR(cxx_name, 1)     // cxx_name(arg1, Thread*, SP)
+    call VAR(cxx_name, 1)     // cxx_name(arg1, Thread*, SP)
     addl MACRO_LITERAL(16), %esp  // pop arguments
     CFI_ADJUST_CFA_OFFSET(-16)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
@@ -366,7 +363,7 @@
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH ecx                      // pass arg2
     PUSH eax                      // pass arg1
-    call PLT_VAR(cxx_name, 1)     // cxx_name(arg1, arg2, Thread*, SP)
+    call VAR(cxx_name, 1)     // cxx_name(arg1, arg2, Thread*, SP)
     addl MACRO_LITERAL(16), %esp  // pop arguments
     CFI_ADJUST_CFA_OFFSET(-16)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
@@ -388,7 +385,7 @@
     PUSH ecx                      // pass arg2
     PUSH eax                      // pass arg1
     SETUP_GOT_NOSAVE              // clobbers EBX
-    call PLT_VAR(cxx_name, 1)     // cxx_name(arg1, arg2, arg3, Thread*, SP)
+    call VAR(cxx_name, 1)     // cxx_name(arg1, arg2, arg3, Thread*, SP)
     addl MACRO_LITERAL(32), %esp  // pop arguments
     CFI_ADJUST_CFA_OFFSET(-32)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
@@ -569,7 +566,7 @@
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH eax                      // pass object
-    call PLT_SYMBOL(artLockObjectFromCode)  // artLockObjectFromCode(object, Thread*, SP)
+    call SYMBOL(artLockObjectFromCode)  // artLockObjectFromCode(object, Thread*, SP)
     addl LITERAL(16), %esp  // pop arguments
     CFI_ADJUST_CFA_OFFSET(-16)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
@@ -603,7 +600,7 @@
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH eax                      // pass object
-    call PLT_SYMBOL(artUnlockObjectFromCode)  // artUnlockObjectFromCode(object, Thread*, SP)
+    call SYMBOL(artUnlockObjectFromCode)  // artUnlockObjectFromCode(object, Thread*, SP)
     addl LITERAL(16), %esp  // pop arguments
     CFI_ADJUST_CFA_OFFSET(-16)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
@@ -615,7 +612,7 @@
     PUSH eax                     // alignment padding
     PUSH ecx                     // pass arg2 - obj->klass
     PUSH eax                     // pass arg1 - checked class
-    call PLT_SYMBOL(artIsAssignableFromCode)  // (Class* klass, Class* ref_klass)
+    call SYMBOL(artIsAssignableFromCode)  // (Class* klass, Class* ref_klass)
     addl LITERAL(12), %esp        // pop arguments
     CFI_ADJUST_CFA_OFFSET(-12)
     ret
@@ -626,7 +623,7 @@
     PUSH eax                     // alignment padding
     PUSH ecx                     // pass arg2 - obj->klass
     PUSH eax                     // pass arg1 - checked class
-    call PLT_SYMBOL(artIsAssignableFromCode)  // (Class* klass, Class* ref_klass)
+    call SYMBOL(artIsAssignableFromCode)  // (Class* klass, Class* ref_klass)
     testl %eax, %eax
     jz 1f                         // jump forward if not assignable
     addl LITERAL(12), %esp        // pop arguments
@@ -645,7 +642,7 @@
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH ecx                      // pass arg2
     PUSH eax                      // pass arg1
-    call PLT_SYMBOL(artThrowClassCastException) // (Class* a, Class* b, Thread*, SP)
+    call SYMBOL(artThrowClassCastException) // (Class* a, Class* b, Thread*, SP)
     int3                          // unreached
 END_FUNCTION art_quick_check_cast
 
@@ -660,7 +657,6 @@
     jmp SYMBOL(art_quick_throw_null_pointer_exception)
 END_FUNCTION art_quick_aput_obj_with_null_and_bound_check
 
-    ASM_HIDDEN art_quick_aput_obj_with_bound_check
 DEFINE_FUNCTION art_quick_aput_obj_with_bound_check
     movl ARRAY_LENGTH_OFFSET(%eax), %ebx
     cmpl %ebx, %ecx
@@ -670,7 +666,6 @@
     jmp SYMBOL(art_quick_throw_array_bounds)
 END_FUNCTION art_quick_aput_obj_with_bound_check
 
-    ASM_HIDDEN art_quick_aput_obj
 DEFINE_FUNCTION art_quick_aput_obj
     test %edx, %edx              // store of null
     jz .Ldo_aput_null
@@ -697,7 +692,7 @@
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH ebx                     // pass arg1 - component type of the array
     SETUP_GOT_NOSAVE             // clobbers EBX
-    call PLT_SYMBOL(artIsAssignableFromCode)  // (Class* a, Class* b)
+    call SYMBOL(artIsAssignableFromCode)  // (Class* a, Class* b)
     addl LITERAL(16), %esp       // pop arguments
     CFI_ADJUST_CFA_OFFSET(-16)
     testl %eax, %eax
@@ -722,7 +717,7 @@
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH edx                      // pass arg2 - value
     PUSH eax                      // pass arg1 - array
-    call PLT_SYMBOL(artThrowArrayStoreException) // (array, value, Thread*, SP)
+    call SYMBOL(artThrowArrayStoreException) // (array, value, Thread*, SP)
     int3                          // unreached
 END_FUNCTION art_quick_aput_obj
 
@@ -744,7 +739,7 @@
     PUSH ecx                      // pass arg2 a.hi
     PUSH eax                      // pass arg1 a.lo
     SETUP_GOT_NOSAVE              // clobbers EBX
-    call PLT_SYMBOL(art_d2l)      // (jdouble a)
+    call SYMBOL(art_d2l)      // (jdouble a)
     addl LITERAL(12), %esp        // pop arguments
     CFI_ADJUST_CFA_OFFSET(-12)
     ret
@@ -755,7 +750,7 @@
     CFI_ADJUST_CFA_OFFSET(8)
     SETUP_GOT_NOSAVE              // clobbers EBX
     PUSH eax                      // pass arg1 a
-    call PLT_SYMBOL(art_f2l)      // (jfloat a)
+    call SYMBOL(art_f2l)      // (jfloat a)
     addl LITERAL(12), %esp        // pop arguments
     CFI_ADJUST_CFA_OFFSET(-12)
     ret
@@ -769,7 +764,7 @@
     PUSH ecx                     // pass arg2 a.hi
     PUSH eax                     // pass arg1 a.lo
     SETUP_GOT_NOSAVE             // clobbers EBX
-    call PLT_SYMBOL(artLdiv)     // (jlong a, jlong b)
+    call SYMBOL(artLdiv)     // (jlong a, jlong b)
     addl LITERAL(28), %esp       // pop arguments
     CFI_ADJUST_CFA_OFFSET(-28)
     ret
@@ -783,7 +778,7 @@
     PUSH ecx                     // pass arg2 a.hi
     PUSH eax                     // pass arg1 a.lo
     SETUP_GOT_NOSAVE             // clobbers EBX
-    call PLT_SYMBOL(artLmod)     // (jlong a, jlong b)
+    call SYMBOL(artLmod)     // (jlong a, jlong b)
     addl LITERAL(28), %esp       // pop arguments
     CFI_ADJUST_CFA_OFFSET(-28)
     ret
@@ -851,7 +846,7 @@
     PUSH ecx                      // pass object
     PUSH eax                      // pass field_idx
     SETUP_GOT_NOSAVE              // clobbers EBX
-    call PLT_SYMBOL(artSet32InstanceFromCode)  // (field_idx, Object*, new_val, referrer, Thread*, SP)
+    call SYMBOL(artSet32InstanceFromCode)  // (field_idx, Object*, new_val, referrer, Thread*, SP)
     addl LITERAL(32), %esp        // pop arguments
     CFI_ADJUST_CFA_OFFSET(-32)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
@@ -871,7 +866,7 @@
     PUSH ecx                      // pass object
     PUSH eax                      // pass field_idx
     SETUP_GOT_NOSAVE              // clobbers EBX
-    call PLT_SYMBOL(artSet64InstanceFromCode)  // (field_idx, Object*, new_val, Thread*, SP)
+    call SYMBOL(artSet64InstanceFromCode)  // (field_idx, Object*, new_val, Thread*, SP)
     addl LITERAL(32), %esp        // pop arguments
     CFI_ADJUST_CFA_OFFSET(-32)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
@@ -892,7 +887,7 @@
     PUSH ecx                      // pass object
     PUSH eax                      // pass field_idx
     SETUP_GOT_NOSAVE              // clobbers EBX
-    call PLT_SYMBOL(artSetObjInstanceFromCode) // (field_idx, Object*, new_val, referrer, Thread*, SP)
+    call SYMBOL(artSetObjInstanceFromCode) // (field_idx, Object*, new_val, referrer, Thread*, SP)
     addl LITERAL(32), %esp        // pop arguments
     CFI_ADJUST_CFA_OFFSET(-32)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
@@ -912,7 +907,7 @@
     PUSH ecx                      // pass object
     PUSH eax                      // pass field_idx
     SETUP_GOT_NOSAVE              // clobbers EBX
-    call PLT_SYMBOL(artGet32InstanceFromCode)  // (field_idx, Object*, referrer, Thread*, SP)
+    call SYMBOL(artGet32InstanceFromCode)  // (field_idx, Object*, referrer, Thread*, SP)
     addl LITERAL(32), %esp        // pop arguments
     CFI_ADJUST_CFA_OFFSET(-32)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
@@ -932,7 +927,7 @@
     PUSH ecx                      // pass object
     PUSH eax                      // pass field_idx
     SETUP_GOT_NOSAVE              // clobbers EBX
-    call PLT_SYMBOL(artGet64InstanceFromCode)  // (field_idx, Object*, referrer, Thread*, SP)
+    call SYMBOL(artGet64InstanceFromCode)  // (field_idx, Object*, referrer, Thread*, SP)
     addl LITERAL(32), %esp        // pop arguments
     CFI_ADJUST_CFA_OFFSET(-32)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
@@ -952,7 +947,7 @@
     PUSH ecx                      // pass object
     PUSH eax                      // pass field_idx
     SETUP_GOT_NOSAVE              // clobbers EBX
-    call PLT_SYMBOL(artGetObjInstanceFromCode) // (field_idx, Object*, referrer, Thread*, SP)
+    call SYMBOL(artGetObjInstanceFromCode) // (field_idx, Object*, referrer, Thread*, SP)
     addl LITERAL(32), %esp        // pop arguments
     CFI_ADJUST_CFA_OFFSET(-32)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
@@ -972,7 +967,7 @@
     PUSH ecx                      // pass new_val
     PUSH eax                      // pass field_idx
     SETUP_GOT_NOSAVE              // clobbers EBX
-    call PLT_SYMBOL(artSet32StaticFromCode)  // (field_idx, new_val, referrer, Thread*, SP)
+    call SYMBOL(artSet32StaticFromCode)  // (field_idx, new_val, referrer, Thread*, SP)
     addl LITERAL(32), %esp        // pop arguments
     CFI_ADJUST_CFA_OFFSET(-32)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
@@ -993,7 +988,7 @@
     PUSH ebx                      // pass referrer
     PUSH eax                      // pass field_idx
     SETUP_GOT_NOSAVE              // clobbers EBX
-    call PLT_SYMBOL(artSet64StaticFromCode)  // (field_idx, referrer, new_val, Thread*, SP)
+    call SYMBOL(artSet64StaticFromCode)  // (field_idx, referrer, new_val, Thread*, SP)
     addl LITERAL(32), %esp        // pop arguments
     CFI_ADJUST_CFA_OFFSET(-32)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
@@ -1013,7 +1008,7 @@
     PUSH ecx                      // pass new_val
     PUSH eax                      // pass field_idx
     SETUP_GOT_NOSAVE              // clobbers EBX
-    call PLT_SYMBOL(artSetObjStaticFromCode)  // (field_idx, new_val, referrer, Thread*, SP)
+    call SYMBOL(artSetObjStaticFromCode)  // (field_idx, new_val, referrer, Thread*, SP)
     addl LITERAL(32), %esp        // pop arguments
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
     RETURN_IF_EAX_ZERO            // return or deliver exception
@@ -1029,7 +1024,7 @@
     PUSH ecx                      // pass referrer
     PUSH eax                      // pass field_idx
     SETUP_GOT_NOSAVE              // clobbers EBX
-    call PLT_SYMBOL(artGet32StaticFromCode)    // (field_idx, referrer, Thread*, SP)
+    call SYMBOL(artGet32StaticFromCode)    // (field_idx, referrer, Thread*, SP)
     addl LITERAL(16), %esp        // pop arguments
     CFI_ADJUST_CFA_OFFSET(-16)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
@@ -1046,7 +1041,7 @@
     PUSH ecx                      // pass referrer
     PUSH eax                      // pass field_idx
     SETUP_GOT_NOSAVE              // clobbers EBX
-    call PLT_SYMBOL(artGet64StaticFromCode)    // (field_idx, referrer, Thread*, SP)
+    call SYMBOL(artGet64StaticFromCode)    // (field_idx, referrer, Thread*, SP)
     addl LITERAL(16), %esp        // pop arguments
     CFI_ADJUST_CFA_OFFSET(-16)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
@@ -1063,7 +1058,7 @@
     PUSH ecx                      // pass referrer
     PUSH eax                      // pass field_idx
     SETUP_GOT_NOSAVE              // clobbers EBX
-    call PLT_SYMBOL(artGetObjStaticFromCode)   // (field_idx, referrer, Thread*, SP)
+    call SYMBOL(artGetObjStaticFromCode)   // (field_idx, referrer, Thread*, SP)
     addl LITERAL(16), %esp        // pop arguments
     CFI_ADJUST_CFA_OFFSET(-16)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
@@ -1078,7 +1073,7 @@
     PUSH ecx                      // pass receiver
     PUSH eax                      // pass proxy method
     SETUP_GOT_NOSAVE              // clobbers EBX
-    call PLT_SYMBOL(artQuickProxyInvokeHandler) // (proxy method, receiver, Thread*, SP)
+    call SYMBOL(artQuickProxyInvokeHandler) // (proxy method, receiver, Thread*, SP)
     movd %eax, %xmm0              // place return value also into floating point return value
     movd %edx, %xmm1
     punpckldq %xmm1, %xmm0
@@ -1110,7 +1105,7 @@
     PUSH ecx                      // pass receiver
     PUSH eax                      // pass method
     SETUP_GOT_NOSAVE              // clobbers EBX
-    call PLT_SYMBOL(artQuickResolutionTrampoline) // (Method* called, receiver, Thread*, SP)
+    call SYMBOL(artQuickResolutionTrampoline) // (Method* called, receiver, Thread*, SP)
     movl %eax, %edi               // remember code pointer in EDI
     addl LITERAL(16), %esp        // pop arguments
     test %eax, %eax               // if code pointer is NULL goto deliver pending exception
@@ -1128,7 +1123,7 @@
     DELIVER_PENDING_EXCEPTION
 END_FUNCTION art_quick_resolution_trampoline
 
-DEFINE_FUNCTION art_quick_generic_jni_trampoline
+DEFINE_FUNCTION_NO_HIDE art_quick_generic_jni_trampoline
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
     // This also stores the native ArtMethod reference at the bottom of the stack.
 
@@ -1145,7 +1140,7 @@
     pushl %ebp                    // Pass SP (to ArtMethod).
     pushl %fs:THREAD_SELF_OFFSET  // Pass Thread::Current().
     SETUP_GOT_NOSAVE              // Clobbers ebx.
-    call PLT_SYMBOL(artQuickGenericJniTrampoline)  // (Thread*, sp)
+    call SYMBOL(artQuickGenericJniTrampoline)  // (Thread*, sp)
 
     // The C call will have registered the complete save-frame on success.
     // The result of the call is:
@@ -1175,7 +1170,7 @@
     pushl %edx                    // Pass int result.
     pushl %eax
     pushl %fs:THREAD_SELF_OFFSET  // Pass Thread::Current().
-    call PLT_SYMBOL(artQuickGenericJniEndTrampoline)
+    call SYMBOL(artQuickGenericJniEndTrampoline)
 
     // Tear down the alloca.
     movl %ebp, %esp
@@ -1209,7 +1204,7 @@
     DELIVER_PENDING_EXCEPTION
 END_FUNCTION art_quick_generic_jni_trampoline
 
-DEFINE_FUNCTION art_quick_to_interpreter_bridge
+DEFINE_FUNCTION_NO_HIDE art_quick_to_interpreter_bridge
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME   // save frame
     mov %esp, %edx                // remember SP
     PUSH eax                      // alignment padding
@@ -1218,7 +1213,7 @@
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH eax                      // pass  method
     SETUP_GOT_NOSAVE              // clobbers EBX
-    call PLT_SYMBOL(artQuickToInterpreterBridge)  // (method, Thread*, SP)
+    call SYMBOL(artQuickToInterpreterBridge)  // (method, Thread*, SP)
     movd %eax, %xmm0              // place return value also into floating point return value
     movd %edx, %xmm1
     punpckldq %xmm1, %xmm0
@@ -1245,7 +1240,7 @@
     PUSH ecx                      // Pass receiver.
     PUSH eax                      // Pass Method*.
     SETUP_GOT_NOSAVE              // clobbers EBX
-    call PLT_SYMBOL(artInstrumentationMethodEntryFromCode) // (Method*, Object*, Thread*, SP, LR)
+    call SYMBOL(artInstrumentationMethodEntryFromCode) // (Method*, Object*, Thread*, SP, LR)
     addl LITERAL(28), %esp        // Pop arguments upto saved Method*.
     movl 28(%esp), %edi           // Restore edi.
     movl %eax, 28(%esp)           // Place code* over edi, just under return pc.
@@ -1280,7 +1275,7 @@
     pushl %fs:THREAD_SELF_OFFSET  // Pass Thread::Current.
     CFI_ADJUST_CFA_OFFSET(4)
     SETUP_GOT_NOSAVE              // clobbers EBX
-    call PLT_SYMBOL(artInstrumentationMethodExitFromCode)  // (Thread*, SP, gpr_result, fpr_result)
+    call SYMBOL(artInstrumentationMethodExitFromCode)  // (Thread*, SP, gpr_result, fpr_result)
     mov   %eax, %ecx              // Move returned link register.
     addl LITERAL(32), %esp        // Pop arguments.
     CFI_ADJUST_CFA_OFFSET(-32)
@@ -1310,7 +1305,7 @@
     pushl %fs:THREAD_SELF_OFFSET  // Pass Thread::Current().
     CFI_ADJUST_CFA_OFFSET(4)
     SETUP_GOT_NOSAVE              // clobbers EBX
-    call PLT_SYMBOL(artDeoptimize)  // artDeoptimize(Thread*, SP)
+    call SYMBOL(artDeoptimize)  // artDeoptimize(Thread*, SP)
     int3                          // Unreachable.
 END_FUNCTION art_quick_deoptimize
 
diff --git a/runtime/arch/x86_64/asm_support_x86_64.S b/runtime/arch/x86_64/asm_support_x86_64.S
index 682ba43..4ae61a2 100644
--- a/runtime/arch/x86_64/asm_support_x86_64.S
+++ b/runtime/arch/x86_64/asm_support_x86_64.S
@@ -107,6 +107,13 @@
     #define PLT_SYMBOL(name) _ ## name
 #endif
 
+// Directive to hide a function symbol.
+#if defined(__APPLE__)
+    #define ASM_HIDDEN .private_extern
+#else
+    #define ASM_HIDDEN .hidden
+#endif
+
     /* Cache alignment for function entry */
 MACRO0(ALIGN_FUNCTION_ENTRY)
     .balign 16
@@ -116,13 +123,20 @@
 // for mac builds.
 MACRO1(DEFINE_FUNCTION, c_name)
     FUNCTION_TYPE(\c_name, 0)
+    ASM_HIDDEN VAR(c_name, 0)
     .globl VAR(c_name, 0)
     ALIGN_FUNCTION_ENTRY
 VAR(c_name, 0):
-#if !defined(__APPLE__)
-    // Have a local entrypoint that's not globl
-VAR(c_name, 0)_local:
-#endif
+    CFI_STARTPROC
+    // Ensure we get a sane starting CFA.
+    CFI_DEF_CFA(rsp, 8)
+END_MACRO
+
+MACRO1(DEFINE_FUNCTION_NO_HIDE, c_name)
+    FUNCTION_TYPE(\c_name, 0)
+    .globl VAR(c_name, 0)
+    ALIGN_FUNCTION_ENTRY
+VAR(c_name, 0):
     CFI_STARTPROC
     // Ensure we get a sane starting CFA.
     CFI_DEF_CFA(rsp, 8)
@@ -147,6 +161,19 @@
 
 MACRO1(UNIMPLEMENTED,name)
     FUNCTION_TYPE(\name, 0)
+    ASM_HIDDEN VAR(c_name, 0)
+    .globl VAR(name, 0)
+    ALIGN_FUNCTION_ENTRY
+VAR(name, 0):
+    CFI_STARTPROC
+    int3
+    int3
+    CFI_ENDPROC
+    SIZE(\name, 0)
+END_MACRO
+
+MACRO1(UNIMPLEMENTED_NO_HIDE,name)
+    FUNCTION_TYPE(\name, 0)
     .globl VAR(name, 0)
     ALIGN_FUNCTION_ENTRY
 VAR(name, 0):
diff --git a/runtime/arch/x86_64/portable_entrypoints_x86_64.S b/runtime/arch/x86_64/portable_entrypoints_x86_64.S
index 2e9d19a..7b84d17 100644
--- a/runtime/arch/x86_64/portable_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/portable_entrypoints_x86_64.S
@@ -25,4 +25,4 @@
 
 UNIMPLEMENTED art_portable_resolution_trampoline
 
-UNIMPLEMENTED art_portable_to_interpreter_bridge
+UNIMPLEMENTED_NO_HIDE art_portable_to_interpreter_bridge
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 48bc240..f95bd22 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -232,7 +232,7 @@
     // (Thread*, SP) setup
     movq %gs:THREAD_SELF_OFFSET, %rdi
     movq %rsp, %rsi
-    call PLT_SYMBOL(artDeliverPendingExceptionFromCode)  // artDeliverPendingExceptionFromCode(Thread*, SP)
+    call SYMBOL(artDeliverPendingExceptionFromCode)  // artDeliverPendingExceptionFromCode(Thread*, SP)
     UNREACHABLE
 END_MACRO
 
@@ -242,7 +242,7 @@
     // Outgoing argument set up
     movq %rsp, %rsi                    // pass SP
     movq %gs:THREAD_SELF_OFFSET, %rdi  // pass Thread::Current()
-    call PLT_VAR(cxx_name, 1)     // cxx_name(Thread*, SP)
+    call VAR(cxx_name, 1)     // cxx_name(Thread*, SP)
     UNREACHABLE
     END_FUNCTION VAR(c_name, 0)
 END_MACRO
@@ -253,7 +253,7 @@
     // Outgoing argument set up
     movq %rsp, %rdx                    // pass SP
     movq %gs:THREAD_SELF_OFFSET, %rsi  // pass Thread::Current()
-    call PLT_VAR(cxx_name, 1)     // cxx_name(arg1, Thread*, SP)
+    call VAR(cxx_name, 1)     // cxx_name(arg1, Thread*, SP)
     UNREACHABLE
     END_FUNCTION VAR(c_name, 0)
 END_MACRO
@@ -264,7 +264,7 @@
     // Outgoing argument set up
     movq %rsp, %rcx                    // pass SP
     movq %gs:THREAD_SELF_OFFSET, %rdx  // pass Thread::Current()
-    call PLT_VAR(cxx_name, 1)     // cxx_name(Thread*, SP)
+    call VAR(cxx_name, 1)     // cxx_name(Thread*, SP)
     UNREACHABLE
     END_FUNCTION VAR(c_name, 0)
 END_MACRO
@@ -329,7 +329,7 @@
     movq %gs:THREAD_SELF_OFFSET, %rcx                      // pass Thread
     movq %rsp, %r8                                         // pass SP
 
-    call PLT_VAR(cxx_name, 1)                   // cxx_name(arg1, arg2, caller method*, Thread*, SP)
+    call VAR(cxx_name, 1)                   // cxx_name(arg1, arg2, caller method*, Thread*, SP)
                                                            // save the code pointer
     movq %rax, %rdi
     movq %rdx, %rax
@@ -643,7 +643,7 @@
     // Outgoing argument set up
     movq %rsp, %rsi                   // pass SP
     movq %gs:THREAD_SELF_OFFSET, %rdi // pass Thread::Current()
-    call PLT_VAR(cxx_name, 1)         // cxx_name(Thread*, SP)
+    call VAR(cxx_name, 1)         // cxx_name(Thread*, SP)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
     CALL_MACRO(return_macro, 2)       // return or deliver exception
     END_FUNCTION VAR(c_name, 0)
@@ -655,7 +655,7 @@
     // Outgoing argument set up
     movq %rsp, %rdx                    // pass SP
     movq %gs:THREAD_SELF_OFFSET, %rsi  // pass Thread::Current()
-    call PLT_VAR(cxx_name, 1)          // cxx_name(arg0, Thread*, SP)
+    call VAR(cxx_name, 1)          // cxx_name(arg0, Thread*, SP)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
     CALL_MACRO(return_macro, 2)        // return or deliver exception
     END_FUNCTION VAR(c_name, 0)
@@ -667,7 +667,7 @@
     // Outgoing argument set up
     movq %rsp, %rcx                    // pass SP
     movq %gs:THREAD_SELF_OFFSET, %rdx  // pass Thread::Current()
-    call PLT_VAR(cxx_name, 1)          // cxx_name(arg0, arg1, Thread*, SP)
+    call VAR(cxx_name, 1)          // cxx_name(arg0, arg1, Thread*, SP)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
     CALL_MACRO(return_macro, 2)       // return or deliver exception
     END_FUNCTION VAR(c_name, 0)
@@ -679,7 +679,7 @@
     // Outgoing argument set up
     movq %rsp, %r8                     // pass SP
     movq %gs:THREAD_SELF_OFFSET, %rcx  // pass Thread::Current()
-    call PLT_VAR(cxx_name, 1)          // cxx_name(arg0, arg1, arg2, Thread*, SP)
+    call VAR(cxx_name, 1)          // cxx_name(arg0, arg1, arg2, Thread*, SP)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
     CALL_MACRO(return_macro, 2)        // return or deliver exception
     END_FUNCTION VAR(c_name, 0)
@@ -692,7 +692,7 @@
                                        // arg0 is in rdi
     movq %gs:THREAD_SELF_OFFSET, %rdx  // pass Thread::Current()
     movq %rsp, %rcx                    // pass SP
-    call PLT_VAR(cxx_name, 1)          // cxx_name(arg0, referrer, Thread*, SP)
+    call VAR(cxx_name, 1)          // cxx_name(arg0, referrer, Thread*, SP)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
     CALL_MACRO(return_macro, 2)
     END_FUNCTION VAR(c_name, 0)
@@ -705,7 +705,7 @@
                                        // arg0 and arg1 are in rdi/rsi
     movq %gs:THREAD_SELF_OFFSET, %rcx  // pass Thread::Current()
     movq %rsp, %r8                     // pass SP
-    call PLT_VAR(cxx_name, 1)          // (arg0, arg1, referrer, Thread*, SP)
+    call VAR(cxx_name, 1)          // (arg0, arg1, referrer, Thread*, SP)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
     CALL_MACRO(return_macro, 2)
     END_FUNCTION VAR(c_name, 0)
@@ -718,7 +718,7 @@
                                        // arg0, arg1, and arg2 are in rdi/rsi/rdx
     movq %gs:THREAD_SELF_OFFSET, %r8    // pass Thread::Current()
     movq %rsp, %r9                     // pass SP
-    call PLT_VAR(cxx_name, 1)          // cxx_name(arg0, arg1, arg2, referrer, Thread*, SP)
+    call VAR(cxx_name, 1)          // cxx_name(arg0, arg1, arg2, referrer, Thread*, SP)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
     CALL_MACRO(return_macro, 2)        // return or deliver exception
     END_FUNCTION VAR(c_name, 0)
@@ -887,7 +887,7 @@
     SETUP_REF_ONLY_CALLEE_SAVE_FRAME
     movq %gs:THREAD_SELF_OFFSET, %rsi     // pass Thread::Current()
     movq %rsp, %rdx                       // pass SP
-    call PLT_SYMBOL(artLockObjectFromCode)  // artLockObjectFromCode(object, Thread*, SP)
+    call SYMBOL(artLockObjectFromCode)  // artLockObjectFromCode(object, Thread*, SP)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME    // restore frame up to return address
     RETURN_IF_EAX_ZERO
 END_FUNCTION art_quick_lock_object
@@ -913,7 +913,7 @@
     SETUP_REF_ONLY_CALLEE_SAVE_FRAME
     movq %gs:THREAD_SELF_OFFSET, %rsi     // pass Thread::Current()
     movq %rsp, %rdx                       // pass SP
-    call PLT_SYMBOL(artUnlockObjectFromCode)  // artUnlockObjectFromCode(object, Thread*, SP)
+    call SYMBOL(artUnlockObjectFromCode)  // artUnlockObjectFromCode(object, Thread*, SP)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME    // restore frame up to return address
     RETURN_IF_EAX_ZERO
 END_FUNCTION art_quick_unlock_object
@@ -922,7 +922,7 @@
     PUSH rdi                          // Save args for exc
     PUSH rsi
     SETUP_FP_CALLEE_SAVE_FRAME
-    call PLT_SYMBOL(artIsAssignableFromCode)  // (Class* klass, Class* ref_klass)
+    call SYMBOL(artIsAssignableFromCode)  // (Class* klass, Class* ref_klass)
     testq %rax, %rax
     jz 1f                             // jump forward if not assignable
     RESTORE_FP_CALLEE_SAVE_FRAME
@@ -937,7 +937,7 @@
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
     mov %rsp, %rcx                    // pass SP
     mov %gs:THREAD_SELF_OFFSET, %rdx  // pass Thread::Current()
-    call PLT_SYMBOL(artThrowClassCastException) // (Class* a, Class* b, Thread*, SP)
+    call SYMBOL(artThrowClassCastException) // (Class* a, Class* b, Thread*, SP)
     int3                              // unreached
 END_FUNCTION art_quick_check_cast
 
@@ -958,8 +958,8 @@
 #else
     testl %edi, %edi
 //  testq %rdi, %rdi
-    jnz art_quick_aput_obj_with_bound_check_local
-    jmp art_quick_throw_null_pointer_exception_local
+    jnz art_quick_aput_obj_with_bound_check
+    jmp art_quick_throw_null_pointer_exception
 #endif  // __APPLE__
 END_FUNCTION art_quick_aput_obj_with_null_and_bound_check
 
@@ -972,12 +972,12 @@
     movl ARRAY_LENGTH_OFFSET(%edi), %ecx
 //  movl ARRAY_LENGTH_OFFSET(%rdi), %ecx      // This zero-extends, so value(%rcx)=value(%ecx)
     cmpl %ecx, %esi
-    jb art_quick_aput_obj_local
+    jb art_quick_aput_obj
     mov %esi, %edi
 //  mov %rsi, %rdi
     mov %ecx, %esi
 //  mov %rcx, %rsi
-    jmp art_quick_throw_array_bounds_local
+    jmp art_quick_throw_array_bounds
 #endif  // __APPLE__
 END_FUNCTION art_quick_aput_obj_with_bound_check
 
@@ -1018,7 +1018,7 @@
     movl CLASS_OFFSET(%edx), %esi // Pass arg2 = value's class.
     movq %rcx, %rdi               // Pass arg1 = array's component type.
 
-    call PLT_SYMBOL(artIsAssignableFromCode)  // (Class* a, Class* b)
+    call SYMBOL(artIsAssignableFromCode)  // (Class* a, Class* b)
 
     // Exception?
     testq %rax, %rax
@@ -1057,7 +1057,7 @@
     movq %gs:THREAD_SELF_OFFSET, %rdx // Pass arg 3 = Thread::Current().
                                             // Pass arg 1 = array.
 
-    call PLT_SYMBOL(artThrowArrayStoreException) // (array, value, Thread*, SP)
+    call SYMBOL(artThrowArrayStoreException) // (array, value, Thread*, SP)
     int3                          // unreached
 END_FUNCTION art_quick_aput_obj
 
@@ -1099,7 +1099,7 @@
                                        // field_idx is in rdi
     movq %gs:THREAD_SELF_OFFSET, %rcx  // pass Thread::Current()
     movq %rsp, %r8                     // pass SP
-    call PLT_SYMBOL(artSet64StaticFromCode)  // (field_idx, referrer, new_val, Thread*, SP)
+    call SYMBOL(artSet64StaticFromCode)  // (field_idx, referrer, new_val, Thread*, SP)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
     RETURN_IF_EAX_ZERO                 // return or deliver exception
 END_FUNCTION art_quick_set64_static
@@ -1139,7 +1139,7 @@
     movq %rdi, 0(%rsp)
     movq %gs:THREAD_SELF_OFFSET, %rdx  // Pass Thread::Current().
     movq %rsp, %rcx                    // Pass SP.
-    call PLT_SYMBOL(artQuickProxyInvokeHandler) // (proxy method, receiver, Thread*, SP)
+    call SYMBOL(artQuickProxyInvokeHandler) // (proxy method, receiver, Thread*, SP)
     movq %rax, %xmm0                   // Copy return value in case of float returns.
     addq LITERAL(168 + 4*8), %rsp            // Pop arguments.
     CFI_ADJUST_CFA_OFFSET(-168 - 4*8)
@@ -1158,7 +1158,7 @@
     movl 8(%rsp), %edi            // load caller Method*
     movl METHOD_DEX_CACHE_METHODS_OFFSET(%rdi), %edi  // load dex_cache_resolved_methods
     movl OBJECT_ARRAY_DATA_OFFSET(%rdi, %rax, 4), %edi  // load the target method
-    jmp art_quick_invoke_interface_trampoline_local
+    jmp art_quick_invoke_interface_trampoline
 #endif  // __APPLE__
 END_FUNCTION art_quick_imt_conflict_trampoline
 
@@ -1166,7 +1166,7 @@
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
     movq %gs:THREAD_SELF_OFFSET, %rdx
     movq %rsp, %rcx
-    call PLT_SYMBOL(artQuickResolutionTrampoline) // (called, receiver, Thread*, SP)
+    call SYMBOL(artQuickResolutionTrampoline) // (called, receiver, Thread*, SP)
     movq %rax, %r10               // Remember returned code pointer in R10.
     movq (%rsp), %rdi             // Load called method into RDI.
     RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
@@ -1254,7 +1254,7 @@
     /*
      * Called to do a generic JNI down-call
      */
-DEFINE_FUNCTION art_quick_generic_jni_trampoline
+DEFINE_FUNCTION_NO_HIDE art_quick_generic_jni_trampoline
     // Save callee and GPR args, mixed together to agree with core spills bitmap.
     PUSH r15  // Callee save.
     PUSH r14  // Callee save.
@@ -1310,7 +1310,7 @@
     //  gs:...   rbp      <= where they are
     movq %gs:THREAD_SELF_OFFSET, %rdi
     movq %rbp, %rsi
-    call PLT_SYMBOL(artQuickGenericJniTrampoline)  // (Thread*, sp)
+    call SYMBOL(artQuickGenericJniTrampoline)  // (Thread*, sp)
 
     // The C call will have registered the complete save-frame on success.
     // The result of the call is:
@@ -1354,7 +1354,7 @@
     movq %gs:THREAD_SELF_OFFSET, %rdi
     movq %rax, %rsi
     movq %xmm0, %rdx
-    call PLT_SYMBOL(artQuickGenericJniEndTrampoline)
+    call SYMBOL(artQuickGenericJniEndTrampoline)
 
     // Tear down the alloca.
     movq %rbp, %rsp
@@ -1441,11 +1441,11 @@
      * RDI = method being called / to bridge to.
      * RSI, RDX, RCX, R8, R9 are arguments to that method.
      */
-DEFINE_FUNCTION art_quick_to_interpreter_bridge
+DEFINE_FUNCTION_NO_HIDE art_quick_to_interpreter_bridge
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME   // Set up frame and save arguments.
     movq %gs:THREAD_SELF_OFFSET, %rsi      // RSI := Thread::Current()
     movq %rsp, %rdx                        // RDX := sp
-    call PLT_SYMBOL(artQuickToInterpreterBridge)  // (method, Thread*, SP)
+    call SYMBOL(artQuickToInterpreterBridge)  // (method, Thread*, SP)
     RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME  // TODO: no need to restore arguments in this case.
     movq %rax, %xmm0                   // Place return value also into floating point return value.
     RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
@@ -1467,12 +1467,12 @@
     movq %rsp, %rcx                     // Pass SP.
     movq FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE-8(%rsp), %r8   // Pass return PC.
 
-    call PLT_SYMBOL(artInstrumentationMethodEntryFromCode) // (Method*, Object*, Thread*, SP, LR)
+    call SYMBOL(artInstrumentationMethodEntryFromCode) // (Method*, Object*, Thread*, SP, LR)
 
                                   // %rax = result of call.
     movq %r12, %rdi               // Reload method pointer.
 
-    leaq art_quick_instrumentation_exit_local(%rip), %r12   // Set up return through instrumentation
+    leaq art_quick_instrumentation_exit(%rip), %r12   // Set up return through instrumentation
     movq %r12, FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE-8(%rsp) // exit.
 
     RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
@@ -1501,7 +1501,7 @@
     movq  %rax, %rdx                          // Pass integer result.
     movq  %xmm0, %rcx                         // Pass floating-point result.
 
-    call PLT_SYMBOL(artInstrumentationMethodExitFromCode)   // (Thread*, SP, gpr_res, fpr_res)
+    call SYMBOL(artInstrumentationMethodExitFromCode)   // (Thread*, SP, gpr_res, fpr_res)
 
     movq  %rax, %rdi          // Store return PC
     movq  %rdx, %rsi          // Store second return PC in hidden arg.
@@ -1526,7 +1526,7 @@
                                    // Stack should be aligned now.
     movq %rsp, %rsi                           // Pass SP.
     movq %gs:THREAD_SELF_OFFSET, %rdi         // Pass Thread.
-    call PLT_SYMBOL(artDeoptimize) // artDeoptimize(Thread*, SP)
+    call SYMBOL(artDeoptimize) // artDeoptimize(Thread*, SP)
     int3                           // Unreachable.
 END_FUNCTION art_quick_deoptimize
 
@@ -1577,7 +1577,7 @@
 
 DEFINE_FUNCTION art_quick_assignable_from_code
     SETUP_FP_CALLEE_SAVE_FRAME
-    call PLT_SYMBOL(artIsAssignableFromCode)       // (const mirror::Class*, const mirror::Class*)
+    call SYMBOL(artIsAssignableFromCode)       // (const mirror::Class*, const mirror::Class*)
     RESTORE_FP_CALLEE_SAVE_FRAME
     ret
 END_FUNCTION art_quick_assignable_from_code
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 69db959..8fc1d07 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -851,7 +851,8 @@
       // We opened the oat file, so we must register it.
       RegisterOatFile(oat_file);
     }
-    return true;
+    // If the file isn't executable we failed patchoat but did manage to get the dex files.
+    return oat_file->IsExecutable();
   } else {
     if (needs_registering) {
       // We opened it, delete it.
@@ -1136,11 +1137,18 @@
     error_msgs->push_back(StringPrintf("Failed to open oat file from dex location '%s'",
                                        dex_location));
     return nullptr;
-  } else if (!VerifyOatWithDexFile(oat_file.get(), dex_location, &error_msg)) {
+  } else if (oat_file->IsExecutable() &&
+             !VerifyOatWithDexFile(oat_file.get(), dex_location, &error_msg)) {
     error_msgs->push_back(StringPrintf("Failed to verify oat file '%s' found for dex location "
                                        "'%s': %s", oat_file->GetLocation().c_str(), dex_location,
                                        error_msg.c_str()));
     return nullptr;
+  } else if (!oat_file->IsExecutable() &&
+             !VerifyOatImageChecksum(oat_file.get(), isa)) {
+    error_msgs->push_back(StringPrintf("Failed to verify non-executable oat file '%s' found for "
+                                       "dex location '%s'. Image checksum incorrect.",
+                                       oat_file->GetLocation().c_str(), dex_location));
+    return nullptr;
   } else {
     return oat_file.release();
   }
@@ -1310,11 +1318,35 @@
   return ret;
 }
 
+const OatFile* ClassLinker::GetInterpretedOnlyOat(const std::string& oat_path,
+                                                  InstructionSet isa,
+                                                  std::string* error_msg) {
+  // We open it non-executable
+  std::unique_ptr<OatFile> output(OatFile::Open(oat_path, oat_path, NULL, false, error_msg));
+  if (output.get() == nullptr) {
+    return nullptr;
+  }
+  if (VerifyOatImageChecksum(output.get(), isa)) {
+    return output.release();
+  } else {
+    *error_msg = StringPrintf("Could not use oat file '%s', image checksum failed to verify.",
+                              oat_path.c_str());
+    return nullptr;
+  }
+}
+
 const OatFile* ClassLinker::PatchAndRetrieveOat(const std::string& input_oat,
                                                 const std::string& output_oat,
                                                 const std::string& image_location,
                                                 InstructionSet isa,
                                                 std::string* error_msg) {
+  if (!Runtime::Current()->IsDex2OatEnabled()) {
+    // We don't have dex2oat so we can assume we don't have patchoat either. We should just use the
+    // input_oat but make sure we only do interpretation on it's dex files.
+    LOG(WARNING) << "Patching of oat file '" << input_oat << "' not attempted due to dex2oat being "
+                 << "disabled. Attempting to use oat file for interpretation";
+    return GetInterpretedOnlyOat(input_oat, isa, error_msg);
+  }
   Locks::mutator_lock_->AssertNotHeld(Thread::Current());  // Avoid starving GC.
   std::string patchoat(Runtime::Current()->GetPatchoatExecutable());
 
@@ -1352,6 +1384,12 @@
                                 "but was unable to open output file '%s': %s",
                                 input_oat.c_str(), output_oat.c_str(), error_msg->c_str());
     }
+  } else if (!Runtime::Current()->IsCompiler()) {
+    // patchoat failed which means we probably don't have enough room to place the output oat file,
+    // instead of failing we should just run the interpreter from the dex files in the input oat.
+    LOG(WARNING) << "Patching of oat file '" << input_oat << "' failed. Attempting to use oat file "
+                 << "for interpretation. patchoat failure was: " << *error_msg;
+    return GetInterpretedOnlyOat(input_oat, isa, error_msg);
   } else {
     *error_msg = StringPrintf("Patching of oat file '%s to '%s' "
                               "failed: %s", input_oat.c_str(), output_oat.c_str(),
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 9ae3862..5694149 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -573,6 +573,10 @@
                                             std::vector<std::string>* error_msg)
       LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_);
 
+  const OatFile* GetInterpretedOnlyOat(const std::string& oat_path,
+                                       InstructionSet isa,
+                                       std::string* error_msg);
+
   const OatFile* PatchAndRetrieveOat(const std::string& input, const std::string& output,
                                      const std::string& image_location, InstructionSet isa,
                                      std::string* error_msg)
@@ -752,6 +756,7 @@
   friend class ImageDumper;  // for FindOpenedOatFileFromOatLocation
   friend class ElfPatcher;  // for FindOpenedOatFileForDexFile & FindOpenedOatFileFromOatLocation
   friend class NoDex2OatTest;  // for FindOpenedOatFileForDexFile
+  friend class NoPatchoatTest;  // for FindOpenedOatFileForDexFile
   FRIEND_TEST(ClassLinkerTest, ClassRootDescriptors);
   FRIEND_TEST(mirror::DexCacheTest, Open);
   FRIEND_TEST(ExceptionTest, FindExceptionHandler);
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 1cddb8b..6d2f21e 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -664,6 +664,11 @@
 }
 
 void Dbg::StopJdwp() {
+  // Post VM_DEATH event before the JDWP connection is closed (either by the JDWP thread or the
+  // destruction of gJdwpState).
+  if (gJdwpState != nullptr && gJdwpState->IsActive()) {
+    gJdwpState->PostVMDeath();
+  }
   // Prevent the JDWP thread from processing JDWP incoming packets after we close the connection.
   Disposed();
   delete gJdwpState;
diff --git a/runtime/gc/accounting/card_table-inl.h b/runtime/gc/accounting/card_table-inl.h
index 217360f..3b06f74 100644
--- a/runtime/gc/accounting/card_table-inl.h
+++ b/runtime/gc/accounting/card_table-inl.h
@@ -55,7 +55,7 @@
   // scan_end is the byte after the last byte we scan.
   DCHECK_LE(scan_end, reinterpret_cast<byte*>(bitmap->HeapLimit()));
   byte* card_cur = CardFromAddr(scan_begin);
-  byte* card_end = CardFromAddr(scan_end);
+  byte* card_end = CardFromAddr(AlignUp(scan_end, kCardSize));
   CheckCardValid(card_cur);
   CheckCardValid(card_end);
   size_t cards_scanned = 0;
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 5d138d2..821d22f 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -2483,7 +2483,6 @@
 bool Heap::VerifyMissingCardMarks() {
   Thread* self = Thread::Current();
   Locks::mutator_lock_->AssertExclusiveHeld(self);
-
   // We need to sort the live stack since we binary search it.
   live_stack_->Sort();
   // Since we sorted the allocation stack content, need to revoke all
@@ -2491,7 +2490,6 @@
   RevokeAllThreadLocalAllocationStacks(self);
   VerifyLiveStackReferences visitor(this);
   GetLiveBitmap()->Visit(visitor);
-
   // We can verify objects in the live stack since none of these should reference dead objects.
   for (mirror::Object** it = live_stack_->Begin(); it != live_stack_->End(); ++it) {
     if (!kUseThreadLocalAllocationStack || *it != nullptr) {
@@ -2689,7 +2687,7 @@
 void Heap::PostGcVerification(collector::GarbageCollector* gc) {
   if (verify_system_weaks_ || verify_post_gc_rosalloc_ || verify_post_gc_heap_) {
     collector::GarbageCollector::ScopedPause pause(gc);
-    PreGcVerificationPaused(gc);
+    PostGcVerificationPaused(gc);
   }
 }
 
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index d5c6e4f..47d35f3 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -121,11 +121,9 @@
     // Do not change stubs for these methods.
     return;
   }
-  std::string temp;
-  // Note that the Proxy class itself is not a proxy class.
-  if (strcmp(method->GetDeclaringClass()->GetDescriptor(&temp), "Ljava/lang/reflect/Proxy;") == 0 &&
-      method->IsConstructor()) {
-    // Do not stub Proxy.<init>.
+  // Don't stub Proxy.<init>. Note that the Proxy class itself is not a proxy class.
+  if (method->IsConstructor() &&
+      method->GetDeclaringClass()->DescriptorEquals("Ljava/lang/reflect/Proxy;")) {
     return;
   }
   const void* new_portable_code;
diff --git a/runtime/jdwp/jdwp_main.cc b/runtime/jdwp/jdwp_main.cc
index 7795b7c..4155c82 100644
--- a/runtime/jdwp/jdwp_main.cc
+++ b/runtime/jdwp/jdwp_main.cc
@@ -283,7 +283,9 @@
     {
       ScopedThreadStateChange tsc(self, kWaitingForDebuggerToAttach);
       MutexLock attach_locker(self, state->attach_lock_);
-      state->attach_cond_.Wait(self);
+      while (state->debug_thread_id_ == 0) {
+        state->attach_cond_.Wait(self);
+      }
     }
     if (!state->IsActive()) {
       LOG(ERROR) << "JDWP connection failed";
@@ -335,10 +337,6 @@
  */
 JdwpState::~JdwpState() {
   if (netState != NULL) {
-    if (IsConnected()) {
-      PostVMDeath();
-    }
-
     /*
      * Close down the network to inspire the thread to halt.
      */
@@ -458,6 +456,7 @@
       if (!netState->Establish(options_)) {
         /* wake anybody who was waiting for us to succeed */
         MutexLock mu(thread_, attach_lock_);
+        debug_thread_id_ = static_cast<ObjectId>(-1);
         attach_cond_.Broadcast(thread_);
         break;
       }
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index b74b10f..7d9922d 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -45,7 +45,7 @@
                              std::string* error_msg) {
   CHECK(!oat_contents.empty()) << location;
   CheckLocation(location);
-  std::unique_ptr<OatFile> oat_file(new OatFile(location));
+  std::unique_ptr<OatFile> oat_file(new OatFile(location, false));
   oat_file->begin_ = &oat_contents[0];
   oat_file->end_ = &oat_contents[oat_contents.size()];
   return oat_file->Setup(error_msg) ? oat_file.release() : nullptr;
@@ -97,7 +97,7 @@
                              const std::string& location,
                              byte* requested_base,
                              std::string* error_msg) {
-  std::unique_ptr<OatFile> oat_file(new OatFile(location));
+  std::unique_ptr<OatFile> oat_file(new OatFile(location, true));
   bool success = oat_file->Dlopen(elf_filename, requested_base, error_msg);
   if (!success) {
     return nullptr;
@@ -111,7 +111,7 @@
                               bool writable,
                               bool executable,
                               std::string* error_msg) {
-  std::unique_ptr<OatFile> oat_file(new OatFile(location));
+  std::unique_ptr<OatFile> oat_file(new OatFile(location, executable));
   bool success = oat_file->ElfFileOpen(file, requested_base, writable, executable, error_msg);
   if (!success) {
     CHECK(!error_msg->empty());
@@ -120,8 +120,9 @@
   return oat_file.release();
 }
 
-OatFile::OatFile(const std::string& location)
-    : location_(location), begin_(NULL), end_(NULL), dlopen_handle_(NULL),
+OatFile::OatFile(const std::string& location, bool is_executable)
+    : location_(location), begin_(NULL), end_(NULL), is_executable_(is_executable),
+      dlopen_handle_(NULL),
       secondary_lookup_lock_("OatFile secondary lookup lock", kOatFileSecondaryLookupLock) {
   CHECK(!location_.empty());
 }
@@ -533,10 +534,15 @@
     methods_pointer_index = num_set_bits;
   }
   const OatMethodOffsets& oat_method_offsets = methods_pointer_[methods_pointer_index];
-  return OatMethod(
-      oat_file_->Begin(),
-      oat_method_offsets.code_offset_,
-      oat_method_offsets.gc_map_offset_);
+  if (oat_file_->IsExecutable() || Runtime::Current()->IsCompiler()) {
+    return OatMethod(
+        oat_file_->Begin(),
+        oat_method_offsets.code_offset_,
+        oat_method_offsets.gc_map_offset_);
+  } else {
+    // We aren't allowed to use the compiled code. We just force it down the interpreted version.
+    return OatMethod(oat_file_->Begin(), 0, 0);
+  }
 }
 
 
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 508bfc2..8535bf4 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -64,6 +64,10 @@
 
   ~OatFile();
 
+  bool IsExecutable() const {
+    return is_executable_;
+  }
+
   ElfFile* GetElfFile() const {
     CHECK_NE(reinterpret_cast<uintptr_t>(elf_file_.get()), reinterpret_cast<uintptr_t>(nullptr))
         << "Cannot get an elf file from " << GetLocation();
@@ -270,7 +274,7 @@
                               bool executable,
                               std::string* error_msg);
 
-  explicit OatFile(const std::string& filename);
+  explicit OatFile(const std::string& filename, bool executable);
   bool Dlopen(const std::string& elf_filename, byte* requested_base, std::string* error_msg);
   bool ElfFileOpen(File* file, byte* requested_base, bool writable, bool executable,
                    std::string* error_msg);
@@ -287,6 +291,9 @@
   // Pointer to end of oat region for bounds checking.
   const byte* end_;
 
+  // Was this oat_file loaded executable?
+  const bool is_executable_;
+
   // Backing memory map for oat file during when opened by ElfWriter during initial compilation.
   std::unique_ptr<MemMap> mem_map_;
 
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 05003cb..ba53c43 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -900,11 +900,7 @@
 
 bool Runtime::AttachCurrentThread(const char* thread_name, bool as_daemon, jobject thread_group,
                                   bool create_peer) {
-  bool success = Thread::Attach(thread_name, as_daemon, thread_group, create_peer) != NULL;
-  if (thread_name == NULL) {
-    LOG(WARNING) << *Thread::Current() << " attached without supplying a name";
-  }
-  return success;
+  return Thread::Attach(thread_name, as_daemon, thread_group, create_peer) != NULL;
 }
 
 void Runtime::DetachCurrentThread() {
diff --git a/runtime/thread.cc b/runtime/thread.cc
index c7cd57d..dcc897f 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -403,6 +403,8 @@
     if (thread_name != nullptr) {
       self->tlsPtr_.name->assign(thread_name);
       ::art::SetThreadName(thread_name);
+    } else if (self->GetJniEnv()->check_jni) {
+      LOG(WARNING) << *Thread::Current() << " attached without supplying a name";
     }
   }
 
diff --git a/test/117-nopatchoat/expected.txt b/test/117-nopatchoat/expected.txt
new file mode 100644
index 0000000..a1293ae
--- /dev/null
+++ b/test/117-nopatchoat/expected.txt
@@ -0,0 +1,9 @@
+Run without dex2oat/patchoat
+dex2oat & patchoat are disabled, has oat is true, has executable oat is false.
+This is a function call
+Run with dexoat/patchoat
+dex2oat & patchoat are enabled, has oat is true, has executable oat is true.
+This is a function call
+Run default
+dex2oat & patchoat are enabled, has oat is true, has executable oat is true.
+This is a function call
diff --git a/test/117-nopatchoat/info.txt b/test/117-nopatchoat/info.txt
new file mode 100644
index 0000000..aa9f57c
--- /dev/null
+++ b/test/117-nopatchoat/info.txt
@@ -0,0 +1 @@
+Test that disables patchoat'ing the application.
diff --git a/test/117-nopatchoat/nopatchoat.cc b/test/117-nopatchoat/nopatchoat.cc
new file mode 100644
index 0000000..ced7f6e
--- /dev/null
+++ b/test/117-nopatchoat/nopatchoat.cc
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include "class_linker.h"
+#include "dex_file-inl.h"
+#include "mirror/class-inl.h"
+#include "scoped_thread_state_change.h"
+#include "thread.h"
+
+namespace art {
+
+class NoPatchoatTest {
+ public:
+  static bool hasExecutableOat(jclass cls) {
+    ScopedObjectAccess soa(Thread::Current());
+    mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+    const DexFile& dex_file = klass->GetDexFile();
+    const OatFile* oat_file =
+        Runtime::Current()->GetClassLinker()->FindOpenedOatFileForDexFile(dex_file);
+    return oat_file != nullptr && oat_file->IsExecutable();
+  }
+};
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasExecutableOat(JNIEnv*, jclass cls) {
+  return NoPatchoatTest::hasExecutableOat(cls);
+}
+
+}  // namespace art
diff --git a/test/117-nopatchoat/run b/test/117-nopatchoat/run
new file mode 100755
index 0000000..a7c96a0
--- /dev/null
+++ b/test/117-nopatchoat/run
@@ -0,0 +1,36 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 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.
+
+# ensure flags includes prebuild and relocate. It doesn't make sense unless we
+# have a oat file we want to relocate.
+# TODO Unfortunately we have no way to force prebuild on for both host and target (or skip if not on).
+flags="${@/--relocate/}"
+flags="${flags/--no-relocate/}"
+flags="${flags} --relocate"
+
+# Make sure we can run without relocation
+echo "Run without dex2oat/patchoat"
+# /bin/false is actually not even there for either, so the exec will fail.
+# Unfortunately there is no equivalent to /bin/false in android.
+${RUN} ${flags} --runtime-option -Xnodex2oat
+
+# Make sure we can run with the oat file.
+echo "Run with dexoat/patchoat"
+${RUN} ${flags} --runtime-option -Xdex2oat
+
+# Make sure we can run with the default settings.
+echo "Run default"
+${RUN} ${flags}
diff --git a/test/117-nopatchoat/src/Main.java b/test/117-nopatchoat/src/Main.java
new file mode 100644
index 0000000..f3f91ce
--- /dev/null
+++ b/test/117-nopatchoat/src/Main.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+public class Main {
+  public static void main(String[] args) {
+    System.out.println(
+        "dex2oat & patchoat are " + ((isDex2OatEnabled()) ? "enabled" : "disabled") +
+        ", has oat is " + hasOat() + ", has executable oat is " + hasExecutableOat() + ".");
+
+    if (!hasOat() && isDex2OatEnabled()) {
+      throw new Error("Application with dex2oat enabled runs without an oat file");
+    }
+
+    System.out.println(functionCall());
+  }
+
+  public static String functionCall() {
+    String arr[] = {"This", "is", "a", "function", "call"};
+    String ret = "";
+    for (int i = 0; i < arr.length; i++) {
+      ret = ret + arr[i] + " ";
+    }
+    return ret.substring(0, ret.length() - 1);
+  }
+
+  static {
+    System.loadLibrary("arttest");
+  }
+
+  private native static boolean isDex2OatEnabled();
+
+  private native static boolean hasOat();
+
+  private native static boolean hasExecutableOat();
+}
diff --git a/test/702-LargeBranchOffset/build b/test/702-LargeBranchOffset/build
new file mode 100644
index 0000000..eacf730
--- /dev/null
+++ b/test/702-LargeBranchOffset/build
@@ -0,0 +1,27 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 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
+
+# Write out a bunch of source files.
+cpp -P src/Main.java.in src/Main.java
+
+mkdir classes
+${JAVAC} -d classes src/*.java
+
+${DX} --debug --dex --output=classes.dex classes
+zip $TEST_NAME.jar classes.dex
diff --git a/test/702-LargeBranchOffset/expected.txt b/test/702-LargeBranchOffset/expected.txt
new file mode 100644
index 0000000..130678f
--- /dev/null
+++ b/test/702-LargeBranchOffset/expected.txt
@@ -0,0 +1,5 @@
+0
+0
+2
+1
+512
diff --git a/test/702-LargeBranchOffset/info.txt b/test/702-LargeBranchOffset/info.txt
new file mode 100644
index 0000000..747263e
--- /dev/null
+++ b/test/702-LargeBranchOffset/info.txt
@@ -0,0 +1 @@
+Simple test to check if large branch offset works correctly.
diff --git a/test/702-LargeBranchOffset/src/Main.java.in b/test/702-LargeBranchOffset/src/Main.java.in
new file mode 100644
index 0000000..270d766
--- /dev/null
+++ b/test/702-LargeBranchOffset/src/Main.java.in
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#define DO_2_TIMES(x) x x
+#define DO_4_TIMES(x) DO_2_TIMES(DO_2_TIMES(x))
+#define DO_16_TIMES(x) DO_4_TIMES(DO_4_TIMES(x))
+#define DO_256_TIMES(x) DO_16_TIMES(DO_16_TIMES(x))
+#define DO_512_TIMES(x) DO_256_TIMES(DO_2_TIMES(x))
+
+
+public class Main {
+  public static void main(String[] args) {
+    Main m = new Main();
+    System.out.println(m.foo(-1, -1));
+    System.out.println(m.foo(-1, +1));
+    System.out.println(m.foo(+1, -1));
+    System.out.println(m.foo(+1, +1));
+    System.out.println(m.value);
+  }
+
+  public int foo(int a, int b) {
+    if ( a >= 0 ) {
+      if ( b < 0 ) {
+        DO_512_TIMES( synchronized(lock) { value++; } )
+        return 2;
+      }
+      return 1;
+    }
+    return 0;
+  }
+
+  Object lock = new Object();
+  int value = 0;
+}
diff --git a/test/Android.libarttest.mk b/test/Android.libarttest.mk
index 3871b28..caaf649 100644
--- a/test/Android.libarttest.mk
+++ b/test/Android.libarttest.mk
@@ -24,7 +24,8 @@
   004-ReferenceMap/stack_walk_refmap_jni.cc \
   004-StackWalk/stack_walk_jni.cc \
   004-UnsafeTest/unsafe_test.cc \
-  116-nodex2oat/nodex2oat.cc
+  116-nodex2oat/nodex2oat.cc \
+  117-nopatchoat/nopatchoat.cc
 
 ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttest.so
 ifdef TARGET_2ND_ARCH
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 0cf9e16..ce0eb3f 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -124,6 +124,42 @@
 ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,-gcverify,-no-prebuild)
 ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,-gcstress,-no-prebuild)
 
+# NB 116-nodex2oat is not broken per-se it just doesn't (and isn't meant to) work with --prebuild.
+# On host this is patched around by changing a run flag but we cannot do this on the target due to
+# a different run-script.
+TEST_ART_TARGET_BROKEN_PREBUILD_RUN_TESTS := \
+  116-nodex2oat
+
+ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_TARGET_PREBUILD_RUN_TESTS), $(call all-run-test-target-names,$(test),,-prebuild))
+ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_TARGET_PREBUILD_RUN_TESTS), $(call all-run-test-target-names,$(test),-trace,-prebuild))
+ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_TARGET_PREBUILD_RUN_TESTS), $(call all-run-test-target-names,$(test),-gcverify,-prebuild))
+ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_TARGET_PREBUILD_RUN_TESTS), $(call all-run-test-target-names,$(test),-gcstress,-prebuild))
+
+# NB 117-nopatchoat is not broken per-se it just doesn't work (and isn't meant to) without --prebuild --relocate
+TEST_ART_BROKEN_RELOCATE_TESTS := \
+  117-nopatchoat
+
+ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_RELOCATE_TESTS), $(call all-run-test-names,$(test),,-relocate))
+ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_RELOCATE_TESTS), $(call all-run-test-names,$(test),-trace,-relocate))
+ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_RELOCATE_TESTS), $(call all-run-test-names,$(test),-gcverify,-relocate))
+ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_RELOCATE_TESTS), $(call all-run-test-names,$(test),-gcstress,-relocate))
+
+TEST_ART_BROKEN_NORELOCATE_TESTS := \
+  117-nopatchoat
+
+ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_NORELOCATE_TESTS), $(call all-run-test-names,$(test),,-norelocate))
+ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_NORELOCATE_TESTS), $(call all-run-test-names,$(test),-trace,-norelocate))
+ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_NORELOCATE_TESTS), $(call all-run-test-names,$(test),-gcverify,-norelocate))
+ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_NORELOCATE_TESTS), $(call all-run-test-names,$(test),-gcstress,-norelocate))
+
+TEST_ART_BROKEN_NO_PREBUILD_TESTS := \
+  117-nopatchoat
+
+ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_NO_PREBUILD_TESTS), $(call all-run-test-names,$(test),,-no-prebuild))
+ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_NO_PREBUILD_TESTS), $(call all-run-test-names,$(test),-trace,-no-prebuild))
+ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_NO_PREBUILD_TESTS), $(call all-run-test-names,$(test),-gcverify,-no-prebuild))
+ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_NO_PREBUILD_TESTS), $(call all-run-test-names,$(test),-gcstress,-no-prebuild))
+
 # The path where build only targets will be output, e.g.
 # out/target/product/generic_x86_64/obj/PACKAGING/art-run-tests_intermediates/DATA
 art_run_tests_dir := $(call intermediates-dir-for,PACKAGING,art-run-tests)/DATA
diff --git a/test/run-test b/test/run-test
index b8e40d9..6fac03b 100755
--- a/test/run-test
+++ b/test/run-test
@@ -212,6 +212,7 @@
 # Cannot use realpath, as it does not exist on Mac.
 # Cannot us a simple "cd", as the path might not be created yet.
 # Use -m option of readlink: canonicalizes, but allows non-existing components.
+noncanonical_tmp_dir=$tmp_dir
 tmp_dir="`cd $oldwd ; readlink -m $tmp_dir`"
 
 mkdir -p $tmp_dir
@@ -474,6 +475,8 @@
         "./${run}" $run_args "$@" >"$output" 2>&1
     else
         cp "$build_output" "$output"
+        echo "Failed to build in tmpdir=${tmp_dir} from oldwd=${oldwd} and cwd=`pwd`"
+        echo "Non-canonical tmpdir was ${noncanonical_tmp_dir}"
         echo "build exit status: $build_exit" >>"$output"
     fi
     ./$check_cmd "$expected" "$output"