Merge "Revert "Do a second check for testing intrinsic types.""
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index a8f6a24..7b42db8 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -759,33 +759,214 @@
   current_block_ = nullptr;
 }
 
-void HGraphBuilder::PotentiallySimplifyFakeString(uint16_t original_dex_register,
-                                                  uint32_t dex_pc,
-                                                  HInvoke* actual_string) {
-  if (!graph_->IsDebuggable()) {
-    // Notify that we cannot compile with baseline. The dex registers aliasing
-    // with `original_dex_register` will be handled when we optimize
-    // (see HInstructionSimplifer::VisitFakeString).
-    can_use_baseline_for_string_init_ = false;
-    return;
+static InvokeType GetInvokeTypeFromOpCode(Instruction::Code opcode) {
+  switch (opcode) {
+    case Instruction::INVOKE_STATIC:
+    case Instruction::INVOKE_STATIC_RANGE:
+      return kStatic;
+    case Instruction::INVOKE_DIRECT:
+    case Instruction::INVOKE_DIRECT_RANGE:
+      return kDirect;
+    case Instruction::INVOKE_VIRTUAL:
+    case Instruction::INVOKE_VIRTUAL_QUICK:
+    case Instruction::INVOKE_VIRTUAL_RANGE:
+    case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
+      return kVirtual;
+    case Instruction::INVOKE_INTERFACE:
+    case Instruction::INVOKE_INTERFACE_RANGE:
+      return kInterface;
+    case Instruction::INVOKE_SUPER_RANGE:
+    case Instruction::INVOKE_SUPER:
+      return kSuper;
+    default:
+      LOG(FATAL) << "Unexpected invoke opcode: " << opcode;
+      UNREACHABLE();
   }
-  const VerifiedMethod* verified_method =
-      compiler_driver_->GetVerifiedMethod(dex_file_, dex_compilation_unit_->GetDexMethodIndex());
-  if (verified_method != nullptr) {
-    UpdateLocal(original_dex_register, actual_string);
-    const SafeMap<uint32_t, std::set<uint32_t>>& string_init_map =
-        verified_method->GetStringInitPcRegMap();
-    auto map_it = string_init_map.find(dex_pc);
-    if (map_it != string_init_map.end()) {
-      std::set<uint32_t> reg_set = map_it->second;
-      for (auto set_it = reg_set.begin(); set_it != reg_set.end(); ++set_it) {
-        HInstruction* load_local = LoadLocal(original_dex_register, Primitive::kPrimNot);
-        UpdateLocal(*set_it, load_local);
-      }
+}
+
+bool HGraphBuilder::BuildInvoke(const Instruction& instruction,
+                                uint32_t dex_pc,
+                                uint32_t method_idx,
+                                uint32_t number_of_vreg_arguments,
+                                bool is_range,
+                                uint32_t* args,
+                                uint32_t register_index) {
+  InvokeType original_invoke_type = GetInvokeTypeFromOpCode(instruction.Opcode());
+  InvokeType optimized_invoke_type = original_invoke_type;
+  const char* descriptor = dex_file_->GetMethodShorty(method_idx);
+  Primitive::Type return_type = Primitive::GetType(descriptor[0]);
+
+  // Remove the return type from the 'proto'.
+  size_t number_of_arguments = strlen(descriptor) - 1;
+  if (original_invoke_type != kStatic) {  // instance call
+    // One extra argument for 'this'.
+    number_of_arguments++;
+  }
+
+  MethodReference target_method(dex_file_, method_idx);
+  int32_t table_index;
+  uintptr_t direct_code;
+  uintptr_t direct_method;
+
+  if (!compiler_driver_->ComputeInvokeInfo(dex_compilation_unit_,
+                                           dex_pc,
+                                           true /* update_stats */,
+                                           true /* enable_devirtualization */,
+                                           &optimized_invoke_type,
+                                           &target_method,
+                                           &table_index,
+                                           &direct_code,
+                                           &direct_method)) {
+    VLOG(compiler) << "Did not compile "
+                   << PrettyMethod(dex_compilation_unit_->GetDexMethodIndex(), *dex_file_)
+                   << " because a method call could not be resolved";
+    MaybeRecordStat(MethodCompilationStat::kNotCompiledUnresolvedMethod);
+    return false;
+  }
+
+  DCHECK(optimized_invoke_type != kSuper);
+
+  // Special handling for string init.
+  int32_t string_init_offset = 0;
+  bool is_string_init = compiler_driver_->IsStringInit(method_idx, dex_file_,
+                                                       &string_init_offset);
+
+  // Potential class initialization check, in the case of a static method call.
+  HClinitCheck* clinit_check = nullptr;
+  HInvoke* invoke = nullptr;
+
+  if (is_string_init
+      || optimized_invoke_type == kDirect
+      || optimized_invoke_type == kStatic) {
+    // By default, consider that the called method implicitly requires
+    // an initialization check of its declaring method.
+    HInvokeStaticOrDirect::ClinitCheckRequirement clinit_check_requirement
+        = HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit;
+    if (optimized_invoke_type == kStatic && !is_string_init) {
+      clinit_check = ProcessClinitCheckForInvoke(dex_pc, method_idx, &clinit_check_requirement);
     }
+
+    // Replace calls to String.<init> with StringFactory.
+    if (is_string_init) {
+      return_type = Primitive::kPrimNot;
+      number_of_arguments--;
+      optimized_invoke_type = kStatic;
+    }
+
+    HInvokeStaticOrDirect::DispatchInfo dispatch_info = ComputeDispatchInfo(is_string_init,
+                                                                            string_init_offset,
+                                                                            target_method,
+                                                                            direct_method,
+                                                                            direct_code);
+    invoke = new (arena_) HInvokeStaticOrDirect(arena_,
+                                                number_of_arguments,
+                                                return_type,
+                                                dex_pc,
+                                                method_idx,
+                                                target_method,
+                                                dispatch_info,
+                                                original_invoke_type,
+                                                optimized_invoke_type,
+                                                clinit_check_requirement);
+  } else if (optimized_invoke_type == kVirtual) {
+    invoke = new (arena_) HInvokeVirtual(arena_,
+                                         number_of_arguments,
+                                         return_type,
+                                         dex_pc,
+                                         method_idx,
+                                         table_index);
   } else {
-    can_use_baseline_for_string_init_ = false;
+    DCHECK_EQ(optimized_invoke_type, kInterface);
+    invoke = new (arena_) HInvokeInterface(arena_,
+                                           number_of_arguments,
+                                           return_type,
+                                           dex_pc,
+                                           method_idx,
+                                           table_index);
   }
+
+  return SetupArgumentsAndAddInvoke(invoke,
+                                    number_of_vreg_arguments,
+                                    args,
+                                    register_index,
+                                    is_range,
+                                    descriptor,
+                                    clinit_check);
+}
+
+HClinitCheck* HGraphBuilder::ProcessClinitCheckForInvoke(
+      uint32_t dex_pc,
+      uint32_t method_idx,
+      HInvokeStaticOrDirect::ClinitCheckRequirement* clinit_check_requirement) {
+  ScopedObjectAccess soa(Thread::Current());
+  StackHandleScope<4> hs(soa.Self());
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(
+      dex_compilation_unit_->GetClassLinker()->FindDexCache(
+          *dex_compilation_unit_->GetDexFile())));
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
+      soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader())));
+  ArtMethod* resolved_method = compiler_driver_->ResolveMethod(
+      soa, dex_cache, class_loader, dex_compilation_unit_, method_idx, InvokeType::kStatic);
+
+  DCHECK(resolved_method != nullptr);
+
+  const DexFile& outer_dex_file = *outer_compilation_unit_->GetDexFile();
+  Handle<mirror::DexCache> outer_dex_cache(hs.NewHandle(
+      outer_compilation_unit_->GetClassLinker()->FindDexCache(outer_dex_file)));
+  Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass()));
+
+  // The index at which the method's class is stored in the DexCache's type array.
+  uint32_t storage_index = DexFile::kDexNoIndex;
+  bool is_outer_class = (resolved_method->GetDeclaringClass() == outer_class.Get());
+  if (is_outer_class) {
+    storage_index = outer_class->GetDexTypeIndex();
+  } else if (outer_dex_cache.Get() == dex_cache.Get()) {
+    // Get `storage_index` from IsClassOfStaticMethodAvailableToReferrer.
+    compiler_driver_->IsClassOfStaticMethodAvailableToReferrer(outer_dex_cache.Get(),
+                                                               GetCompilingClass(),
+                                                               resolved_method,
+                                                               method_idx,
+                                                               &storage_index);
+  }
+
+  HClinitCheck* clinit_check = nullptr;
+
+  if (!outer_class->IsInterface()
+      && outer_class->IsSubClass(resolved_method->GetDeclaringClass())) {
+    // If the outer class is the declaring class or a subclass
+    // of the declaring class, no class initialization is needed
+    // before the static method call.
+    // Note that in case of inlining, we do not need to add clinit checks
+    // to calls that satisfy this subclass check with any inlined methods. This
+    // will be detected by the optimization passes.
+    *clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kNone;
+  } else if (storage_index != DexFile::kDexNoIndex) {
+    // If the method's class type index is available, check
+    // whether we should add an explicit class initialization
+    // check for its declaring class before the static method call.
+
+    // TODO: find out why this check is needed.
+    bool is_in_dex_cache = compiler_driver_->CanAssumeTypeIsPresentInDexCache(
+        *outer_compilation_unit_->GetDexFile(), storage_index);
+    bool is_initialized =
+        resolved_method->GetDeclaringClass()->IsInitialized() && is_in_dex_cache;
+
+    if (is_initialized) {
+      *clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kNone;
+    } else {
+      *clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit;
+      HLoadClass* load_class = new (arena_) HLoadClass(
+          graph_->GetCurrentMethod(),
+          storage_index,
+          *dex_compilation_unit_->GetDexFile(),
+          is_outer_class,
+          dex_pc);
+      current_block_->AddInstruction(load_class);
+      clinit_check = new (arena_) HClinitCheck(load_class, dex_pc);
+      current_block_->AddInstruction(clinit_check);
+    }
+  }
+  return clinit_check;
 }
 
 HInvokeStaticOrDirect::DispatchInfo HGraphBuilder::ComputeDispatchInfo(
@@ -859,210 +1040,40 @@
     method_load_kind, code_ptr_location, method_load_data, direct_code_ptr };
 }
 
-bool HGraphBuilder::BuildInvoke(const Instruction& instruction,
-                                uint32_t dex_pc,
-                                uint32_t method_idx,
-                                uint32_t number_of_vreg_arguments,
-                                bool is_range,
-                                uint32_t* args,
-                                uint32_t register_index) {
-  Instruction::Code opcode = instruction.Opcode();
-  InvokeType invoke_type;
-  switch (opcode) {
-    case Instruction::INVOKE_STATIC:
-    case Instruction::INVOKE_STATIC_RANGE:
-      invoke_type = kStatic;
-      break;
-    case Instruction::INVOKE_DIRECT:
-    case Instruction::INVOKE_DIRECT_RANGE:
-      invoke_type = kDirect;
-      break;
-    case Instruction::INVOKE_VIRTUAL:
-    case Instruction::INVOKE_VIRTUAL_QUICK:
-    case Instruction::INVOKE_VIRTUAL_RANGE:
-    case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
-      invoke_type = kVirtual;
-      break;
-    case Instruction::INVOKE_INTERFACE:
-    case Instruction::INVOKE_INTERFACE_RANGE:
-      invoke_type = kInterface;
-      break;
-    case Instruction::INVOKE_SUPER_RANGE:
-    case Instruction::INVOKE_SUPER:
-      invoke_type = kSuper;
-      break;
-    default:
-      LOG(FATAL) << "Unexpected invoke op: " << opcode;
-      return false;
-  }
-
-  const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
-  const DexFile::ProtoId& proto_id = dex_file_->GetProtoId(method_id.proto_idx_);
-  const char* descriptor = dex_file_->StringDataByIdx(proto_id.shorty_idx_);
-  Primitive::Type return_type = Primitive::GetType(descriptor[0]);
-  bool is_instance_call = invoke_type != kStatic;
-  // Remove the return type from the 'proto'.
-  size_t number_of_arguments = strlen(descriptor) - 1;
-  if (is_instance_call) {
-    // One extra argument for 'this'.
-    ++number_of_arguments;
-  }
-
-  MethodReference target_method(dex_file_, method_idx);
-  uintptr_t direct_code;
-  uintptr_t direct_method;
-  int table_index;
-  InvokeType optimized_invoke_type = invoke_type;
-
-  if (!compiler_driver_->ComputeInvokeInfo(dex_compilation_unit_, dex_pc, true, true,
-                                           &optimized_invoke_type, &target_method, &table_index,
-                                           &direct_code, &direct_method)) {
-    VLOG(compiler) << "Did not compile "
-                   << PrettyMethod(dex_compilation_unit_->GetDexMethodIndex(), *dex_file_)
-                   << " because a method call could not be resolved";
-    MaybeRecordStat(MethodCompilationStat::kNotCompiledUnresolvedMethod);
-    return false;
-  }
-  DCHECK(optimized_invoke_type != kSuper);
-
-  // By default, consider that the called method implicitly requires
-  // an initialization check of its declaring method.
-  HInvokeStaticOrDirect::ClinitCheckRequirement clinit_check_requirement =
-      HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit;
-  // Potential class initialization check, in the case of a static method call.
-  HClinitCheck* clinit_check = nullptr;
-  // Replace calls to String.<init> with StringFactory.
-  int32_t string_init_offset = 0;
-  bool is_string_init = compiler_driver_->IsStringInit(method_idx, dex_file_, &string_init_offset);
-  if (is_string_init) {
-    return_type = Primitive::kPrimNot;
-    is_instance_call = false;
-    number_of_arguments--;
-    invoke_type = kStatic;
-    optimized_invoke_type = kStatic;
-  }
-
-  HInvoke* invoke = nullptr;
-
-  if (optimized_invoke_type == kVirtual) {
-    invoke = new (arena_) HInvokeVirtual(
-        arena_, number_of_arguments, return_type, dex_pc, method_idx, table_index);
-  } else if (optimized_invoke_type == kInterface) {
-    invoke = new (arena_) HInvokeInterface(
-        arena_, number_of_arguments, return_type, dex_pc, method_idx, table_index);
-  } else {
-    DCHECK(optimized_invoke_type == kDirect || optimized_invoke_type == kStatic);
-
-    if (optimized_invoke_type == kStatic && !is_string_init) {
-      ScopedObjectAccess soa(Thread::Current());
-      StackHandleScope<4> hs(soa.Self());
-      Handle<mirror::DexCache> dex_cache(hs.NewHandle(
-          dex_compilation_unit_->GetClassLinker()->FindDexCache(
-              *dex_compilation_unit_->GetDexFile())));
-      Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
-          soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader())));
-      ArtMethod* resolved_method = compiler_driver_->ResolveMethod(
-          soa, dex_cache, class_loader, dex_compilation_unit_, method_idx, optimized_invoke_type);
-
-      if (resolved_method == nullptr) {
-        MaybeRecordStat(MethodCompilationStat::kNotCompiledUnresolvedMethod);
-        return false;
-      }
-
-      const DexFile& outer_dex_file = *outer_compilation_unit_->GetDexFile();
-      Handle<mirror::DexCache> outer_dex_cache(hs.NewHandle(
-          outer_compilation_unit_->GetClassLinker()->FindDexCache(outer_dex_file)));
-      Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass()));
-
-      // The index at which the method's class is stored in the DexCache's type array.
-      uint32_t storage_index = DexFile::kDexNoIndex;
-      bool is_outer_class = (resolved_method->GetDeclaringClass() == outer_class.Get());
-      if (is_outer_class) {
-        storage_index = outer_class->GetDexTypeIndex();
-      } else if (outer_dex_cache.Get() == dex_cache.Get()) {
-        // Get `storage_index` from IsClassOfStaticMethodAvailableToReferrer.
-        compiler_driver_->IsClassOfStaticMethodAvailableToReferrer(outer_dex_cache.Get(),
-                                                                   GetCompilingClass(),
-                                                                   resolved_method,
-                                                                   method_idx,
-                                                                   &storage_index);
-      }
-
-      if (!outer_class->IsInterface()
-          && outer_class->IsSubClass(resolved_method->GetDeclaringClass())) {
-        // If the outer class is the declaring class or a subclass
-        // of the declaring class, no class initialization is needed
-        // before the static method call.
-        // Note that in case of inlining, we do not need to add clinit checks
-        // to calls that satisfy this subclass check with any inlined methods. This
-        // will be detected by the optimization passes.
-        clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kNone;
-      } else if (storage_index != DexFile::kDexNoIndex) {
-        // If the method's class type index is available, check
-        // whether we should add an explicit class initialization
-        // check for its declaring class before the static method call.
-
-        // TODO: find out why this check is needed.
-        bool is_in_dex_cache = compiler_driver_->CanAssumeTypeIsPresentInDexCache(
-            *outer_compilation_unit_->GetDexFile(), storage_index);
-        bool is_initialized =
-            resolved_method->GetDeclaringClass()->IsInitialized() && is_in_dex_cache;
-
-        if (is_initialized) {
-          clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kNone;
-        } else {
-          clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit;
-          HLoadClass* load_class = new (arena_) HLoadClass(
-              graph_->GetCurrentMethod(),
-              storage_index,
-              *dex_compilation_unit_->GetDexFile(),
-              is_outer_class,
-              dex_pc);
-          current_block_->AddInstruction(load_class);
-          clinit_check = new (arena_) HClinitCheck(load_class, dex_pc);
-          current_block_->AddInstruction(clinit_check);
-        }
-      }
-    }
-
-    HInvokeStaticOrDirect::DispatchInfo dispatch_info = ComputeDispatchInfo(is_string_init,
-                                                                            string_init_offset,
-                                                                            target_method,
-                                                                            direct_method,
-                                                                            direct_code);
-    invoke = new (arena_) HInvokeStaticOrDirect(arena_,
-                                                number_of_arguments,
-                                                return_type,
-                                                dex_pc,
-                                                method_idx,
-                                                target_method,
-                                                dispatch_info,
-                                                invoke_type,
-                                                optimized_invoke_type,
-                                                clinit_check_requirement);
-  }
-
+bool HGraphBuilder::SetupArgumentsAndAddInvoke(HInvoke* invoke,
+                                               uint32_t number_of_vreg_arguments,
+                                               uint32_t* args,
+                                               uint32_t register_index,
+                                               bool is_range,
+                                               const char* descriptor,
+                                               HClinitCheck* clinit_check) {
   size_t start_index = 0;
-  Temporaries temps(graph_);
-  if (is_instance_call) {
+  size_t argument_index = 0;
+  uint32_t descriptor_index = 1;  // Skip the return type.
+
+  bool is_instance_call = invoke->GetOriginalInvokeType() != InvokeType::kStatic;
+  bool is_string_init = invoke->IsInvokeStaticOrDirect()
+      && invoke->AsInvokeStaticOrDirect()->IsStringInit();
+
+  if (is_string_init) {
+    start_index = 1;
+    argument_index = 0;
+  } else if (is_instance_call) {
+    Temporaries temps(graph_);
     HInstruction* arg = LoadLocal(is_range ? register_index : args[0], Primitive::kPrimNot);
-    HNullCheck* null_check = new (arena_) HNullCheck(arg, dex_pc);
+    HNullCheck* null_check = new (arena_) HNullCheck(arg, invoke->GetDexPc());
     current_block_->AddInstruction(null_check);
     temps.Add(null_check);
     invoke->SetArgumentAt(0, null_check);
     start_index = 1;
+    argument_index = 1;
   }
 
-  uint32_t descriptor_index = 1;  // Skip the return type.
-  uint32_t argument_index = start_index;
-  if (is_string_init) {
-    start_index = 1;
-  }
   for (size_t i = start_index;
        // Make sure we don't go over the expected arguments or over the number of
        // dex registers given. If the instruction was seen as dead by the verifier,
        // it hasn't been properly checked.
-       (i < number_of_vreg_arguments) && (argument_index < number_of_arguments);
+       (i < number_of_vreg_arguments) && (argument_index < invoke->GetNumberOfArguments());
        i++, argument_index++) {
     Primitive::Type type = Primitive::GetType(descriptor[descriptor_index++]);
     bool is_wide = (type == Primitive::kPrimLong) || (type == Primitive::kPrimDouble);
@@ -1085,7 +1096,7 @@
     }
   }
 
-  if (argument_index != number_of_arguments) {
+  if (argument_index != invoke->GetNumberOfArguments()) {
     VLOG(compiler) << "Did not compile "
                    << PrettyMethod(dex_compilation_unit_->GetDexMethodIndex(), *dex_file_)
                    << " because of wrong number of arguments in invoke instruction";
@@ -1098,10 +1109,12 @@
     argument_index++;
   }
 
-  if (clinit_check_requirement == HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit) {
+  if (clinit_check != nullptr) {
     // Add the class initialization check as last input of `invoke`.
-    DCHECK(clinit_check != nullptr);
     DCHECK(!is_string_init);
+    DCHECK(invoke->IsInvokeStaticOrDirect());
+    DCHECK(invoke->AsInvokeStaticOrDirect()->GetClinitCheckRequirement()
+        == HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit);
     invoke->SetArgumentAt(argument_index, clinit_check);
     argument_index++;
   }
@@ -1112,15 +1125,45 @@
     HInstruction* fake_string = LoadLocal(orig_this_reg, Primitive::kPrimNot);
     invoke->SetArgumentAt(argument_index, fake_string);
     current_block_->AddInstruction(invoke);
-    PotentiallySimplifyFakeString(orig_this_reg, dex_pc, invoke);
+    PotentiallySimplifyFakeString(orig_this_reg, invoke->GetDexPc(), invoke);
   } else {
     current_block_->AddInstruction(invoke);
   }
+
   latest_result_ = invoke;
 
   return true;
 }
 
+void HGraphBuilder::PotentiallySimplifyFakeString(uint16_t original_dex_register,
+                                                  uint32_t dex_pc,
+                                                  HInvoke* actual_string) {
+  if (!graph_->IsDebuggable()) {
+    // Notify that we cannot compile with baseline. The dex registers aliasing
+    // with `original_dex_register` will be handled when we optimize
+    // (see HInstructionSimplifer::VisitFakeString).
+    can_use_baseline_for_string_init_ = false;
+    return;
+  }
+  const VerifiedMethod* verified_method =
+      compiler_driver_->GetVerifiedMethod(dex_file_, dex_compilation_unit_->GetDexMethodIndex());
+  if (verified_method != nullptr) {
+    UpdateLocal(original_dex_register, actual_string);
+    const SafeMap<uint32_t, std::set<uint32_t>>& string_init_map =
+        verified_method->GetStringInitPcRegMap();
+    auto map_it = string_init_map.find(dex_pc);
+    if (map_it != string_init_map.end()) {
+      std::set<uint32_t> reg_set = map_it->second;
+      for (auto set_it = reg_set.begin(); set_it != reg_set.end(); ++set_it) {
+        HInstruction* load_local = LoadLocal(original_dex_register, Primitive::kPrimNot);
+        UpdateLocal(*set_it, load_local);
+      }
+    }
+  } else {
+    can_use_baseline_for_string_init_ = false;
+  }
+}
+
 bool HGraphBuilder::BuildInstanceFieldAccess(const Instruction& instruction,
                                              uint32_t dex_pc,
                                              bool is_put) {
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index 08600c7..19dd944 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -272,6 +272,19 @@
                                                           uintptr_t direct_method,
                                                           uintptr_t direct_code);
 
+  bool SetupArgumentsAndAddInvoke(HInvoke* invoke,
+                                  uint32_t number_of_vreg_arguments,
+                                  uint32_t* args,
+                                  uint32_t register_index,
+                                  bool is_range,
+                                  const char* descriptor,
+                                  HClinitCheck* clinit_check);
+
+  HClinitCheck* ProcessClinitCheckForInvoke(
+      uint32_t dex_pc,
+      uint32_t method_idx,
+      HInvokeStaticOrDirect::ClinitCheckRequirement* clinit_check_requirement);
+
   ArenaAllocator* const arena_;
 
   // A list of the size of the dex code holding block information for
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 4152355..25b3ea2 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -3202,6 +3202,15 @@
     Register source = InputRegisterAt(conversion, 0);
     if ((result_type == Primitive::kPrimChar) && (input_size < result_size)) {
       __ Ubfx(output, source, 0, result_size * kBitsPerByte);
+    } else if (result_type == Primitive::kPrimInt && input_type == Primitive::kPrimLong) {
+      // 'int' values are used directly as W registers, discarding the top
+      // bits, so we don't need to sign-extend and can just perform a move.
+      // We do not pass the `kDiscardForSameWReg` argument to force clearing the
+      // top 32 bits of the target register. We theoretically could leave those
+      // bits unchanged, but we would have to make sure that no code uses a
+      // 32bit input value as a 64bit value assuming that the top 32 bits are
+      // zero.
+      __ Mov(output.W(), source.W());
     } else if ((result_type == Primitive::kPrimChar) ||
                ((input_type == Primitive::kPrimChar) && (result_size > input_size))) {
       __ Ubfx(output, output.IsX() ? source.X() : source.W(), 0, min_size * kBitsPerByte);
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index 1527a6a..806fd7a 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -919,6 +919,104 @@
   __ Bind(slow_path->GetExitLabel());
 }
 
+void IntrinsicLocationsBuilderARM::VisitStringEquals(HInvoke* invoke) {
+  LocationSummary* locations = new (arena_) LocationSummary(invoke,
+                                                            LocationSummary::kNoCall,
+                                                            kIntrinsified);
+  InvokeRuntimeCallingConvention calling_convention;
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+  // Temporary registers to store lengths of strings and for calculations.
+  // Using instruction cbz requires a low register, so explicitly set a temp to be R0.
+  locations->AddTemp(Location::RegisterLocation(R0));
+  locations->AddTemp(Location::RequiresRegister());
+  locations->AddTemp(Location::RequiresRegister());
+
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void IntrinsicCodeGeneratorARM::VisitStringEquals(HInvoke* invoke) {
+  ArmAssembler* assembler = GetAssembler();
+  LocationSummary* locations = invoke->GetLocations();
+
+  Register str = locations->InAt(0).AsRegister<Register>();
+  Register arg = locations->InAt(1).AsRegister<Register>();
+  Register out = locations->Out().AsRegister<Register>();
+
+  Register temp = locations->GetTemp(0).AsRegister<Register>();
+  Register temp1 = locations->GetTemp(1).AsRegister<Register>();
+  Register temp2 = locations->GetTemp(2).AsRegister<Register>();
+
+  Label loop;
+  Label end;
+  Label return_true;
+  Label return_false;
+
+  // Get offsets of count, value, and class fields within a string object.
+  const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+  const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value();
+  const uint32_t class_offset = mirror::Object::ClassOffset().Uint32Value();
+
+  // Note that the null check must have been done earlier.
+  DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
+
+  // Check if input is null, return false if it is.
+  __ CompareAndBranchIfZero(arg, &return_false);
+
+  // Instanceof check for the argument by comparing class fields.
+  // All string objects must have the same type since String cannot be subclassed.
+  // Receiver must be a string object, so its class field is equal to all strings' class fields.
+  // If the argument is a string object, its class field must be equal to receiver's class field.
+  __ ldr(temp, Address(str, class_offset));
+  __ ldr(temp1, Address(arg, class_offset));
+  __ cmp(temp, ShifterOperand(temp1));
+  __ b(&return_false, NE);
+
+  // Load lengths of this and argument strings.
+  __ ldr(temp, Address(str, count_offset));
+  __ ldr(temp1, Address(arg, count_offset));
+  // Check if lengths are equal, return false if they're not.
+  __ cmp(temp, ShifterOperand(temp1));
+  __ b(&return_false, NE);
+  // Return true if both strings are empty.
+  __ cbz(temp, &return_true);
+
+  // Reference equality check, return true if same reference.
+  __ cmp(str, ShifterOperand(arg));
+  __ b(&return_true, EQ);
+
+  // Assertions that must hold in order to compare strings 2 characters at a time.
+  DCHECK_ALIGNED(value_offset, 4);
+  static_assert(IsAligned<4>(kObjectAlignment), "String of odd length is not zero padded");
+
+  // temp cannot overflow because we cannot allocate a String object with size 4GiB or greater.
+  __ add(temp, temp, ShifterOperand(temp));
+  __ LoadImmediate(temp1, value_offset);
+  __ add(temp, temp, ShifterOperand(value_offset));
+
+  // Loop to compare strings 2 characters at a time starting at the front of the string.
+  // Ok to do this because strings with an odd length are zero-padded.
+  __ Bind(&loop);
+  __ ldr(out, Address(str, temp1));
+  __ ldr(temp2, Address(arg, temp1));
+  __ cmp(out, ShifterOperand(temp2));
+  __ b(&return_false, NE);
+  __ add(temp1, temp1, ShifterOperand(sizeof(uint32_t)));
+  __ cmp(temp1, ShifterOperand(temp));
+  __ b(&loop, LO);
+
+  // Return true and exit the function.
+  // If loop does not result in returning false, we return true.
+  __ Bind(&return_true);
+  __ LoadImmediate(out, 1);
+  __ b(&end);
+
+  // Return false and exit the function.
+  __ Bind(&return_false);
+  __ LoadImmediate(out, 0);
+  __ Bind(&end);
+}
+
 static void GenerateVisitStringIndexOf(HInvoke* invoke,
                                        ArmAssembler* assembler,
                                        CodeGeneratorARM* codegen,
@@ -1110,7 +1208,6 @@
 UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar)
 UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
 UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck)
-UNIMPLEMENTED_INTRINSIC(StringEquals)
 
 #undef UNIMPLEMENTED_INTRINSIC
 
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index f2db330..2ed2d9a 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -3181,6 +3181,8 @@
     return dispatch_info_.direct_code_ptr;
   }
 
