Merge "Trampoline and assembly fixes for ARM64"
diff --git a/compiler/dex/local_value_numbering.cc b/compiler/dex/local_value_numbering.cc
index 45167a8..8dbc2bb 100644
--- a/compiler/dex/local_value_numbering.cc
+++ b/compiler/dex/local_value_numbering.cc
@@ -482,9 +482,9 @@
     case Instruction::SHL_INT_LIT8:
     case Instruction::SHR_INT_LIT8:
     case Instruction::USHR_INT_LIT8: {
-        // Same as res = op + 2 operands, except use vB as operand 2
+        // Same as res = op + 2 operands, except use vC as operand 2
         uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
-        uint16_t operand2 = LookupValue(Instruction::CONST, mir->dalvikInsn.vB, 0, 0);
+        uint16_t operand2 = LookupValue(Instruction::CONST, mir->dalvikInsn.vC, 0, 0);
         res = LookupValue(opcode, operand1, operand2, NO_VALUE);
         SetOperandValue(mir->ssa_rep->defs[0], res);
       }
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index 34f140b..8ce4f1f 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -766,7 +766,7 @@
   for (idx = 0; idx < num_blocks; idx++) {
     int block_idx = all_blocks ? idx : dfs_order_->Get(idx);
     BasicBlock *bb = GetBasicBlock(block_idx);
-    if (bb == NULL) break;
+    if (bb == NULL) continue;
     if (bb->block_type == kDead) continue;
     if (bb->block_type == kEntryBlock) {
       fprintf(file, "  entry_%d [shape=Mdiamond];\n", bb->id);
@@ -838,21 +838,19 @@
       fprintf(file, "  %s:s -> succ%04x_%d:n [style=dashed]\n",
               block_name1, bb->start_offset, bb->id);
 
-      if (bb->successor_block_list_type == kPackedSwitch ||
-          bb->successor_block_list_type == kSparseSwitch) {
-        GrowableArray<SuccessorBlockInfo*>::Iterator iter(bb->successor_blocks);
+      // Link the successor pseudo-block with all of its potential targets.
+      GrowableArray<SuccessorBlockInfo*>::Iterator iter(bb->successor_blocks);
 
-        succ_id = 0;
-        while (true) {
-          SuccessorBlockInfo *successor_block_info = iter.Next();
-          if (successor_block_info == NULL) break;
+      succ_id = 0;
+      while (true) {
+        SuccessorBlockInfo *successor_block_info = iter.Next();
+        if (successor_block_info == NULL) break;
 
-          BasicBlock* dest_block = GetBasicBlock(successor_block_info->block);
+        BasicBlock* dest_block = GetBasicBlock(successor_block_info->block);
 
-          GetBlockName(dest_block, block_name2);
-          fprintf(file, "  succ%04x_%d:f%d:e -> %s:n\n", bb->start_offset,
-                  bb->id, succ_id++, block_name2);
-        }
+        GetBlockName(dest_block, block_name2);
+        fprintf(file, "  succ%04x_%d:f%d:e -> %s:n\n", bb->start_offset,
+                bb->id, succ_id++, block_name2);
       }
     }
     fprintf(file, "\n");
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 5078182..6824183 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -579,37 +579,51 @@
   image_writer->FixupObject(obj, copy);
 }
 
+class FixupVisitor {
+ public:
+  FixupVisitor(ImageWriter* image_writer, Object* copy) : image_writer_(image_writer), copy_(copy) {
+  }
+
+  void operator()(Object* obj, MemberOffset offset, bool /*is_static*/) const
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) {
+    Object* ref = obj->GetFieldObject<Object, kVerifyNone>(offset, false);
+    // Use SetFieldObjectWithoutWriteBarrier to avoid card marking since we are writing to the
+    // image.
+    copy_->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(
+        offset, image_writer_->GetImageAddress(ref), false);
+  }
+
+  // java.lang.ref.Reference visitor.
+  void operator()(mirror::Class* /*klass*/, mirror::Reference* ref) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
+    copy_->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(
+        mirror::Reference::ReferentOffset(), image_writer_->GetImageAddress(ref->GetReferent()),
+        false);
+  }
+
+ private:
+  ImageWriter* const image_writer_;
+  mirror::Object* const copy_;
+};
+
 void ImageWriter::FixupObject(Object* orig, Object* copy) {
-  DCHECK(orig != NULL);
-  DCHECK(copy != NULL);
-  copy->SetClass<kVerifyNone>(down_cast<Class*>(GetImageAddress(orig->GetClass())));
+  DCHECK(orig != nullptr);
+  DCHECK(copy != nullptr);
   if (kUseBrooksPointer) {
     orig->AssertSelfBrooksPointer();
     // Note the address 'copy' isn't the same as the image address of 'orig'.
     copy->SetBrooksPointer(GetImageAddress(orig));
-    DCHECK(copy->GetBrooksPointer() == GetImageAddress(orig));
+    DCHECK_EQ(copy->GetBrooksPointer(), GetImageAddress(orig));
   }
-  // TODO: special case init of pointers to malloc data (or removal of these pointers)
-  if (orig->IsClass<kVerifyNone>()) {
-    FixupClass(orig->AsClass<kVerifyNone>(), down_cast<Class*>(copy));
-  } else if (orig->IsObjectArray<kVerifyNone>()) {
-    FixupObjectArray(orig->AsObjectArray<Object, kVerifyNone>(),
-                     down_cast<ObjectArray<Object>*>(copy));
-  } else if (orig->IsArtMethod<kVerifyNone>()) {
+  FixupVisitor visitor(this, copy);
+  orig->VisitReferences<true /*visit class*/>(visitor, visitor);
+  if (orig->IsArtMethod<kVerifyNone>()) {
     FixupMethod(orig->AsArtMethod<kVerifyNone>(), down_cast<ArtMethod*>(copy));
-  } else {
-    FixupInstanceFields(orig, copy);
   }
 }
 
-void ImageWriter::FixupClass(Class* orig, Class* copy) {
-  FixupInstanceFields(orig, copy);
-  FixupStaticFields(orig, copy);
-}
-
 void ImageWriter::FixupMethod(ArtMethod* orig, ArtMethod* copy) {
-  FixupInstanceFields(orig, copy);
-
   // OatWriter replaces the code_ with an offset value. Here we re-adjust to a pointer relative to
   // oat_begin_
 
@@ -680,79 +694,6 @@
   }
 }
 
