Revert "Revert "ART: Implement literal pool for arm, fix branch fixup.""

This reverts commit fbeb4aede0ddc5b1e6a5a3a40cc6266fe8518c98.

Adjust block label positions. Bad catch block labels were the
reason for the revert.

Change-Id: Ia6950d639d46b9da6b07f3ade63ab46d03d63310
diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h
index 2382b74..5e6969b 100644
--- a/compiler/utils/arm/assembler_thumb2.h
+++ b/compiler/utils/arm/assembler_thumb2.h
@@ -17,6 +17,7 @@
 #ifndef ART_COMPILER_UTILS_ARM_ASSEMBLER_THUMB2_H_
 #define ART_COMPILER_UTILS_ARM_ASSEMBLER_THUMB2_H_
 
+#include <deque>
 #include <vector>
 
 #include "base/logging.h"
@@ -34,13 +35,15 @@
       : can_relocate_branches_(can_relocate_branches),
         force_32bit_(false),
         it_cond_index_(kNoItCondition),
-        next_condition_(AL) {
+        next_condition_(AL),
+        fixups_(),
+        literals_(),
+        last_position_adjustment_(0u),
+        last_old_position_(0u),
+        last_fixup_id_(0u) {
   }
 
   virtual ~Thumb2Assembler() {
-    for (auto& branch : branches_) {
-      delete branch;
-    }
   }
 
   bool IsThumb() const OVERRIDE {
@@ -55,10 +58,7 @@
     return can_relocate_branches_;
   }
 
-  void FinalizeInstructions(const MemoryRegion& region) OVERRIDE {
-    EmitBranches();
-    Assembler::FinalizeInstructions(region);
-  }
+  void FinalizeCode() OVERRIDE;
 
   // Data-processing instructions.
   void and_(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE;
@@ -238,7 +238,6 @@
 
   // Branch instructions.
   void b(Label* label, Condition cond = AL);
-  void b(NearLabel* label, Condition cond = AL);
   void bl(Label* label, Condition cond = AL);
   void blx(Label* label);
   void blx(Register rm, Condition cond = AL) OVERRIDE;
@@ -273,13 +272,23 @@
   void Mov(Register rd, Register rm, Condition cond = AL) OVERRIDE;
 
   void CompareAndBranchIfZero(Register r, Label* label) OVERRIDE;
-  void CompareAndBranchIfZero(Register r, NearLabel* label) OVERRIDE;
   void CompareAndBranchIfNonZero(Register r, Label* label) OVERRIDE;
 
   // Memory barriers.
   void dmb(DmbOptions flavor) OVERRIDE;
 
-  // Macros.
+  // Get the final position of a label after local fixup based on the old position
+  // recorded before FinalizeCode().
+  uint32_t GetAdjustedPosition(uint32_t old_position) OVERRIDE;
+
+  using ArmAssembler::NewLiteral;  // Make the helper template visible.
+
+  Literal* NewLiteral(size_t size, const uint8_t* data) OVERRIDE;
+  void LoadLiteral(Register rt, Literal* literal) OVERRIDE;
+  void LoadLiteral(Register rt, Register rt2, Literal* literal) OVERRIDE;
+  void LoadLiteral(SRegister sd, Literal* literal) OVERRIDE;
+  void LoadLiteral(DRegister dd, Literal* literal) OVERRIDE;
+
   // Add signed constant value to rd. May clobber IP.
   void AddConstant(Register rd, int32_t value, Condition cond = AL) OVERRIDE;
   void AddConstant(Register rd, Register rn, int32_t value,
@@ -340,6 +349,244 @@
   }
 
  private:
+  typedef uint16_t FixupId;
+
+  // Fixup: branches and literal pool references.
+  //
+  // The thumb2 architecture allows branches to be either 16 or 32 bit instructions. This
+  // depends on both the type of branch and the offset to which it is branching. The 16-bit
+  // cbz and cbnz instructions may also need to be replaced with a separate 16-bit compare
+  // instruction and a 16- or 32-bit branch instruction. Load from a literal pool can also be
+  // 16-bit or 32-bit instruction and, if the method is large, we may need to use a sequence
+  // of instructions to make up for the limited range of load literal instructions (up to
+  // 4KiB for the 32-bit variant). When generating code for these insns we don't know the
+  // size before hand, so we assume it is the smallest available size and determine the final
+  // code offsets and sizes and emit code in FinalizeCode().
+  //
+  // To handle this, we keep a record of every branch and literal pool load in the program.
+  // The actual instruction encoding for these is delayed until we know the final size of
+  // every instruction. When we bind a label to a branch we don't know the final location yet
+  // as some preceding instructions may need to be expanded, so we record a non-final offset.
+  // In FinalizeCode(), we expand the sizes of branches and literal loads that are out of
+  // range. With each expansion, we need to update dependent Fixups, i.e. insntructios with
+  // target on the other side of the expanded insn, as their offsets change and this may
+  // trigger further expansion.
+  //
+  // All Fixups have a 'fixup id' which is a 16 bit unsigned number used to identify the
+  // Fixup. For each unresolved label we keep a singly-linked list of all Fixups pointing
+  // to it, using the fixup ids as links. The first link is stored in the label's position
+  // (the label is linked but not bound), the following links are stored in the code buffer,
+  // in the placeholder where we will eventually emit the actual code.
+
+  class Fixup {
+   public:
+    // Branch type.
+    enum Type : uint8_t {
+      kConditional,               // B<cond>.
+      kUnconditional,             // B.
+      kUnconditionalLink,         // BL.
+      kUnconditionalLinkX,        // BLX.
+      kCompareAndBranchXZero,     // cbz/cbnz.
+      kLoadLiteralNarrow,         // Load narrrow integer literal.
+      kLoadLiteralWide,           // Load wide integer literal.
+      kLoadFPLiteralSingle,       // Load FP literal single.
+      kLoadFPLiteralDouble,       // Load FP literal double.
+    };
+
+    // Calculated size of branch instruction based on type and offset.
+    enum Size : uint8_t {
+      // Branch variants.
+      kBranch16Bit,
+      kBranch32Bit,
+      // NOTE: We don't support branches which would require multiple instructions, i.e.
+      // conditinoal branches beyond +-1MiB and unconditional branches beyond +-16MiB.
+
+      // CBZ/CBNZ variants.
+      kCbxz16Bit,   // CBZ/CBNZ rX, label; X < 8; 7-bit positive offset.
+      kCbxz32Bit,   // CMP rX, #0 + Bcc label; X < 8; 16-bit Bcc; +-8-bit offset.
+      kCbxz48Bit,   // CMP rX, #0 + Bcc label; X < 8; 32-bit Bcc; up to +-1MiB offset.
+
+      // Load integer literal variants.
+      // LDR rX, label; X < 8; 16-bit variant up to 1KiB offset; 2 bytes.
+      kLiteral1KiB,
+      // LDR rX, label; 32-bit variant up to 4KiB offset; 4 bytes.
+      kLiteral4KiB,
+      // MOV rX, imm16 + ADD rX, pc + LDR rX, [rX]; X < 8; up to 64KiB offset; 8 bytes.
+      kLiteral64KiB,
+      // MOV rX, modimm + ADD rX, pc + LDR rX, [rX, #imm12]; up to 1MiB offset; 10 bytes.
+      kLiteral1MiB,
+      // NOTE: We don't provide the 12-byte version of kLiteralFar below where the LDR is 16-bit.
+      // MOV rX, imm16 + MOVT rX, imm16 + ADD rX, pc + LDR rX, [rX]; any offset; 14 bytes.
+      kLiteralFar,
+
+      // Load long or FP literal variants.
+      // VLDR s/dX, label; 32-bit insn, up to 1KiB offset; 4 bytes.
+      kLongOrFPLiteral1KiB,
+      // MOV ip, modimm + ADD ip, pc + VLDR s/dX, [IP, #imm8*4]; up to 256KiB offset; 10 bytes.
+      kLongOrFPLiteral256KiB,
+      // MOV ip, imm16 + MOVT ip, imm16 + ADD ip, pc + VLDR s/dX, [IP]; any offset; 14 bytes.
+      kLongOrFPLiteralFar,
+    };
+
+    // Unresolved branch possibly with a condition.
+    static Fixup Branch(uint32_t location, Type type, Size size = kBranch16Bit,
+                        Condition cond = AL) {
+      DCHECK(type == kConditional || type == kUnconditional ||
+             type == kUnconditionalLink || type == kUnconditionalLinkX);
+      DCHECK(size == kBranch16Bit || size == kBranch32Bit);
+      DCHECK(size == kBranch32Bit || (type == kConditional || type == kUnconditional));
+      return Fixup(kNoRegister, kNoRegister, kNoSRegister, kNoDRegister,
+                   cond, type, size, location);
+    }
+
+    // Unresolved compare-and-branch instruction with a register and condition (EQ or NE).
+    static Fixup CompareAndBranch(uint32_t location, Register rn, Condition cond) {
+      DCHECK(cond == EQ || cond == NE);
+      return Fixup(rn, kNoRegister, kNoSRegister, kNoDRegister,
+                   cond, kCompareAndBranchXZero, kCbxz16Bit, location);
+    }
+
+    // Load narrow literal.
+    static Fixup LoadNarrowLiteral(uint32_t location, Register rt, Size size = kLiteral1KiB) {
+      DCHECK(size == kLiteral1KiB || size == kLiteral4KiB || size == kLiteral64KiB ||
+             size == kLiteral1MiB || size == kLiteralFar);
+      DCHECK(!IsHighRegister(rt) || (size != kLiteral1KiB && size != kLiteral64KiB));
+      return Fixup(rt, kNoRegister, kNoSRegister, kNoDRegister,
+                   AL, kLoadLiteralNarrow, size, location);
+    }
+
+    // Load wide literal.
+    static Fixup LoadWideLiteral(uint32_t location, Register rt, Register rt2,
+                                 Size size = kLongOrFPLiteral1KiB) {
+      DCHECK(size == kLongOrFPLiteral1KiB || size == kLongOrFPLiteral256KiB ||
+             size == kLongOrFPLiteralFar);
+      DCHECK(!IsHighRegister(rt) || (size != kLiteral1KiB && size != kLiteral64KiB));
+      return Fixup(rt, rt2, kNoSRegister, kNoDRegister,
+                   AL, kLoadLiteralWide, size, location);
+    }
+
+    // Load FP single literal.
+    static Fixup LoadSingleLiteral(uint32_t location, SRegister sd,
+                                   Size size = kLongOrFPLiteral1KiB) {
+      DCHECK(size == kLongOrFPLiteral1KiB || size == kLongOrFPLiteral256KiB ||
+             size == kLongOrFPLiteralFar);
+      return Fixup(kNoRegister, kNoRegister, sd, kNoDRegister,
+                   AL, kLoadFPLiteralSingle, size, location);
+    }
+
+    // Load FP double literal.
+    static Fixup LoadDoubleLiteral(uint32_t location, DRegister dd,
+                                   Size size = kLongOrFPLiteral1KiB) {
+      DCHECK(size == kLongOrFPLiteral1KiB || size == kLongOrFPLiteral256KiB ||
+             size == kLongOrFPLiteralFar);
+      return Fixup(kNoRegister, kNoRegister, kNoSRegister, dd,
+                   AL, kLoadFPLiteralDouble, size, location);
+    }
+
+    Type GetType() const {
+      return type_;
+    }
+
+    Size GetOriginalSize() const {
+      return original_size_;
+    }
+
+    Size GetSize() const {
+      return size_;
+    }
+
+    uint32_t GetOriginalSizeInBytes() const;
+
+    uint32_t GetSizeInBytes() const;
+
+    uint32_t GetLocation() const {
+      return location_;
+    }
+
+    uint32_t GetAdjustment() const {
+      return adjustment_;
+    }
+
+    const std::vector<FixupId>& Dependents() const {
+      return dependents_;
+    }
+
+    void AddDependent(FixupId dependent_id) {
+      dependents_.push_back(dependent_id);
+    }
+
+    // Resolve a branch when the target is known.
+    void Resolve(uint32_t target) {
+      DCHECK_EQ(target_, kUnresolved);
+      DCHECK_NE(target, kUnresolved);
+      target_ = target;
+    }
+
+    // Check if the current size is OK for current location_, target_ and adjustment_.
+    // If not, increase the size. Return the size increase, 0 if unchanged.
+    // If the target if after this Fixup, also add the difference to adjustment_,
+    // so that we don't need to consider forward Fixups as their own dependencies.
+    uint32_t AdjustSizeIfNeeded(uint32_t current_code_size);
+
+    // Increase adjustments. This is called for dependents of a Fixup when its size changes.
+    void IncreaseAdjustment(uint32_t increase) {
+      adjustment_ += increase;
+    }
+
+    // Finalize the branch with an adjustment to the location. Both location and target are updated.
+    void Finalize(uint32_t location_adjustment) {
+      DCHECK_NE(target_, kUnresolved);
+      location_ += location_adjustment;
+      target_ += location_adjustment;
+    }
+
+    // Emit the branch instruction into the assembler buffer.  This does the
+    // encoding into the thumb instruction.
+    void Emit(AssemblerBuffer* buffer, uint32_t code_size) const;
+
+   private:
+    Fixup(Register rn, Register rt2, SRegister sd, DRegister dd,
+          Condition cond, Type type, Size size, uint32_t location)
+        : rn_(rn),
+          rt2_(rt2),
+          sd_(sd),
+          dd_(dd),
+          cond_(cond),
+          type_(type),
+          original_size_(size), size_(size),
+          location_(location),
+          target_(kUnresolved),
+          adjustment_(0u),
+          dependents_() {
+    }
+    static size_t SizeInBytes(Size size);
+
+    // The size of padding added before the literal pool.
+    static size_t LiteralPoolPaddingSize(uint32_t current_code_size);
+
+    // Returns the offset from the PC-using insn to the target.
+    int32_t GetOffset(uint32_t current_code_size) const;
+
+    size_t IncreaseSize(Size new_size);
+
+    int32_t LoadWideOrFpEncoding(Register rbase, int32_t offset) const;
+
+    static constexpr uint32_t kUnresolved = 0xffffffff;     // Value for target_ for unresolved.
+
+    const Register rn_;   // Rn for cbnz/cbz, Rt for literal loads.
+    Register rt2_;        // For kLoadLiteralWide.
+    SRegister sd_;        // For kLoadFPLiteralSingle.
+    DRegister dd_;        // For kLoadFPLiteralDouble.
+    const Condition cond_;
+    const Type type_;
+    Size original_size_;
+    Size size_;
+    uint32_t location_;     // Offset into assembler buffer in bytes.
+    uint32_t target_;       // Offset into assembler buffer in bytes.
+    uint32_t adjustment_;   // The number of extra bytes inserted between location_ and target_.
+    std::vector<FixupId> dependents_;  // Fixups that require adjustment when current size changes.
+  };
+
   // Emit a single 32 or 16 bit data processing instruction.
   void EmitDataProcessing(Condition cond,
                           Opcode opcode,
@@ -432,7 +679,7 @@
 
   void EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond);
 
-  void EmitBranch(Condition cond, Label* label, bool link, bool x, bool is_near = false);
+  void EmitBranch(Condition cond, Label* label, bool link, bool x);
   static int32_t EncodeBranchOffset(int32_t offset, int32_t inst);
   static int DecodeBranchOffset(int32_t inst);
   int32_t EncodeTstOffset(int offset, int32_t inst);
@@ -475,275 +722,53 @@
     CheckCondition(cond);
   }
 
-  // Branches.
-  //
-  // The thumb2 architecture allows branches to be either 16 or 32 bit instructions.  This
-  // depends on both the type of branch and the offset to which it is branching.  When
-  // generating code for branches we don't know the size before hand (if the branch is
-  // going forward, because we haven't seen the target address yet), so we need to assume
-  // that it is going to be one of 16 or 32 bits.  When we know the target (the label is 'bound')
-  // we can determine the actual size of the branch.  However, if we had guessed wrong before
-  // we knew the target there will be no room in the instruction sequence for the new
-  // instruction (assume that we never decrease the size of a branch).
-  //
-  // To handle this, we keep a record of every branch in the program.  The actual instruction
-  // encoding for these is delayed until we know the final size of every branch.  When we
-  // bind a label to a branch (we then know the target address) we determine if the branch
-  // has changed size.  If it has we need to move all the instructions in the buffer after
-  // the branch point forward by the change in size of the branch.  This will create a gap
-  // in the code big enough for the new branch encoding.  However, since we have moved
-  // a chunk of code we need to relocate the branches in that code to their new address.
-  //
-  // Creating a hole in the code for the new branch encoding might cause another branch that was
-  // 16 bits to become 32 bits, so we need to find this in another pass.
-  //
-  // We also need to deal with a cbz/cbnz instruction that becomes too big for its offset
-  // range.  We do this by converting it to two instructions:
-  //     cmp Rn, #0
-  //     b<cond> target
-  // But we also need to handle the case where the conditional branch is out of range and
-  // becomes a 32 bit conditional branch.
-  //
-  // All branches have a 'branch id' which is a 16 bit unsigned number used to identify
-  // the branch.  Unresolved labels use the branch id to link to the next unresolved branch.
-
-  class Branch {
-   public:
-    // Branch type.
-    enum Type {
-      kUnconditional,             // B.
-      kConditional,               // B<cond>.
-      kCompareAndBranchZero,      // cbz.
-      kCompareAndBranchNonZero,   // cbnz.
-      kUnconditionalLink,         // BL.
-      kUnconditionalLinkX,        // BLX.
-      kUnconditionalX             // BX.
-    };
-
-    // Calculated size of branch instruction based on type and offset.
-    enum Size {
-      k16Bit,
-      k32Bit
-    };
-
-    // Unresolved branch possibly with a condition.
-    Branch(const Thumb2Assembler* assembler, Type type, uint32_t location, Condition cond = AL) :
-        assembler_(assembler), type_(type), location_(location),
-        target_(kUnresolved),
-        cond_(cond), rn_(R0) {
-      CHECK(!IsCompareAndBranch());
-      size_ = CalculateSize();
-    }
-
-    // Unresolved compare-and-branch instruction with a register.
-    Branch(const Thumb2Assembler* assembler, Type type, uint32_t location, Register rn) :
-        assembler_(assembler), type_(type), location_(location),
-        target_(kUnresolved), cond_(AL), rn_(rn) {
-      CHECK(IsCompareAndBranch());
-      size_ = CalculateSize();
-    }
-
-    // Resolved branch (can't be compare-and-branch) with a target and possibly a condition.
-    Branch(const Thumb2Assembler* assembler, Type type, uint32_t location, uint32_t target,
-           Condition cond = AL) :
-           assembler_(assembler), type_(type), location_(location),
-           target_(target), cond_(cond), rn_(R0) {
-      CHECK(!IsCompareAndBranch());
-      // Resolved branch.
-      size_ = CalculateSize();
-    }
-
-    bool IsCompareAndBranch() const {
-      return type_ == kCompareAndBranchNonZero || type_ == kCompareAndBranchZero;
-    }
-
-    // Resolve a branch when the target is known.  If this causes the
-    // size of the branch to change return true.  Otherwise return false.
-    bool Resolve(uint32_t target) {
-      uint32_t old_target = target_;
-      target_ = target;
-      if (assembler_->CanRelocateBranches()) {
-        Size new_size = CalculateSize();
-        if (size_ != new_size) {
-          size_ = new_size;
-          return true;
-        }
-        return false;
-      } else {
-        if (kIsDebugBuild) {
-          if (old_target == kUnresolved) {
-            // Check that the size has not increased.
-            DCHECK(!(CalculateSize() == k32Bit && size_ == k16Bit));
-          } else {
-            DCHECK(CalculateSize() == size_);
-          }
-        }
-        return false;
-      }
-    }
-
-    // Move a cbz/cbnz branch.  This is always forward.
-    void Move(int32_t delta) {
-      CHECK(IsCompareAndBranch());
-      CHECK_GT(delta, 0);
-      location_ += delta;
-      target_ += delta;
-    }
-
-    // Relocate a branch by a given delta.  This changed the location and
-    // target if they need to be changed.  It also recalculates the
-    // size of the branch instruction.  It returns true if the branch
-    // has changed size.
-    bool Relocate(uint32_t oldlocation, int32_t delta) {
-      DCHECK(assembler_->CanRelocateBranches());
-      if (location_ > oldlocation) {
-        location_ += delta;
-      }
-      if (target_ != kUnresolved) {
-        if (target_ > oldlocation) {
-          target_ += delta;
-        }
-      } else {
-        return false;       // Don't know the size yet.
-      }
-
-      // Calculate the new size.
-      Size new_size = CalculateSize();
-      if (size_ != new_size) {
-        size_ = new_size;
-        return true;
-      }
-      return false;
-    }
-
-    Size GetSize() const {
-      return size_;
-    }
-
-    Type GetType() const {
-      return type_;
-    }
-
-    uint32_t GetLocation() const {
-      return location_;
-    }
-
-    // Emit the branch instruction into the assembler buffer.  This does the
-    // encoding into the thumb instruction.
-    void Emit(AssemblerBuffer* buffer) const;
-
-    // Reset the type and condition to those given.  This used for
-    // cbz/cbnz instructions when they are converted to cmp/b<cond>
-    void ResetTypeAndCondition(Type type, Condition cond) {
-      CHECK(IsCompareAndBranch());
-      CHECK(cond == EQ || cond == NE);
-      type_ = type;
-      cond_ = cond;
-    }
-
-    Register GetRegister() const {
-      return rn_;
-    }
-
-    void ResetSize(Size size) {
-      size_ = size;
-    }
-
-   private:
-    // Calculate the size of the branch instruction based on its type and offset.
-    Size CalculateSize() const {
-      if (target_ == kUnresolved) {
-        if (assembler_->IsForced32Bit() && (type_ == kUnconditional || type_ == kConditional)) {
-          return k32Bit;
-        }
-        if (IsCompareAndBranch()) {
-          // Compare and branch instructions can only be encoded on 16 bits.
-          return k16Bit;
-        }
-        return assembler_->CanRelocateBranches() ? k16Bit : k32Bit;
-      }
-      // When the target is resolved, we know the best encoding for it.
-      int32_t delta = target_ - location_ - 4;
-      if (delta < 0) {
-        delta = -delta;
-      }
-      switch (type_) {
-        case kUnconditional:
-          if (assembler_->IsForced32Bit() || delta >= (1 << 11)) {
-            return k32Bit;
-          } else {
-            return k16Bit;
-          }
-        case kConditional:
-          if (assembler_->IsForced32Bit() || delta >= (1 << 8)) {
-            return k32Bit;
-          } else {
-            return k16Bit;
-          }
-        case kCompareAndBranchZero:
-        case kCompareAndBranchNonZero:
-          if (delta >= (1 << 7)) {
-            return k32Bit;      // Will cause this branch to become invalid.
-          }
-          return k16Bit;
-
-        case kUnconditionalX:
-        case kUnconditionalLinkX:
-          return k16Bit;
-        case kUnconditionalLink:
-          return k32Bit;
-      }
-      LOG(FATAL) << "Cannot reach";
-      return k16Bit;
-    }
-
-    static constexpr uint32_t kUnresolved = 0xffffffff;     // Value for target_ for unresolved.
-    const Thumb2Assembler* assembler_;
-    Type type_;
-    uint32_t location_;     // Offset into assembler buffer in bytes.
-    uint32_t target_;       // Offset into assembler buffer in bytes.
-    Size size_;
-    Condition cond_;
-    const Register rn_;
-  };
-
-  std::vector<Branch*> branches_;
-
-  // Add a resolved branch and return its size.
-  Branch::Size AddBranch(Branch::Type type, uint32_t location, uint32_t target,
-                         Condition cond = AL) {
-    branches_.push_back(new Branch(this, type, location, target, cond));
-    return branches_[branches_.size()-1]->GetSize();
+  FixupId AddFixup(Fixup fixup) {
+    FixupId fixup_id = static_cast<FixupId>(fixups_.size());
+    fixups_.push_back(fixup);
+    // For iterating using FixupId, we need the next id to be representable.
+    DCHECK_EQ(static_cast<size_t>(static_cast<FixupId>(fixups_.size())), fixups_.size());
+    return fixup_id;
   }
 
-  // Add a compare and branch (with a register) and return its id.
-  uint16_t AddBranch(Branch::Type type, uint32_t location, Register rn) {
-    branches_.push_back(new Branch(this, type, location, rn));
-    return branches_.size() - 1;
+  Fixup* GetFixup(FixupId fixup_id) {
+    DCHECK_LT(fixup_id, fixups_.size());
+    return &fixups_[fixup_id];
   }
 
-  // Add an unresolved branch and return its id.
-  uint16_t AddBranch(Branch::Type type,
-                     uint32_t location,
-                     Condition cond = AL,
-                     bool is_near = false) {
-    Branch* branch = new Branch(this, type, location, cond);
-    if (is_near) {
-      branch->ResetSize(Branch::k16Bit);
-    }
-    branches_.push_back(branch);
-    return branches_.size() - 1;
-  }
+  void BindLabel(Label* label, uint32_t bound_pc);
+  void BindLiterals();
+  void AdjustFixupIfNeeded(Fixup* fixup, uint32_t* current_code_size,
+                           std::deque<FixupId>* fixups_to_recalculate);
+  uint32_t AdjustFixups();
+  void EmitFixups(uint32_t adjusted_code_size);
+  void EmitLiterals();
 
-  Branch* GetBranch(uint16_t branchid) {
-    if (branchid >= branches_.size()) {
-      return nullptr;
-    }
-    return branches_[branchid];
-  }
+  static int16_t BEncoding16(int32_t offset, Condition cond);
+  static int32_t BEncoding32(int32_t offset, Condition cond);
+  static int16_t CbxzEncoding16(Register rn, int32_t offset, Condition cond);
+  static int16_t CmpRnImm8Encoding16(Register rn, int32_t value);
+  static int16_t AddRdnRmEncoding16(Register rdn, Register rm);
+  static int32_t MovwEncoding32(Register rd, int32_t value);
+  static int32_t MovtEncoding32(Register rd, int32_t value);
+  static int32_t MovModImmEncoding32(Register rd, int32_t value);
+  static int16_t LdrLitEncoding16(Register rt, int32_t offset);
+  static int32_t LdrLitEncoding32(Register rt, int32_t offset);
+  static int32_t LdrdEncoding32(Register rt, Register rt2, Register rn, int32_t offset);
+  static int32_t VldrsEncoding32(SRegister sd, Register rn, int32_t offset);
+  static int32_t VldrdEncoding32(DRegister dd, Register rn, int32_t offset);
+  static int16_t LdrRtRnImm5Encoding16(Register rt, Register rn, int32_t offset);
+  static int32_t LdrRtRnImm12Encoding(Register rt, Register rn, int32_t offset);
 
-  void EmitBranches();
-  void MakeHoleForBranch(uint32_t location, uint32_t size);
+  std::vector<Fixup> fixups_;
+
+  // Use std::deque<> for literal labels to allow insertions at the end
+  // without invalidating pointers and references to existing elements.
+  std::deque<Literal> literals_;
+
+  // Data for AdjustedPosition(), see the description there.
+  uint32_t last_position_adjustment_;
+  uint32_t last_old_position_;
+  FixupId last_fixup_id_;
 };
 
 }  // namespace arm