+  ClinitCheckRequirement GetClinitCheckRequirement() const { return clinit_check_requirement_; }
+
   // Is this instruction a call to a static method?
   bool IsStatic() const {
     return GetInvokeType() == kStatic;
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 45b3df0..97b9972 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -475,7 +475,7 @@
 
   if (catch_info->IsCatchAllTypeIndex()) {
     instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(throwable_class_handle_,
-                                /* is_exact */ false));
+                                                          /* is_exact */ false));
   } else {
     UpdateReferenceTypeInfo(instr,
                             catch_info->GetCatchTypeIndex(),
diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc
index 9f32a9e..37c8bc5 100644
--- a/compiler/optimizing/register_allocator.cc
+++ b/compiler/optimizing/register_allocator.cc
@@ -587,9 +587,17 @@
   while (!unhandled_->IsEmpty()) {
     // (1) Remove interval with the lowest start position from unhandled.
     LiveInterval* current = unhandled_->Pop();
+
+    // Make sure the interval is an expected state.
     DCHECK(!current->IsFixed() && !current->HasSpillSlot());
+    // Make sure we are going in the right order.
     DCHECK(unhandled_->IsEmpty() || unhandled_->Peek()->GetStart() >= current->GetStart());
+    // Make sure a low interval is always with a high.
     DCHECK(!current->IsLowInterval() || unhandled_->Peek()->IsHighInterval());
+    // Make sure a high interval is always with a low.
+    DCHECK(current->IsLowInterval() ||
+           unhandled_->IsEmpty() ||
+           !unhandled_->Peek()->IsHighInterval());
 
     size_t position = current->GetStart();
 
@@ -916,13 +924,19 @@
     if (active->IsHighInterval()) continue;
     if (first_register_use > next_use[active->GetRegister()]) continue;
 
-    // Split the first interval found.
-    if (!active->IsLowInterval() || IsLowOfUnalignedPairInterval(active)) {
+    // Split the first interval found that is either:
+    // 1) A non-pair interval.
+    // 2) A pair interval whose high is not low + 1.
+    // 3) A pair interval whose low is not even.
+    if (!active->IsLowInterval() ||
+        IsLowOfUnalignedPairInterval(active) ||
+        !IsLowRegister(active->GetRegister())) {
       LiveInterval* split = Split(active, position);
       active_.DeleteAt(i);
       if (split != active) {
         handled_.Add(active);
       }
+      PotentiallyRemoveOtherHalf(active, &active_, i);
       AddSorted(unhandled_, split);
       return true;
     }
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index 35acd42..084c88e 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -141,10 +141,10 @@
 #define MIRROR_CLASS_ACCESS_FLAGS_OFFSET (36 + MIRROR_OBJECT_HEADER_SIZE)
 ADD_TEST_EQ(MIRROR_CLASS_ACCESS_FLAGS_OFFSET,
             art::mirror::Class::AccessFlagsOffset().Int32Value())
-#define MIRROR_CLASS_OBJECT_SIZE_OFFSET (96 + MIRROR_OBJECT_HEADER_SIZE)
+#define MIRROR_CLASS_OBJECT_SIZE_OFFSET (100 + MIRROR_OBJECT_HEADER_SIZE)
 ADD_TEST_EQ(MIRROR_CLASS_OBJECT_SIZE_OFFSET,
             art::mirror::Class::ObjectSizeOffset().Int32Value())
-#define MIRROR_CLASS_STATUS_OFFSET (108 + MIRROR_OBJECT_HEADER_SIZE)
+#define MIRROR_CLASS_STATUS_OFFSET (112 + MIRROR_OBJECT_HEADER_SIZE)
 ADD_TEST_EQ(MIRROR_CLASS_STATUS_OFFSET,
             art::mirror::Class::StatusOffset().Int32Value())
 
@@ -153,7 +153,7 @@
             static_cast<uint32_t>(art::mirror::Class::kStatusInitialized))
 #define ACCESS_FLAGS_CLASS_IS_FINALIZABLE 0x80000000
 ADD_TEST_EQ(static_cast<uint32_t>(ACCESS_FLAGS_CLASS_IS_FINALIZABLE),
-            static_cast<uint32_t>(kAccClassIsFinalizable))
+            static_cast<uint32_t>(art::kAccClassIsFinalizable))
 
 // Array offsets.
 #define MIRROR_ARRAY_LENGTH_OFFSET      MIRROR_OBJECT_HEADER_SIZE
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index 4172b89..b6ad547 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -66,6 +66,8 @@
 #define kFlag_Invocation    0x8000      // Part of the invocation interface (JavaVM*).
 
 #define kFlag_ForceTrace    0x80000000  // Add this to a JNI function's flags if you want to trace every call.
+
+class VarArgs;
 /*
  * Java primitive types:
  * B - jbyte
@@ -126,6 +128,116 @@
   jshort S;
   const void* V;  // void
   jboolean Z;
+  const VarArgs* va;
+};
+
+/*
+ * A structure containing all the information needed to validate varargs arguments.
+ *
+ * Note that actually getting the arguments from this structure mutates it so should only be done on
+ * owned copies.
+ */
+class VarArgs {
+ public:
+  VarArgs(jmethodID m, va_list var) : m_(m), type_(kTypeVaList), cnt_(0) {
+    va_copy(vargs_, var);
+  }
+
+  VarArgs(jmethodID m, const jvalue* vals) : m_(m), type_(kTypePtr), cnt_(0), ptr_(vals) {}
+
+  ~VarArgs() {
+    if (type_ == kTypeVaList) {
+      va_end(vargs_);
+    }
+  }
+
+  VarArgs(VarArgs&& other) {
+    m_ = other.m_;
+    cnt_ = other.cnt_;
+    type_ = other.type_;
+    if (other.type_ == kTypeVaList) {
+      va_copy(vargs_, other.vargs_);
+    } else {
+      ptr_ = other.ptr_;
+    }
+  }
+
+  // This method is const because we need to ensure that one only uses the GetValue method on an
+  // owned copy of the VarArgs. This is because getting the next argument from a va_list is a
+  // mutating operation. Therefore we pass around these VarArgs with the 'const' qualifier and when
+  // we want to use one we need to Clone() it.
+  VarArgs Clone() const {
+    if (type_ == kTypeVaList) {
+      // const_cast needed to make sure the compiler is okay with va_copy, which (being a macro) is
+      // messed up if the source argument is not the exact type 'va_list'.
+      return VarArgs(m_, cnt_, const_cast<VarArgs*>(this)->vargs_);
+    } else {
+      return VarArgs(m_, cnt_, ptr_);
+    }
+  }
+
+  jmethodID GetMethodID() const {
+    return m_;
+  }
+
+  JniValueType GetValue(char fmt) {
+    JniValueType o;
+    if (type_ == kTypeVaList) {
+      switch (fmt) {
+        case 'Z': o.Z = static_cast<jboolean>(va_arg(vargs_, jint)); break;
+        case 'B': o.B = static_cast<jbyte>(va_arg(vargs_, jint)); break;
+        case 'C': o.C = static_cast<jchar>(va_arg(vargs_, jint)); break;
+        case 'S': o.S = static_cast<jshort>(va_arg(vargs_, jint)); break;
+        case 'I': o.I = va_arg(vargs_, jint); break;
+        case 'J': o.J = va_arg(vargs_, jlong); break;
+        case 'F': o.F = static_cast<jfloat>(va_arg(vargs_, jdouble)); break;
+        case 'D': o.D = va_arg(vargs_, jdouble); break;
+        case 'L': o.L = va_arg(vargs_, jobject); break;
+        default:
+          LOG(FATAL) << "Illegal type format char " << fmt;
+          UNREACHABLE();
+      }
+    } else {
+      CHECK(type_ == kTypePtr);
+      jvalue v = ptr_[cnt_];
+      cnt_++;
+      switch (fmt) {
+        case 'Z': o.Z = v.z; break;
+        case 'B': o.B = v.b; break;
+        case 'C': o.C = v.c; break;
+        case 'S': o.S = v.s; break;
+        case 'I': o.I = v.i; break;
+        case 'J': o.J = v.j; break;
+        case 'F': o.F = v.f; break;
+        case 'D': o.D = v.d; break;
+        case 'L': o.L = v.l; break;
+        default:
+          LOG(FATAL) << "Illegal type format char " << fmt;
+          UNREACHABLE();
+      }
+    }
+    return o;
+  }
+
+ private:
+  VarArgs(jmethodID m, uint32_t cnt, va_list var) : m_(m), type_(kTypeVaList), cnt_(cnt) {
+    va_copy(vargs_, var);
+  }
+
+  VarArgs(jmethodID m, uint32_t cnt, const jvalue* vals) : m_(m), type_(kTypePtr), cnt_(cnt), ptr_(vals) {}
+
+  enum VarArgsType {
+    kTypeVaList,
+    kTypePtr,
+  };
+
+  jmethodID m_;
+  VarArgsType type_;
+  uint32_t cnt_;
+  union {
+    va_list vargs_;
+    const jvalue* ptr_;
+  };
 };
 
 class ScopedCheck {
@@ -339,7 +451,7 @@
    * z - jsize (for lengths; use i if negative values are okay)
    * v - JavaVM*
    * E - JNIEnv*
-   * . - no argument; just print "..." (used for varargs JNI calls)
+   * . - VarArgs* for Jni calls with variable length arguments
    *
    * Use the kFlag_NullableUtf flag where 'u' field(s) are nullable.
    */
@@ -736,11 +848,35 @@
         return CheckThread(arg.E);
       case 'L':  // jobject
         return CheckInstance(soa, kObject, arg.L, true);
+      case '.':  // A VarArgs list
+        return CheckVarArgs(soa, arg.va);
       default:
         return CheckNonHeapValue(fmt, arg);
     }
   }
 
+  bool CheckVarArgs(ScopedObjectAccess& soa, const VarArgs* args_p)
+      SHARED_REQUIRES(Locks::mutator_lock_) {
+    CHECK(args_p != nullptr);
+    VarArgs args(args_p->Clone());
+    ArtMethod* m = CheckMethodID(soa, args.GetMethodID());
+    if (m == nullptr) {
+      return false;
+    }
+    uint32_t len = 0;
+    const char* shorty = m->GetShorty(&len);
+    // Skip the return type
+    CHECK_GE(len, 1u);
+    len--;
+    shorty++;
+    for (uint32_t i = 0; i < len; i++) {
+      if (!CheckPossibleHeapValue(soa, shorty[i], args.GetValue(shorty[i]))) {
+        return false;
+      }
+    }
+    return true;
+  }
+
   bool CheckNonHeapValue(char fmt, JniValueType arg) {
     switch (fmt) {
       case 'p':  // TODO: pointer - null or readable?
@@ -833,6 +969,24 @@
         }
         break;
       }
+      case '.': {
+        const VarArgs* va = arg.va;
+        VarArgs args(va->Clone());
+        ArtMethod* m = soa.DecodeMethod(args.GetMethodID());
+        uint32_t len;
+        const char* shorty = m->GetShorty(&len);
+        CHECK_GE(len, 1u);
+        // Skip past return value.
+        len--;
+        shorty++;
+        // Remove the previous ', ' from the message.
+        msg->erase(msg->length() - 2);
+        for (uint32_t i = 0; i < len; i++) {
+          *msg += ", ";
+          TracePossibleHeapValue(soa, entry, shorty[i], args.GetValue(shorty[i]), msg);
+        }
+        break;
+      }
       default:
         TraceNonHeapValue(fmt, arg, msg);
         break;
@@ -1836,8 +1990,9 @@
   static jobject NewObjectV(JNIEnv* env, jclass c, jmethodID mid, va_list vargs) {
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
-    JniValueType args[3] = {{.E = env}, {.c = c}, {.m = mid}};
-    if (sc.Check(soa, true, "Ecm", args) && sc.CheckInstantiableNonArray(soa, c) &&
+    VarArgs rest(mid, vargs);
+    JniValueType args[4] = {{.E = env}, {.c = c}, {.m = mid}, {.va = &rest}};
+    if (sc.Check(soa, true, "Ecm.", args) && sc.CheckInstantiableNonArray(soa, c) &&
         sc.CheckConstructor(soa, mid)) {
       JniValueType result;
       result.L = baseEnv(env)->NewObjectV(env, c, mid, vargs);
@@ -1859,8 +2014,9 @@
   static jobject NewObjectA(JNIEnv* env, jclass c, jmethodID mid, jvalue* vargs) {
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
-    JniValueType args[3] = {{.E = env}, {.c = c}, {.m = mid}};
-    if (sc.Check(soa, true, "Ecm", args) && sc.CheckInstantiableNonArray(soa, c) &&
+    VarArgs rest(mid, vargs);
+    JniValueType args[4] = {{.E = env}, {.c = c}, {.m = mid}, {.va = &rest}};
+    if (sc.Check(soa, true, "Ecm.", args) && sc.CheckInstantiableNonArray(soa, c) &&
         sc.CheckConstructor(soa, mid)) {
       JniValueType result;
       result.L = baseEnv(env)->NewObjectA(env, c, mid, vargs);
@@ -2689,25 +2845,25 @@
   }
 
   static bool CheckCallArgs(ScopedObjectAccess& soa, ScopedCheck& sc, JNIEnv* env, jobject obj,
-                            jclass c, jmethodID mid, InvokeType invoke)
+                            jclass c, jmethodID mid, InvokeType invoke, const VarArgs* vargs)
       SHARED_REQUIRES(Locks::mutator_lock_) {
     bool checked;
     switch (invoke) {
       case kVirtual: {
         DCHECK(c == nullptr);
-        JniValueType args[3] = {{.E = env}, {.L = obj}, {.m = mid}};
-        checked = sc.Check(soa, true, "ELm", args);
+        JniValueType args[4] = {{.E = env}, {.L = obj}, {.m = mid}, {.va = vargs}};
+        checked = sc.Check(soa, true, "ELm.", args);
         break;
       }
       case kDirect: {
-        JniValueType args[4] = {{.E = env}, {.L = obj}, {.c = c}, {.m = mid}};
-        checked = sc.Check(soa, true, "ELcm", args);
+        JniValueType args[5] = {{.E = env}, {.L = obj}, {.c = c}, {.m = mid}, {.va = vargs}};
+        checked = sc.Check(soa, true, "ELcm.", args);
         break;
       }
       case kStatic: {
         DCHECK(obj == nullptr);
-        JniValueType args[3] = {{.E = env}, {.c = c}, {.m = mid}};
-        checked = sc.Check(soa, true, "Ecm", args);
+        JniValueType args[4] = {{.E = env}, {.c = c}, {.m = mid}, {.va = vargs}};
+        checked = sc.Check(soa, true, "Ecm.", args);
         break;
       }
       default:
@@ -2724,7 +2880,8 @@
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, function_name);
     JniValueType result;
-    if (CheckCallArgs(soa, sc, env, obj, c, mid, invoke) &&
+    VarArgs rest(mid, vargs);
+    if (CheckCallArgs(soa, sc, env, obj, c, mid, invoke, &rest) &&
         sc.CheckMethodAndSig(soa, obj, c, mid, type, invoke)) {
       const char* result_check;
       switch (type) {
@@ -2907,7 +3064,8 @@
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, function_name);
     JniValueType result;
-    if (CheckCallArgs(soa, sc, env, obj, c, mid, invoke) &&
+    VarArgs rest(mid, vargs);
+    if (CheckCallArgs(soa, sc, env, obj, c, mid, invoke, &rest) &&
         sc.CheckMethodAndSig(soa, obj, c, mid, type, invoke)) {
       const char* result_check;
       switch (type) {
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index c179c64..dc273d8 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -358,9 +358,9 @@
   // Setup String.
   Handle<mirror::Class> java_lang_String(hs.NewHandle(
       AllocClass(self, java_lang_Class.Get(), mirror::String::ClassSize(image_pointer_size_))));
+  java_lang_String->SetStringClass();
   mirror::String::SetClass(java_lang_String.Get());
   mirror::Class::SetStatus(java_lang_String, mirror::Class::kStatusResolved, self);
-  java_lang_String->SetStringClass();
 
   // Setup java.lang.ref.Reference.
   Handle<mirror::Class> java_lang_ref_Reference(hs.NewHandle(
@@ -570,16 +570,13 @@
   CHECK_EQ(java_lang_ref_Reference->GetClassSize(),
            mirror::Reference::ClassSize(image_pointer_size_));
   class_root = FindSystemClass(self, "Ljava/lang/ref/FinalizerReference;");
-  class_root->SetAccessFlags(class_root->GetAccessFlags() |
-                             kAccClassIsReference | kAccClassIsFinalizerReference);
+  class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagFinalizerReference);
   class_root = FindSystemClass(self, "Ljava/lang/ref/PhantomReference;");
-  class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference |
-                             kAccClassIsPhantomReference);
+  class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagPhantomReference);
   class_root = FindSystemClass(self, "Ljava/lang/ref/SoftReference;");
-  class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference);
+  class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagSoftReference);
   class_root = FindSystemClass(self, "Ljava/lang/ref/WeakReference;");
-  class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference |
-                             kAccClassIsWeakReference);
+  class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagWeakReference);
 
   // Setup the ClassLoader, verifying the object_size_.
   class_root = FindSystemClass(self, "Ljava/lang/ClassLoader;");
@@ -2701,6 +2698,11 @@
   new_class->SetVTable(java_lang_Object->GetVTable());
   new_class->SetPrimitiveType(Primitive::kPrimNot);
   new_class->SetClassLoader(component_type->GetClassLoader());
+  if (component_type->IsPrimitive()) {
+    new_class->SetClassFlags(mirror::kClassFlagNoReferenceFields);
+  } else {
+    new_class->SetClassFlags(mirror::kClassFlagObjectArray);
+  }
   mirror::Class::SetStatus(new_class, mirror::Class::kStatusLoaded, self);
   {
     ArtMethod* imt[mirror::Class::kImtSize];
@@ -4385,9 +4387,9 @@
   }
 
   // Inherit reference flags (if any) from the superclass.
-  int reference_flags = (super->GetAccessFlags() & kAccReferenceFlagsMask);
+  int reference_flags = (super->GetClassFlags() & mirror::kClassFlagReference);
   if (reference_flags != 0) {
-    klass->SetAccessFlags(klass->GetAccessFlags() | reference_flags);
+    klass->SetClassFlags(klass->GetClassFlags() | reference_flags);
   }
   // Disallow custom direct subclasses of java.lang.ref.Reference.
   if (init_done_ && super == GetClassRoot(kJavaLangRefReference)) {
@@ -5227,6 +5229,22 @@
     *class_size = size;
   } else {
     klass->SetNumReferenceInstanceFields(num_reference_fields);
+    mirror::Class* super_class = klass->GetSuperClass();
+    if (num_reference_fields == 0 || super_class == nullptr) {
+      // object has one reference field, klass, but we ignore it since we always visit the class.
+      // If the super_class is null then we are java.lang.Object.
+      if (super_class == nullptr ||
+          (super_class->GetClassFlags() & mirror::kClassFlagNoReferenceFields) != 0) {
+        klass->SetClassFlags(klass->GetClassFlags() | mirror::kClassFlagNoReferenceFields);
+      } else if (kIsDebugBuild) {
+        size_t total_reference_instance_fields = 0;
+        while (super_class != nullptr) {
+          total_reference_instance_fields += super_class->NumReferenceInstanceFields();
+          super_class = super_class->GetSuperClass();
+        }
+        CHECK_GT(total_reference_instance_fields, 1u);
+      }
+    }
     if (!klass->IsVariableSize()) {
       std::string temp;
       DCHECK_GE(size, sizeof(mirror::Object)) << klass->GetDescriptor(&temp);
@@ -5528,6 +5546,36 @@
   }
 }
 
+ArtMethod* ClassLinker::ResolveMethodWithoutInvokeType(const DexFile& dex_file,
+                                                       uint32_t method_idx,
+                                                       Handle<mirror::DexCache> dex_cache,
+                                                       Handle<mirror::ClassLoader> class_loader) {
+  ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx, image_pointer_size_);
+  if (resolved != nullptr && !resolved->IsRuntimeMethod()) {
+    DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();
+    return resolved;
+  }
+  // Fail, get the declaring class.
+  const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
+  mirror::Class* klass = ResolveType(dex_file, method_id.class_idx_, dex_cache, class_loader);
+  if (klass == nullptr) {
+    Thread::Current()->AssertPendingException();
+    return nullptr;
+  }
+  if (klass->IsInterface()) {
+    LOG(FATAL) << "ResolveAmbiguousMethod: unexpected method in interface: " << PrettyClass(klass);
+    return nullptr;
+  }
+
+  // Search both direct and virtual methods
+  resolved = klass->FindDirectMethod(dex_cache.Get(), method_idx, image_pointer_size_);
+  if (resolved == nullptr) {
+    resolved = klass->FindVirtualMethod(dex_cache.Get(), method_idx, image_pointer_size_);
+  }
+
+  return resolved;
+}
+
 ArtField* ClassLinker::ResolveField(const DexFile& dex_file, uint32_t field_idx,
                                     Handle<mirror::DexCache> dex_cache,
                                     Handle<mirror::ClassLoader> class_loader, bool is_static) {
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 7243a25..fbf4035 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -229,6 +229,12 @@
       SHARED_REQUIRES(Locks::mutator_lock_);
   ArtMethod* ResolveMethod(Thread* self, uint32_t method_idx, ArtMethod* referrer, InvokeType type)
       SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
+  ArtMethod* ResolveMethodWithoutInvokeType(const DexFile& dex_file,
+                                            uint32_t method_idx,
+                                            Handle<mirror::DexCache> dex_cache,
+                                            Handle<mirror::ClassLoader> class_loader)
+      SHARED_REQUIRES(Locks::mutator_lock_)
+      REQUIRES(!dex_lock_, !Roles::uninterruptible_);
 
   ArtField* GetResolvedField(uint32_t field_idx, mirror::Class* field_declaring_class)
       SHARED_REQUIRES(Locks::mutator_lock_);
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 3c84d8f..0d1c875 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -488,6 +488,7 @@
 struct ClassOffsets : public CheckOffsets<mirror::Class> {
   ClassOffsets() : CheckOffsets<mirror::Class>(false, "Ljava/lang/Class;") {
     addOffset(OFFSETOF_MEMBER(mirror::Class, access_flags_), "accessFlags");
+    addOffset(OFFSETOF_MEMBER(mirror::Class, class_flags_), "classFlags");
     addOffset(OFFSETOF_MEMBER(mirror::Class, class_loader_), "classLoader");
     addOffset(OFFSETOF_MEMBER(mirror::Class, class_size_), "classSize");
     addOffset(OFFSETOF_MEMBER(mirror::Class, clinit_thread_id_), "clinitThreadId");
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 52590a5..213f25d 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -32,13 +32,16 @@
 #include "base/hash_map.h"
 #include "base/logging.h"
 #include "base/stringprintf.h"
-#include "class_linker.h"
+#include "class_linker-inl.h"
 #include "dex_file-inl.h"
 #include "dex_file_verifier.h"
 #include "globals.h"
 #include "leb128.h"
+#include "mirror/field.h"
+#include "mirror/method.h"
 #include "mirror/string.h"
 #include "os.h"
+#include "reflection.h"
 #include "safe_map.h"
 #include "handle_scope-inl.h"
 #include "thread.h"
@@ -1044,6 +1047,918 @@
   }
 }
 
+// Read a signed integer.  "zwidth" is the zero-based byte count.
+static int32_t ReadSignedInt(const uint8_t* ptr, int zwidth) {
+  int32_t val = 0;
+  for (int i = zwidth; i >= 0; --i) {
+    val = ((uint32_t)val >> 8) | (((int32_t)*ptr++) << 24);
+  }
+  val >>= (3 - zwidth) * 8;
+  return val;
+}
+
+// Read an unsigned integer.  "zwidth" is the zero-based byte count,
+// "fill_on_right" indicates which side we want to zero-fill from.
+static uint32_t ReadUnsignedInt(const uint8_t* ptr, int zwidth, bool fill_on_right) {
+  uint32_t val = 0;
+  for (int i = zwidth; i >= 0; --i) {
+    val = (val >> 8) | (((uint32_t)*ptr++) << 24);
+  }
+  if (!fill_on_right) {
+    val >>= (3 - zwidth) * 8;
+  }
+  return val;
+}
+
+// Read a signed long.  "zwidth" is the zero-based byte count.
+static int64_t ReadSignedLong(const uint8_t* ptr, int zwidth) {
+  int64_t val = 0;
+  for (int i = zwidth; i >= 0; --i) {
+    val = ((uint64_t)val >> 8) | (((int64_t)*ptr++) << 56);
+  }
+  val >>= (7 - zwidth) * 8;
+  return val;
+}
+
+// Read an unsigned long.  "zwidth" is the zero-based byte count,
+// "fill_on_right" indicates which side we want to zero-fill from.
+static uint64_t ReadUnsignedLong(const uint8_t* ptr, int zwidth, bool fill_on_right) {
+  uint64_t val = 0;
+  for (int i = zwidth; i >= 0; --i) {
+    val = (val >> 8) | (((uint64_t)*ptr++) << 56);
+  }
+  if (!fill_on_right) {
+    val >>= (7 - zwidth) * 8;
+  }
+  return val;
+}
+
+const DexFile::AnnotationSetItem* DexFile::FindAnnotationSetForField(ArtField* field) const {
+  mirror::Class* klass = field->GetDeclaringClass();
+  const AnnotationsDirectoryItem* annotations_dir = GetAnnotationsDirectory(*klass->GetClassDef());
+  if (annotations_dir == nullptr) {
+    return nullptr;
+  }
+  const FieldAnnotationsItem* field_annotations = GetFieldAnnotations(annotations_dir);
+  if (field_annotations == nullptr) {
+    return nullptr;
+  }
+  uint32_t field_index = field->GetDexFieldIndex();
+  uint32_t field_count = annotations_dir->fields_size_;
+  for (uint32_t i = 0; i < field_count; ++i) {
+    if (field_annotations[i].field_idx_ == field_index) {
+      return GetFieldAnnotationSetItem(field_annotations[i]);
+    }
+  }
+  return nullptr;
+}
+
+mirror::Object* DexFile::GetAnnotationForField(ArtField* field,
+                                               Handle<mirror::Class> annotation_class) const {
+  const AnnotationSetItem* annotation_set = FindAnnotationSetForField(field);
+  if (annotation_set == nullptr) {
+    return nullptr;
+  }
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::Class> field_class(hs.NewHandle(field->GetDeclaringClass()));
+  return GetAnnotationObjectFromAnnotationSet(
+      field_class, annotation_set, kDexVisibilityRuntime, annotation_class);
+}
+
+mirror::ObjectArray<mirror::Object>* DexFile::GetAnnotationsForField(ArtField* field) const {
+  const AnnotationSetItem* annotation_set = FindAnnotationSetForField(field);
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::Class> field_class(hs.NewHandle(field->GetDeclaringClass()));
+  return ProcessAnnotationSet(field_class, annotation_set, kDexVisibilityRuntime);
+}
+
+mirror::ObjectArray<mirror::Object>* DexFile::GetSignatureAnnotationForField(ArtField* field)
+    const {
+  const AnnotationSetItem* annotation_set = FindAnnotationSetForField(field);
+  if (annotation_set == nullptr) {
+    return nullptr;
+  }
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::Class> field_class(hs.NewHandle(field->GetDeclaringClass()));
+  return GetSignatureValue(field_class, annotation_set);
+}
+
+bool DexFile::IsFieldAnnotationPresent(ArtField* field, Handle<mirror::Class> annotation_class)
+    const {
+  const AnnotationSetItem* annotation_set = FindAnnotationSetForField(field);
+  if (annotation_set == nullptr) {
+    return false;
+  }
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::Class> field_class(hs.NewHandle(field->GetDeclaringClass()));
+  const AnnotationItem* annotation_item = GetAnnotationItemFromAnnotationSet(
+      field_class, annotation_set, kDexVisibilityRuntime, annotation_class);
+  return annotation_item != nullptr;
+}
+
+const DexFile::AnnotationSetItem* DexFile::FindAnnotationSetForMethod(ArtMethod* method) const {
+  mirror::Class* klass = method->GetDeclaringClass();
+  const AnnotationsDirectoryItem* annotations_dir = GetAnnotationsDirectory(*klass->GetClassDef());
+  if (annotations_dir == nullptr) {
+    return nullptr;
+  }
+  const MethodAnnotationsItem* method_annotations = GetMethodAnnotations(annotations_dir);
+  if (method_annotations == nullptr) {
+    return nullptr;
+  }
+  uint32_t method_index = method->GetDexMethodIndex();
+  uint32_t method_count = annotations_dir->methods_size_;
+  for (uint32_t i = 0; i < method_count; ++i) {
+    if (method_annotations[i].method_idx_ == method_index) {
+      return GetMethodAnnotationSetItem(method_annotations[i]);
+    }
+  }
+  return nullptr;
+}
+
+const DexFile::ParameterAnnotationsItem* DexFile::FindAnnotationsItemForMethod(ArtMethod* method)
+    const {
+  mirror::Class* klass = method->GetDeclaringClass();
+  const AnnotationsDirectoryItem* annotations_dir = GetAnnotationsDirectory(*klass->GetClassDef());
+  if (annotations_dir == nullptr) {
+    return nullptr;
+  }
+  const ParameterAnnotationsItem* parameter_annotations = GetParameterAnnotations(annotations_dir);
+  if (parameter_annotations == nullptr) {
+    return nullptr;
+  }
+  uint32_t method_index = method->GetDexMethodIndex();
+  uint32_t parameter_count = annotations_dir->parameters_size_;
+  for (uint32_t i = 0; i < parameter_count; ++i) {
+    if (parameter_annotations[i].method_idx_ == method_index) {
+      return &parameter_annotations[i];
+    }
+  }
+  return nullptr;
+}
+
+mirror::Object* DexFile::GetAnnotationDefaultValue(ArtMethod* method) const {
+  mirror::Class* klass = method->GetDeclaringClass();
+  const AnnotationsDirectoryItem* annotations_dir = GetAnnotationsDirectory(*klass->GetClassDef());
+  if (annotations_dir == nullptr) {
+    return nullptr;
+  }
+  const AnnotationSetItem* annotation_set = GetClassAnnotationSet(annotations_dir);
+  if (annotation_set == nullptr) {
+    return nullptr;
+  }
+  const AnnotationItem* annotation_item = SearchAnnotationSet(annotation_set,
+      "Ldalvik/annotation/AnnotationDefault;", kDexVisibilitySystem);
+  if (annotation_item == nullptr) {
+    return nullptr;
+  }
+  const uint8_t* annotation = SearchEncodedAnnotation(annotation_item->annotation_, "value");
+  if (annotation == nullptr) {
+    return nullptr;
+  }
+  uint8_t header_byte = *(annotation++);
+  if ((header_byte & kDexAnnotationValueTypeMask) != kDexAnnotationAnnotation) {
+    return nullptr;
+  }
+  annotation = SearchEncodedAnnotation(annotation, method->GetName());
+  if (annotation == nullptr) {
+    return nullptr;
+  }
+  AnnotationValue annotation_value;
+  StackHandleScope<2> hs(Thread::Current());
+  Handle<mirror::Class> h_klass(hs.NewHandle(klass));
+  Handle<mirror::Class> return_type(hs.NewHandle(method->GetReturnType()));
+  if (!ProcessAnnotationValue(h_klass, &annotation, &annotation_value, return_type, kAllObjects)) {
+    return nullptr;
+  }
+  return annotation_value.value_.GetL();
+}
+
+mirror::Object* DexFile::GetAnnotationForMethod(ArtMethod* method,
+                                                Handle<mirror::Class> annotation_class) const {
+  const AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method);
+  if (annotation_set == nullptr) {
+    return nullptr;
+  }
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
+  return GetAnnotationObjectFromAnnotationSet(method_class, annotation_set,
+                                              kDexVisibilityRuntime, annotation_class);
+}
+
+mirror::ObjectArray<mirror::Object>* DexFile::GetAnnotationsForMethod(ArtMethod* method) const {
+  const AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method);
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
+  return ProcessAnnotationSet(method_class, annotation_set, kDexVisibilityRuntime);
+}
+
+mirror::ObjectArray<mirror::Object>* DexFile::GetExceptionTypesForMethod(ArtMethod* method) const {
+  const AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method);
+  if (annotation_set == nullptr) {
+    return nullptr;
+  }
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
+  return GetThrowsValue(method_class, annotation_set);
+}
+
+mirror::ObjectArray<mirror::Object>* DexFile::GetParameterAnnotations(ArtMethod* method) const {
+  const ParameterAnnotationsItem* parameter_annotations = FindAnnotationsItemForMethod(method);
+  if (parameter_annotations == nullptr) {
+    return nullptr;
+  }
+  const AnnotationSetRefList* set_ref_list =
+      GetParameterAnnotationSetRefList(parameter_annotations);
+  if (set_ref_list == nullptr) {
+    return nullptr;
+  }
+  uint32_t size = set_ref_list->size_;
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
+  return ProcessAnnotationSetRefList(method_class, set_ref_list, size);
+}
+
+bool DexFile::IsMethodAnnotationPresent(ArtMethod* method, Handle<mirror::Class> annotation_class)
+    const {
+  const AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method);
+  if (annotation_set == nullptr) {
+    return false;
+  }
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
+  const AnnotationItem* annotation_item = GetAnnotationItemFromAnnotationSet(
+      method_class, annotation_set, kDexVisibilityRuntime, annotation_class);
+  return (annotation_item != nullptr);
+}
+
+const DexFile::AnnotationSetItem* DexFile::FindAnnotationSetForClass(Handle<mirror::Class> klass)
+    const {
+  const AnnotationsDirectoryItem* annotations_dir = GetAnnotationsDirectory(*klass->GetClassDef());
+  if (annotations_dir == nullptr) {
+    return nullptr;
+  }
+  return GetClassAnnotationSet(annotations_dir);
+}
+
+mirror::Object* DexFile::GetAnnotationForClass(Handle<mirror::Class> klass,
+                                               Handle<mirror::Class> annotation_class) const {
+  const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  if (annotation_set == nullptr) {
+    return nullptr;
+  }
+  return GetAnnotationObjectFromAnnotationSet(klass, annotation_set, kDexVisibilityRuntime,
+                                              annotation_class);
+}
+
+mirror::ObjectArray<mirror::Object>* DexFile::GetAnnotationsForClass(Handle<mirror::Class> klass)
+    const {
+  const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  return ProcessAnnotationSet(klass, annotation_set, kDexVisibilityRuntime);
+}
+
+bool DexFile::IsClassAnnotationPresent(Handle<mirror::Class> klass,
+                                       Handle<mirror::Class> annotation_class) const {
+  const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  if (annotation_set == nullptr) {
+    return false;
+  }
+  const AnnotationItem* annotation_item = GetAnnotationItemFromAnnotationSet(
+      klass, annotation_set, kDexVisibilityRuntime, annotation_class);
+  return (annotation_item != nullptr);
+}
+
+mirror::Object* DexFile::CreateAnnotationMember(Handle<mirror::Class> klass,
+    Handle<mirror::Class> annotation_class, const uint8_t** annotation) const {
+  Thread* self = Thread::Current();
+  ScopedObjectAccessUnchecked soa(self);
+  StackHandleScope<5> hs(self);
+  uint32_t element_name_index = DecodeUnsignedLeb128(annotation);
+  const char* name = StringDataByIdx(element_name_index);
+  Handle<mirror::String> string_name(
+      hs.NewHandle(mirror::String::AllocFromModifiedUtf8(self, name)));
+
+  ArtMethod* annotation_method =
+      annotation_class->FindDeclaredVirtualMethodByName(name, sizeof(void*));
+  if (annotation_method == nullptr) {
+    return nullptr;
+  }
+  Handle<mirror::Class> method_return(hs.NewHandle(annotation_method->GetReturnType()));
+
+  AnnotationValue annotation_value;
+  if (!ProcessAnnotationValue(klass, annotation, &annotation_value, method_return, kAllObjects)) {
+    return nullptr;
+  }
+  Handle<mirror::Object> value_object(hs.NewHandle(annotation_value.value_.GetL()));
+
+  mirror::Class* annotation_member_class =
+      WellKnownClasses::ToClass(WellKnownClasses::libcore_reflect_AnnotationMember);
+  Handle<mirror::Object> new_member(hs.NewHandle(annotation_member_class->AllocObject(self)));
+  Handle<mirror::Method> method_object(
+      hs.NewHandle(mirror::Method::CreateFromArtMethod(self, annotation_method)));
+
+  if (new_member.Get() == nullptr || string_name.Get() == nullptr ||
+      method_object.Get() == nullptr || method_return.Get() == nullptr) {
+    LOG(ERROR) << StringPrintf("Failed creating annotation element (m=%p n=%p a=%p r=%p",
+        new_member.Get(), string_name.Get(), method_object.Get(), method_return.Get());
+    return nullptr;
+  }
+
+  JValue result;
+  ArtMethod* annotation_member_init =
+      soa.DecodeMethod(WellKnownClasses::libcore_reflect_AnnotationMember_init);
+  uint32_t args[5] = { static_cast<uint32_t>(reinterpret_cast<uintptr_t>(new_member.Get())),
+                       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(string_name.Get())),
+                       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(value_object.Get())),
+                       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(method_return.Get())),
+                       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(method_object.Get()))
+  };
+  annotation_member_init->Invoke(self, args, sizeof(args), &result, "VLLLL");
+  if (self->IsExceptionPending()) {
+    LOG(INFO) << "Exception in AnnotationMember.<init>";
+    return nullptr;
+  }
+
+  return new_member.Get();
+}
+
+const DexFile::AnnotationItem* DexFile::GetAnnotationItemFromAnnotationSet(
+    Handle<mirror::Class> klass, const AnnotationSetItem* annotation_set, uint32_t visibility,
+    Handle<mirror::Class> annotation_class) const {
+  for (uint32_t i = 0; i < annotation_set->size_; ++i) {
+    const AnnotationItem* annotation_item = GetAnnotationItem(annotation_set, i);
+    if (annotation_item->visibility_ != visibility) {
+      continue;
+    }
+    const uint8_t* annotation = annotation_item->annotation_;
+    uint32_t type_index = DecodeUnsignedLeb128(&annotation);
+    mirror::Class* resolved_class = Runtime::Current()->GetClassLinker()->ResolveType(
+        klass->GetDexFile(), type_index, klass.Get());
+    if (resolved_class == nullptr) {
+      std::string temp;
+      LOG(WARNING) << StringPrintf("Unable to resolve %s annotation class %d",
+                                   klass->GetDescriptor(&temp), type_index);
+      CHECK(Thread::Current()->IsExceptionPending());
+      Thread::Current()->ClearException();
+      continue;
+    }
+    if (resolved_class == annotation_class.Get()) {
+      return annotation_item;
+    }
+  }
+
+  return nullptr;
+}
+
+mirror::Object* DexFile::GetAnnotationObjectFromAnnotationSet(Handle<mirror::Class> klass,
+    const AnnotationSetItem* annotation_set, uint32_t visibility,
+    Handle<mirror::Class> annotation_class) const {
+  const AnnotationItem* annotation_item =
+      GetAnnotationItemFromAnnotationSet(klass, annotation_set, visibility, annotation_class);
+  if (annotation_item == nullptr) {
+    return nullptr;
+  }
+  const uint8_t* annotation = annotation_item->annotation_;
+  return ProcessEncodedAnnotation(klass, &annotation);
+}
+
+mirror::Object* DexFile::GetAnnotationValue(Handle<mirror::Class> klass,
+    const AnnotationItem* annotation_item, const char* annotation_name,
+    Handle<mirror::Class> array_class, uint32_t expected_type) const {
+  const uint8_t* annotation =
+      SearchEncodedAnnotation(annotation_item->annotation_, annotation_name);
+  if (annotation == nullptr) {
+    return nullptr;
+  }
+  AnnotationValue annotation_value;
+  if (!ProcessAnnotationValue(klass, &annotation, &annotation_value, array_class, kAllObjects)) {
+    return nullptr;
+  }
+  if (annotation_value.type_ != expected_type) {
+    return nullptr;
+  }
+  return annotation_value.value_.GetL();
+}
+
+mirror::ObjectArray<mirror::Object>* DexFile::GetSignatureValue(Handle<mirror::Class> klass,
+    const AnnotationSetItem* annotation_set) const {
+  StackHandleScope<1> hs(Thread::Current());
+  const AnnotationItem* annotation_item =
+      SearchAnnotationSet(annotation_set, "Ldalvik/annotation/Signature;", kDexVisibilitySystem);
+  if (annotation_item == nullptr) {
+    return nullptr;
+  }
+  mirror::Class* string_class = mirror::String::GetJavaLangString();
+  Handle<mirror::Class> string_array_class(hs.NewHandle(
+      Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &string_class)));
+  mirror::Object* obj =
+      GetAnnotationValue(klass, annotation_item, "value", string_array_class, kDexAnnotationArray);
+  if (obj == nullptr) {
+    return nullptr;
+  }
+  return obj->AsObjectArray<mirror::Object>();
+}
+
+mirror::ObjectArray<mirror::Object>* DexFile::GetThrowsValue(Handle<mirror::Class> klass,
+    const AnnotationSetItem* annotation_set) const {
+  StackHandleScope<1> hs(Thread::Current());
+  const AnnotationItem* annotation_item =
+      SearchAnnotationSet(annotation_set, "Ldalvik/annotation/Throws;", kDexVisibilitySystem);
+  if (annotation_item == nullptr) {
+    return nullptr;
+  }
+  mirror::Class* class_class = mirror::Class::GetJavaLangClass();
+  Handle<mirror::Class> class_array_class(hs.NewHandle(
+      Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &class_class)));
+  mirror::Object* obj =
+      GetAnnotationValue(klass, annotation_item, "value", class_array_class, kDexAnnotationArray);
+  if (obj == nullptr) {
+    return nullptr;
+  }
+  return obj->AsObjectArray<mirror::Object>();
+}
+
+mirror::ObjectArray<mirror::Object>* DexFile::ProcessAnnotationSet(Handle<mirror::Class> klass,
+    const AnnotationSetItem* annotation_set, uint32_t visibility) const {
+  Thread* self = Thread::Current();
+  ScopedObjectAccessUnchecked soa(self);
+  StackHandleScope<2> hs(self);
+  Handle<mirror::Class> annotation_array_class(hs.NewHandle(
+      soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array)));
+  if (annotation_set == nullptr) {
+    return mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_array_class.Get(), 0);
+  }
+
+  uint32_t size = annotation_set->size_;
+  Handle<mirror::ObjectArray<mirror::Object>> result(hs.NewHandle(
+      mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_array_class.Get(), size)));
+  if (result.Get() == nullptr) {
+    return nullptr;
+  }
+
+  uint32_t dest_index = 0;
+  for (uint32_t i = 0; i < size; ++i) {
+    const AnnotationItem* annotation_item = GetAnnotationItem(annotation_set, i);
+    if (annotation_item->visibility_ != visibility) {
+      continue;
+    }
+    const uint8_t* annotation = annotation_item->annotation_;
+    mirror::Object* annotation_obj = ProcessEncodedAnnotation(klass, &annotation);
+    if (annotation_obj != nullptr) {
+      result->SetWithoutChecks<false>(dest_index, annotation_obj);
+      ++dest_index;
+    }
+  }
+
+  if (dest_index == size) {
+    return result.Get();
+  }
+
+  mirror::ObjectArray<mirror::Object>* trimmed_result =
+      mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_array_class.Get(), dest_index);
+  for (uint32_t i = 0; i < dest_index; ++i) {
+    mirror::Object* obj = result->GetWithoutChecks(i);
+    trimmed_result->SetWithoutChecks<false>(i, obj);
+  }
+
+  return trimmed_result;
+}
+
+mirror::ObjectArray<mirror::Object>* DexFile::ProcessAnnotationSetRefList(
+    Handle<mirror::Class> klass, const AnnotationSetRefList* set_ref_list, uint32_t size) const {
+  Thread* self = Thread::Current();
+  ScopedObjectAccessUnchecked soa(self);
+  StackHandleScope<1> hs(self);
+  mirror::Class* annotation_array_class =
+      soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array);
+  mirror::Class* annotation_array_array_class =
+      Runtime::Current()->GetClassLinker()->FindArrayClass(self, &annotation_array_class);
+  Handle<mirror::ObjectArray<mirror::Object>> annotation_array_array(hs.NewHandle(
+      mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_array_array_class, size)));
+  if (annotation_array_array.Get() == nullptr) {
+    LOG(ERROR) << "Annotation set ref array allocation failed";
+    return nullptr;
+  }
+  for (uint32_t index = 0; index < size; ++index) {
+    const AnnotationSetRefItem* set_ref_item = &set_ref_list->list_[index];
+    const AnnotationSetItem* set_item = GetSetRefItemItem(set_ref_item);
+    mirror::Object* annotation_set = ProcessAnnotationSet(klass, set_item, kDexVisibilityRuntime);
+    if (annotation_set == nullptr) {
+      return nullptr;
+    }
+    annotation_array_array->SetWithoutChecks<false>(index, annotation_set);
+  }
+  return annotation_array_array.Get();
+}
+
+bool DexFile::ProcessAnnotationValue(Handle<mirror::Class> klass, const uint8_t** annotation_ptr,
+    AnnotationValue* annotation_value, Handle<mirror::Class> array_class,
+    DexFile::AnnotationResultStyle result_style) const {
+  Thread* self = Thread::Current();
+  mirror::Object* element_object = nullptr;
+  bool set_object = false;
+  Primitive::Type primitive_type = Primitive::kPrimVoid;
+  const uint8_t* annotation = *annotation_ptr;
+  uint8_t header_byte = *(annotation++);
+  uint8_t value_type = header_byte & kDexAnnotationValueTypeMask;
+  uint8_t value_arg = header_byte >> kDexAnnotationValueArgShift;
+  int32_t width = value_arg + 1;
+  annotation_value->type_ = value_type;
+
+  switch (value_type) {
+    case kDexAnnotationByte:
+      annotation_value->value_.SetB(static_cast<int8_t>(ReadSignedInt(annotation, value_arg)));
+      primitive_type = Primitive::kPrimByte;
+      break;
+    case kDexAnnotationShort:
+      annotation_value->value_.SetS(static_cast<int16_t>(ReadSignedInt(annotation, value_arg)));
+      primitive_type = Primitive::kPrimShort;
+      break;
+    case kDexAnnotationChar:
+      annotation_value->value_.SetC(static_cast<uint16_t>(ReadUnsignedInt(annotation, value_arg,
+                                                                          false)));
+      primitive_type = Primitive::kPrimChar;
+      break;
+    case kDexAnnotationInt:
+      annotation_value->value_.SetI(ReadSignedInt(annotation, value_arg));
+      primitive_type = Primitive::kPrimInt;
+      break;
+    case kDexAnnotationLong:
+      annotation_value->value_.SetJ(ReadSignedLong(annotation, value_arg));
+      primitive_type = Primitive::kPrimLong;
+      break;
+    case kDexAnnotationFloat:
+      annotation_value->value_.SetI(ReadUnsignedInt(annotation, value_arg, true));
+      primitive_type = Primitive::kPrimFloat;
+      break;
+    case kDexAnnotationDouble:
+      annotation_value->value_.SetJ(ReadUnsignedLong(annotation, value_arg, true));
+      primitive_type = Primitive::kPrimDouble;
+      break;
+    case kDexAnnotationBoolean:
+      annotation_value->value_.SetZ(value_arg != 0);
+      primitive_type = Primitive::kPrimBoolean;
+      width = 0;
+      break;
+    case kDexAnnotationString: {
+      uint32_t index = ReadUnsignedInt(annotation, value_arg, false);
+      if (result_style == kAllRaw) {
+        annotation_value->value_.SetI(index);
+      } else {
+        StackHandleScope<1> hs(self);
+        Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
+        element_object = Runtime::Current()->GetClassLinker()->ResolveString(
+            klass->GetDexFile(), index, dex_cache);
+        set_object = true;
+        if (element_object == nullptr) {
+          return false;
+        }
+      }
+      break;
+    }
+    case kDexAnnotationType: {
+      uint32_t index = ReadUnsignedInt(annotation, value_arg, false);
+      if (result_style == kAllRaw) {
+        annotation_value->value_.SetI(index);
+      } else {
+        element_object = Runtime::Current()->GetClassLinker()->ResolveType(
+            klass->GetDexFile(), index, klass.Get());
+        set_object = true;
+        if (element_object == nullptr) {
+          self->ClearException();
+          const char* msg = StringByTypeIdx(index);
+          self->ThrowNewException("Ljava/lang/TypeNotPresentException;", msg);
+        }
+      }
+      break;
+    }
+    case kDexAnnotationMethod: {
+      uint32_t index = ReadUnsignedInt(annotation, value_arg, false);
+      if (result_style == kAllRaw) {
+        annotation_value->value_.SetI(index);
+      } else {
+        StackHandleScope<2> hs(self);
+        Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
+        Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
+        ArtMethod* method = Runtime::Current()->GetClassLinker()->ResolveMethodWithoutInvokeType(
+            klass->GetDexFile(), index, dex_cache, class_loader);
+        if (method == nullptr) {
+          return false;
+        }
+        set_object = true;
+        if (method->IsConstructor()) {
+          element_object = mirror::Constructor::CreateFromArtMethod(self, method);
+        } else {
+          element_object = mirror::Method::CreateFromArtMethod(self, method);
+        }
+        if (element_object == nullptr) {
+          return false;
+        }
+      }
+      break;
+    }
+    case kDexAnnotationField: {
+      uint32_t index = ReadUnsignedInt(annotation, value_arg, false);
+      if (result_style == kAllRaw) {
+        annotation_value->value_.SetI(index);
+      } else {
+        StackHandleScope<2> hs(self);
+        Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
+        Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
+        ArtField* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(
+            klass->GetDexFile(), index, dex_cache, class_loader);
+        if (field == nullptr) {
+          return false;
+        }
+        set_object = true;
+        element_object = mirror::Field::CreateFromArtField(self, field, true);
+        if (element_object == nullptr) {
+          return false;
+        }
+      }
+      break;
+    }
+    case kDexAnnotationEnum: {
+      uint32_t index = ReadUnsignedInt(annotation, value_arg, false);
+      if (result_style == kAllRaw) {
+        annotation_value->value_.SetI(index);
+      } else {
+        StackHandleScope<3> hs(self);
+        Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
+        Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
+        ArtField* enum_field = Runtime::Current()->GetClassLinker()->ResolveField(
+            klass->GetDexFile(), index, dex_cache, class_loader, true);
+        Handle<mirror::Class> field_class(hs.NewHandle(enum_field->GetDeclaringClass()));
+        if (enum_field == nullptr) {
+          return false;
+        } else {
+          Runtime::Current()->GetClassLinker()->EnsureInitialized(self, field_class, true, true);
+          element_object = enum_field->GetObject(field_class.Get());
+          set_object = true;
+        }
+      }
+      break;
+    }
+    case kDexAnnotationArray:
+      if (result_style == kAllRaw || array_class.Get() == nullptr) {
+        return false;
+      } else {
+        ScopedObjectAccessUnchecked soa(self);
+        StackHandleScope<2> hs(self);
+        uint32_t size = DecodeUnsignedLeb128(&annotation);
+        Handle<mirror::Class> component_type(hs.NewHandle(array_class->GetComponentType()));
+        Handle<mirror::Array> new_array(hs.NewHandle(mirror::Array::Alloc<true>(
+            self, array_class.Get(), size, array_class->GetComponentSizeShift(),
+            Runtime::Current()->GetHeap()->GetCurrentAllocator())));
+        if (new_array.Get() == nullptr) {
+          LOG(ERROR) << "Annotation element array allocation failed with size " << size;
+          return false;
+        }
+        AnnotationValue new_annotation_value;
+        for (uint32_t i = 0; i < size; ++i) {
+          if (!ProcessAnnotationValue(klass, &annotation, &new_annotation_value, component_type,
+                                      kPrimitivesOrObjects)) {
+            return false;
+          }
+          if (!component_type->IsPrimitive()) {
+            mirror::Object* obj = new_annotation_value.value_.GetL();
+            new_array->AsObjectArray<mirror::Object>()->SetWithoutChecks<false>(i, obj);
+          } else {
+            switch (new_annotation_value.type_) {
+              case kDexAnnotationByte:
+                new_array->AsByteArray()->SetWithoutChecks<false>(
+                    i, new_annotation_value.value_.GetB());
+                break;
+              case kDexAnnotationShort:
+                new_array->AsShortArray()->SetWithoutChecks<false>(
+                    i, new_annotation_value.value_.GetS());
+                break;
+              case kDexAnnotationChar:
+                new_array->AsCharArray()->SetWithoutChecks<false>(
+                    i, new_annotation_value.value_.GetC());
+                break;
+              case kDexAnnotationInt:
+                new_array->AsIntArray()->SetWithoutChecks<false>(
+                    i, new_annotation_value.value_.GetI());
+                break;
+              case kDexAnnotationLong:
+                new_array->AsLongArray()->SetWithoutChecks<false>(
+                    i, new_annotation_value.value_.GetJ());
+                break;
+              case kDexAnnotationFloat:
+                new_array->AsFloatArray()->SetWithoutChecks<false>(
+                    i, new_annotation_value.value_.GetF());
+                break;
+              case kDexAnnotationDouble:
+                new_array->AsDoubleArray()->SetWithoutChecks<false>(
+                    i, new_annotation_value.value_.GetD());
+                break;
+              case kDexAnnotationBoolean:
+                new_array->AsBooleanArray()->SetWithoutChecks<false>(
+                    i, new_annotation_value.value_.GetZ());
+                break;
+              default:
+                LOG(FATAL) << "Found invalid annotation value type while building annotation array";
+                return false;
+            }
+          }
+        }
+        element_object = new_array.Get();
+        set_object = true;
+        width = 0;
+      }
+      break;
+    case kDexAnnotationAnnotation:
+      if (result_style == kAllRaw) {
+        return false;
+      }
+      element_object = ProcessEncodedAnnotation(klass, &annotation);
+      if (element_object == nullptr) {
+        return false;
+      }
+      set_object = true;
+      width = 0;
+      break;
+    case kDexAnnotationNull:
+      if (result_style == kAllRaw) {
+        annotation_value->value_.SetI(0);
+      } else {
+        CHECK(element_object == nullptr);
+        set_object = true;
+      }
+      width = 0;
+      break;
+    default:
+      LOG(ERROR) << StringPrintf("Bad annotation element value type 0x%02x", value_type);
+      return false;
+  }
+
+  annotation += width;
+  *annotation_ptr = annotation;
+
+  if (result_style == kAllObjects && primitive_type != Primitive::kPrimVoid) {
+    element_object = BoxPrimitive(primitive_type, annotation_value->value_);
+    set_object = true;
+  }
+
+  if (set_object) {
+    annotation_value->value_.SetL(element_object);
+  }
+
+  return true;
+}
+
+mirror::Object* DexFile::ProcessEncodedAnnotation(Handle<mirror::Class> klass,
+    const uint8_t** annotation) const {
+  uint32_t type_index = DecodeUnsignedLeb128(annotation);
+  uint32_t size = DecodeUnsignedLeb128(annotation);
+
+  Thread* self = Thread::Current();
+  ScopedObjectAccessUnchecked soa(self);
+  StackHandleScope<2> hs(self);
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  Handle<mirror::Class> annotation_class(hs.NewHandle(
+      class_linker->ResolveType(klass->GetDexFile(), type_index, klass.Get())));
+  if (annotation_class.Get() == nullptr) {
+    LOG(INFO) << "Unable to resolve " << PrettyClass(klass.Get()) << " annotation class "
+              << type_index;
+    DCHECK(Thread::Current()->IsExceptionPending());
+    Thread::Current()->ClearException();
+    return nullptr;
+  }
+
+  mirror::Class* annotation_member_class =
+      soa.Decode<mirror::Class*>(WellKnownClasses::libcore_reflect_AnnotationMember);
+  mirror::Class* annotation_member_array_class =
+      class_linker->FindArrayClass(self, &annotation_member_class);
+  mirror::ObjectArray<mirror::Object>* element_array = nullptr;
+
+  if (size > 0) {
+    element_array =
+        mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_member_array_class, size);
+    if (element_array == nullptr) {
+      LOG(ERROR) << "Failed to allocate annotation member array (" << size << " elements)";
+      return nullptr;
+    }
+  }
+
+  Handle<mirror::ObjectArray<mirror::Object>> h_element_array(hs.NewHandle(element_array));
+  for (uint32_t i = 0; i < size; ++i) {
+    mirror::Object* new_member = CreateAnnotationMember(klass, annotation_class, annotation);
+    if (new_member == nullptr) {
+      return nullptr;
+    }
+    h_element_array->SetWithoutChecks<false>(i, new_member);
+  }
+
+  JValue result;
+  ArtMethod* create_annotation_method =
+      soa.DecodeMethod(WellKnownClasses::libcore_reflect_AnnotationFactory_createAnnotation);
+  uint32_t args[2] = { static_cast<uint32_t>(reinterpret_cast<uintptr_t>(annotation_class.Get())),
+                       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(h_element_array.Get())) };
+  create_annotation_method->Invoke(self, args, sizeof(args), &result, "LLL");
+  if (self->IsExceptionPending()) {
+    LOG(INFO) << "Exception in AnnotationFactory.createAnnotation";
+    return nullptr;
+  }
+
+  return result.GetL();
+}
+
+const DexFile::AnnotationItem* DexFile::SearchAnnotationSet(const AnnotationSetItem* annotation_set,
+    const char* descriptor, uint32_t visibility) const {
+  const AnnotationItem* result = nullptr;
+  for (uint32_t i = 0; i < annotation_set->size_; ++i) {
+    const AnnotationItem* annotation_item = GetAnnotationItem(annotation_set, i);
+    if (annotation_item->visibility_ != visibility) {
+      continue;
+    }
+    const uint8_t* annotation = annotation_item->annotation_;
+    uint32_t type_index = DecodeUnsignedLeb128(&annotation);
+
+    if (strcmp(descriptor, StringByTypeIdx(type_index)) == 0) {
+      result = annotation_item;
+      break;
+    }
+  }
+  return result;
+}
+
+const uint8_t* DexFile::SearchEncodedAnnotation(const uint8_t* annotation, const char* name) const {
+  DecodeUnsignedLeb128(&annotation);  // unused type_index
+  uint32_t size = DecodeUnsignedLeb128(&annotation);
+
+  while (size != 0) {
+    uint32_t element_name_index = DecodeUnsignedLeb128(&annotation);
+    const char* element_name = GetStringData(GetStringId(element_name_index));
+    if (strcmp(name, element_name) == 0) {
+      return annotation;
+    }
+    SkipAnnotationValue(&annotation);
+    size--;
+  }
+  return nullptr;
+}
+
+bool DexFile::SkipAnnotationValue(const uint8_t** annotation_ptr) const {
+  const uint8_t* annotation = *annotation_ptr;
+  uint8_t header_byte = *(annotation++);
+  uint8_t value_type = header_byte & kDexAnnotationValueTypeMask;
+  uint8_t value_arg = header_byte >> kDexAnnotationValueArgShift;
+  int32_t width = value_arg + 1;
+
+  switch (value_type) {
+    case kDexAnnotationByte:
+    case kDexAnnotationShort:
+    case kDexAnnotationChar:
+    case kDexAnnotationInt:
+    case kDexAnnotationLong:
+    case kDexAnnotationFloat:
+    case kDexAnnotationDouble:
+    case kDexAnnotationString:
+    case kDexAnnotationType:
+    case kDexAnnotationMethod:
+    case kDexAnnotationField:
+    case kDexAnnotationEnum:
+      break;
+    case kDexAnnotationArray:
+    {
+      uint32_t size = DecodeUnsignedLeb128(&annotation);
+      while (size--) {
+        if (!SkipAnnotationValue(&annotation)) {
+          return false;
+        }
+      }
+      width = 0;
+      break;
+    }
+    case kDexAnnotationAnnotation:
+    {
+      DecodeUnsignedLeb128(&annotation);  // unused type_index
+      uint32_t size = DecodeUnsignedLeb128(&annotation);
+      while (size--) {
+        DecodeUnsignedLeb128(&annotation);  // unused element_name_index
+        if (!SkipAnnotationValue(&annotation)) {
+          return false;
+        }
+      }
+      width = 0;
+      break;
+    }
+    case kDexAnnotationBoolean:
+    case kDexAnnotationNull:
+      width = 0;
+      break;
+    default:
+      LOG(FATAL) << StringPrintf("Bad annotation element value byte 0x%02x", value_type);
+      return false;
+  }
+
+  annotation += width;
+  *annotation_ptr = annotation;
+  return true;
+}
+
 std::ostream& operator<<(std::ostream& os, const DexFile& dex_file) {
   os << StringPrintf("[DexFile: %s dex-checksum=%08x location-checksum=%08x %p-%p]",
                      dex_file.GetLocation().c_str(),
@@ -1127,60 +2042,6 @@
   }
 }
 