-void ImageWriter::FixupObjectArray(ObjectArray<Object>* orig, ObjectArray<Object>* copy) {
-  for (int32_t i = 0; i < orig->GetLength(); ++i) {
-    Object* element = orig->Get(i);
-    copy->SetWithoutChecksAndWriteBarrier<false, true, kVerifyNone>(i, GetImageAddress(element));
-  }
-}
-
-void ImageWriter::FixupInstanceFields(Object* orig, Object* copy) {
-  DCHECK(orig != NULL);
-  DCHECK(copy != NULL);
-  Class* klass = orig->GetClass();
-  DCHECK(klass != NULL);
-  FixupFields(orig, copy, klass->GetReferenceInstanceOffsets(), false);
-}
-
-void ImageWriter::FixupStaticFields(Class* orig, Class* copy) {
-  DCHECK(orig != NULL);
-  DCHECK(copy != NULL);
-  FixupFields(orig, copy, orig->GetReferenceStaticOffsets(), true);
-}
-
-void ImageWriter::FixupFields(Object* orig,
-                              Object* copy,
-                              uint32_t ref_offsets,
-                              bool is_static) {
-  if (ref_offsets != CLASS_WALK_SUPER) {
-    // Found a reference offset bitmap.  Fixup the specified offsets.
-    while (ref_offsets != 0) {
-      size_t right_shift = CLZ(ref_offsets);
-      MemberOffset byte_offset = CLASS_OFFSET_FROM_CLZ(right_shift);
-      Object* ref = orig->GetFieldObject<Object, kVerifyNone>(byte_offset, false);
-      // Use SetFieldObjectWithoutWriteBarrier to avoid card marking since we are writing to the
-      // image.
-      copy->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(
-          byte_offset, GetImageAddress(ref), false);
-      ref_offsets &= ~(CLASS_HIGH_BIT >> right_shift);
-    }
-  } else {
-    // There is no reference offset bitmap.  In the non-static case,
-    // walk up the class inheritance hierarchy and find reference
-    // offsets the hard way. In the static case, just consider this
-    // class.
-    for (Class *klass = is_static ? orig->AsClass() : orig->GetClass();
-         klass != NULL;
-         klass = is_static ? NULL : klass->GetSuperClass()) {
-      size_t num_reference_fields = (is_static
-                                     ? klass->NumReferenceStaticFields()
-                                     : klass->NumReferenceInstanceFields());
-      for (size_t i = 0; i < num_reference_fields; ++i) {
-        ArtField* field = (is_static
-                           ? klass->GetStaticField(i)
-                           : klass->GetInstanceField(i));
-        MemberOffset field_offset = field->GetOffset();
-        Object* ref = orig->GetFieldObject<Object, kVerifyNone>(field_offset, false);
-        // Use SetFieldObjectWithoutWriteBarrier to avoid card marking since we are writing to the
-        // image.
-        copy->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(
-            field_offset, GetImageAddress(ref), false);
-      }
-    }
-  }
-  if (!is_static && orig->IsReferenceInstance()) {
-    // Fix-up referent, that isn't marked as an object field, for References.
-    ArtField* field = orig->GetClass()->FindInstanceField("referent", "Ljava/lang/Object;");
-    MemberOffset field_offset = field->GetOffset();
-    Object* ref = orig->GetFieldObject<Object>(field_offset, false);
-    // Use SetFieldObjectWithoutWriteBarrier to avoid card marking since we are writing to the
-    // image.
-    copy->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(
-        field_offset, GetImageAddress(ref), false);
-  }
-}
-
 static ArtMethod* GetTargetMethod(const CompilerDriver::CallPatchInformation* patch)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