-// Read a signed integer.  "zwidth" is the zero-based byte count.
-static int32_t ReadSignedInt(const uint8_t* ptr, int zwidth) {
-  int32_t val = 0;
-  for (int i = zwidth; i >= 0; --i) {
-    val = ((uint32_t)val >> 8) | (((int32_t)*ptr++) << 24);
-  }
-  val >>= (3 - zwidth) * 8;
-  return val;
-}
-
-// Read an unsigned integer.  "zwidth" is the zero-based byte count,
-// "fill_on_right" indicates which side we want to zero-fill from.
-static uint32_t ReadUnsignedInt(const uint8_t* ptr, int zwidth, bool fill_on_right) {
-  uint32_t val = 0;
-  if (!fill_on_right) {
-    for (int i = zwidth; i >= 0; --i) {
-      val = (val >> 8) | (((uint32_t)*ptr++) << 24);
-    }
-    val >>= (3 - zwidth) * 8;
-  } else {
-    for (int i = zwidth; i >= 0; --i) {
-      val = (val >> 8) | (((uint32_t)*ptr++) << 24);
-    }
-  }
-  return val;
-}
-
-// Read a signed long.  "zwidth" is the zero-based byte count.
-static int64_t ReadSignedLong(const uint8_t* ptr, int zwidth) {
-  int64_t val = 0;
-  for (int i = zwidth; i >= 0; --i) {
-    val = ((uint64_t)val >> 8) | (((int64_t)*ptr++) << 56);
-  }
-  val >>= (7 - zwidth) * 8;
-  return val;
-}
-
-// Read an unsigned long.  "zwidth" is the zero-based byte count,
-// "fill_on_right" indicates which side we want to zero-fill from.
-static uint64_t ReadUnsignedLong(const uint8_t* ptr, int zwidth, bool fill_on_right) {
-  uint64_t val = 0;
-  if (!fill_on_right) {
-    for (int i = zwidth; i >= 0; --i) {
-      val = (val >> 8) | (((uint64_t)*ptr++) << 56);
-    }
-    val >>= (7 - zwidth) * 8;
-  } else {
-    for (int i = zwidth; i >= 0; --i) {
-      val = (val >> 8) | (((uint64_t)*ptr++) << 56);
-    }
-  }
-  return val;
-}
-
 EncodedStaticFieldValueIterator::EncodedStaticFieldValueIterator(
     const DexFile& dex_file, Handle<mirror::DexCache>* dex_cache,
     Handle<mirror::ClassLoader>* class_loader, ClassLinker* linker,
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index a1ddbc7..8928321 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -28,6 +28,8 @@
 #include "globals.h"
 #include "invoke_type.h"
 #include "jni.h"
+#include "jvalue.h"
+#include "mirror/object_array.h"
 #include "modifiers.h"
 #include "utf.h"
 
@@ -384,6 +386,17 @@
     DISALLOW_COPY_AND_ASSIGN(AnnotationItem);
   };
 
+  struct AnnotationValue {
+    JValue value_;
+    uint8_t type_;
+  };
+
+  enum AnnotationResultStyle {  // private
+    kAllObjects,
+    kPrimitivesOrObjects,
+    kAllRaw
+  };
+
   // Returns the checksum of a file for comparison with GetLocationChecksum().
   // For .dex files, this is the header checksum.
   // For zip files, this is the classes.dex zip entry CRC32 checksum.
@@ -643,6 +656,11 @@
     return StringDataByIdx(method_id.name_idx_);
   }
 
+  // Returns the shorty of a method by its index.
+  const char* GetMethodShorty(uint32_t idx) const {
+    return StringDataByIdx(GetProtoId(GetMethodId(idx).proto_idx_).shorty_idx_);
+  }
+
   // Returns the shorty of a method id.
   const char* GetMethodShorty(const MethodId& method_id) const {
     return StringDataByIdx(GetProtoId(method_id.proto_idx_).shorty_idx_);
@@ -812,6 +830,187 @@
 
   static bool LineNumForPcCb(void* context, uint32_t address, uint32_t line_num);
 
+  const AnnotationsDirectoryItem* GetAnnotationsDirectory(const ClassDef& class_def) const {
+    if (class_def.annotations_off_ == 0) {
+      return nullptr;
+    } else {
+      return reinterpret_cast<const AnnotationsDirectoryItem*>(begin_ + class_def.annotations_off_);
+    }
+  }
+
+  const AnnotationSetItem* GetClassAnnotationSet(const AnnotationsDirectoryItem* anno_dir) const {
+    if (anno_dir->class_annotations_off_ == 0) {
+      return nullptr;
+    } else {
+      return reinterpret_cast<const AnnotationSetItem*>(begin_ + anno_dir->class_annotations_off_);
+    }
+  }
+
+  const FieldAnnotationsItem* GetFieldAnnotations(const AnnotationsDirectoryItem* anno_dir) const {
+    if (anno_dir->fields_size_ == 0) {
+      return nullptr;
+    } else {
+      return reinterpret_cast<const FieldAnnotationsItem*>(&anno_dir[1]);
+    }
+  }
+
+  const MethodAnnotationsItem* GetMethodAnnotations(const AnnotationsDirectoryItem* anno_dir)
+      const {
+    if (anno_dir->methods_size_ == 0) {
+      return nullptr;
+    } else {
+      // Skip past the header and field annotations.
+      const uint8_t* addr = reinterpret_cast<const uint8_t*>(&anno_dir[1]);
+      addr += anno_dir->fields_size_ * sizeof(FieldAnnotationsItem);
+      return reinterpret_cast<const MethodAnnotationsItem*>(addr);
+    }
+  }
+
+  const ParameterAnnotationsItem* GetParameterAnnotations(const AnnotationsDirectoryItem* anno_dir)
+      const {
+    if (anno_dir->parameters_size_ == 0) {
+      return nullptr;
+    } else {
+      // Skip past the header, field annotations, and method annotations.
+      const uint8_t* addr = reinterpret_cast<const uint8_t*>(&anno_dir[1]);
+      addr += anno_dir->fields_size_ * sizeof(FieldAnnotationsItem);
+      addr += anno_dir->methods_size_ * sizeof(MethodAnnotationsItem);
+      return reinterpret_cast<const ParameterAnnotationsItem*>(addr);
+    }
+  }
+
+  const AnnotationSetItem* GetFieldAnnotationSetItem(const FieldAnnotationsItem& anno_item) const {
+    uint32_t offset = anno_item.annotations_off_;
+    if (offset == 0) {
+      return nullptr;
+    } else {
+      return reinterpret_cast<const AnnotationSetItem*>(begin_ + offset);
+    }
+  }
+
+  const AnnotationSetItem* GetMethodAnnotationSetItem(const MethodAnnotationsItem& anno_item)
+      const {
+    uint32_t offset = anno_item.annotations_off_;
+    if (offset == 0) {
+      return nullptr;
+    } else {
+      return reinterpret_cast<const AnnotationSetItem*>(begin_ + offset);
+    }
+  }
+
+  const AnnotationSetRefList* GetParameterAnnotationSetRefList(
+      const ParameterAnnotationsItem* anno_item) const {
+    uint32_t offset = anno_item->annotations_off_;
+    if (offset == 0) {
+      return nullptr;
+    }
+    return reinterpret_cast<const AnnotationSetRefList*>(begin_ + offset);
+  }
+
+  const AnnotationItem* GetAnnotationItem(const AnnotationSetItem* set_item, uint32_t index) const {
+    DCHECK_LE(index, set_item->size_);
+    uint32_t offset = set_item->entries_[index];
+    if (offset == 0) {
+      return nullptr;
+    } else {
+      return reinterpret_cast<const AnnotationItem*>(begin_ + offset);
+    }
+  }
+
+  const AnnotationSetItem* GetSetRefItemItem(const AnnotationSetRefItem* anno_item) const {
+    uint32_t offset = anno_item->annotations_off_;
+    if (offset == 0) {
+      return nullptr;
+    }
+    return reinterpret_cast<const AnnotationSetItem*>(begin_ + offset);
+  }
+
+  const AnnotationSetItem* FindAnnotationSetForField(ArtField* field) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  mirror::Object* GetAnnotationForField(ArtField* field, Handle<mirror::Class> annotation_class)
+      const SHARED_REQUIRES(Locks::mutator_lock_);
+  mirror::ObjectArray<mirror::Object>* GetAnnotationsForField(ArtField* field) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  mirror::ObjectArray<mirror::Object>* GetSignatureAnnotationForField(ArtField* field) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  bool IsFieldAnnotationPresent(ArtField* field, Handle<mirror::Class> annotation_class) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+
+  const AnnotationSetItem* FindAnnotationSetForMethod(ArtMethod* method) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  const ParameterAnnotationsItem* FindAnnotationsItemForMethod(ArtMethod* method) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  mirror::Object* GetAnnotationDefaultValue(ArtMethod* method) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  mirror::Object* GetAnnotationForMethod(ArtMethod* method, Handle<mirror::Class> annotation_class)
+      const SHARED_REQUIRES(Locks::mutator_lock_);
+  mirror::ObjectArray<mirror::Object>* GetAnnotationsForMethod(ArtMethod* method) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  mirror::ObjectArray<mirror::Object>* GetExceptionTypesForMethod(ArtMethod* method) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  mirror::ObjectArray<mirror::Object>* GetParameterAnnotations(ArtMethod* method) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  bool IsMethodAnnotationPresent(ArtMethod* method, Handle<mirror::Class> annotation_class) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+
+  const AnnotationSetItem* FindAnnotationSetForClass(Handle<mirror::Class> klass) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  mirror::Object* GetAnnotationForClass(Handle<mirror::Class> klass,
+                                        Handle<mirror::Class> annotation_class) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  mirror::ObjectArray<mirror::Object>* GetAnnotationsForClass(Handle<mirror::Class> klass) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  bool IsClassAnnotationPresent(Handle<mirror::Class> klass, Handle<mirror::Class> annotation_class)
+      const SHARED_REQUIRES(Locks::mutator_lock_);
+
+  mirror::Object* CreateAnnotationMember(Handle<mirror::Class> klass,
+                                         Handle<mirror::Class> annotation_class,
+                                         const uint8_t** annotation) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  const AnnotationItem* GetAnnotationItemFromAnnotationSet(Handle<mirror::Class> klass,
+                                                           const AnnotationSetItem* annotation_set,
+                                                           uint32_t visibility,
+                                                           Handle<mirror::Class> annotation_class)
+      const SHARED_REQUIRES(Locks::mutator_lock_);
+  mirror::Object* GetAnnotationObjectFromAnnotationSet(Handle<mirror::Class> klass,
+                                                       const AnnotationSetItem* annotation_set,
+                                                       uint32_t visibility,
+                                                       Handle<mirror::Class> annotation_class) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  mirror::Object* GetAnnotationValue(Handle<mirror::Class> klass,
+                                     const AnnotationItem* annotation_item,
+                                     const char* annotation_name,
+                                     Handle<mirror::Class> array_class,
+                                     uint32_t expected_type) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  mirror::ObjectArray<mirror::Object>* GetSignatureValue(Handle<mirror::Class> klass,
+                                                         const AnnotationSetItem* annotation_set)
+      const SHARED_REQUIRES(Locks::mutator_lock_);
+  mirror::ObjectArray<mirror::Object>* GetThrowsValue(Handle<mirror::Class> klass,
+                                                      const AnnotationSetItem* annotation_set) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  mirror::ObjectArray<mirror::Object>* ProcessAnnotationSet(Handle<mirror::Class> klass,
+                                                            const AnnotationSetItem* annotation_set,
+                                                            uint32_t visibility) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  mirror::ObjectArray<mirror::Object>* ProcessAnnotationSetRefList(Handle<mirror::Class> klass,
+      const AnnotationSetRefList* set_ref_list, uint32_t size) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  bool ProcessAnnotationValue(Handle<mirror::Class> klass, const uint8_t** annotation_ptr,
+                              AnnotationValue* annotation_value, Handle<mirror::Class> return_class,
+                              DexFile::AnnotationResultStyle result_style) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  mirror::Object* ProcessEncodedAnnotation(Handle<mirror::Class> klass,
+                                           const uint8_t** annotation) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  const AnnotationItem* SearchAnnotationSet(const AnnotationSetItem* annotation_set,
+                                            const char* descriptor, uint32_t visibility) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  const uint8_t* SearchEncodedAnnotation(const uint8_t* annotation, const char* name) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  bool SkipAnnotationValue(const uint8_t** annotation_ptr) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+
   // Debug info opcodes and constants
   enum {
     DBG_END_SEQUENCE         = 0x00,
diff --git a/runtime/gc/collector/mark_sweep-inl.h b/runtime/gc/collector/mark_sweep-inl.h
index a3cc831..56edcc9 100644
--- a/runtime/gc/collector/mark_sweep-inl.h
+++ b/runtime/gc/collector/mark_sweep-inl.h
@@ -35,10 +35,17 @@
   obj->VisitReferences(visitor, ref_visitor);
   if (kCountScannedTypes) {
     mirror::Class* klass = obj->GetClass<kVerifyNone>();
-    if (UNLIKELY(klass == mirror::Class::GetJavaLangClass())) {
+    uint32_t class_flags = klass->GetClassFlags();
+    if ((class_flags & mirror::kClassFlagNoReferenceFields) != 0) {
+      ++no_reference_class_count_;
+    } else if (class_flags == mirror::kClassFlagNormal) {
+      ++normal_count_;
+    } else if (class_flags == mirror::kClassFlagObjectArray) {
+      ++object_array_count_;
+    } else if (class_flags == mirror::kClassFlagClass) {
       ++class_count_;
-    } else if (UNLIKELY(klass->IsArrayClass<kVerifyNone>())) {
-      ++array_count_;
+    } else if ((class_flags & mirror::kClassFlagReference) != 0) {
+      ++reference_count_;
     } else {
       ++other_count_;
     }
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index b0a8a5b..7ddc7cc 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -70,7 +70,6 @@
 static constexpr bool kProfileLargeObjects = false;
 static constexpr bool kMeasureOverhead = false;
 static constexpr bool kCountTasks = false;
-static constexpr bool kCountJavaLangRefs = false;
 static constexpr bool kCountMarkedObjects = false;
 
 // Turn off kCheckLocks when profiling the GC since it slows the GC down by up to 40%.
@@ -114,15 +113,17 @@
   mark_stack_ = heap_->GetMarkStack();
   DCHECK(mark_stack_ != nullptr);
   immune_region_.Reset();
+  no_reference_class_count_.StoreRelaxed(0);
+  normal_count_.StoreRelaxed(0);
   class_count_.StoreRelaxed(0);
-  array_count_.StoreRelaxed(0);
+  object_array_count_.StoreRelaxed(0);
   other_count_.StoreRelaxed(0);
+  reference_count_.StoreRelaxed(0);
   large_object_test_.StoreRelaxed(0);
   large_object_mark_.StoreRelaxed(0);
   overhead_time_ .StoreRelaxed(0);
   work_chunks_created_.StoreRelaxed(0);
   work_chunks_deleted_.StoreRelaxed(0);
-  reference_count_.StoreRelaxed(0);
   mark_null_count_.StoreRelaxed(0);
   mark_immune_count_.StoreRelaxed(0);
   mark_fastpath_count_.StoreRelaxed(0);
@@ -1265,9 +1266,6 @@
 // Process the "referent" field in a java.lang.ref.Reference.  If the referent has not yet been
 // marked, put it on the appropriate list in the heap for later processing.
 void MarkSweep::DelayReferenceReferent(mirror::Class* klass, mirror::Reference* ref) {
-  if (kCountJavaLangRefs) {
-    ++reference_count_;
-  }
   heap_->GetReferenceProcessor()->DelayReferenceReferent(klass, ref, this);
 }
 
@@ -1386,8 +1384,14 @@
 void MarkSweep::FinishPhase() {
   TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   if (kCountScannedTypes) {
-    VLOG(gc) << "MarkSweep scanned classes=" << class_count_.LoadRelaxed()
-        << " arrays=" << array_count_.LoadRelaxed() << " other=" << other_count_.LoadRelaxed();
+    VLOG(gc)
+        << "MarkSweep scanned"
+        << " no reference objects=" << no_reference_class_count_.LoadRelaxed()
+        << " normal objects=" << normal_count_.LoadRelaxed()
+        << " classes=" << class_count_.LoadRelaxed()
+        << " object arrays=" << object_array_count_.LoadRelaxed()
+        << " references=" << reference_count_.LoadRelaxed()
+        << " other=" << other_count_.LoadRelaxed();
   }
   if (kCountTasks) {
     VLOG(gc) << "Total number of work chunks allocated: " << work_chunks_created_.LoadRelaxed();
@@ -1399,9 +1403,6 @@
     VLOG(gc) << "Large objects tested " << large_object_test_.LoadRelaxed()
         << " marked " << large_object_mark_.LoadRelaxed();
   }
-  if (kCountJavaLangRefs) {
-    VLOG(gc) << "References scanned " << reference_count_.LoadRelaxed();
-  }
   if (kCountMarkedObjects) {
     VLOG(gc) << "Marked: null=" << mark_null_count_.LoadRelaxed()
         << " immune=" <<  mark_immune_count_.LoadRelaxed()
diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h
index 8bd1dc7..371bba5 100644
--- a/runtime/gc/collector/mark_sweep.h
+++ b/runtime/gc/collector/mark_sweep.h
@@ -245,7 +245,7 @@
   void RevokeAllThreadLocalBuffers();
 
   // Whether or not we count how many of each type of object were scanned.
-  static const bool kCountScannedTypes = false;
+  static constexpr bool kCountScannedTypes = false;
 
   // Current space, we check this space first to avoid searching for the appropriate space for an
   // object.
@@ -260,18 +260,23 @@
 
   // Parallel finger.
   AtomicInteger atomic_finger_;
+
+  AtomicInteger no_reference_class_count_;
+  AtomicInteger normal_count_;
   // Number of classes scanned, if kCountScannedTypes.
   AtomicInteger class_count_;
-  // Number of arrays scanned, if kCountScannedTypes.
-  AtomicInteger array_count_;
+  // Number of object arrays scanned, if kCountScannedTypes.
+  AtomicInteger object_array_count_;
   // Number of non-class/arrays scanned, if kCountScannedTypes.
   AtomicInteger other_count_;
+  // Number of java.lang.ref.Reference instances.
+  AtomicInteger reference_count_;
+
   AtomicInteger large_object_test_;
   AtomicInteger large_object_mark_;
   AtomicInteger overhead_time_;
   AtomicInteger work_chunks_created_;
   AtomicInteger work_chunks_deleted_;
-  AtomicInteger reference_count_;
   AtomicInteger mark_null_count_;
   AtomicInteger mark_immune_count_;
   AtomicInteger mark_fastpath_count_;
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index d7f918b..b8c4478 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -3707,7 +3707,7 @@
 
 void Heap::CheckPreconditionsForAllocObject(mirror::Class* c, size_t byte_count) {
   CHECK(c == nullptr || (c->IsClassClass() && byte_count >= sizeof(mirror::Class)) ||
-        (c->IsVariableSize() || c->GetObjectSize() == byte_count));
+        (c->IsVariableSize() || c->GetObjectSize() == byte_count)) << c->GetClassFlags();
   CHECK_GE(byte_count, sizeof(mirror::Object));
 }
 
diff --git a/runtime/image.cc b/runtime/image.cc
index 2586959..8df17c6 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -24,7 +24,7 @@
 namespace art {
 
 const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '1', '9', '\0' };
+const uint8_t ImageHeader::kImageVersion[] = { '0', '2', '0', '\0' };
 
 ImageHeader::ImageHeader(uint32_t image_begin,
                          uint32_t image_size,
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index cd678f6..b2c6e4d 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -547,6 +547,7 @@
 inline String* Class::GetName() {
   return GetFieldObject<String>(OFFSET_OF_OBJECT_MEMBER(Class, name_));
 }
+
 inline void Class::SetName(String* name) {
   if (Runtime::Current()->IsActiveTransaction()) {
     SetFieldObject<true>(OFFSET_OF_OBJECT_MEMBER(Class, name_), name);
@@ -784,9 +785,17 @@
 inline void Class::SetAccessFlags(uint32_t new_access_flags) {
   // Called inside a transaction when setting pre-verified flag during boot image compilation.
   if (Runtime::Current()->IsActiveTransaction()) {
-    SetField32<true>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags);
+    SetField32<true>(AccessFlagsOffset(), new_access_flags);
   } else {
-    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags);
+    SetField32<false>(AccessFlagsOffset(), new_access_flags);
+  }
+}
+
+inline void Class::SetClassFlags(uint32_t new_flags) {
+  if (Runtime::Current()->IsActiveTransaction()) {
+    SetField32<true>(OFFSET_OF_OBJECT_MEMBER(Class, class_flags_), new_flags);
+  } else {
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, class_flags_), new_flags);
   }
 }
 
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 055b3e5..949ff5f 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -44,6 +44,7 @@
       << java_lang_Class_.Read()
       << " " << java_lang_Class;
   CHECK(java_lang_Class != nullptr);
+  java_lang_Class->SetClassFlags(java_lang_Class->GetClassFlags() | mirror::kClassFlagClass);
   java_lang_Class_ = GcRoot<Class>(java_lang_Class);
 }
 
@@ -504,6 +505,16 @@
   return nullptr;
 }
 
+ArtMethod* Class::FindDeclaredVirtualMethodByName(const StringPiece& name, size_t pointer_size) {
+  for (auto& method : GetVirtualMethods(pointer_size)) {
+    ArtMethod* const np_method = method.GetInterfaceMethodIfProxy(pointer_size);
+    if (name == np_method->GetName()) {
+      return &method;
+    }
+  }
+  return nullptr;
+}
+
 ArtMethod* Class::FindVirtualMethod(
     const StringPiece& name, const StringPiece& signature, size_t pointer_size) {
   for (Class* klass = this; klass != nullptr; klass = klass->GetSuperClass()) {
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 3f375be..ef257ae 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -19,6 +19,7 @@
 
 #include "base/iteration_range.h"
 #include "dex_file.h"
+#include "class_flags.h"
 #include "gc_root.h"
 #include "gc/allocator_type.h"
 #include "invoke_type.h"
@@ -201,6 +202,12 @@
     return OFFSET_OF_OBJECT_MEMBER(Class, access_flags_);
   }
 
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  ALWAYS_INLINE uint32_t GetClassFlags() SHARED_REQUIRES(Locks::mutator_lock_) {
+    return GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Class, class_flags_));
+  }
+  void SetClassFlags(uint32_t new_flags) SHARED_REQUIRES(Locks::mutator_lock_);
+
   void SetAccessFlags(uint32_t new_access_flags) SHARED_REQUIRES(Locks::mutator_lock_);
 
   // Returns true if the class is an interface.
@@ -228,21 +235,19 @@
   }
 
   ALWAYS_INLINE bool IsStringClass() SHARED_REQUIRES(Locks::mutator_lock_) {
-    return (GetField32(AccessFlagsOffset()) & kAccClassIsStringClass) != 0;
+    return (GetClassFlags() & kClassFlagString) != 0;
   }
 
   ALWAYS_INLINE void SetStringClass() SHARED_REQUIRES(Locks::mutator_lock_) {
-    uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
-    SetAccessFlags(flags | kAccClassIsStringClass);
+    SetClassFlags(GetClassFlags() | kClassFlagString | kClassFlagNoReferenceFields);
   }
 
   ALWAYS_INLINE bool IsClassLoaderClass() SHARED_REQUIRES(Locks::mutator_lock_) {
-    return (GetField32(AccessFlagsOffset()) & kAccClassIsClassLoaderClass) != 0;
+    return (GetClassFlags() & kClassFlagClassLoader) != 0;
   }
 
   ALWAYS_INLINE void SetClassLoaderClass() SHARED_REQUIRES(Locks::mutator_lock_) {
-    uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
-    SetAccessFlags(flags | kAccClassIsClassLoaderClass);
+    SetClassFlags(GetClassFlags() | kClassFlagClassLoader);
   }
 
   // Returns true if the class is abstract.