diff --git a/compiler/image_writer.h b/compiler/image_writer.h
index dff33ba..92b24f6 100644
--- a/compiler/image_writer.h
+++ b/compiler/image_writer.h
@@ -141,22 +141,10 @@
   void CopyAndFixupObjects();
   static void CopyAndFixupObjectsCallback(mirror::Object* obj, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void FixupClass(mirror::Class* orig, mirror::Class* copy)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void FixupMethod(mirror::ArtMethod* orig, mirror::ArtMethod* copy)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void FixupObject(mirror::Object* orig, mirror::Object* copy)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void FixupObjectArray(mirror::ObjectArray<mirror::Object>* orig,
-                        mirror::ObjectArray<mirror::Object>* copy)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void FixupInstanceFields(mirror::Object* orig, mirror::Object* copy)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void FixupStaticFields(mirror::Class* orig, mirror::Class* copy)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void FixupFields(mirror::Object* orig, mirror::Object* copy, uint32_t ref_offsets,
-                   bool is_static)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Patches references in OatFile to expect runtime addresses.
   void PatchOatCodeAndMethods()
@@ -164,7 +152,6 @@
   void SetPatchLocation(const CompilerDriver::PatchInformation* patch, uint32_t value)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-
   const CompilerDriver& compiler_driver_;
 
   // oat file with code for this image
@@ -199,6 +186,9 @@
   uint32_t quick_imt_conflict_trampoline_offset_;
   uint32_t quick_resolution_trampoline_offset_;
   uint32_t quick_to_interpreter_bridge_offset_;
+
+  friend class FixupVisitor;
+  DISALLOW_COPY_AND_ASSIGN(ImageWriter);
 };
 
 }  // namespace art