@@ -272,27 +277,27 @@
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   bool IsTypeOfReferenceClass() SHARED_REQUIRES(Locks::mutator_lock_) {
-    return (GetAccessFlags<kVerifyFlags>() & kAccClassIsReference) != 0;
+    return (GetClassFlags<kVerifyFlags>() & kClassFlagReference) != 0;
   }
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   bool IsWeakReferenceClass() SHARED_REQUIRES(Locks::mutator_lock_) {
-    return (GetAccessFlags<kVerifyFlags>() & kAccClassIsWeakReference) != 0;
+    return (GetClassFlags<kVerifyFlags>() & kClassFlagWeakReference) != 0;
   }
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   bool IsSoftReferenceClass() SHARED_REQUIRES(Locks::mutator_lock_) {
-    return (GetAccessFlags<kVerifyFlags>() & kAccReferenceFlagsMask) == kAccClassIsReference;
+    return (GetClassFlags<kVerifyFlags>() & kClassFlagSoftReference) != 0;
   }
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   bool IsFinalizerReferenceClass() SHARED_REQUIRES(Locks::mutator_lock_) {
-    return (GetAccessFlags<kVerifyFlags>() & kAccClassIsFinalizerReference) != 0;
+    return (GetClassFlags<kVerifyFlags>() & kClassFlagFinalizerReference) != 0;
   }
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   bool IsPhantomReferenceClass() SHARED_REQUIRES(Locks::mutator_lock_) {
-    return (GetAccessFlags<kVerifyFlags>() & kAccClassIsPhantomReference) != 0;
+    return (GetClassFlags<kVerifyFlags>() & kClassFlagPhantomReference) != 0;
   }
 
   // Can references of this type be assigned to by things of another type? For non-array types
@@ -826,6 +831,9 @@
                                        size_t pointer_size)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
+  ArtMethod* FindDeclaredVirtualMethodByName(const StringPiece& name, size_t pointer_size)
+      SHARED_REQUIRES(Locks::mutator_lock_);
+
   ArtMethod* FindVirtualMethod(const StringPiece& name, const StringPiece& signature,
                                size_t pointer_size)
       SHARED_REQUIRES(Locks::mutator_lock_);
@@ -862,7 +870,8 @@
   uint32_t NumInstanceFields() SHARED_REQUIRES(Locks::mutator_lock_);
   ArtField* GetInstanceField(uint32_t i) SHARED_REQUIRES(Locks::mutator_lock_);
 
-  // Returns the number of instance fields containing reference types.
+  // Returns the number of instance fields containing reference types not counting fields in the
+  // super class.
   uint32_t NumReferenceInstanceFields() SHARED_REQUIRES(Locks::mutator_lock_) {
     DCHECK(IsResolved() || IsErroneous());
     return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_));
@@ -1225,6 +1234,9 @@
   // length-prefixed array.
   uint64_t virtual_methods_;
 
+  // Class flags to help speed up visiting object references.
+  uint32_t class_flags_;
+
   // Total size of the Class instance; used when allocating storage on gc heap.
   // See also object_size_.
   uint32_t class_size_;
diff --git a/runtime/mirror/class_flags.h b/runtime/mirror/class_flags.h
new file mode 100644
index 0000000..6c15639
--- /dev/null
+++ b/runtime/mirror/class_flags.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_MIRROR_CLASS_FLAGS_H_
+#define ART_RUNTIME_MIRROR_CLASS_FLAGS_H_
+
+#include <stdint.h>
+
+namespace art {
+namespace mirror {
+
+// Object types stored in class to help GC with faster object marking.
+static constexpr uint32_t kClassFlagNormal             = 0x00000000;
+// Only normal objects which have no reference fields, e.g. string or primitive array or normal
+// class instance.
+static constexpr uint32_t kClassFlagNoReferenceFields  = 0x00000001;
+static constexpr uint32_t kClassFlagString             = 0x00000004;
+static constexpr uint32_t kClassFlagObjectArray        = 0x00000008;
+static constexpr uint32_t kClassFlagClass              = 0x00000010;
+
+// class is ClassLoader or one of its subclasses
+static constexpr uint32_t kClassFlagClassLoader        = 0x00000020;
+
+// class is a soft/weak/phantom ref
+static constexpr uint32_t kClassFlagSoftReference      = 0x00000040;
+// class is a weak reference
+static constexpr uint32_t kClassFlagWeakReference      = 0x00000080;
+// class is a finalizer reference
+static constexpr uint32_t kClassFlagFinalizerReference = 0x00000100;
+// class is a phantom reference
+static constexpr uint32_t kClassFlagPhantomReference   = 0x00000200;
+
+static constexpr uint32_t kClassFlagReference =
+    kClassFlagSoftReference |
+    kClassFlagWeakReference |
+    kClassFlagFinalizerReference |
+    kClassFlagPhantomReference;
+
+}  // namespace mirror
+}  // namespace art
+
+#endif  // ART_RUNTIME_MIRROR_CLASS_FLAGS_H_
+
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 586ae30..702a0f4 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -24,6 +24,7 @@
 #include "atomic.h"
 #include "array-inl.h"
 #include "class.h"
+#include "class_flags.h"
 #include "class_linker.h"
 #include "class_loader-inl.h"
 #include "lock_word-inl.h"
@@ -1010,20 +1011,43 @@
                                     const JavaLangRefVisitor& ref_visitor) {
   mirror::Class* klass = GetClass<kVerifyFlags>();
   visitor(this, ClassOffset(), false);
-  if (klass == Class::GetJavaLangClass()) {
-    AsClass<kVerifyNone>()->VisitReferences(klass, visitor);
-  } else if (klass->IsArrayClass() || klass->IsStringClass()) {
-    if (klass->IsObjectArrayClass<kVerifyNone>()) {
-      AsObjectArray<mirror::Object, kVerifyNone>()->VisitReferences(visitor);
-    }
-  } else if (klass->IsClassLoaderClass()) {
-    mirror::ClassLoader* class_loader = AsClassLoader<kVerifyFlags>();
-    class_loader->VisitReferences<kVerifyFlags>(klass, visitor);
-  } else {
+  const uint32_t class_flags = klass->GetClassFlags<kVerifyNone>();
+  if (LIKELY(class_flags == kClassFlagNormal)) {
     DCHECK(!klass->IsVariableSize());
     VisitInstanceFieldsReferences(klass, visitor);
-    if (UNLIKELY(klass->IsTypeOfReferenceClass<kVerifyNone>())) {
-      ref_visitor(klass, AsReference());
+    DCHECK(!klass->IsClassClass());
+  } else {
+    if ((class_flags & kClassFlagNoReferenceFields) == 0) {
+      DCHECK(!klass->IsStringClass());
+      if (class_flags == kClassFlagClass) {
+        DCHECK(klass->IsClassClass());
+        AsClass<kVerifyNone>()->VisitReferences(klass, visitor);
+      } else if (class_flags == kClassFlagObjectArray) {
+        DCHECK(klass->IsObjectArrayClass());
+        AsObjectArray<mirror::Object, kVerifyNone>()->VisitReferences(visitor);
+      } else if ((class_flags & kClassFlagReference) != 0) {
+        VisitInstanceFieldsReferences(klass, visitor);
+        ref_visitor(klass, AsReference());
+      } else {
+        mirror::ClassLoader* const class_loader = AsClassLoader<kVerifyFlags>();
+        class_loader->VisitReferences<kVerifyFlags>(klass, visitor);
+      }
+    } else if (kIsDebugBuild) {
+      CHECK(!klass->IsClassClass());
+      CHECK(!klass->IsObjectArrayClass());
+      // String still has instance fields for reflection purposes but these don't exist in
+      // actual string instances.
+      if (!klass->IsStringClass()) {
+        size_t total_reference_instance_fields = 0;
+        mirror::Class* super_class = klass;
+        do {
+          total_reference_instance_fields += super_class->NumReferenceInstanceFields();
+          super_class = super_class->GetSuperClass();
+        } while (super_class != nullptr);
+        // The only reference field should be the object's class. This field is handled at the
+        // beginning of the function.
+        CHECK_EQ(total_reference_instance_fields, 1u);
+      }
     }
   }
 }
diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc
index b6236b1..45610dc 100644
--- a/runtime/mirror/string.cc
+++ b/runtime/mirror/string.cc
@@ -55,6 +55,7 @@
 void String::SetClass(Class* java_lang_String) {
   CHECK(java_lang_String_.IsNull());
   CHECK(java_lang_String != nullptr);
+  CHECK(java_lang_String->IsStringClass());
   java_lang_String_ = GcRoot<Class>(java_lang_String);
 }
 
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index eb2e1f6..fbee2d7 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -157,10 +157,9 @@
     return java_lang_String_.Read();
   }
 
-  static void SetClass(Class* java_lang_String);
-  static void ResetClass();
-  static void VisitRoots(RootVisitor* visitor)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+  static void SetClass(Class* java_lang_String) SHARED_REQUIRES(Locks::mutator_lock_);
+  static void ResetClass() SHARED_REQUIRES(Locks::mutator_lock_);
+  static void VisitRoots(RootVisitor* visitor) SHARED_REQUIRES(Locks::mutator_lock_);
 
  private:
   void SetHashCode(int32_t new_hash_code) SHARED_REQUIRES(Locks::mutator_lock_) {
diff --git a/runtime/modifiers.h b/runtime/modifiers.h
index 0d9ec29..f7ab10b 100644
--- a/runtime/modifiers.h
+++ b/runtime/modifiers.h
@@ -19,6 +19,8 @@
 
 #include <stdint.h>
 
+namespace art {
+
 static constexpr uint32_t kAccPublic =       0x0001;  // class, field, method, ic
 static constexpr uint32_t kAccPrivate =      0x0002;  // field, method, ic
 static constexpr uint32_t kAccProtected =    0x0004;  // field, method, ic
@@ -49,28 +51,8 @@
 static constexpr uint32_t kAccMiranda =              0x00200000;  // method (dex only)
 
 // Special runtime-only flags.
-// Note: if only kAccClassIsReference is set, we have a soft reference.
-
-// class is ClassLoader or one of its subclasses
-static constexpr uint32_t kAccClassIsClassLoaderClass   = 0x10000000;
-
 // class/ancestor overrides finalize()
 static constexpr uint32_t kAccClassIsFinalizable        = 0x80000000;
-// class is a soft/weak/phantom ref
-static constexpr uint32_t kAccClassIsReference          = 0x08000000;
-// class is a weak reference
-static constexpr uint32_t kAccClassIsWeakReference      = 0x04000000;
-// class is a finalizer reference
-static constexpr uint32_t kAccClassIsFinalizerReference = 0x02000000;
-// class is a phantom reference
-static constexpr uint32_t kAccClassIsPhantomReference   = 0x01000000;
-// class is the string class
-static constexpr uint32_t kAccClassIsStringClass        = 0x00800000;
-
-static constexpr uint32_t kAccReferenceFlagsMask = (kAccClassIsReference
-                                                  | kAccClassIsWeakReference
-                                                  | kAccClassIsFinalizerReference
-                                                  | kAccClassIsPhantomReference);
 
 // Valid (meaningful) bits for a field.
 static constexpr uint32_t kAccValidFieldFlags = kAccPublic | kAccPrivate | kAccProtected |
@@ -95,5 +77,7 @@
 static constexpr uint32_t kAccValidInterfaceFlags = kAccPublic | kAccInterface |
     kAccAbstract | kAccSynthetic | kAccAnnotation;
 
+}  // namespace art
+
 #endif  // ART_RUNTIME_MODIFIERS_H_
 
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index c337e91..b9cc219 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -426,6 +426,45 @@
   return soa.AddLocalReference<jobjectArray>(ret.Get());
 }
 
+static jobject Class_getDeclaredAnnotation(JNIEnv* env, jobject javaThis, jclass annotationType) {
+  ScopedFastNativeObjectAccess soa(env);
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis)));
+  if (klass->IsProxyClass()) {
+    return nullptr;
+  }
+  Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+  return soa.AddLocalReference<jobject>(
+      klass->GetDexFile().GetAnnotationForClass(klass, annotation_class));
+}
+
+static jobjectArray Class_getDeclaredAnnotations(JNIEnv* env, jobject javaThis) {
+  ScopedFastNativeObjectAccess soa(env);
+  StackHandleScope<1> hs(soa.Self());
+  Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis)));
+  if (klass->IsProxyClass()) {
+    // Return an empty array instead of a null pointer
+    mirror::Class* annotation_array_class =
+        soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array);
+    mirror::ObjectArray<mirror::Object>* empty_array =
+        mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0);
+    return soa.AddLocalReference<jobjectArray>(empty_array);
+  }
+  return soa.AddLocalReference<jobjectArray>(klass->GetDexFile().GetAnnotationsForClass(klass));
+}
+
+static jboolean Class_isDeclaredAnnotationPresent(JNIEnv* env, jobject javaThis,
+                                                  jclass annotationType) {
+  ScopedFastNativeObjectAccess soa(env);
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis)));
+  if (klass->IsProxyClass()) {
+    return false;
+  }
+  Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+  return klass->GetDexFile().IsClassAnnotationPresent(klass, annotation_class);
+}
+
 static jobject Class_newInstance(JNIEnv* env, jobject javaThis) {
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<4> hs(soa.Self());
@@ -508,6 +547,9 @@
 static JNINativeMethod gMethods[] = {
   NATIVE_METHOD(Class, classForName,
                 "!(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"),
+  NATIVE_METHOD(Class, getDeclaredAnnotation,
+                "!(Ljava/lang/Class;)Ljava/lang/annotation/Annotation;"),
+  NATIVE_METHOD(Class, getDeclaredAnnotations, "!()[Ljava/lang/annotation/Annotation;"),
   NATIVE_METHOD(Class, getDeclaredConstructorInternal,
                 "!([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;"),
   NATIVE_METHOD(Class, getDeclaredConstructorsInternal, "!(Z)[Ljava/lang/reflect/Constructor;"),
@@ -518,10 +560,11 @@
   NATIVE_METHOD(Class, getDeclaredMethodInternal,
                 "!(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;"),
   NATIVE_METHOD(Class, getDeclaredMethodsUnchecked,
-                  "!(Z)[Ljava/lang/reflect/Method;"),
+                "!(Z)[Ljava/lang/reflect/Method;"),
   NATIVE_METHOD(Class, getNameNative, "!()Ljava/lang/String;"),
   NATIVE_METHOD(Class, getProxyInterfaces, "!()[Ljava/lang/Class;"),
   NATIVE_METHOD(Class, getPublicDeclaredFields, "!()[Ljava/lang/reflect/Field;"),
+  NATIVE_METHOD(Class, isDeclaredAnnotationPresent, "!(Ljava/lang/Class;)Z"),
   NATIVE_METHOD(Class, newInstance, "!()Ljava/lang/Object;"),
 };
 
diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc
index 93ba84a..cf3346d 100644
--- a/runtime/native/java_lang_reflect_Constructor.cc
+++ b/runtime/native/java_lang_reflect_Constructor.cc
@@ -18,6 +18,7 @@
 
 #include "art_method-inl.h"
 #include "class_linker.h"
+#include "class_linker-inl.h"
 #include "jni_internal.h"
 #include "mirror/class-inl.h"
 #include "mirror/method.h"
@@ -28,6 +29,55 @@
 
 namespace art {
 
+static jobject Constructor_getAnnotationNative(JNIEnv* env, jobject javaMethod,
+                                               jclass annotationType) {
+  ScopedFastNativeObjectAccess soa(env);
+  StackHandleScope<1> hs(soa.Self());
+  ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
+  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+  return soa.AddLocalReference<jobject>(
+      method->GetDexFile()->GetAnnotationForMethod(method, klass));
+}
+
+static jobjectArray Constructor_getDeclaredAnnotations(JNIEnv* env, jobject javaMethod) {
+  ScopedFastNativeObjectAccess soa(env);
+  ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
+  return soa.AddLocalReference<jobjectArray>(method->GetDexFile()->GetAnnotationsForMethod(method));
+}
+
+static jobjectArray Constructor_getExceptionTypes(JNIEnv* env, jobject javaMethod) {
+  ScopedFastNativeObjectAccess soa(env);
+  ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
+  mirror::ObjectArray<mirror::Object>* result_array =
+      method->GetDexFile()->GetExceptionTypesForMethod(method);
+  if (result_array == nullptr) {
+    // Return an empty array instead of a null pointer
+    mirror::Class* class_class = mirror::Class::GetJavaLangClass();
+    mirror::Class* class_array_class =
+        Runtime::Current()->GetClassLinker()->FindArrayClass(soa.Self(), &class_class);
+    mirror::ObjectArray<mirror::Object>* empty_array =
+        mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), class_array_class, 0);
+    return soa.AddLocalReference<jobjectArray>(empty_array);
+  } else {
+    return soa.AddLocalReference<jobjectArray>(result_array);
+  }
+}
+
+static jobjectArray Constructor_getParameterAnnotationsNative(JNIEnv* env, jobject javaMethod) {
+  ScopedFastNativeObjectAccess soa(env);
+  ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
+  return soa.AddLocalReference<jobjectArray>(method->GetDexFile()->GetParameterAnnotations(method));
+}
+
+static jboolean Constructor_isAnnotationPresentNative(JNIEnv* env, jobject javaMethod,
+                                                      jclass annotationType) {
+  ScopedFastNativeObjectAccess soa(env);
+  StackHandleScope<1> hs(soa.Self());
+  ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
+  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+  return method->GetDexFile()->IsMethodAnnotationPresent(method, klass);
+}
+
 /*
  * We can also safely assume the constructor isn't associated
  * with an interface, array, or primitive class. If this is coming from
@@ -82,6 +132,13 @@
 }
 
 static JNINativeMethod gMethods[] = {
+  NATIVE_METHOD(Constructor, getAnnotationNative,
+                "!(Ljava/lang/Class;)Ljava/lang/annotation/Annotation;"),
+  NATIVE_METHOD(Constructor, getDeclaredAnnotations, "!()[Ljava/lang/annotation/Annotation;"),
+  NATIVE_METHOD(Constructor, getExceptionTypes, "!()[Ljava/lang/Class;"),
+  NATIVE_METHOD(Constructor, getParameterAnnotationsNative,
+                "!()[[Ljava/lang/annotation/Annotation;"),
+  NATIVE_METHOD(Constructor, isAnnotationPresentNative, "!(Ljava/lang/Class;)Z"),
   NATIVE_METHOD(Constructor, newInstance, "!([Ljava/lang/Object;)Ljava/lang/Object;"),
 };
 
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 5bbb0dc..cc60fe0 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -415,16 +415,51 @@
   SetPrimitiveField<Primitive::kPrimShort>(env, javaField, javaObj, value);
 }
 
+static jobject Field_getAnnotationNative(JNIEnv* env, jobject javaField, jclass annotationType) {
+  ScopedFastNativeObjectAccess soa(env);
+  StackHandleScope<1> hs(soa.Self());
+  ArtField* field = soa.Decode<mirror::Field*>(javaField)->GetArtField();
+  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+  return soa.AddLocalReference<jobject>(field->GetDexFile()->GetAnnotationForField(field, klass));
+}
+
+static jobjectArray Field_getDeclaredAnnotations(JNIEnv* env, jobject javaField) {
+  ScopedFastNativeObjectAccess soa(env);
+  ArtField* field = soa.Decode<mirror::Field*>(javaField)->GetArtField();
+  return soa.AddLocalReference<jobjectArray>(field->GetDexFile()->GetAnnotationsForField(field));
+}
+
+static jobjectArray Field_getSignatureAnnotation(JNIEnv* env, jobject javaField) {
+  ScopedFastNativeObjectAccess soa(env);
+  ArtField* field = soa.Decode<mirror::Field*>(javaField)->GetArtField();
+  return soa.AddLocalReference<jobjectArray>(
+      field->GetDexFile()->GetSignatureAnnotationForField(field));
+}
+
+static jboolean Field_isAnnotationPresentNative(JNIEnv* env, jobject javaField,
+                                                jclass annotationType) {
+  ScopedFastNativeObjectAccess soa(env);
+  StackHandleScope<1> hs(soa.Self());
+  ArtField* field = soa.Decode<mirror::Field*>(javaField)->GetArtField();
+  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+  return field->GetDexFile()->IsFieldAnnotationPresent(field, klass);
+}
+
 static JNINativeMethod gMethods[] = {
   NATIVE_METHOD(Field, get,        "!(Ljava/lang/Object;)Ljava/lang/Object;"),
   NATIVE_METHOD(Field, getBoolean, "!(Ljava/lang/Object;)Z"),
   NATIVE_METHOD(Field, getByte,    "!(Ljava/lang/Object;)B"),
   NATIVE_METHOD(Field, getChar,    "!(Ljava/lang/Object;)C"),
+  NATIVE_METHOD(Field, getAnnotationNative,
+                "!(Ljava/lang/Class;)Ljava/lang/annotation/Annotation;"),
+  NATIVE_METHOD(Field, getDeclaredAnnotations, "!()[Ljava/lang/annotation/Annotation;"),
+  NATIVE_METHOD(Field, getSignatureAnnotation, "!()[Ljava/lang/String;"),
   NATIVE_METHOD(Field, getDouble,  "!(Ljava/lang/Object;)D"),
   NATIVE_METHOD(Field, getFloat,   "!(Ljava/lang/Object;)F"),
   NATIVE_METHOD(Field, getInt,     "!(Ljava/lang/Object;)I"),
   NATIVE_METHOD(Field, getLong,    "!(Ljava/lang/Object;)J"),
   NATIVE_METHOD(Field, getShort,   "!(Ljava/lang/Object;)S"),
+  NATIVE_METHOD(Field, isAnnotationPresentNative, "!(Ljava/lang/Class;)Z"),
   NATIVE_METHOD(Field, set,        "!(Ljava/lang/Object;Ljava/lang/Object;)V"),
   NATIVE_METHOD(Field, setBoolean, "!(Ljava/lang/Object;Z)V"),
   NATIVE_METHOD(Field, setByte,    "!(Ljava/lang/Object;B)V"),
diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc
index 9533b4d..2f0e7fe 100644
--- a/runtime/native/java_lang_reflect_Method.cc
+++ b/runtime/native/java_lang_reflect_Method.cc
@@ -18,6 +18,7 @@
 
 #include "art_method-inl.h"
 #include "class_linker.h"
+#include "class_linker-inl.h"
 #include "jni_internal.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
@@ -28,35 +29,111 @@
 
 namespace art {
 
+static jobject Method_getAnnotationNative(JNIEnv* env, jobject javaMethod, jclass annotationType) {
+  ScopedFastNativeObjectAccess soa(env);
+  ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
+  if (method->GetDeclaringClass()->IsProxyClass()) {
+    return nullptr;
+  }
+  StackHandleScope<1> hs(soa.Self());
+  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+  return soa.AddLocalReference<jobject>(
+      method->GetDexFile()->GetAnnotationForMethod(method, klass));
+}
+
+static jobjectArray Method_getDeclaredAnnotations(JNIEnv* env, jobject javaMethod) {
+  ScopedFastNativeObjectAccess soa(env);
+  ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
+  if (method->GetDeclaringClass()->IsProxyClass()) {
+    // Return an empty array instead of a null pointer
+    mirror::Class* annotation_array_class =
+        soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array);
+    mirror::ObjectArray<mirror::Object>* empty_array =
+        mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0);
+    return soa.AddLocalReference<jobjectArray>(empty_array);
+  }
+  return soa.AddLocalReference<jobjectArray>(method->GetDexFile()->GetAnnotationsForMethod(method));
+}
+
+static jobject Method_getDefaultValue(JNIEnv* env, jobject javaMethod) {
+  ScopedFastNativeObjectAccess soa(env);
+  ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
+  if (!method->GetDeclaringClass()->IsAnnotation()) {
+    return nullptr;
+  }
+  return soa.AddLocalReference<jobject>(method->GetDexFile()->GetAnnotationDefaultValue(method));
+}
+
+static jobjectArray Method_getExceptionTypes(JNIEnv* env, jobject javaMethod) {
+  ScopedFastNativeObjectAccess soa(env);
+  ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
+  if (method->GetDeclaringClass()->IsProxyClass()) {
+    mirror::Class* klass = method->GetDeclaringClass();
+    int throws_index = -1;
+    size_t i = 0;
+    for (const auto& m : klass->GetVirtualMethods(sizeof(void*))) {
+      if (&m == method) {
+        throws_index = i;
+        break;
+      }
+      ++i;
+    }
+    CHECK_NE(throws_index, -1);
+    mirror::ObjectArray<mirror::Class>* declared_exceptions = klass->GetThrows()->Get(throws_index);
+    return soa.AddLocalReference<jobjectArray>(declared_exceptions->Clone(soa.Self()));
+  } else {
+    mirror::ObjectArray<mirror::Object>* result_array =
+        method->GetDexFile()->GetExceptionTypesForMethod(method);
+    if (result_array == nullptr) {
+      // Return an empty array instead of a null pointer
+      mirror::Class* class_class = mirror::Class::GetJavaLangClass();
+      mirror::Class* class_array_class =
+          Runtime::Current()->GetClassLinker()->FindArrayClass(soa.Self(), &class_class);
+      mirror::ObjectArray<mirror::Object>* empty_array =
+          mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), class_array_class, 0);
+      return soa.AddLocalReference<jobjectArray>(empty_array);
+    } else {
+      return soa.AddLocalReference<jobjectArray>(result_array);
+    }
+  }
+}
+
+static jobjectArray Method_getParameterAnnotationsNative(JNIEnv* env, jobject javaMethod) {
+  ScopedFastNativeObjectAccess soa(env);
+  ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
+  if (method->GetDeclaringClass()->IsProxyClass()) {
+    return nullptr;
+  }
+  return soa.AddLocalReference<jobjectArray>(method->GetDexFile()->GetParameterAnnotations(method));
+}
+
 static jobject Method_invoke(JNIEnv* env, jobject javaMethod, jobject javaReceiver,
                              jobject javaArgs) {
   ScopedFastNativeObjectAccess soa(env);
   return InvokeMethod(soa, javaMethod, javaReceiver, javaArgs);
 }
 
-static jobject Method_getExceptionTypesNative(JNIEnv* env, jobject javaMethod) {
+static jboolean Method_isAnnotationPresentNative(JNIEnv* env, jobject javaMethod,
+                                                 jclass annotationType) {
   ScopedFastNativeObjectAccess soa(env);
-  ArtMethod* proxy_method = ArtMethod::FromReflectedMethod(soa, javaMethod);
-  CHECK(proxy_method->GetDeclaringClass()->IsProxyClass());
-  mirror::Class* proxy_class = proxy_method->GetDeclaringClass();
-  int throws_index = -1;
-  size_t i = 0;
-  for (const auto& m : proxy_class->GetVirtualMethods(sizeof(void*))) {
-    if (&m == proxy_method) {
-      throws_index = i;
-      break;
-    }
-    ++i;
+  ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
+  if (method->GetDeclaringClass()->IsProxyClass()) {
+    return false;
   }
-  CHECK_NE(throws_index, -1);
-  mirror::ObjectArray<mirror::Class>* declared_exceptions =
-          proxy_class->GetThrows()->Get(throws_index);
-  return soa.AddLocalReference<jobject>(declared_exceptions->Clone(soa.Self()));
+  StackHandleScope<1> hs(soa.Self());
+  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+  return method->GetDexFile()->IsMethodAnnotationPresent(method, klass);
 }
 
 static JNINativeMethod gMethods[] = {
+  NATIVE_METHOD(Method, getAnnotationNative,
+                "!(Ljava/lang/Class;)Ljava/lang/annotation/Annotation;"),
+  NATIVE_METHOD(Method, getDeclaredAnnotations, "!()[Ljava/lang/annotation/Annotation;"),
+  NATIVE_METHOD(Method, getDefaultValue, "!()Ljava/lang/Object;"),
+  NATIVE_METHOD(Method, getExceptionTypes, "!()[Ljava/lang/Class;"),
+  NATIVE_METHOD(Method, getParameterAnnotationsNative, "!()[[Ljava/lang/annotation/Annotation;"),
   NATIVE_METHOD(Method, invoke, "!(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"),
-  NATIVE_METHOD(Method, getExceptionTypesNative, "!()[Ljava/lang/Class;"),
+  NATIVE_METHOD(Method, isAnnotationPresentNative, "!(Ljava/lang/Class;)Z"),
 };
 
 void register_java_lang_reflect_Method(JNIEnv* env) {
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 1828b91..a506071 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -1956,6 +1956,32 @@
     }
     case Instruction::MONITOR_ENTER:
       work_line_->PushMonitor(this, inst->VRegA_11x(), work_insn_idx_);
+      // Check whether the previous instruction is a move-object with vAA as a source, creating
+      // untracked lock aliasing.
+      if (0 != work_insn_idx_ && !insn_flags_[work_insn_idx_].IsBranchTarget()) {
+        uint32_t prev_idx = work_insn_idx_ - 1;
+        while (0 != prev_idx && !insn_flags_[prev_idx].IsOpcode()) {
+          prev_idx--;
+        }
+        const Instruction* prev_inst = Instruction::At(code_item_->insns_ + prev_idx);
+        switch (prev_inst->Opcode()) {
+          case Instruction::MOVE_OBJECT:
+          case Instruction::MOVE_OBJECT_16:
+          case Instruction::MOVE_OBJECT_FROM16:
+            if (prev_inst->VRegB() == inst->VRegA_11x()) {
+              // Redo the copy. This won't change the register types, but update the lock status
+              // for the aliased register.
+              work_line_->CopyRegister1(this,
+                                        prev_inst->VRegA(),
+                                        prev_inst->VRegB(),
+                                        kTypeCategoryRef);
+            }
+            break;
+
+          default:  // Other instruction types ignored.
+            break;
+        }
+      }
       break;
     case Instruction::MONITOR_EXIT:
       /*
diff --git a/runtime/verifier/register_line.h b/runtime/verifier/register_line.h
index f61e51f..a9c4c95 100644
--- a/runtime/verifier/register_line.h
+++ b/runtime/verifier/register_line.h
@@ -344,6 +344,14 @@
     } else {
       reg_to_lock_depths_.erase(it);
     }
+    // Need to unlock every register at the same lock depth. These are aliased locks.
+    uint32_t mask = 1 << depth;
+    for (auto& pair : reg_to_lock_depths_) {
+      if ((pair.second & mask) != 0) {
+        VLOG(verifier) << "Also unlocking " << pair.first;
+        pair.second ^= mask;
+      }
+    }
   }
 
   void ClearAllRegToLockDepths(size_t reg) {
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 0c7cce9..e2c3afb 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -35,6 +35,7 @@
 jclass WellKnownClasses::dalvik_system_DexPathList__Element;
 jclass WellKnownClasses::dalvik_system_PathClassLoader;
 jclass WellKnownClasses::dalvik_system_VMRuntime;
+jclass WellKnownClasses::java_lang_annotation_Annotation__array;
 jclass WellKnownClasses::java_lang_BootClassLoader;
 jclass WellKnownClasses::java_lang_ClassLoader;
 jclass WellKnownClasses::java_lang_ClassNotFoundException;
@@ -59,6 +60,8 @@
 jclass WellKnownClasses::java_nio_DirectByteBuffer;
 jclass WellKnownClasses::java_util_ArrayList;
 jclass WellKnownClasses::java_util_Collections;
+jclass WellKnownClasses::libcore_reflect_AnnotationFactory;
+jclass WellKnownClasses::libcore_reflect_AnnotationMember;
 jclass WellKnownClasses::libcore_util_EmptyArray;
 jclass WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk;
 jclass WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer;
@@ -120,6 +123,8 @@
 jmethodID WellKnownClasses::java_lang_Thread__UncaughtExceptionHandler_uncaughtException;
 jmethodID WellKnownClasses::java_lang_ThreadGroup_removeThread;
 jmethodID WellKnownClasses::java_nio_DirectByteBuffer_init;
+jmethodID WellKnownClasses::libcore_reflect_AnnotationFactory_createAnnotation;
+jmethodID WellKnownClasses::libcore_reflect_AnnotationMember_init;
 jmethodID WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer_broadcast;
 jmethodID WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer_dispatch;
 
@@ -213,6 +218,7 @@
   dalvik_system_PathClassLoader = CacheClass(env, "dalvik/system/PathClassLoader");
   dalvik_system_VMRuntime = CacheClass(env, "dalvik/system/VMRuntime");
 
+  java_lang_annotation_Annotation__array = CacheClass(env, "[Ljava/lang/annotation/Annotation;");
   java_lang_BootClassLoader = CacheClass(env, "java/lang/BootClassLoader");
   java_lang_ClassLoader = CacheClass(env, "java/lang/ClassLoader");
   java_lang_ClassNotFoundException = CacheClass(env, "java/lang/ClassNotFoundException");
@@ -238,6 +244,8 @@
   java_nio_DirectByteBuffer = CacheClass(env, "java/nio/DirectByteBuffer");
   java_util_ArrayList = CacheClass(env, "java/util/ArrayList");
   java_util_Collections = CacheClass(env, "java/util/Collections");
+  libcore_reflect_AnnotationFactory = CacheClass(env, "libcore/reflect/AnnotationFactory");
+  libcore_reflect_AnnotationMember = CacheClass(env, "libcore/reflect/AnnotationMember");
   libcore_util_EmptyArray = CacheClass(env, "libcore/util/EmptyArray");
   org_apache_harmony_dalvik_ddmc_Chunk = CacheClass(env, "org/apache/harmony/dalvik/ddmc/Chunk");
   org_apache_harmony_dalvik_ddmc_DdmServer = CacheClass(env, "org/apache/harmony/dalvik/ddmc/DdmServer");
@@ -262,6 +270,8 @@
   java_lang_Thread__UncaughtExceptionHandler_uncaughtException = CacheMethod(env, java_lang_Thread__UncaughtExceptionHandler, false, "uncaughtException", "(Ljava/lang/Thread;Ljava/lang/Throwable;)V");
   java_lang_ThreadGroup_removeThread = CacheMethod(env, java_lang_ThreadGroup, false, "removeThread", "(Ljava/lang/Thread;)V");
   java_nio_DirectByteBuffer_init = CacheMethod(env, java_nio_DirectByteBuffer, false, "<init>", "(JI)V");
+  libcore_reflect_AnnotationFactory_createAnnotation = CacheMethod(env, libcore_reflect_AnnotationFactory, true, "createAnnotation", "(Ljava/lang/Class;[Llibcore/reflect/AnnotationMember;)Ljava/lang/annotation/Annotation;");
+  libcore_reflect_AnnotationMember_init = CacheMethod(env, libcore_reflect_AnnotationMember, false, "<init>", "(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/reflect/Method;)V");
   org_apache_harmony_dalvik_ddmc_DdmServer_broadcast = CacheMethod(env, org_apache_harmony_dalvik_ddmc_DdmServer, true, "broadcast", "(I)V");
   org_apache_harmony_dalvik_ddmc_DdmServer_dispatch = CacheMethod(env, org_apache_harmony_dalvik_ddmc_DdmServer, true, "dispatch", "(I[BII)Lorg/apache/harmony/dalvik/ddmc/Chunk;");
 
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index 6dd8168..c856291 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -46,6 +46,7 @@
   static jclass dalvik_system_DexPathList__Element;
   static jclass dalvik_system_PathClassLoader;
   static jclass dalvik_system_VMRuntime;
+  static jclass java_lang_annotation_Annotation__array;
   static jclass java_lang_BootClassLoader;
   static jclass java_lang_ClassLoader;
   static jclass java_lang_ClassNotFoundException;
@@ -70,6 +71,8 @@
   static jclass java_util_ArrayList;
   static jclass java_util_Collections;
   static jclass java_nio_DirectByteBuffer;
+  static jclass libcore_reflect_AnnotationFactory;
+  static jclass libcore_reflect_AnnotationMember;
   static jclass libcore_util_EmptyArray;
   static jclass org_apache_harmony_dalvik_ddmc_Chunk;
   static jclass org_apache_harmony_dalvik_ddmc_DdmServer;
@@ -131,6 +134,8 @@
   static jmethodID java_lang_Thread__UncaughtExceptionHandler_uncaughtException;
   static jmethodID java_lang_ThreadGroup_removeThread;
   static jmethodID java_nio_DirectByteBuffer_init;
+  static jmethodID libcore_reflect_AnnotationFactory_createAnnotation;
+  static jmethodID libcore_reflect_AnnotationMember_init;
   static jmethodID org_apache_harmony_dalvik_ddmc_DdmServer_broadcast;
   static jmethodID org_apache_harmony_dalvik_ddmc_DdmServer_dispatch;
 
diff --git a/test/004-SignalTest/signaltest.cc b/test/004-SignalTest/signaltest.cc
index 1414715..34e331b 100644
--- a/test/004-SignalTest/signaltest.cc
+++ b/test/004-SignalTest/signaltest.cc
@@ -93,13 +93,16 @@
 char *go_away_compiler = nullptr;
 
 extern "C" JNIEXPORT jint JNICALL Java_Main_testSignal(JNIEnv*, jclass) {
-#if defined(__arm__) || defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
+#if defined(__arm__) || defined(__i386__) || defined(__aarch64__)
   // On supported architectures we cause a real SEGV.
   *go_away_compiler = 'a';
+#elif defined(__x86_64__)
+  // Cause a SEGV using an instruction known to be 3 bytes long to account for hardcoded jump
+  // in the signal handler
+  asm volatile("movl $0, %%eax;" "movb $1, (%%al);" : : : "%eax");
 #else
   // On other architectures we simulate SEGV.
   kill(getpid(), SIGSEGV);
 #endif
   return 1234;
 }
-
diff --git a/test/115-native-bridge/nativebridge.cc b/test/115-native-bridge/nativebridge.cc
index 04326b3..702e779 100644
--- a/test/115-native-bridge/nativebridge.cc
+++ b/test/115-native-bridge/nativebridge.cc
@@ -206,8 +206,9 @@
 #if defined(__arm__) || defined(__i386__) || defined(__aarch64__)
   *go_away_compiler = 'a';
 #elif defined(__x86_64__)
-  // Cause a SEGV using an instruction known to be 3 bytes long
-  asm volatile("movl $0, %%eax;" "movb $1, (%%eax);" : : : "%eax");
+  // Cause a SEGV using an instruction known to be 3 bytes long to account for hardcoded jump
+  // in the signal handler
+  asm volatile("movl $0, %%eax;" "movb $1, (%%al);" : : : "%eax");
 #else
   // On other architectures we simulate SEGV.
   kill(getpid(), SIGSEGV);
diff --git a/test/529-long-split/expected.txt b/test/529-long-split/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/529-long-split/expected.txt
diff --git a/test/529-long-split/info.txt b/test/529-long-split/info.txt
new file mode 100644
index 0000000..39b5b96
--- /dev/null
+++ b/test/529-long-split/info.txt
@@ -0,0 +1,2 @@
+Regression test for optimizing that used to trip
+during register allocation.
diff --git a/test/529-long-split/src/Main.java b/test/529-long-split/src/Main.java
new file mode 100644
index 0000000..dc52d88
--- /dev/null
+++ b/test/529-long-split/src/Main.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main  {
+  public static void main(String[] args) throws Exception {
+    if (testOddLow1(5L)) {
+      throw new Error();
+    }
+
+    if (testNonFollowingHigh(5)) {
+      throw new Error();
+    }
+
+    if (testOddLow2()) {
+      throw new Error();
+    }
+  }
+
+  public static boolean testOddLow1(long a /* ECX-EDX */) {
+    // class instance is in EBP
+    long b = myLongField1; // ESI-EDI
+    int f = myField1; // EBX
+    int e = myField2; // EAX
+    int g = myField3; // ESI (by spilling ESI-EDI, see below)
+    int h = myField4; // EDI
+    myLongField2 = a; // Make sure ESI-EDI gets spilled and not ECX-EDX
+    myField2 = f; // use of EBX
+    myField1 = e; // use of EAX
+    myField3 = h; // use of ESI
+    myField4 = g; // use if EDI
+
+    // At this point `b` has been spilled and needs to have a pair. The ordering
+    // in the register allocator triggers the allocation of `res` before `b`.
+    // `res` being used after the `doCall`, we want a callee saved register.
+    //
+    // EBP is taken by the class instance and EDI is taken by `g` (both used in the `myField4`
+    // assignment below). So we end up allocating ESI for `res`.
+    //
+    // When we try to allocate a pair for `b` we're in the following situation:
+    // EAX is free
+    // ECX is taken
+    // EDX is taken
+    // EBX is free
+    // ESP is blocked
+    // EBP could be spilled
+    // ESI is taken
+    // EDI could be spilled
+    //
+    // So there is no consecutive registers available to please the register allocator.
+    // The compiler used to trip then because of a bogus implementation of trying to split
+    // an unaligned register pair (here ECX and EDX). The implementation would not find
+    // a register and the register allocator would then complain about not having
+    // enough registers for the operation.
+    boolean res = a == b;
+    $noinline$doCall();
+    myField4 = g;
+    return res;
+  }
+
+  public static boolean testNonFollowingHigh(int i) {
+    // class instance is in EBP
+    long b = myLongField1; // ESI-EDI
+    long a = (long)i; // EAX-EDX
+    int f = myField1; // EBX
+    int e = myField2; // ECX
+    int g = myField3; // ESI (by spilling ESI-EDI, see below)
+    int h = myField4; // EDI
+    myLongField2 = a; // Make sure ESI-EDI gets spilled and not ECX-EDX
+    myField2 = f; // use of EBX
+    myField1 = e; // use of ECX
+    myField3 = h; // use of EDI
+    myField4 = g; // use of ESI
+
+    // At this point `b` has been spilled and needs to have a pair. The ordering
+    // in the register allocator triggers the allocation of `res` before `b`.
+    // `res` being used after the `doCall`, we want a callee saved register.
+    //
+    // EBP is taken by the class instance and ESI is taken by `g` (both used in the `myField4`
+    // assignment below). So we end up allocating EDI for `res`.
+    //
+    // When we try to allocate a pair for `b` we're in the following situation:
+    // EAX is taken
+    // ECX is free
+    // EDX is taken
+    // EBX is free
+    // ESP is blocked
+    // EBP could be spilled
+    // ESI is taken
+    // EDI could be spilled
+    //
+    // So there is no consecutive registers available to please the register allocator.
+    // The compiler used to be in a bad state because of a bogus implementation of trying
+    // to split an unaligned register pair (here EAX and EDX).
+    boolean res = a == b;
+    $noinline$doCall();
+    myField4 = g;
+    return res;
+  }
+
+  public static boolean testOddLow2() {
+    // class instance is in EBP
+    long b = myLongField1; // ECX-EDX (hint due to call below).
+    long a = myLongField2; // ESI-EDI
+    int f = myField1; // EBX
+    int e = myField2; // EAX
+    int g = myField3; // ECX
+    int h = myField4; // EDX
+    int i = myField5; // ESI - callee saved due to assignment after call to $noinline$doCall.
+    myField2 = f; // use of EBX
+    myField1 = e; // use of EAX
+    myField3 = h; // use of EDX
+    myField4 = i; // use of ESI
+    myField5 = g; // use of ECX
+
+    // At this point `a` and `b` have been spilled and need to have a pairs. The ordering
+    // in the register allocator triggers the allocation of `res` before `a` and `b`.
+    // `res` being used after the `doCall`, we want a callee saved register.
+    //
+    // EBP is taken by the class instance and ESI is taken by `i` (both used in the `myField4`
+    // assignment below). So we end up allocating EDI for `res`.
+    //
+    // We first try to allocator a pair for `b`. We're in the following situation:
+    // EAX is free
+    // ECX is free
+    // EDX is free
+    // EBX is free
+    // ESP is blocked
+    // EBP could be spilled
+    // ESI could be spilled
+    // EDI is taken
+    //
+    // Because `b` is used as a first argument to a call, we take its hint and allocate
+    // ECX-EDX to it.
+    //
+    // We then try to allocate a pair for `a`. We're in the following situation:
+    // EAX is free
+    // ECX could be spilled
+    // EDX could be spilled
+    // EBX is free
+    // ESP is blocked
+    // EBP could be spilled
+    // ESI could be spilled
+    // EDI is taken
+    //
+    // So no consecutive two free registers are available. When trying to find a slot, we pick
+    // the first unaligned or non-pair interval. In this case, this is the unaligned ECX-EDX.
+    // The compiler used to then trip because it forgot to remove the high interval containing
+    // the pair from the active list.
+
+    boolean res = a == b;
+    $noinline$doCall(b);
+    myField4 = i; // use of ESI
+    return res;
+  }
+
+  public static void $noinline$doCall() {
+    if (doThrow) throw new Error();
+  }
+
+  public static void $noinline$doCall(long e) {
+    if (doThrow) throw new Error();
+  }
+
+  public static boolean doThrow;
+  public static int myField1;
+  public static int myField2;
+  public static int myField3;
+  public static int myField4;
+  public static int myField5;
+  public static long myLongField1;
+  public static long myLongField2;
+}
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index dd37cdb..6a452eb 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -1,6 +1,5 @@
 PackedSwitch
 b/17790197
-b/17978759
 FloatBadArgReg
 negLong
 sameFieldNames
@@ -41,4 +40,6 @@
 b/20843113
 b/23201502 (float)
 b/23201502 (double)
+b/23300986
+b/23300986 (2)
 Done!
diff --git a/test/800-smali/smali/b_17978759.smali b/test/800-smali/smali/b_17978759.smali
deleted file mode 100644
index 07bcae5..0000000
--- a/test/800-smali/smali/b_17978759.smali
+++ /dev/null
@@ -1,28 +0,0 @@
-.class public LB17978759;
-.super Ljava/lang/Object;
-
-  .method public constructor <init>()V
-    .registers 1
-    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
-    return-void
-  .end method
-
-  .method public test()V
-    .registers 2
-
-    move-object   v0, p0
-    # v0 and p0 alias
-    monitor-enter p0
-    # monitor-enter on p0
-    monitor-exit  v0
-    # monitor-exit on v0, however, verifier doesn't track this and so this is
-    # a warning. Verifier will still think p0 is locked.
-
-    move-object   v0, p0
-    # v0 will now appear locked.
-    monitor-enter v0
-    # Attempt to lock v0 twice is a verifier failure.
-    monitor-exit  v0
-
-    return-void
-  .end method
diff --git a/test/800-smali/smali/b_23300986.smali b/test/800-smali/smali/b_23300986.smali
new file mode 100644
index 0000000..f008b92
--- /dev/null
+++ b/test/800-smali/smali/b_23300986.smali
@@ -0,0 +1,23 @@
+.class public LB23300986;
+
+.super Ljava/lang/Object;
+
+.method public static runAliasAfterEnter(Ljava/lang/Object;)V
+   .registers 3
+   monitor-enter v2        # Lock on parameter
+   move-object v1, v2      # Copy parameter into v1, establishing an alias.
+   monitor-exit v1         # Unlock on alias
+   monitor-enter v2        # Do it again.
+   monitor-exit v1
+   return-void
+.end method
+
+.method public static runAliasBeforeEnter(Ljava/lang/Object;)V
+   .registers 3
+   move-object v1, v2      # Copy parameter into v1, establishing an alias.
+   monitor-enter v2        # Lock on parameter
+   monitor-exit v1         # Unlock on alias
+   monitor-enter v2        # Do it again.
+   monitor-exit v1
+   return-void
+.end method
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index b481a1d..183958a 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -53,8 +53,6 @@
                 new Object[]{123}, null, 123));
 
         testCases.add(new TestCase("b/17790197", "B17790197", "getInt", null, null, 100));
-        testCases.add(new TestCase("b/17978759", "B17978759", "test", null, new VerifyError(),
-                null));
         testCases.add(new TestCase("FloatBadArgReg", "FloatBadArgReg", "getInt",
                 new Object[]{100}, null, 100));
         testCases.add(new TestCase("negLong", "negLong", "negLong", null, null, 122142L));
@@ -127,6 +125,10 @@
                 new NullPointerException(), null));
         testCases.add(new TestCase("b/23201502 (double)", "B23201502", "runDouble", null,
                 new NullPointerException(), null));
+        testCases.add(new TestCase("b/23300986", "B23300986", "runAliasAfterEnter",
+                new Object[] { new Object() }, null, null));
+        testCases.add(new TestCase("b/23300986 (2)", "B23300986", "runAliasBeforeEnter",
+                new Object[] { new Object() }, null, null));
     }
 
     public void runTests() {
diff --git a/tools/buildbot-build.sh b/tools/buildbot-build.sh
index 62fd67b..1dced32 100755
--- a/tools/buildbot-build.sh
+++ b/tools/buildbot-build.sh
@@ -24,6 +24,7 @@
 linker="linker"
 mode="target"
 j_arg="-j$(nproc)"
+showcommands=
 make_command=
 
 if [[ "$TARGET_PRODUCT" == "armv8" ]]; then
@@ -54,6 +55,9 @@
   elif [[ "$1" == -j* ]]; then
     j_arg=$1
     shift
+  elif [[ "$1" == "--showcommands" ]]; then
+    showcommands="showcommands"
+    shift
   elif [[ "$1" == "" ]]; then
     break
   fi
@@ -70,7 +74,7 @@
   # Use '-e' to force the override of TARGET_GLOBAL_LDFLAGS.
   # Also, we build extra tools that will be used by tests, so that
   # they are compiled with our own linker.
-  make_command="make -e $j_arg build-art-target-tests $common_targets libjavacrypto libjavacoretests linker toybox toolbox sh"
+  make_command="make -e $j_arg $showcommands build-art-target-tests $common_targets libjavacrypto libjavacoretests linker toybox toolbox sh"
   echo "Executing env $env $make_command"
   env $env $make_command
 fi
diff --git a/tools/checker/README b/tools/checker/README
index 259691e..65f5bd2 100644
--- a/tools/checker/README
+++ b/tools/checker/README
@@ -2,10 +2,10 @@
 state of the control-flow graph before and after each optimization pass
 against a set of assertions specified alongside the tests.
 
-Tests are written in Java, turned into DEX and compiled with the Optimizing
-compiler. "Check lines" are assertions formatted as comments of the Java file.
-They begin with prefix 'CHECK' followed by a pattern that the engine attempts
-to match in the compiler-generated output.
+Tests are written in Java or Smali, turned into DEX and compiled with the
+Optimizing compiler. "Check lines" are assertions formatted as comments of the
+source file. They begin with prefix "/// CHECK" or "## CHECK", respectively,
+followed by a pattern that the engine attempts to match in the compiler output.
 
 Assertions are tested in groups which correspond to the individual compiler
 passes. Each group of check lines therefore must start with a 'CHECK-START'
@@ -15,19 +15,23 @@
 
 Matching of check lines is carried out in the order of appearance in the
 source file. There are three types of check lines:
- - CHECK:     Must match an output line which appears in the output group
-              later than lines matched against any preceeding checks. Output
-              lines must therefore match the check lines in the same order.
-              These are referred to as "in-order" checks in the code.
- - CHECK-DAG: Must match an output line which appears in the output group
-              later than lines matched against any preceeding in-order checks.
-              In other words, the order of output lines does not matter
-              between consecutive DAG checks.
- - CHECK-NOT: Must not match any output line which appears in the output group
-              later than lines matched against any preceeding checks and
-              earlier than lines matched against any subsequent checks.
-              Surrounding non-negative checks (or boundaries of the group)
-              therefore create a scope within which the assertion is verified.
+ - CHECK:      Must match an output line which appears in the output group
+               later than lines matched against any preceeding checks. Output
+               lines must therefore match the check lines in the same order.
+               These are referred to as "in-order" checks in the code.
+ - CHECK-DAG:  Must match an output line which appears in the output group
+               later than lines matched against any preceeding in-order checks.
+               In other words, the order of output lines does not matter
+               between consecutive DAG checks.
+ - CHECK-NOT:  Must not match any output line which appears in the output group
+               later than lines matched against any preceeding checks and
+               earlier than lines matched against any subsequent checks.
+               Surrounding non-negative checks (or boundaries of the group)
+               therefore create a scope within which the assertion is verified.
+ - CHECK-NEXT: Must match the output line which comes right after the line which
+               matched the previous check. Cannot be used after any but the
+               in-order CHECK.
+ - CHECK-EVAL: Specifies a Python expression which must evaluate to 'True'.
 
 Check-line patterns are treated as plain text rather than regular expressions
 but are whitespace agnostic.
@@ -45,18 +49,30 @@
 Example:
   The following assertions can be placed in a Java source file:
 
-  // CHECK-START: int MyClass.MyMethod() constant_folding (after)
-  // CHECK:         <<ID:i\d+>>  IntConstant {{11|22}}
-  // CHECK:                      Return [<<ID>>]
+  /// CHECK-START: int MyClass.MyMethod() constant_folding (after)
+  /// CHECK:         <<ID:i\d+>>  IntConstant {{11|22}}
+  /// CHECK:                      Return [<<ID>>]
 
   The engine will attempt to match the check lines against the output of the
   group named on the first line. Together they verify that the CFG after
   constant folding returns an integer constant with value either 11 or 22.
 
+
+Of the language constructs above, 'CHECK-EVAL' lines support only referencing of
+variables. Any other surrounding text will be passed to Python's `eval` as is.
+
+Example:
+  /// CHECK-START: int MyClass.MyMethod() liveness (after)
+  /// CHECK:         InstructionA liveness:<<VarA:\d+>>
+  /// CHECK:         InstructionB liveness:<<VarB:\d+>>
+  /// CHECK-EVAL:    <<VarA>> != <<VarB>>
+
+
 A group of check lines can be made architecture-specific by inserting '-<arch>'
 after the 'CHECK-START' keyword. The previous example can be updated to run for
 arm64 only with:
 
-  // CHECK-START-ARM64: int MyClass.MyMethod() constant_folding (after)
-  // CHECK:         <<ID:i\d+>>  IntConstant {{11|22}}
-  // CHECK:                      Return [<<ID>>]
+Example:
+  /// CHECK-START-ARM64: int MyClass.MyMethod() constant_folding (after)
+  /// CHECK:         <<ID:i\d+>>  IntConstant {{11|22}}
+  /// CHECK:                      Return [<<ID>>]
diff --git a/tools/checker/file_format/checker/parser.py b/tools/checker/file_format/checker/parser.py
index 001f72a..446302f 100644
--- a/tools/checker/file_format/checker/parser.py
+++ b/tools/checker/file_format/checker/parser.py
@@ -15,7 +15,7 @@
 from common.archs               import archs_list
 from common.logger              import Logger
 from file_format.common         import SplitStream
-from file_format.checker.struct import CheckerFile, TestCase, TestAssertion, RegexExpression
+from file_format.checker.struct import CheckerFile, TestCase, TestAssertion, TestExpression
 
 import re
 
@@ -81,6 +81,11 @@
   if notLine is not None:
     return (notLine, TestAssertion.Variant.Not, lineNo), None, None
 
+  # 'CHECK-EVAL' lines evaluate a Python expression.
+  evalLine = __extractLine(prefix + "-EVAL", line)
+  if evalLine is not None:
+    return (evalLine, TestAssertion.Variant.Eval, lineNo), None, None
+
   Logger.fail("Checker assertion could not be parsed: '" + line + "'", fileName, lineNo)
 
 def __isMatchAtStart(match):
@@ -97,16 +102,24 @@
 
 def ParseCheckerAssertion(parent, line, variant, lineNo):
   """ This method parses the content of a check line stripped of the initial
-      comment symbol and the CHECK keyword.
+      comment symbol and the CHECK-* keyword.
   """
   assertion = TestAssertion(parent, variant, line, lineNo)
+  isEvalLine = (variant == TestAssertion.Variant.Eval)
+
   # Loop as long as there is something to parse.
   while line:
     # Search for the nearest occurrence of the special markers.
-    matchWhitespace = re.search(r"\s+", line)
-    matchPattern = re.search(RegexExpression.Regex.regexPattern, line)
-    matchVariableReference = re.search(RegexExpression.Regex.regexVariableReference, line)
-    matchVariableDefinition = re.search(RegexExpression.Regex.regexVariableDefinition, line)
+    if isEvalLine:
+      # The following constructs are not supported in CHECK-EVAL lines
+      matchWhitespace = None
+      matchPattern = None
+      matchVariableDefinition = None
+    else:
+      matchWhitespace = re.search(r"\s+", line)
+      matchPattern = re.search(TestExpression.Regex.regexPattern, line)
+      matchVariableDefinition = re.search(TestExpression.Regex.regexVariableDefinition, line)
+    matchVariableReference = re.search(TestExpression.Regex.regexVariableReference, line)
 
     # If one of the above was identified at the current position, extract them
     # from the line, parse them and add to the list of line parts.
@@ -114,24 +127,24 @@
       # A whitespace in the check line creates a new separator of line parts.
       # This allows for ignored output between the previous and next parts.
       line = line[matchWhitespace.end():]
-      assertion.addExpression(RegexExpression.createSeparator())
+      assertion.addExpression(TestExpression.createSeparator())
     elif __isMatchAtStart(matchPattern):
       pattern = line[0:matchPattern.end()]
       pattern = pattern[2:-2]
       line = line[matchPattern.end():]
-      assertion.addExpression(RegexExpression.createPattern(pattern))
+      assertion.addExpression(TestExpression.createPattern(pattern))
     elif __isMatchAtStart(matchVariableReference):
       var = line[0:matchVariableReference.end()]
       line = line[matchVariableReference.end():]
       name = var[2:-2]
-      assertion.addExpression(RegexExpression.createVariableReference(name))
+      assertion.addExpression(TestExpression.createVariableReference(name))
     elif __isMatchAtStart(matchVariableDefinition):
       var = line[0:matchVariableDefinition.end()]
       line = line[matchVariableDefinition.end():]
       colonPos = var.find(":")
       name = var[2:colonPos]
       body = var[colonPos+1:-2]
-      assertion.addExpression(RegexExpression.createVariableDefinition(name, body))
+      assertion.addExpression(TestExpression.createVariableDefinition(name, body))
     else:
       # If we're not currently looking at a special marker, this is a plain
       # text match all the way until the first special marker (or the end
@@ -143,7 +156,10 @@
                                 line)
       text = line[0:firstMatch]
       line = line[firstMatch:]
-      assertion.addExpression(RegexExpression.createText(text))
+      if isEvalLine:
+        assertion.addExpression(TestExpression.createPlainText(text))
+      else:
+        assertion.addExpression(TestExpression.createPatternFromPlainText(text))
   return assertion
 
 def ParseCheckerStream(fileName, prefix, stream):
diff --git a/tools/checker/file_format/checker/struct.py b/tools/checker/file_format/checker/struct.py
index 2b2e442..7ee09cd 100644
--- a/tools/checker/file_format/checker/struct.py
+++ b/tools/checker/file_format/checker/struct.py
@@ -74,7 +74,7 @@
 
   class Variant(object):
     """Supported types of assertions."""
-    InOrder, NextLine, DAG, Not = range(4)
+    InOrder, NextLine, DAG, Not, Eval = range(5)
 
   def __init__(self, parent, variant, originalText, lineNo):
     assert isinstance(parent, TestCase)
@@ -92,9 +92,9 @@
     return self.parent.fileName
 
   def addExpression(self, new_expression):
-    assert isinstance(new_expression, RegexExpression)
+    assert isinstance(new_expression, TestExpression)
     if self.variant == TestAssertion.Variant.Not:
-      if new_expression.variant == RegexExpression.Variant.VarDef:
+      if new_expression.variant == TestExpression.Variant.VarDef:
         Logger.fail("CHECK-NOT lines cannot define variables", self.fileName, self.lineNo)
     self.expressions.append(new_expression)
 
@@ -102,10 +102,10 @@
     """ Returns a regex pattern for this entire assertion. Only used in tests. """
     regex = ""
     for expression in self.expressions:
-      if expression.variant == RegexExpression.Variant.Separator:
+      if expression.variant == TestExpression.Variant.Separator:
         regex = regex + ", "
       else:
-        regex = regex + "(" + expression.pattern + ")"
+        regex = regex + "(" + expression.text + ")"
     return regex
 
   def __eq__(self, other):
@@ -114,11 +114,11 @@
        and self.expressions == other.expressions
 
 
-class RegexExpression(EqualityMixin, PrintableMixin):
+class TestExpression(EqualityMixin, PrintableMixin):
 
   class Variant(object):
     """Supported language constructs."""
-    Text, Pattern, VarRef, VarDef, Separator = range(5)
+    PlainText, Pattern, VarRef, VarDef, Separator = range(5)
 
   class Regex(object):
     rName = r"([a-zA-Z][a-zA-Z0-9]*)"
@@ -128,40 +128,45 @@
     rVariableStartSym = r"(<<)"
     rVariableEndSym = r"(>>)"
     rVariableSeparator = r"(:)"
+    rVariableDefinitionBody = rName + rVariableSeparator + rRegex
 
     regexPattern = rPatternStartSym + rRegex + rPatternEndSym
     regexVariableReference = rVariableStartSym + rName + rVariableEndSym
-    regexVariableDefinition = rVariableStartSym + rName + rVariableSeparator + rRegex + rVariableEndSym
+    regexVariableDefinition = rVariableStartSym + rVariableDefinitionBody + rVariableEndSym
 
-  def __init__(self, variant, name, pattern):
+  def __init__(self, variant, name, text):
     self.variant = variant
     self.name = name
-    self.pattern = pattern
+    self.text = text
 
   def __eq__(self, other):
     return isinstance(other, self.__class__) \
        and self.variant == other.variant \
        and self.name == other.name \
-       and self.pattern == other.pattern
+       and self.text == other.text
 
   @staticmethod
   def createSeparator():
-    return RegexExpression(RegexExpression.Variant.Separator, None, None)
+    return TestExpression(TestExpression.Variant.Separator, None, None)
 
   @staticmethod
-  def createText(text):
-    return RegexExpression(RegexExpression.Variant.Text, None, re.escape(text))
+  def createPlainText(text):
+    return TestExpression(TestExpression.Variant.PlainText, None, text)
+
+  @staticmethod
+  def createPatternFromPlainText(text):
+    return TestExpression(TestExpression.Variant.Pattern, None, re.escape(text))
 
   @staticmethod
   def createPattern(pattern):
-    return RegexExpression(RegexExpression.Variant.Pattern, None, pattern)
+    return TestExpression(TestExpression.Variant.Pattern, None, pattern)
 
   @staticmethod
   def createVariableReference(name):
-    assert re.match(RegexExpression.Regex.rName, name)
-    return RegexExpression(RegexExpression.Variant.VarRef, name, None)
+    assert re.match(TestExpression.Regex.rName, name)
+    return TestExpression(TestExpression.Variant.VarRef, name, None)
 
   @staticmethod
   def createVariableDefinition(name, pattern):
-    assert re.match(RegexExpression.Regex.rName, name)
-    return RegexExpression(RegexExpression.Variant.VarDef, name, pattern)
+    assert re.match(TestExpression.Regex.rName, name)
+    return TestExpression(TestExpression.Variant.VarDef, name, pattern)
diff --git a/tools/checker/file_format/checker/test.py b/tools/checker/file_format/checker/test.py
index 36ed4b1..495dabc 100644
--- a/tools/checker/file_format/checker/test.py
+++ b/tools/checker/file_format/checker/test.py
@@ -17,7 +17,7 @@
 from common.archs               import archs_list
 from common.testing             import ToUnicode
 from file_format.checker.parser import ParseCheckerStream
-from file_format.checker.struct import CheckerFile, TestCase, TestAssertion, RegexExpression
+from file_format.checker.struct import CheckerFile, TestCase, TestAssertion, TestExpression
 
 import io
 import unittest
@@ -73,10 +73,11 @@
     self.assertParses("    ///CHECK: foo")
     self.assertParses("///    CHECK: foo")
 
-class CheckerParser_RegexExpressionTest(unittest.TestCase):
+class CheckerParser_TestExpressionTest(unittest.TestCase):
 
   def parseAssertion(self, string, variant=""):
-    checkerText = u"/// CHECK-START: pass\n/// CHECK" + ToUnicode(variant) + u": " + ToUnicode(string)
+    checkerText = (u"/// CHECK-START: pass\n" +
+                   u"/// CHECK" + ToUnicode(variant) + u": " + ToUnicode(string))
     checkerFile = ParseCheckerStream("<test-file>", "CHECK", io.StringIO(checkerText))
     self.assertEqual(len(checkerFile.testCases), 1)
     testCase = checkerFile.testCases[0]
@@ -92,17 +93,17 @@
     self.assertEqual(expected, self.parseAssertion(string).toRegex())
 
   def assertEqualsText(self, string, text):
-    self.assertEqual(self.parseExpression(string), RegexExpression.createText(text))
+    self.assertEqual(self.parseExpression(string), TestExpression.createPatternFromPlainText(text))
 
   def assertEqualsPattern(self, string, pattern):
-    self.assertEqual(self.parseExpression(string), RegexExpression.createPattern(pattern))
+    self.assertEqual(self.parseExpression(string), TestExpression.createPattern(pattern))
 
   def assertEqualsVarRef(self, string, name):
-    self.assertEqual(self.parseExpression(string), RegexExpression.createVariableReference(name))
+    self.assertEqual(self.parseExpression(string), TestExpression.createVariableReference(name))
 
   def assertEqualsVarDef(self, string, name, pattern):
     self.assertEqual(self.parseExpression(string),
-                     RegexExpression.createVariableDefinition(name, pattern))
+                     TestExpression.createVariableDefinition(name, pattern))
 
   def assertVariantNotEqual(self, string, variant):
     self.assertNotEqual(variant, self.parseExpression(string).variant)
@@ -166,17 +167,17 @@
     self.assertEqualsVarDef("<<ABC:(a[bc])>>", "ABC", "(a[bc])")
 
   def test_Empty(self):
-    self.assertVariantNotEqual("{{}}", RegexExpression.Variant.Pattern)
-    self.assertVariantNotEqual("<<>>", RegexExpression.Variant.VarRef)
-    self.assertVariantNotEqual("<<:>>", RegexExpression.Variant.VarDef)
+    self.assertEqualsText("{{}}", "{{}}")
+    self.assertVariantNotEqual("<<>>", TestExpression.Variant.VarRef)
+    self.assertVariantNotEqual("<<:>>", TestExpression.Variant.VarDef)
 
   def test_InvalidVarName(self):
-    self.assertVariantNotEqual("<<0ABC>>", RegexExpression.Variant.VarRef)
-    self.assertVariantNotEqual("<<AB=C>>", RegexExpression.Variant.VarRef)
-    self.assertVariantNotEqual("<<ABC=>>", RegexExpression.Variant.VarRef)
-    self.assertVariantNotEqual("<<0ABC:abc>>", RegexExpression.Variant.VarDef)
-    self.assertVariantNotEqual("<<AB=C:abc>>", RegexExpression.Variant.VarDef)
-    self.assertVariantNotEqual("<<ABC=:abc>>", RegexExpression.Variant.VarDef)
+    self.assertVariantNotEqual("<<0ABC>>", TestExpression.Variant.VarRef)
+    self.assertVariantNotEqual("<<AB=C>>", TestExpression.Variant.VarRef)
+    self.assertVariantNotEqual("<<ABC=>>", TestExpression.Variant.VarRef)
+    self.assertVariantNotEqual("<<0ABC:abc>>", TestExpression.Variant.VarDef)
+    self.assertVariantNotEqual("<<AB=C:abc>>", TestExpression.Variant.VarDef)
+    self.assertVariantNotEqual("<<ABC=:abc>>", TestExpression.Variant.VarDef)
 
   def test_BodyMatchNotGreedy(self):
     self.assertEqualsRegex("{{abc}}{{def}}", "(abc)(def)")
@@ -201,7 +202,7 @@
         content = assertionEntry[0]
         variant = assertionEntry[1]
         assertion = TestAssertion(testCase, variant, content, 0)
-        assertion.addExpression(RegexExpression.createText(content))
+        assertion.addExpression(TestExpression.createPatternFromPlainText(content))
     return testFile
 
   def assertParsesTo(self, checkerText, expectedData):
@@ -279,9 +280,15 @@
       self.parse(
         """
           /// CHECK-START: Example Group
+          /// CHECK-EVAL: foo
           /// CHECK-NEXT: bar
         """)
-
+    with self.assertRaises(CheckerException):
+      self.parse(
+        """
+          /// CHECK-START: Example Group
+          /// CHECK-NEXT: bar
+        """)
 
 class CheckerParser_ArchTests(unittest.TestCase):
 
@@ -329,3 +336,61 @@
       self.assertEqual(len(checkerFile.testCases), 1)
       self.assertEqual(len(checkerFile.testCasesForArch(arch)), 1)
       self.assertEqual(len(checkerFile.testCases[0].assertions), 4)
+
+
+class CheckerParser_EvalTests(unittest.TestCase):
+  def parseTestCase(self, string):
+    checkerText = u"/// CHECK-START: pass\n" + ToUnicode(string)
+    checkerFile = ParseCheckerStream("<test-file>", "CHECK", io.StringIO(checkerText))
+    self.assertEqual(len(checkerFile.testCases), 1)
+    return checkerFile.testCases[0]
+
+  def parseExpressions(self, string):
+    testCase = self.parseTestCase("/// CHECK-EVAL: " + string)
+    self.assertEqual(len(testCase.assertions), 1)
+    assertion = testCase.assertions[0]
+    self.assertEqual(assertion.variant, TestAssertion.Variant.Eval)
+    self.assertEqual(assertion.originalText, string)
+    return assertion.expressions
+
+  def assertParsesToPlainText(self, text):
+    testCase = self.parseTestCase("/// CHECK-EVAL: " + text)
+    self.assertEqual(len(testCase.assertions), 1)
+    assertion = testCase.assertions[0]
+    self.assertEqual(assertion.variant, TestAssertion.Variant.Eval)
+    self.assertEqual(assertion.originalText, text)
+    self.assertEqual(len(assertion.expressions), 1)
+    expression = assertion.expressions[0]
+    self.assertEqual(expression.variant, TestExpression.Variant.PlainText)
+    self.assertEqual(expression.text, text)
+
+  def test_PlainText(self):
+    self.assertParsesToPlainText("XYZ")
+    self.assertParsesToPlainText("True")
+    self.assertParsesToPlainText("{{abc}}")
+    self.assertParsesToPlainText("<<ABC:abc>>")
+    self.assertParsesToPlainText("<<ABC=>>")
+
+  def test_VariableReference(self):
+    self.assertEqual(self.parseExpressions("<<ABC>>"),
+                     [ TestExpression.createVariableReference("ABC") ])
+    self.assertEqual(self.parseExpressions("123<<ABC>>"),
+                     [ TestExpression.createPlainText("123"),
+                       TestExpression.createVariableReference("ABC") ])
+    self.assertEqual(self.parseExpressions("123  <<ABC>>"),
+                     [ TestExpression.createPlainText("123  "),
+                       TestExpression.createVariableReference("ABC") ])
+    self.assertEqual(self.parseExpressions("<<ABC>>XYZ"),
+                     [ TestExpression.createVariableReference("ABC"),
+                       TestExpression.createPlainText("XYZ") ])
+    self.assertEqual(self.parseExpressions("<<ABC>>   XYZ"),
+                     [ TestExpression.createVariableReference("ABC"),
+                       TestExpression.createPlainText("   XYZ") ])
+    self.assertEqual(self.parseExpressions("123<<ABC>>XYZ"),
+                     [ TestExpression.createPlainText("123"),
+                       TestExpression.createVariableReference("ABC"),
+                       TestExpression.createPlainText("XYZ") ])
+    self.assertEqual(self.parseExpressions("123 <<ABC>>  XYZ"),
+                     [ TestExpression.createPlainText("123 "),
+                       TestExpression.createVariableReference("ABC"),
+                       TestExpression.createPlainText("  XYZ") ])
diff --git a/tools/checker/match/file.py b/tools/checker/match/file.py
index 42ca7df..6601a1e 100644
--- a/tools/checker/match/file.py
+++ b/tools/checker/match/file.py
@@ -17,7 +17,7 @@
 from common.logger                    import Logger
 from file_format.c1visualizer.struct  import C1visualizerFile, C1visualizerPass
 from file_format.checker.struct       import CheckerFile, TestCase, TestAssertion
-from match.line                       import MatchLines
+from match.line                       import MatchLines, EvaluateLine
 
 MatchScope = namedtuple("MatchScope", ["start", "end"])
 MatchInfo = namedtuple("MatchInfo", ["scope", "variables"])
@@ -94,6 +94,11 @@
       if MatchLines(assertion, line, variables) is not None:
         raise MatchFailedException(assertion, i)
 
+def testEvalGroup(assertions, scope, variables):
+  for assertion in assertions:
+    if not EvaluateLine(assertion, variables):
+      raise MatchFailedException(assertion, scope.start)
+
 def MatchTestCase(testCase, c1Pass):
   """ Runs a test case against a C1visualizer graph dump.
 
@@ -132,11 +137,15 @@
       assert len(assertionGroup) == 1
       scope = MatchScope(matchFrom, matchFrom + 1)
       match = findMatchingLine(assertionGroup[0], c1Pass, scope, variables)
-    else:
+    elif assertionGroup[0].variant == TestAssertion.Variant.DAG:
       # A group of DAG assertions. Match them all starting from the same point.
-      assert assertionGroup[0].variant == TestAssertion.Variant.DAG
       scope = MatchScope(matchFrom, c1Length)
       match = matchDagGroup(assertionGroup, c1Pass, scope, variables)
+    else:
+      assert assertionGroup[0].variant == TestAssertion.Variant.Eval
+      scope = MatchScope(matchFrom, c1Length)
+      testEvalGroup(assertionGroup, scope, variables)
+      continue
 
     if pendingNotAssertions:
       # Previous group were NOT assertions. Make sure they don't match any lines
diff --git a/tools/checker/match/line.py b/tools/checker/match/line.py
index ce11e2a..08f001f 100644
--- a/tools/checker/match/line.py
+++ b/tools/checker/match/line.py
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 from common.logger              import Logger
-from file_format.checker.struct import RegexExpression
+from file_format.checker.struct import TestExpression, TestAssertion
 
 import re
 
@@ -21,30 +21,40 @@
   return list[0], list[1:]
 
 def splitAtSeparators(expressions):
-  """ Splits a list of RegexExpressions at separators. """
+  """ Splits a list of TestExpressions at separators. """
   splitExpressions = []
   wordStart = 0
   for index, expression in enumerate(expressions):
-    if expression.variant == RegexExpression.Variant.Separator:
+    if expression.variant == TestExpression.Variant.Separator:
       splitExpressions.append(expressions[wordStart:index])
       wordStart = index + 1
   splitExpressions.append(expressions[wordStart:])
   return splitExpressions
 
+def getVariable(name, variables, pos):
+  if name in variables:
+    return variables[name]
+  else:
+    Logger.testFailed("Missing definition of variable \"{}\"".format(name),
+                      pos.fileName, pos.lineNo)
+
+def setVariable(name, value, variables, pos):
+  if name not in variables:
+    return variables.copyWith(name, value)
+  else:
+    Logger.testFailed("Multiple definitions of variable \"{}\"".format(name),
+                      pos.fileName, pos.lineNo)
+
 def matchWords(checkerWord, stringWord, variables, pos):
-  """ Attempts to match a list of RegexExpressions against a string.
+  """ Attempts to match a list of TestExpressions against a string.
       Returns updated variable dictionary if successful and None otherwise.
   """
   for expression in checkerWord:
     # If `expression` is a variable reference, replace it with the value.
-    if expression.variant == RegexExpression.Variant.VarRef:
-      if expression.name in variables:
-        pattern = re.escape(variables[expression.name])
-      else:
-        Logger.testFailed("Missing definition of variable \"{}\"".format(expression.name),
-                          pos.fileName, pos.lineNo)
+    if expression.variant == TestExpression.Variant.VarRef:
+      pattern = re.escape(getVariable(expression.name, variables, pos))
     else:
-      pattern = expression.pattern
+      pattern = expression.text
 
     # Match the expression's regex pattern against the remainder of the word.
     # Note: re.match will succeed only if matched from the beginning.
@@ -53,12 +63,8 @@
       return None
 
     # If `expression` was a variable definition, set the variable's value.
-    if expression.variant == RegexExpression.Variant.VarDef:
-      if expression.name not in variables:
-        variables = variables.copyWith(expression.name, stringWord[:match.end()])
-      else:
-        Logger.testFailed("Multiple definitions of variable \"{}\"".format(expression.name),
-                          pos.fileName, pos.lineNo)
+    if expression.variant == TestExpression.Variant.VarDef:
+      variables = setVariable(expression.name, stringWord[:match.end()], variables, pos)
 
     # Move cursor by deleting the matched characters.
     stringWord = stringWord[match.end():]
@@ -73,11 +79,13 @@
   """ Attempts to match a CHECK line against a string. Returns variable state
       after the match if successful and None otherwise.
   """
+  assert checkerLine.variant != TestAssertion.Variant.Eval
+
   checkerWords = splitAtSeparators(checkerLine.expressions)
   stringWords = stringLine.split()
 
   while checkerWords:
-    # Get the next run of RegexExpressions which must match one string word.
+    # Get the next run of TestExpressions which must match one string word.
     checkerWord, checkerWords = headAndTail(checkerWords)
 
     # Keep reading words until a match is found.
@@ -92,5 +100,18 @@
     if not wordMatched:
       return None
 
-  # All RegexExpressions matched. Return new variable state.
+  # All TestExpressions matched. Return new variable state.
   return variables
+
+def getEvalText(expression, variables, pos):
+  if expression.variant == TestExpression.Variant.PlainText:
+    return expression.text
+  else:
+    assert expression.variant == TestExpression.Variant.VarRef
+    return getVariable(expression.name, variables, pos)
+
+def EvaluateLine(checkerLine, variables):
+  assert checkerLine.variant == TestAssertion.Variant.Eval
+  eval_string = "".join(map(lambda expr: getEvalText(expr, variables, checkerLine),
+                            checkerLine.expressions))
+  return eval(eval_string)
diff --git a/tools/checker/match/test.py b/tools/checker/match/test.py
index ca748c7..5144ca9 100644
--- a/tools/checker/match/test.py
+++ b/tools/checker/match/test.py
@@ -17,7 +17,7 @@
 from file_format.c1visualizer.parser import ParseC1visualizerStream
 from file_format.c1visualizer.struct import C1visualizerFile, C1visualizerPass
 from file_format.checker.parser      import ParseCheckerStream, ParseCheckerAssertion
-from file_format.checker.struct      import CheckerFile, TestCase, TestAssertion, RegexExpression
+from file_format.checker.struct      import CheckerFile, TestCase, TestAssertion
 from match.file                      import MatchTestCase, MatchFailedException
 from match.line                      import MatchLines
 
@@ -386,3 +386,17 @@
       abc
       bar
     """)
+
+  def test_EvalAssertions(self):
+    self.assertMatches("/// CHECK-EVAL: True", "foo")
+    self.assertDoesNotMatch("/// CHECK-EVAL: False", "foo")
+
+    self.assertMatches("/// CHECK-EVAL: 1 + 2 == 3", "foo")
+    self.assertDoesNotMatch("/// CHECK-EVAL: 1 + 2 == 4", "foo")
+
+    twoVarTestCase = """
+                       /// CHECK-DAG: <<X:\d+>> <<Y:\d+>>
+                       /// CHECK-EVAL: <<X>> > <<Y>>
+                     """
+    self.assertMatches(twoVarTestCase, "42 41");
+    self.assertDoesNotMatch(twoVarTestCase, "42 43")
diff --git a/tools/checker/run_unit_tests.py b/tools/checker/run_unit_tests.py
index 2f5b1fe..2e8f208 100755
--- a/tools/checker/run_unit_tests.py
+++ b/tools/checker/run_unit_tests.py
@@ -17,9 +17,10 @@
 from common.logger                 import Logger
 from file_format.c1visualizer.test import C1visualizerParser_Test
 from file_format.checker.test      import CheckerParser_PrefixTest, \
-                                          CheckerParser_RegexExpressionTest, \
+                                          CheckerParser_TestExpressionTest, \
                                           CheckerParser_FileLayoutTest, \
-                                          CheckerParser_ArchTests
+                                          CheckerParser_ArchTests, \
+                                          CheckerParser_EvalTests
 from match.test                    import MatchLines_Test, \
                                           MatchFiles_Test
 
diff --git a/tools/setup-buildbot-device.sh b/tools/setup-buildbot-device.sh
index 7faf86e..8466bb3 100755
--- a/tools/setup-buildbot-device.sh
+++ b/tools/setup-buildbot-device.sh
@@ -30,3 +30,6 @@
 
 echo -e "${green}List properties${nc}"
 adb shell getprop
+
+echo -e "${green}Stopping framework${nc}"
+adb shell stop