Home | History | Annotate | Download | only in arm
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "linker/arm/relative_patcher_thumb2.h"
     18 
     19 #include "arch/arm/instruction_set_features_arm.h"
     20 #include "base/casts.h"
     21 #include "driver/compiler_options.h"
     22 #include "linker/relative_patcher_test.h"
     23 #include "lock_word.h"
     24 #include "mirror/array-inl.h"
     25 #include "mirror/object.h"
     26 #include "oat_quick_method_header.h"
     27 #include "optimizing/code_generator_arm_vixl.h"
     28 #include "optimizing/optimizing_unit_test.h"
     29 
     30 namespace art {
     31 namespace linker {
     32 
     33 class Thumb2RelativePatcherTest : public RelativePatcherTest {
     34  public:
     35   Thumb2RelativePatcherTest() : RelativePatcherTest(InstructionSet::kThumb2, "default") { }
     36 
     37  protected:
     38   static const uint8_t kCallRawCode[];
     39   static const ArrayRef<const uint8_t> kCallCode;
     40   static const uint8_t kNopRawCode[];
     41   static const ArrayRef<const uint8_t> kNopCode;
     42   static const uint8_t kUnpatchedPcRelativeRawCode[];
     43   static const ArrayRef<const uint8_t> kUnpatchedPcRelativeCode;
     44   static const uint32_t kPcInsnOffset;
     45 
     46   // The PC in Thumb mode is 4 bytes after the instruction location.
     47   static constexpr uint32_t kPcAdjustment = 4u;
     48 
     49   // Branches within range [-256, 256) can be created from these by adding the low 8 bits.
     50   static constexpr uint32_t kBlPlus0 = 0xf000f800u;
     51   static constexpr uint32_t kBlMinus256 = 0xf7ffff00u;
     52 
     53   // Special BL values.
     54   static constexpr uint32_t kBlPlusMax = 0xf3ffd7ffu;
     55   static constexpr uint32_t kBlMinusMax = 0xf400d000u;
     56 
     57   // BNE +0, 32-bit, encoding T3. Bits 0-10, 11, 13, 16-21, 26 are placeholder for target offset.
     58   static constexpr uint32_t kBneWPlus0 = 0xf0408000u;
     59 
     60   // LDR immediate, 16-bit, encoding T1. Bits 6-10 are imm5, 0-2 are Rt, 3-5 are Rn.
     61   static constexpr uint32_t kLdrInsn = 0x6800u;
     62 
     63   // LDR immediate, 32-bit, encoding T3. Bits 0-11 are offset, 12-15 are Rt, 16-20 are Rn.
     64   static constexpr uint32_t kLdrWInsn = 0xf8d00000u;
     65 
     66   // LDR immediate, negative offset, encoding T4. Bits 0-7 are the offset to subtract.
     67   static constexpr uint32_t kLdrNegativeOffset = 0xf8500c00u;
     68 
     69   // LDR register, lsl #2. Bits 4-5 are the imm2, i.e. the lsl shift.
     70   static constexpr uint32_t kLdrRegLsl2 = 0xf8500020u;
     71 
     72   // NOP instructions.
     73   static constexpr uint32_t kNopInsn = 0xbf00u;
     74   static constexpr uint32_t kNopWInsn = 0xf3af8000u;
     75 
     76   void InsertInsn(std::vector<uint8_t>* code, size_t pos, uint32_t insn) {
     77     CHECK_LE(pos, code->size());
     78     if (IsUint<16>(insn)) {
     79       const uint8_t insn_code[] = {
     80           static_cast<uint8_t>(insn),
     81           static_cast<uint8_t>(insn >> 8),
     82       };
     83       static_assert(sizeof(insn_code) == 2u, "Invalid sizeof(insn_code).");
     84       code->insert(code->begin() + pos, insn_code, insn_code + sizeof(insn_code));
     85     } else {
     86       const uint8_t insn_code[] = {
     87           static_cast<uint8_t>(insn >> 16),
     88           static_cast<uint8_t>(insn >> 24),
     89           static_cast<uint8_t>(insn),
     90           static_cast<uint8_t>(insn >> 8),
     91       };
     92       static_assert(sizeof(insn_code) == 4u, "Invalid sizeof(insn_code).");
     93       code->insert(code->begin() + pos, insn_code, insn_code + sizeof(insn_code));
     94     }
     95   }
     96 
     97   void PushBackInsn(std::vector<uint8_t>* code, uint32_t insn) {
     98     InsertInsn(code, code->size(), insn);
     99   }
    100 
    101   std::vector<uint8_t> GenNops(size_t num_nops) {
    102     std::vector<uint8_t> result;
    103     result.reserve(num_nops * 2u);
    104     for (size_t i = 0; i != num_nops; ++i) {
    105       PushBackInsn(&result, kNopInsn);
    106     }
    107     return result;
    108   }
    109 
    110   std::vector<uint8_t> RawCode(std::initializer_list<uint32_t> insns) {
    111     std::vector<uint8_t> raw_code;
    112     size_t number_of_16_bit_insns =
    113         std::count_if(insns.begin(), insns.end(), [](uint32_t x) { return IsUint<16>(x); });
    114     raw_code.reserve(insns.size() * 4u - number_of_16_bit_insns * 2u);
    115     for (uint32_t insn : insns) {
    116       PushBackInsn(&raw_code, insn);
    117     }
    118     return raw_code;
    119   }
    120 
    121   uint32_t BneWWithOffset(uint32_t bne_offset, uint32_t target_offset) {
    122     if (!IsAligned<2u>(bne_offset)) {
    123       LOG(ERROR) << "Unaligned bne_offset: " << bne_offset;
    124       return 0xffffffffu;  // Fails code diff later.
    125     }
    126     if (!IsAligned<2u>(target_offset)) {
    127       LOG(ERROR) << "Unaligned target_offset: " << target_offset;
    128       return 0xffffffffu;  // Fails code diff later.
    129     }
    130     uint32_t diff = target_offset - bne_offset - kPcAdjustment;
    131     DCHECK_ALIGNED(diff, 2u);
    132     if ((diff >> 20) != 0 && (diff >> 20) != 0xfffu) {
    133       LOG(ERROR) << "Target out of range: " << diff;
    134       return 0xffffffffu;  // Fails code diff later.
    135     }
    136     return kBneWPlus0 | ((diff >> 1) & 0x7ffu)          // imm11
    137                       | (((diff >> 12) & 0x3fu) << 16)  // imm6
    138                       | (((diff >> 18) & 1) << 13)      // J1
    139                       | (((diff >> 19) & 1) << 11)      // J2
    140                       | (((diff >> 20) & 1) << 26);     // S
    141   }
    142 
    143   uint32_t Create2MethodsWithGap(const ArrayRef<const uint8_t>& method1_code,
    144                                  const ArrayRef<const LinkerPatch>& method1_patches,
    145                                  const ArrayRef<const uint8_t>& last_method_code,
    146                                  const ArrayRef<const LinkerPatch>& last_method_patches,
    147                                  uint32_t distance_without_thunks) {
    148     CHECK_EQ(distance_without_thunks % kArmAlignment, 0u);
    149     uint32_t method1_offset =
    150         kTrampolineSize + CodeAlignmentSize(kTrampolineSize) + sizeof(OatQuickMethodHeader);
    151     AddCompiledMethod(MethodRef(1u), method1_code, method1_patches);
    152     const uint32_t gap_start = method1_offset + method1_code.size();
    153 
    154     // We want to put the last method at a very precise offset.
    155     const uint32_t last_method_offset = method1_offset + distance_without_thunks;
    156     CHECK_ALIGNED(last_method_offset, kArmAlignment);
    157     const uint32_t gap_end = last_method_offset - sizeof(OatQuickMethodHeader);
    158 
    159     // Fill the gap with intermediate methods in chunks of 2MiB and the first in [2MiB, 4MiB).
    160     // (This allows deduplicating the small chunks to avoid using 32MiB of memory for +-16MiB
    161     // offsets by this test. Making the first chunk bigger makes it easy to give all intermediate
    162     // methods the same alignment of the end, so the thunk insertion adds a predictable size as
    163     // long as it's after the first chunk.)
    164     uint32_t method_idx = 2u;
    165     constexpr uint32_t kSmallChunkSize = 2 * MB;
    166     std::vector<uint8_t> gap_code;
    167     uint32_t gap_size = gap_end - gap_start;
    168     uint32_t num_small_chunks = std::max(gap_size / kSmallChunkSize, 1u) - 1u;
    169     uint32_t chunk_start = gap_start;
    170     uint32_t chunk_size = gap_size - num_small_chunks * kSmallChunkSize;
    171     for (uint32_t i = 0; i <= num_small_chunks; ++i) {  // num_small_chunks+1 iterations.
    172       uint32_t chunk_code_size =
    173           chunk_size - CodeAlignmentSize(chunk_start) - sizeof(OatQuickMethodHeader);
    174       gap_code.resize(chunk_code_size, 0u);
    175       AddCompiledMethod(MethodRef(method_idx), ArrayRef<const uint8_t>(gap_code));
    176       method_idx += 1u;
    177       chunk_start += chunk_size;
    178       chunk_size = kSmallChunkSize;  // For all but the first chunk.
    179       DCHECK_EQ(CodeAlignmentSize(gap_end), CodeAlignmentSize(chunk_start));
    180     }
    181 
    182     // Add the last method and link
    183     AddCompiledMethod(MethodRef(method_idx), last_method_code, last_method_patches);
    184     Link();
    185 
    186     // Check assumptions.
    187     CHECK_EQ(GetMethodOffset(1), method1_offset);
    188     auto last_result = method_offset_map_.FindMethodOffset(MethodRef(method_idx));
    189     CHECK(last_result.first);
    190     // There may be a thunk before method2.
    191     if (last_result.second != last_method_offset + 1 /* thumb mode */) {
    192       // Thunk present. Check that there's only one.
    193       uint32_t thunk_end =
    194           CompiledCode::AlignCode(gap_end, InstructionSet::kThumb2) + MethodCallThunkSize();
    195       uint32_t header_offset = thunk_end + CodeAlignmentSize(thunk_end);
    196       CHECK_EQ(last_result.second,
    197                header_offset + sizeof(OatQuickMethodHeader) + 1 /* thumb mode */);
    198     }
    199     return method_idx;
    200   }
    201 
    202   uint32_t GetMethodOffset(uint32_t method_idx) {
    203     auto result = method_offset_map_.FindMethodOffset(MethodRef(method_idx));
    204     CHECK(result.first);
    205     CHECK_NE(result.second & 1u, 0u);
    206     return result.second - 1 /* thumb mode */;
    207   }
    208 
    209   std::vector<uint8_t> CompileThunk(const LinkerPatch& patch,
    210                                     /*out*/ std::string* debug_name = nullptr) {
    211     OptimizingUnitTestHelper helper;
    212     HGraph* graph = helper.CreateGraph();
    213     CompilerOptions compiler_options;
    214     arm::CodeGeneratorARMVIXL codegen(graph, compiler_options);
    215     ArenaVector<uint8_t> code(helper.GetAllocator()->Adapter());
    216     codegen.EmitThunkCode(patch, &code, debug_name);
    217     return std::vector<uint8_t>(code.begin(), code.end());
    218   }
    219 
    220   void AddCompiledMethod(
    221       MethodReference method_ref,
    222       const ArrayRef<const uint8_t>& code,
    223       const ArrayRef<const LinkerPatch>& patches = ArrayRef<const LinkerPatch>()) {
    224     RelativePatcherTest::AddCompiledMethod(method_ref, code, patches);
    225 
    226     // Make sure the ThunkProvider has all the necessary thunks.
    227     for (const LinkerPatch& patch : patches) {
    228       if (patch.GetType() == LinkerPatch::Type::kBakerReadBarrierBranch ||
    229           patch.GetType() == LinkerPatch::Type::kCallRelative) {
    230         std::string debug_name;
    231         std::vector<uint8_t> thunk_code = CompileThunk(patch, &debug_name);
    232         thunk_provider_.SetThunkCode(patch, ArrayRef<const uint8_t>(thunk_code), debug_name);
    233       }
    234     }
    235   }
    236 
    237   std::vector<uint8_t> CompileMethodCallThunk() {
    238     LinkerPatch patch = LinkerPatch::RelativeCodePatch(/* literal_offset */ 0u,
    239                                                        /* target_dex_file*/ nullptr,
    240                                                        /* target_method_idx */ 0u);
    241     return CompileThunk(patch);
    242   }
    243 
    244   uint32_t MethodCallThunkSize() {
    245     return CompileMethodCallThunk().size();
    246   }
    247 
    248   bool CheckThunk(uint32_t thunk_offset) {
    249     const std::vector<uint8_t> expected_code = CompileMethodCallThunk();
    250     if (output_.size() < thunk_offset + expected_code.size()) {
    251       LOG(ERROR) << "output_.size() == " << output_.size() << " < "
    252           << "thunk_offset + expected_code.size() == " << (thunk_offset + expected_code.size());
    253       return false;
    254     }
    255     ArrayRef<const uint8_t> linked_code(&output_[thunk_offset], expected_code.size());
    256     if (linked_code == ArrayRef<const uint8_t>(expected_code)) {
    257       return true;
    258     }
    259     // Log failure info.
    260     DumpDiff(ArrayRef<const uint8_t>(expected_code), linked_code);
    261     return false;
    262   }
    263 
    264   std::vector<uint8_t> GenNopsAndBl(size_t num_nops, uint32_t bl) {
    265     std::vector<uint8_t> result;
    266     result.reserve(num_nops * 2u + 4u);
    267     for (size_t i = 0; i != num_nops; ++i) {
    268       PushBackInsn(&result, kNopInsn);
    269     }
    270     PushBackInsn(&result, bl);
    271     return result;
    272   }
    273 
    274   void TestStringBssEntry(uint32_t bss_begin, uint32_t string_entry_offset);
    275   void TestStringReference(uint32_t string_offset);
    276   void CheckPcRelativePatch(const ArrayRef<const LinkerPatch>& patches, uint32_t target_offset);
    277 
    278   static uint32_t EncodeBakerReadBarrierFieldData(uint32_t base_reg,
    279                                                   uint32_t holder_reg,
    280                                                   bool narrow) {
    281     return arm::CodeGeneratorARMVIXL::EncodeBakerReadBarrierFieldData(base_reg, holder_reg, narrow);
    282   }
    283 
    284   static uint32_t EncodeBakerReadBarrierArrayData(uint32_t base_reg) {
    285     return arm::CodeGeneratorARMVIXL::EncodeBakerReadBarrierArrayData(base_reg);
    286   }
    287 
    288   static uint32_t EncodeBakerReadBarrierGcRootData(uint32_t root_reg, bool narrow) {
    289     return arm::CodeGeneratorARMVIXL::EncodeBakerReadBarrierGcRootData(root_reg, narrow);
    290   }
    291 
    292   std::vector<uint8_t> CompileBakerOffsetThunk(uint32_t base_reg,
    293                                                uint32_t holder_reg,
    294                                                bool narrow) {
    295     const LinkerPatch patch = LinkerPatch::BakerReadBarrierBranchPatch(
    296         /* literal_offset */ 0u, EncodeBakerReadBarrierFieldData(base_reg, holder_reg, narrow));
    297     return CompileThunk(patch);
    298   }
    299 
    300   std::vector<uint8_t> CompileBakerArrayThunk(uint32_t base_reg) {
    301     LinkerPatch patch = LinkerPatch::BakerReadBarrierBranchPatch(
    302         /* literal_offset */ 0u, EncodeBakerReadBarrierArrayData(base_reg));
    303     return CompileThunk(patch);
    304   }
    305 
    306   std::vector<uint8_t> CompileBakerGcRootThunk(uint32_t root_reg, bool narrow) {
    307     LinkerPatch patch = LinkerPatch::BakerReadBarrierBranchPatch(
    308         /* literal_offset */ 0u, EncodeBakerReadBarrierGcRootData(root_reg, narrow));
    309     return CompileThunk(patch);
    310   }
    311 
    312   uint32_t GetOutputInsn32(uint32_t offset) {
    313     CHECK_LE(offset, output_.size());
    314     CHECK_GE(output_.size() - offset, 4u);
    315     return (static_cast<uint32_t>(output_[offset]) << 16) |
    316            (static_cast<uint32_t>(output_[offset + 1]) << 24) |
    317            (static_cast<uint32_t>(output_[offset + 2]) << 0) |
    318            (static_cast<uint32_t>(output_[offset + 3]) << 8);
    319   }
    320 
    321   uint16_t GetOutputInsn16(uint32_t offset) {
    322     CHECK_LE(offset, output_.size());
    323     CHECK_GE(output_.size() - offset, 2u);
    324     return (static_cast<uint32_t>(output_[offset]) << 0) |
    325            (static_cast<uint32_t>(output_[offset + 1]) << 8);
    326   }
    327 
    328   void TestBakerFieldWide(uint32_t offset, uint32_t ref_reg);
    329   void TestBakerFieldNarrow(uint32_t offset, uint32_t ref_reg);
    330 };
    331 
    332 const uint8_t Thumb2RelativePatcherTest::kCallRawCode[] = {
    333     0x00, 0xf0, 0x00, 0xf8
    334 };
    335 
    336 const ArrayRef<const uint8_t> Thumb2RelativePatcherTest::kCallCode(kCallRawCode);
    337 
    338 const uint8_t Thumb2RelativePatcherTest::kNopRawCode[] = {
    339     0x00, 0xbf
    340 };
    341 
    342 const ArrayRef<const uint8_t> Thumb2RelativePatcherTest::kNopCode(kNopRawCode);
    343 
    344 const uint8_t Thumb2RelativePatcherTest::kUnpatchedPcRelativeRawCode[] = {
    345     0x40, 0xf2, 0x00, 0x00,   // MOVW r0, #0 (placeholder)
    346     0xc0, 0xf2, 0x00, 0x00,   // MOVT r0, #0 (placeholder)
    347     0x78, 0x44,               // ADD r0, pc
    348 };
    349 const ArrayRef<const uint8_t> Thumb2RelativePatcherTest::kUnpatchedPcRelativeCode(
    350     kUnpatchedPcRelativeRawCode);
    351 const uint32_t Thumb2RelativePatcherTest::kPcInsnOffset = 8u;
    352 
    353 void Thumb2RelativePatcherTest::TestStringBssEntry(uint32_t bss_begin,
    354                                                    uint32_t string_entry_offset) {
    355   constexpr uint32_t kStringIndex = 1u;
    356   string_index_to_offset_map_.Put(kStringIndex, string_entry_offset);
    357   bss_begin_ = bss_begin;
    358   const LinkerPatch patches[] = {
    359       LinkerPatch::StringBssEntryPatch(0u, nullptr, kPcInsnOffset, kStringIndex),
    360       LinkerPatch::StringBssEntryPatch(4u, nullptr, kPcInsnOffset, kStringIndex),
    361   };
    362   CheckPcRelativePatch(ArrayRef<const LinkerPatch>(patches), bss_begin_ + string_entry_offset);
    363 }
    364 
    365 void Thumb2RelativePatcherTest::TestStringReference(uint32_t string_offset) {
    366   constexpr uint32_t kStringIndex = 1u;
    367   string_index_to_offset_map_.Put(kStringIndex, string_offset);
    368   const LinkerPatch patches[] = {
    369       LinkerPatch::RelativeStringPatch(0u, nullptr, kPcInsnOffset, kStringIndex),
    370       LinkerPatch::RelativeStringPatch(4u, nullptr, kPcInsnOffset, kStringIndex),
    371   };
    372   CheckPcRelativePatch(ArrayRef<const LinkerPatch>(patches), string_offset);
    373 }
    374 
    375 void Thumb2RelativePatcherTest::CheckPcRelativePatch(const ArrayRef<const LinkerPatch>& patches,
    376                                                      uint32_t target_offset) {
    377   AddCompiledMethod(MethodRef(1u), kUnpatchedPcRelativeCode, ArrayRef<const LinkerPatch>(patches));
    378   Link();
    379 
    380   uint32_t method1_offset = GetMethodOffset(1u);
    381   uint32_t pc_base_offset = method1_offset + kPcInsnOffset + 4u /* PC adjustment */;
    382   uint32_t diff = target_offset - pc_base_offset;
    383   // Distribute the bits of the diff between the MOVW and MOVT:
    384   uint32_t diffw = diff & 0xffffu;
    385   uint32_t difft = diff >> 16;
    386   uint32_t movw = 0xf2400000u |           // MOVW r0, #0 (placeholder),
    387       ((diffw & 0xf000u) << (16 - 12)) |  // move imm4 from bits 12-15 to bits 16-19,
    388       ((diffw & 0x0800u) << (26 - 11)) |  // move imm from bit 11 to bit 26,
    389       ((diffw & 0x0700u) << (12 - 8)) |   // move imm3 from bits 8-10 to bits 12-14,
    390       ((diffw & 0x00ffu));                // keep imm8 at bits 0-7.
    391   uint32_t movt = 0xf2c00000u |           // MOVT r0, #0 (placeholder),
    392       ((difft & 0xf000u) << (16 - 12)) |  // move imm4 from bits 12-15 to bits 16-19,
    393       ((difft & 0x0800u) << (26 - 11)) |  // move imm from bit 11 to bit 26,
    394       ((difft & 0x0700u) << (12 - 8)) |   // move imm3 from bits 8-10 to bits 12-14,
    395       ((difft & 0x00ffu));                // keep imm8 at bits 0-7.
    396   const uint8_t expected_code[] = {
    397       static_cast<uint8_t>(movw >> 16), static_cast<uint8_t>(movw >> 24),
    398       static_cast<uint8_t>(movw >> 0), static_cast<uint8_t>(movw >> 8),
    399       static_cast<uint8_t>(movt >> 16), static_cast<uint8_t>(movt >> 24),
    400       static_cast<uint8_t>(movt >> 0), static_cast<uint8_t>(movt >> 8),
    401       0x78, 0x44,
    402   };
    403   EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
    404 }
    405 
    406 TEST_F(Thumb2RelativePatcherTest, CallSelf) {
    407   const LinkerPatch patches[] = {
    408       LinkerPatch::RelativeCodePatch(0u, nullptr, 1u),
    409   };
    410   AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<const LinkerPatch>(patches));
    411   Link();
    412 
    413   static const uint8_t expected_code[] = {
    414       0xff, 0xf7, 0xfe, 0xff
    415   };
    416   EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
    417 }
    418 
    419 TEST_F(Thumb2RelativePatcherTest, CallOther) {
    420   const LinkerPatch method1_patches[] = {
    421       LinkerPatch::RelativeCodePatch(0u, nullptr, 2u),
    422   };
    423   AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<const LinkerPatch>(method1_patches));
    424   const LinkerPatch method2_patches[] = {
    425       LinkerPatch::RelativeCodePatch(0u, nullptr, 1u),
    426   };
    427   AddCompiledMethod(MethodRef(2u), kCallCode, ArrayRef<const LinkerPatch>(method2_patches));
    428   Link();
    429 
    430   uint32_t method1_offset = GetMethodOffset(1u);
    431   uint32_t method2_offset = GetMethodOffset(2u);
    432   uint32_t diff_after = method2_offset - (method1_offset + 4u /* PC adjustment */);
    433   ASSERT_EQ(diff_after & 1u, 0u);
    434   ASSERT_LT(diff_after >> 1, 1u << 8);  // Simple encoding, (diff_after >> 1) fits into 8 bits.
    435   static const uint8_t method1_expected_code[] = {
    436       0x00, 0xf0, static_cast<uint8_t>(diff_after >> 1), 0xf8
    437   };
    438   EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(method1_expected_code)));
    439   uint32_t diff_before = method1_offset - (method2_offset + 4u /* PC adjustment */);
    440   ASSERT_EQ(diff_before & 1u, 0u);
    441   ASSERT_GE(diff_before, -1u << 9);  // Simple encoding, -256 <= (diff >> 1) < 0.
    442   auto method2_expected_code = GenNopsAndBl(0u, kBlMinus256 | ((diff_before >> 1) & 0xffu));
    443   EXPECT_TRUE(CheckLinkedMethod(MethodRef(2u), ArrayRef<const uint8_t>(method2_expected_code)));
    444 }
    445 
    446 TEST_F(Thumb2RelativePatcherTest, CallTrampoline) {
    447   const LinkerPatch patches[] = {
    448       LinkerPatch::RelativeCodePatch(0u, nullptr, 2u),
    449   };
    450   AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<const LinkerPatch>(patches));
    451   Link();
    452 
    453   uint32_t method1_offset = GetMethodOffset(1u);
    454   uint32_t diff = kTrampolineOffset - (method1_offset + 4u);
    455   ASSERT_EQ(diff & 1u, 0u);
    456   ASSERT_GE(diff, -1u << 9);  // Simple encoding, -256 <= (diff >> 1) < 0 (checked as unsigned).
    457   auto expected_code = GenNopsAndBl(0u, kBlMinus256 | ((diff >> 1) & 0xffu));
    458   EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
    459 }
    460 
    461 TEST_F(Thumb2RelativePatcherTest, CallTrampolineTooFar) {
    462   constexpr uint32_t missing_method_index = 1024u;
    463   auto last_method_raw_code = GenNopsAndBl(3u, kBlPlus0);
    464   constexpr uint32_t bl_offset_in_last_method = 3u * 2u;  // After NOPs.
    465   ArrayRef<const uint8_t> last_method_code(last_method_raw_code);
    466   ASSERT_EQ(bl_offset_in_last_method + 4u, last_method_code.size());
    467   const LinkerPatch last_method_patches[] = {
    468       LinkerPatch::RelativeCodePatch(bl_offset_in_last_method, nullptr, missing_method_index),
    469   };
    470 
    471   constexpr uint32_t just_over_max_negative_disp = 16 * MB + 2 - 4u /* PC adjustment */;
    472   uint32_t last_method_idx = Create2MethodsWithGap(
    473       kNopCode,
    474       ArrayRef<const LinkerPatch>(),
    475       last_method_code,
    476       ArrayRef<const LinkerPatch>(last_method_patches),
    477       just_over_max_negative_disp - bl_offset_in_last_method);
    478   uint32_t method1_offset = GetMethodOffset(1u);
    479   uint32_t last_method_offset = GetMethodOffset(last_method_idx);
    480   ASSERT_EQ(method1_offset,
    481             last_method_offset + bl_offset_in_last_method - just_over_max_negative_disp);
    482   ASSERT_FALSE(method_offset_map_.FindMethodOffset(MethodRef(missing_method_index)).first);
    483 
    484   // Check linked code.
    485   uint32_t thunk_offset = CompiledCode::AlignCode(
    486       last_method_offset + last_method_code.size(), InstructionSet::kThumb2);
    487   uint32_t diff =
    488       thunk_offset - (last_method_offset + bl_offset_in_last_method + 4u /* PC adjustment */);
    489   ASSERT_TRUE(IsAligned<2u>(diff));
    490   ASSERT_LT(diff >> 1, 1u << 8);  // Simple encoding, (diff >> 1) fits into 8 bits.
    491   auto expected_code = GenNopsAndBl(3u, kBlPlus0 | ((diff >> 1) & 0xffu));
    492   EXPECT_TRUE(CheckLinkedMethod(MethodRef(last_method_idx),
    493                                 ArrayRef<const uint8_t>(expected_code)));
    494   EXPECT_TRUE(CheckThunk(thunk_offset));
    495 }
    496 
    497 TEST_F(Thumb2RelativePatcherTest, CallOtherAlmostTooFarAfter) {
    498   auto method1_raw_code = GenNopsAndBl(3u, kBlPlus0);
    499   constexpr uint32_t bl_offset_in_method1 = 3u * 2u;  // After NOPs.
    500   ArrayRef<const uint8_t> method1_code(method1_raw_code);
    501   ASSERT_EQ(bl_offset_in_method1 + 4u, method1_code.size());
    502   const uint32_t kExpectedLastMethodIdx = 9u;  // Based on 2MiB chunks in Create2MethodsWithGap().
    503   const LinkerPatch method1_patches[] = {
    504       LinkerPatch::RelativeCodePatch(bl_offset_in_method1, nullptr, kExpectedLastMethodIdx),
    505   };
    506 
    507   constexpr uint32_t max_positive_disp = 16 * MB - 2u + 4u /* PC adjustment */;
    508   uint32_t last_method_idx = Create2MethodsWithGap(method1_code,
    509                                                    ArrayRef<const LinkerPatch>(method1_patches),
    510                                                    kNopCode,
    511                                                    ArrayRef<const LinkerPatch>(),
    512                                                    bl_offset_in_method1 + max_positive_disp);
    513   ASSERT_EQ(kExpectedLastMethodIdx, last_method_idx);
    514 
    515   // Check linked code.
    516   auto expected_code = GenNopsAndBl(3u, kBlPlusMax);
    517   EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
    518 }
    519 
    520 TEST_F(Thumb2RelativePatcherTest, CallOtherAlmostTooFarBefore) {
    521   auto last_method_raw_code = GenNopsAndBl(2u, kBlPlus0);
    522   constexpr uint32_t bl_offset_in_last_method = 2u * 2u;  // After NOPs.
    523   ArrayRef<const uint8_t> last_method_code(last_method_raw_code);
    524   ASSERT_EQ(bl_offset_in_last_method + 4u, last_method_code.size());
    525   const LinkerPatch last_method_patches[] = {
    526       LinkerPatch::RelativeCodePatch(bl_offset_in_last_method, nullptr, 1u),
    527   };
    528 
    529   constexpr uint32_t max_negative_disp = 16 * MB - 4u /* PC adjustment */;
    530   uint32_t last_method_idx = Create2MethodsWithGap(kNopCode,
    531                                                    ArrayRef<const LinkerPatch>(),
    532                                                    last_method_code,
    533                                                    ArrayRef<const LinkerPatch>(last_method_patches),
    534                                                    max_negative_disp - bl_offset_in_last_method);
    535   uint32_t method1_offset = GetMethodOffset(1u);
    536   uint32_t last_method_offset = GetMethodOffset(last_method_idx);
    537   ASSERT_EQ(method1_offset, last_method_offset + bl_offset_in_last_method - max_negative_disp);
    538 
    539   // Check linked code.
    540   auto expected_code = GenNopsAndBl(2u, kBlMinusMax);
    541   EXPECT_TRUE(CheckLinkedMethod(MethodRef(last_method_idx),
    542                                 ArrayRef<const uint8_t>(expected_code)));
    543 }
    544 
    545 TEST_F(Thumb2RelativePatcherTest, CallOtherJustTooFarAfter) {
    546   auto method1_raw_code = GenNopsAndBl(2u, kBlPlus0);
    547   constexpr uint32_t bl_offset_in_method1 = 2u * 2u;  // After NOPs.
    548   ArrayRef<const uint8_t> method1_code(method1_raw_code);
    549   ASSERT_EQ(bl_offset_in_method1 + 4u, method1_code.size());
    550   const uint32_t kExpectedLastMethodIdx = 9u;  // Based on 2MiB chunks in Create2MethodsWithGap().
    551   const LinkerPatch method1_patches[] = {
    552       LinkerPatch::RelativeCodePatch(bl_offset_in_method1, nullptr, kExpectedLastMethodIdx),
    553   };
    554 
    555   constexpr uint32_t just_over_max_positive_disp = 16 * MB + 4u /* PC adjustment */;
    556   uint32_t last_method_idx = Create2MethodsWithGap(
    557       method1_code,
    558       ArrayRef<const LinkerPatch>(method1_patches),
    559       kNopCode,
    560       ArrayRef<const LinkerPatch>(),
    561       bl_offset_in_method1 + just_over_max_positive_disp);
    562   ASSERT_EQ(kExpectedLastMethodIdx, last_method_idx);
    563   uint32_t method_after_thunk_idx = last_method_idx;
    564   if (sizeof(OatQuickMethodHeader) < kArmAlignment) {
    565     // The thunk needs to start on a kArmAlignment-aligned address before the address where the
    566     // last method would have been if there was no thunk. If the size of the OatQuickMethodHeader
    567     // is at least kArmAlignment, the thunk start shall fit between the previous filler method
    568     // and that address. Otherwise, it shall be inserted before that filler method.
    569     method_after_thunk_idx -= 1u;
    570   }
    571 
    572   uint32_t method1_offset = GetMethodOffset(1u);
    573   uint32_t method_after_thunk_offset = GetMethodOffset(method_after_thunk_idx);
    574   ASSERT_TRUE(IsAligned<kArmAlignment>(method_after_thunk_offset));
    575   uint32_t method_after_thunk_header_offset =
    576       method_after_thunk_offset - sizeof(OatQuickMethodHeader);
    577   uint32_t thunk_size = MethodCallThunkSize();
    578   uint32_t thunk_offset = RoundDown(method_after_thunk_header_offset - thunk_size, kArmAlignment);
    579   DCHECK_EQ(thunk_offset + thunk_size + CodeAlignmentSize(thunk_offset + thunk_size),
    580             method_after_thunk_header_offset);
    581   ASSERT_TRUE(IsAligned<kArmAlignment>(thunk_offset));
    582   uint32_t diff = thunk_offset - (method1_offset + bl_offset_in_method1 + 4u /* PC adjustment */);
    583   ASSERT_TRUE(IsAligned<2u>(diff));
    584   ASSERT_GE(diff, 16 * MB - (1u << 22));  // Simple encoding, unknown bits fit into imm10:imm11:0.
    585   auto expected_code =
    586       GenNopsAndBl(2u, 0xf000d000 | ((diff >> 1) & 0x7ffu) | (((diff >> 12) & 0x3ffu) << 16));
    587   EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
    588   CheckThunk(thunk_offset);
    589 }
    590 
    591 TEST_F(Thumb2RelativePatcherTest, CallOtherJustTooFarBefore) {
    592   auto last_method_raw_code = GenNopsAndBl(3u, kBlPlus0);
    593   constexpr uint32_t bl_offset_in_last_method = 3u * 2u;  // After NOPs.
    594   ArrayRef<const uint8_t> last_method_code(last_method_raw_code);
    595   ASSERT_EQ(bl_offset_in_last_method + 4u, last_method_code.size());
    596   const LinkerPatch last_method_patches[] = {
    597       LinkerPatch::RelativeCodePatch(bl_offset_in_last_method, nullptr, 1u),
    598   };
    599 
    600   constexpr uint32_t just_over_max_negative_disp = 16 * MB + 2 - 4u /* PC adjustment */;
    601   uint32_t last_method_idx = Create2MethodsWithGap(
    602       kNopCode,
    603       ArrayRef<const LinkerPatch>(),
    604       last_method_code,
    605       ArrayRef<const LinkerPatch>(last_method_patches),
    606       just_over_max_negative_disp - bl_offset_in_last_method);
    607   uint32_t method1_offset = GetMethodOffset(1u);
    608   uint32_t last_method_offset = GetMethodOffset(last_method_idx);
    609   ASSERT_EQ(method1_offset,
    610             last_method_offset + bl_offset_in_last_method - just_over_max_negative_disp);
    611 
    612   // Check linked code.
    613   uint32_t thunk_offset = CompiledCode::AlignCode(
    614       last_method_offset + last_method_code.size(), InstructionSet::kThumb2);
    615   uint32_t diff =
    616       thunk_offset - (last_method_offset + bl_offset_in_last_method + 4u /* PC adjustment */);
    617   ASSERT_TRUE(IsAligned<2u>(diff));
    618   ASSERT_LT(diff >> 1, 1u << 8);  // Simple encoding, (diff >> 1) fits into 8 bits.
    619   auto expected_code = GenNopsAndBl(3u, kBlPlus0 | ((diff >> 1) & 0xffu));
    620   EXPECT_TRUE(CheckLinkedMethod(MethodRef(last_method_idx),
    621                                 ArrayRef<const uint8_t>(expected_code)));
    622   EXPECT_TRUE(CheckThunk(thunk_offset));
    623 }
    624 
    625 TEST_F(Thumb2RelativePatcherTest, StringBssEntry1) {
    626   TestStringBssEntry(0x00ff0000u, 0x00fcu);
    627   ASSERT_LT(GetMethodOffset(1u), 0xfcu);
    628 }
    629 
    630 TEST_F(Thumb2RelativePatcherTest, StringBssEntry2) {
    631   TestStringBssEntry(0x02ff0000u, 0x05fcu);
    632   ASSERT_LT(GetMethodOffset(1u), 0xfcu);
    633 }
    634 
    635 TEST_F(Thumb2RelativePatcherTest, StringBssEntry3) {
    636   TestStringBssEntry(0x08ff0000u, 0x08fcu);
    637   ASSERT_LT(GetMethodOffset(1u), 0xfcu);
    638 }
    639 
    640 TEST_F(Thumb2RelativePatcherTest, StringBssEntry4) {
    641   TestStringBssEntry(0xd0ff0000u, 0x60fcu);
    642   ASSERT_LT(GetMethodOffset(1u), 0xfcu);
    643 }
    644 
    645 TEST_F(Thumb2RelativePatcherTest, StringReference1) {
    646   TestStringReference(0x00ff00fcu);
    647   ASSERT_LT(GetMethodOffset(1u), 0xfcu);
    648 }
    649 
    650 TEST_F(Thumb2RelativePatcherTest, StringReference2) {
    651   TestStringReference(0x02ff05fcu);
    652   ASSERT_LT(GetMethodOffset(1u), 0xfcu);
    653 }
    654 
    655 TEST_F(Thumb2RelativePatcherTest, StringReference3) {
    656   TestStringReference(0x08ff08fcu);
    657   ASSERT_LT(GetMethodOffset(1u), 0xfcu);
    658 }
    659 
    660 TEST_F(Thumb2RelativePatcherTest, StringReference4) {
    661   TestStringReference(0xd0ff60fcu);
    662   ASSERT_LT(GetMethodOffset(1u), 0xfcu);
    663 }
    664 
    665 const uint32_t kBakerValidRegs[] = {
    666     0,  1,  2,  3,  4,  5,  6,  7,
    667     9, 10, 11,                      // r8 (rMR), IP, SP, LR and PC are reserved.
    668 };
    669 
    670 const uint32_t kBakerValidRegsNarrow[] = {
    671     0,  1,  2,  3,  4,  5,  6,  7,
    672 };
    673 
    674 void Thumb2RelativePatcherTest::TestBakerFieldWide(uint32_t offset, uint32_t ref_reg) {
    675   DCHECK_ALIGNED(offset, 4u);
    676   DCHECK_LT(offset, 4 * KB);
    677   constexpr size_t kMethodCodeSize = 8u;
    678   constexpr size_t kLiteralOffset = 0u;
    679   uint32_t method_idx = 0u;
    680   for (uint32_t base_reg : kBakerValidRegs) {
    681     for (uint32_t holder_reg : kBakerValidRegs) {
    682       uint32_t ldr = kLdrWInsn | offset | (base_reg << 16) | (ref_reg << 12);
    683       const std::vector<uint8_t> raw_code = RawCode({kBneWPlus0, ldr});
    684       ASSERT_EQ(kMethodCodeSize, raw_code.size());
    685       ArrayRef<const uint8_t> code(raw_code);
    686       uint32_t encoded_data = EncodeBakerReadBarrierFieldData(
    687           base_reg, holder_reg, /* narrow */ false);
    688       const LinkerPatch patches[] = {
    689           LinkerPatch::BakerReadBarrierBranchPatch(kLiteralOffset, encoded_data),
    690       };
    691       ++method_idx;
    692       AddCompiledMethod(MethodRef(method_idx), code, ArrayRef<const LinkerPatch>(patches));
    693     }
    694   }
    695   Link();
    696 
    697   // All thunks are at the end.
    698   uint32_t thunk_offset = GetMethodOffset(method_idx) + RoundUp(kMethodCodeSize, kArmAlignment);
    699   method_idx = 0u;
    700   for (uint32_t base_reg : kBakerValidRegs) {
    701     for (uint32_t holder_reg : kBakerValidRegs) {
    702       ++method_idx;
    703       uint32_t bne = BneWWithOffset(GetMethodOffset(method_idx) + kLiteralOffset, thunk_offset);
    704       uint32_t ldr = kLdrWInsn | offset | (base_reg << 16) | (ref_reg << 12);
    705       const std::vector<uint8_t> expected_code = RawCode({bne, ldr});
    706       ASSERT_EQ(kMethodCodeSize, expected_code.size()) << "bne=0x" << std::hex << bne;
    707       ASSERT_TRUE(
    708           CheckLinkedMethod(MethodRef(method_idx), ArrayRef<const uint8_t>(expected_code)));
    709 
    710       std::vector<uint8_t> expected_thunk =
    711           CompileBakerOffsetThunk(base_reg, holder_reg, /* narrow */ false);
    712       ASSERT_GT(output_.size(), thunk_offset);
    713       ASSERT_GE(output_.size() - thunk_offset, expected_thunk.size());
    714       ArrayRef<const uint8_t> compiled_thunk(output_.data() + thunk_offset,
    715                                              expected_thunk.size());
    716       if (ArrayRef<const uint8_t>(expected_thunk) != compiled_thunk) {
    717         DumpDiff(ArrayRef<const uint8_t>(expected_thunk), compiled_thunk);
    718         ASSERT_TRUE(false);
    719       }
    720 
    721       size_t gray_check_offset = thunk_offset;
    722       if (holder_reg == base_reg) {
    723         // Verify that the null-check uses the correct register, i.e. holder_reg.
    724         if (holder_reg < 8) {
    725           ASSERT_GE(output_.size() - gray_check_offset, 2u);
    726           ASSERT_EQ(0xb100 | holder_reg, GetOutputInsn16(thunk_offset) & 0xfd07u);
    727           gray_check_offset +=2u;
    728         } else {
    729           ASSERT_GE(output_.size() - gray_check_offset, 6u);
    730           ASSERT_EQ(0xf1b00f00u | (holder_reg << 16), GetOutputInsn32(thunk_offset) & 0xfbff8f00u);
    731           ASSERT_EQ(0xd000u, GetOutputInsn16(thunk_offset + 4u) & 0xff00u);  // BEQ
    732           gray_check_offset += 6u;
    733         }
    734       }
    735       // Verify that the lock word for gray bit check is loaded from the holder address.
    736       ASSERT_GE(output_.size() - gray_check_offset,
    737                 4u * /* 32-bit instructions */ 4u + 2u * /* 16-bit instructions */ 2u);
    738       const uint32_t load_lock_word =
    739           kLdrWInsn |
    740           (holder_reg << 16) |
    741           (/* IP */ 12 << 12) |
    742           mirror::Object::MonitorOffset().Uint32Value();
    743       ASSERT_EQ(load_lock_word, GetOutputInsn32(gray_check_offset));
    744       // Verify the gray bit check.
    745       DCHECK_GE(LockWord::kReadBarrierStateShift, 8u);  // ROR modified immediate.
    746       uint32_t ror_shift = 7 + (32 - LockWord::kReadBarrierStateShift);
    747       const uint32_t tst_gray_bit_without_offset =
    748           0xf0100f00 | (/* IP */ 12 << 16)
    749                      | (((ror_shift >> 4) & 1) << 26)   // i
    750                      | (((ror_shift >> 1) & 7) << 12)   // imm3
    751                      | ((ror_shift & 1) << 7);          // imm8, ROR('1':imm8<7:0>, ror_shift).
    752       EXPECT_EQ(tst_gray_bit_without_offset, GetOutputInsn32(gray_check_offset + 4u));
    753       EXPECT_EQ(0xd100u, GetOutputInsn16(gray_check_offset + 8u) & 0xff00u);  // BNE
    754       // Verify the fake dependency (skip "ADD LR, LR, #ldr_offset").
    755       const uint32_t fake_dependency =
    756           0xeb000010 |              // ADD Rd, Rn, Rm, LSR 32 (type=01, imm3=000, imm2=00)
    757           (/* IP */ 12) |           // Rm = IP
    758           (base_reg << 16) |        // Rn = base_reg
    759           (base_reg << 8);          // Rd = base_reg
    760       EXPECT_EQ(fake_dependency, GetOutputInsn32(gray_check_offset + 14u));
    761       // Do not check the rest of the implementation.
    762 
    763       // The next thunk follows on the next aligned offset.
    764       thunk_offset += RoundUp(expected_thunk.size(), kArmAlignment);
    765     }
    766   }
    767 }
    768 
    769 void Thumb2RelativePatcherTest::TestBakerFieldNarrow(uint32_t offset, uint32_t ref_reg) {
    770   DCHECK_ALIGNED(offset, 4u);
    771   DCHECK_LT(offset, 32u);
    772   constexpr size_t kMethodCodeSize = 6u;
    773   constexpr size_t kLiteralOffset = 0u;
    774   uint32_t method_idx = 0u;
    775   for (uint32_t base_reg : kBakerValidRegs) {
    776     if (base_reg >= 8u) {
    777       continue;
    778     }
    779     for (uint32_t holder_reg : kBakerValidRegs) {
    780       uint32_t ldr = kLdrInsn | (offset << (6 - 2)) | (base_reg << 3) | ref_reg;
    781       const std::vector<uint8_t> raw_code = RawCode({kBneWPlus0, ldr});
    782       ASSERT_EQ(kMethodCodeSize, raw_code.size());
    783       ArrayRef<const uint8_t> code(raw_code);
    784       uint32_t encoded_data = EncodeBakerReadBarrierFieldData(
    785           base_reg, holder_reg, /* narrow */ true);
    786       const LinkerPatch patches[] = {
    787           LinkerPatch::BakerReadBarrierBranchPatch(kLiteralOffset, encoded_data),
    788       };
    789       ++method_idx;
    790       AddCompiledMethod(MethodRef(method_idx), code, ArrayRef<const LinkerPatch>(patches));
    791     }
    792   }
    793   Link();
    794 
    795   // All thunks are at the end.
    796   uint32_t thunk_offset = GetMethodOffset(method_idx) + RoundUp(kMethodCodeSize, kArmAlignment);
    797   method_idx = 0u;
    798   for (uint32_t base_reg : kBakerValidRegs) {
    799     if (base_reg >= 8u) {
    800       continue;
    801     }
    802     for (uint32_t holder_reg : kBakerValidRegs) {
    803       ++method_idx;
    804       uint32_t bne = BneWWithOffset(GetMethodOffset(method_idx) + kLiteralOffset, thunk_offset);
    805       uint32_t ldr = kLdrInsn | (offset << (6 - 2)) | (base_reg << 3) | ref_reg;
    806       const std::vector<uint8_t> expected_code = RawCode({bne, ldr});
    807       ASSERT_EQ(kMethodCodeSize, expected_code.size()) << "bne=0x" << std::hex << bne;
    808       ASSERT_TRUE(
    809           CheckLinkedMethod(MethodRef(method_idx), ArrayRef<const uint8_t>(expected_code)));
    810 
    811       std::vector<uint8_t> expected_thunk =
    812           CompileBakerOffsetThunk(base_reg, holder_reg, /* narrow */ true);
    813       ASSERT_GT(output_.size(), thunk_offset);
    814       ASSERT_GE(output_.size() - thunk_offset, expected_thunk.size());
    815       ArrayRef<const uint8_t> compiled_thunk(output_.data() + thunk_offset,
    816                                              expected_thunk.size());
    817       if (ArrayRef<const uint8_t>(expected_thunk) != compiled_thunk) {
    818         DumpDiff(ArrayRef<const uint8_t>(expected_thunk), compiled_thunk);
    819         ASSERT_TRUE(false);
    820       }
    821 
    822       size_t gray_check_offset = thunk_offset;
    823       if (holder_reg == base_reg) {
    824         // Verify that the null-check uses the correct register, i.e. holder_reg.
    825         if (holder_reg < 8) {
    826           ASSERT_GE(output_.size() - gray_check_offset, 2u);
    827           ASSERT_EQ(0xb100 | holder_reg, GetOutputInsn16(thunk_offset) & 0xfd07u);
    828           gray_check_offset +=2u;
    829         } else {
    830           ASSERT_GE(output_.size() - gray_check_offset, 6u);
    831           ASSERT_EQ(0xf1b00f00u | (holder_reg << 16), GetOutputInsn32(thunk_offset) & 0xfbff8f00u);
    832           ASSERT_EQ(0xd000u, GetOutputInsn16(thunk_offset + 4u) & 0xff00u);  // BEQ
    833           gray_check_offset += 6u;
    834         }
    835       }
    836       // Verify that the lock word for gray bit check is loaded from the holder address.
    837       ASSERT_GE(output_.size() - gray_check_offset,
    838                 4u * /* 32-bit instructions */ 4u + 2u * /* 16-bit instructions */ 2u);
    839       const uint32_t load_lock_word =
    840           kLdrWInsn |
    841           (holder_reg << 16) |
    842           (/* IP */ 12 << 12) |
    843           mirror::Object::MonitorOffset().Uint32Value();
    844       ASSERT_EQ(load_lock_word, GetOutputInsn32(gray_check_offset));
    845       // Verify the gray bit check.
    846       DCHECK_GE(LockWord::kReadBarrierStateShift, 8u);  // ROR modified immediate.
    847       uint32_t ror_shift = 7 + (32 - LockWord::kReadBarrierStateShift);
    848       const uint32_t tst_gray_bit_without_offset =
    849           0xf0100f00 | (/* IP */ 12 << 16)
    850                      | (((ror_shift >> 4) & 1) << 26)   // i
    851                      | (((ror_shift >> 1) & 7) << 12)   // imm3
    852                      | ((ror_shift & 1) << 7);          // imm8, ROR('1':imm8<7:0>, ror_shift).
    853       EXPECT_EQ(tst_gray_bit_without_offset, GetOutputInsn32(gray_check_offset + 4u));
    854       EXPECT_EQ(0xd100u, GetOutputInsn16(gray_check_offset + 8u) & 0xff00u);  // BNE
    855       // Verify the fake dependency (skip "ADD LR, LR, #ldr_offset").
    856       const uint32_t fake_dependency =
    857           0xeb000010 |              // ADD Rd, Rn, Rm, LSR 32 (type=01, imm3=000, imm2=00)
    858           (/* IP */ 12) |           // Rm = IP
    859           (base_reg << 16) |        // Rn = base_reg
    860           (base_reg << 8);          // Rd = base_reg
    861       EXPECT_EQ(fake_dependency, GetOutputInsn32(gray_check_offset + 14u));
    862       // Do not check the rest of the implementation.
    863 
    864       // The next thunk follows on the next aligned offset.
    865       thunk_offset += RoundUp(expected_thunk.size(), kArmAlignment);
    866     }
    867   }
    868 }
    869 
    870 TEST_F(Thumb2RelativePatcherTest, BakerOffsetWide) {
    871   struct TestCase {
    872     uint32_t offset;
    873     uint32_t ref_reg;
    874   };
    875   static const TestCase test_cases[] = {
    876       { 0u, 0u },
    877       { 8u, 3u },
    878       { 28u, 7u },
    879       { 0xffcu, 11u },
    880   };
    881   for (const TestCase& test_case : test_cases) {
    882     Reset();
    883     TestBakerFieldWide(test_case.offset, test_case.ref_reg);
    884   }
    885 }
    886 
    887 TEST_F(Thumb2RelativePatcherTest, BakerOffsetNarrow) {
    888   struct TestCase {
    889     uint32_t offset;
    890     uint32_t ref_reg;
    891   };
    892   static const TestCase test_cases[] = {
    893       { 0, 0u },
    894       { 8, 3u },
    895       { 28, 7u },
    896   };
    897   for (const TestCase& test_case : test_cases) {
    898     Reset();
    899     TestBakerFieldNarrow(test_case.offset, test_case.ref_reg);
    900   }
    901 }
    902 
    903 TEST_F(Thumb2RelativePatcherTest, BakerOffsetThunkInTheMiddle) {
    904   // One thunk in the middle with maximum distance branches to it from both sides.
    905   // Use offset = 0, base_reg = 0, ref_reg = 0, the LDR is simply `kLdrWInsn`.
    906   constexpr uint32_t kLiteralOffset1 = 6u;
    907   const std::vector<uint8_t> raw_code1 = RawCode({kNopWInsn, kNopInsn, kBneWPlus0, kLdrWInsn});
    908   ArrayRef<const uint8_t> code1(raw_code1);
    909   uint32_t encoded_data = EncodeBakerReadBarrierFieldData(
    910       /* base_reg */ 0, /* holder_reg */ 0, /* narrow */ false);
    911   const LinkerPatch patches1[] = {
    912       LinkerPatch::BakerReadBarrierBranchPatch(kLiteralOffset1, encoded_data),
    913   };
    914   AddCompiledMethod(MethodRef(1u), code1, ArrayRef<const LinkerPatch>(patches1));
    915 
    916   constexpr uint32_t expected_thunk_offset =
    917       kLiteralOffset1 + kPcAdjustment + /* kMaxBcondPositiveDisplacement */ ((1 << 20) - 2u);
    918   static_assert(IsAligned<kArmAlignment>(expected_thunk_offset), "Target offset must be aligned.");
    919   size_t filler1_size = expected_thunk_offset -
    920                         RoundUp(raw_code1.size() + sizeof(OatQuickMethodHeader), kArmAlignment);
    921   std::vector<uint8_t> raw_filler1_code = GenNops(filler1_size / 2u);
    922   ArrayRef<const uint8_t> filler1_code(raw_filler1_code);
    923   AddCompiledMethod(MethodRef(2u), filler1_code);
    924 
    925   // Enforce thunk reservation with a tiny method.
    926   AddCompiledMethod(MethodRef(3u), kNopCode);
    927 
    928   constexpr uint32_t kLiteralOffset2 = 4;
    929   static_assert(IsAligned<kArmAlignment>(kLiteralOffset2 + kPcAdjustment),
    930                 "PC for BNE must be aligned.");
    931 
    932   // Allow reaching the thunk from the very beginning of a method almost 1MiB away. Backward branch
    933   // reaches the full 1MiB but we need to take PC adjustment into account. Things to subtract:
    934   //   - thunk size and method 3 pre-header, rounded up (padding in between if needed)
    935   //   - method 3 code and method 4 pre-header, rounded up (padding in between if needed)
    936   //   - method 4 header (let there be no padding between method 4 code and method 5 pre-header).
    937   size_t thunk_size =
    938       CompileBakerOffsetThunk(/* base_reg */ 0, /* holder_reg */ 0, /* narrow */ false).size();
    939   size_t filler2_size =
    940       1 * MB - (kLiteralOffset2 + kPcAdjustment)
    941              - RoundUp(thunk_size + sizeof(OatQuickMethodHeader), kArmAlignment)
    942              - RoundUp(kNopCode.size() + sizeof(OatQuickMethodHeader), kArmAlignment)
    943              - sizeof(OatQuickMethodHeader);
    944   std::vector<uint8_t> raw_filler2_code = GenNops(filler2_size / 2u);
    945   ArrayRef<const uint8_t> filler2_code(raw_filler2_code);
    946   AddCompiledMethod(MethodRef(4u), filler2_code);
    947 
    948   const std::vector<uint8_t> raw_code2 = RawCode({kNopWInsn, kBneWPlus0, kLdrWInsn});
    949   ArrayRef<const uint8_t> code2(raw_code2);
    950   const LinkerPatch patches2[] = {
    951       LinkerPatch::BakerReadBarrierBranchPatch(kLiteralOffset2, encoded_data),
    952   };
    953   AddCompiledMethod(MethodRef(5u), code2, ArrayRef<const LinkerPatch>(patches2));
    954 
    955   Link();
    956 
    957   uint32_t first_method_offset = GetMethodOffset(1u);
    958   uint32_t last_method_offset = GetMethodOffset(5u);
    959   EXPECT_EQ(2 * MB, last_method_offset - first_method_offset);
    960 
    961   const uint32_t bne_max_forward = kBneWPlus0 | 0x003f2fff;
    962   const uint32_t bne_max_backward = kBneWPlus0 | 0x04000000;
    963   const std::vector<uint8_t> expected_code1 =
    964       RawCode({kNopWInsn, kNopInsn, bne_max_forward, kLdrWInsn});
    965   const std::vector<uint8_t> expected_code2 = RawCode({kNopWInsn, bne_max_backward, kLdrWInsn});
    966   ASSERT_TRUE(CheckLinkedMethod(MethodRef(1), ArrayRef<const uint8_t>(expected_code1)));
    967   ASSERT_TRUE(CheckLinkedMethod(MethodRef(5), ArrayRef<const uint8_t>(expected_code2)));
    968 }
    969 
    970 TEST_F(Thumb2RelativePatcherTest, BakerOffsetThunkBeforeFiller) {
    971   // Based on the first part of BakerOffsetThunkInTheMiddle but the BNE is one instruction
    972   // earlier, so the thunk is emitted before the filler.
    973   // Use offset = 0, base_reg = 0, ref_reg = 0, the LDR is simply `kLdrWInsn`.
    974   constexpr uint32_t kLiteralOffset1 = 4u;
    975   const std::vector<uint8_t> raw_code1 = RawCode({kNopWInsn, kBneWPlus0, kLdrWInsn, kNopInsn});
    976   ArrayRef<const uint8_t> code1(raw_code1);
    977   uint32_t encoded_data = EncodeBakerReadBarrierFieldData(
    978       /* base_reg */ 0, /* holder_reg */ 0, /* narrow */ false);
    979   const LinkerPatch patches1[] = {
    980       LinkerPatch::BakerReadBarrierBranchPatch(kLiteralOffset1, encoded_data),
    981   };
    982   AddCompiledMethod(MethodRef(1u), code1, ArrayRef<const LinkerPatch>(patches1));
    983 
    984   constexpr uint32_t expected_thunk_offset =
    985       kLiteralOffset1 + kPcAdjustment + /* kMaxBcondPositiveDisplacement + 2 */ (1u << 20);
    986   static_assert(IsAligned<kArmAlignment>(expected_thunk_offset), "Target offset must be aligned.");
    987   size_t filler1_size = expected_thunk_offset -
    988                         RoundUp(raw_code1.size() + sizeof(OatQuickMethodHeader), kArmAlignment);
    989   std::vector<uint8_t> raw_filler1_code = GenNops(filler1_size / 2u);
    990   ArrayRef<const uint8_t> filler1_code(raw_filler1_code);
    991   AddCompiledMethod(MethodRef(2u), filler1_code);
    992 
    993   Link();
    994 
    995   const uint32_t bne = BneWWithOffset(kLiteralOffset1, RoundUp(raw_code1.size(), kArmAlignment));
    996   const std::vector<uint8_t> expected_code1 = RawCode({kNopWInsn, bne, kLdrWInsn, kNopInsn});
    997   ASSERT_TRUE(CheckLinkedMethod(MethodRef(1), ArrayRef<const uint8_t>(expected_code1)));
    998 }
    999 
   1000 TEST_F(Thumb2RelativePatcherTest, BakerOffsetThunkInTheMiddleUnreachableFromLast) {
   1001   // Based on the BakerOffsetThunkInTheMiddle but the BNE in the last method is preceded
   1002   // by NOP and cannot reach the thunk in the middle, so we emit an extra thunk at the end.
   1003   // Use offset = 0, base_reg = 0, ref_reg = 0, the LDR is simply `kLdrWInsn`.
   1004   constexpr uint32_t kLiteralOffset1 = 6u;
   1005   const std::vector<uint8_t> raw_code1 = RawCode({kNopWInsn, kNopInsn, kBneWPlus0, kLdrWInsn});
   1006   ArrayRef<const uint8_t> code1(raw_code1);
   1007   uint32_t encoded_data = EncodeBakerReadBarrierFieldData(
   1008       /* base_reg */ 0, /* holder_reg */ 0, /* narrow */ false);
   1009   const LinkerPatch patches1[] = {
   1010       LinkerPatch::BakerReadBarrierBranchPatch(kLiteralOffset1, encoded_data),
   1011   };
   1012   AddCompiledMethod(MethodRef(1u), code1, ArrayRef<const LinkerPatch>(patches1));
   1013 
   1014   constexpr uint32_t expected_thunk_offset =
   1015       kLiteralOffset1 + kPcAdjustment + /* kMaxBcondPositiveDisplacement */ ((1 << 20) - 2u);
   1016   static_assert(IsAligned<kArmAlignment>(expected_thunk_offset), "Target offset must be aligned.");
   1017   size_t filler1_size = expected_thunk_offset -
   1018                         RoundUp(raw_code1.size() + sizeof(OatQuickMethodHeader), kArmAlignment);
   1019   std::vector<uint8_t> raw_filler1_code = GenNops(filler1_size / 2u);
   1020   ArrayRef<const uint8_t> filler1_code(raw_filler1_code);
   1021   AddCompiledMethod(MethodRef(2u), filler1_code);
   1022 
   1023   // Enforce thunk reservation with a tiny method.
   1024   AddCompiledMethod(MethodRef(3u), kNopCode);
   1025 
   1026   constexpr uint32_t kReachableFromOffset2 = 4;
   1027   constexpr uint32_t kLiteralOffset2 = kReachableFromOffset2 + 2;
   1028   static_assert(IsAligned<kArmAlignment>(kReachableFromOffset2 + kPcAdjustment),
   1029                 "PC for BNE must be aligned.");
   1030 
   1031   // If not for the extra NOP, this would allow reaching the thunk from the BNE
   1032   // of a method 1MiB away. Backward branch reaches the full 1MiB  but we need to take
   1033   // PC adjustment into account. Things to subtract:
   1034   //   - thunk size and method 3 pre-header, rounded up (padding in between if needed)
   1035   //   - method 3 code and method 4 pre-header, rounded up (padding in between if needed)
   1036   //   - method 4 header (let there be no padding between method 4 code and method 5 pre-header).
   1037   size_t thunk_size =
   1038       CompileBakerOffsetThunk(/* base_reg */ 0, /* holder_reg */ 0, /* narrow */ false).size();
   1039   size_t filler2_size =
   1040       1 * MB - (kReachableFromOffset2 + kPcAdjustment)
   1041              - RoundUp(thunk_size + sizeof(OatQuickMethodHeader), kArmAlignment)
   1042              - RoundUp(kNopCode.size() + sizeof(OatQuickMethodHeader), kArmAlignment)
   1043              - sizeof(OatQuickMethodHeader);
   1044   std::vector<uint8_t> raw_filler2_code = GenNops(filler2_size / 2u);
   1045   ArrayRef<const uint8_t> filler2_code(raw_filler2_code);
   1046   AddCompiledMethod(MethodRef(4u), filler2_code);
   1047 
   1048   // Extra 16-bit NOP compared to BakerOffsetThunkInTheMiddle.
   1049   const std::vector<uint8_t> raw_code2 = RawCode({kNopWInsn, kNopInsn, kBneWPlus0, kLdrWInsn});
   1050   ArrayRef<const uint8_t> code2(raw_code2);
   1051   const LinkerPatch patches2[] = {
   1052       LinkerPatch::BakerReadBarrierBranchPatch(kLiteralOffset2, encoded_data),
   1053   };
   1054   AddCompiledMethod(MethodRef(5u), code2, ArrayRef<const LinkerPatch>(patches2));
   1055 
   1056   Link();
   1057 
   1058   uint32_t first_method_offset = GetMethodOffset(1u);
   1059   uint32_t last_method_offset = GetMethodOffset(5u);
   1060   EXPECT_EQ(2 * MB, last_method_offset - first_method_offset);
   1061 
   1062   const uint32_t bne_max_forward = kBneWPlus0 | 0x003f2fff;
   1063   const uint32_t bne_last =
   1064       BneWWithOffset(kLiteralOffset2, RoundUp(raw_code2.size(), kArmAlignment));
   1065   const std::vector<uint8_t> expected_code1 =
   1066       RawCode({kNopWInsn, kNopInsn, bne_max_forward, kLdrWInsn});
   1067   const std::vector<uint8_t> expected_code2 =
   1068       RawCode({kNopWInsn, kNopInsn, bne_last, kLdrWInsn});
   1069   ASSERT_TRUE(CheckLinkedMethod(MethodRef(1), ArrayRef<const uint8_t>(expected_code1)));
   1070   ASSERT_TRUE(CheckLinkedMethod(MethodRef(5), ArrayRef<const uint8_t>(expected_code2)));
   1071 }
   1072 
   1073 TEST_F(Thumb2RelativePatcherTest, BakerArray) {
   1074   auto ldr = [](uint32_t base_reg) {
   1075     uint32_t index_reg = (base_reg == 0u) ? 1u : 0u;
   1076     uint32_t ref_reg = (base_reg == 2) ? 3u : 2u;
   1077     return kLdrRegLsl2 | index_reg | (base_reg << 16) | (ref_reg << 12);
   1078   };
   1079   constexpr size_t kMethodCodeSize = 8u;
   1080   constexpr size_t kLiteralOffset = 0u;
   1081   uint32_t method_idx = 0u;
   1082   for (uint32_t base_reg : kBakerValidRegs) {
   1083     ++method_idx;
   1084     const std::vector<uint8_t> raw_code = RawCode({kBneWPlus0, ldr(base_reg)});
   1085     ASSERT_EQ(kMethodCodeSize, raw_code.size());
   1086     ArrayRef<const uint8_t> code(raw_code);
   1087     const LinkerPatch patches[] = {
   1088         LinkerPatch::BakerReadBarrierBranchPatch(
   1089             kLiteralOffset, EncodeBakerReadBarrierArrayData(base_reg)),
   1090     };
   1091     AddCompiledMethod(MethodRef(method_idx), code, ArrayRef<const LinkerPatch>(patches));
   1092   }
   1093   Link();
   1094 
   1095   // All thunks are at the end.
   1096   uint32_t thunk_offset = GetMethodOffset(method_idx) + RoundUp(kMethodCodeSize, kArmAlignment);
   1097   method_idx = 0u;
   1098   for (uint32_t base_reg : kBakerValidRegs) {
   1099     ++method_idx;
   1100     uint32_t bne = BneWWithOffset(GetMethodOffset(method_idx) + kLiteralOffset, thunk_offset);
   1101     const std::vector<uint8_t> expected_code = RawCode({bne, ldr(base_reg)});
   1102     ASSERT_EQ(kMethodCodeSize, expected_code.size());
   1103     EXPECT_TRUE(CheckLinkedMethod(MethodRef(method_idx), ArrayRef<const uint8_t>(expected_code)));
   1104 
   1105     std::vector<uint8_t> expected_thunk = CompileBakerArrayThunk(base_reg);
   1106     ASSERT_GT(output_.size(), thunk_offset);
   1107     ASSERT_GE(output_.size() - thunk_offset, expected_thunk.size());
   1108     ArrayRef<const uint8_t> compiled_thunk(output_.data() + thunk_offset,
   1109                                            expected_thunk.size());
   1110     if (ArrayRef<const uint8_t>(expected_thunk) != compiled_thunk) {
   1111       DumpDiff(ArrayRef<const uint8_t>(expected_thunk), compiled_thunk);
   1112       ASSERT_TRUE(false);
   1113     }
   1114 
   1115     // Verify that the lock word for gray bit check is loaded from the correct address
   1116     // before the base_reg which points to the array data.
   1117     ASSERT_GE(output_.size() - thunk_offset,
   1118               4u * /* 32-bit instructions */ 4u + 2u * /* 16-bit instructions */ 2u);
   1119     int32_t data_offset =
   1120         mirror::Array::DataOffset(Primitive::ComponentSize(Primitive::kPrimNot)).Int32Value();
   1121     int32_t offset = mirror::Object::MonitorOffset().Int32Value() - data_offset;
   1122     ASSERT_LT(offset, 0);
   1123     ASSERT_GT(offset, -256);
   1124     const uint32_t load_lock_word =
   1125         kLdrNegativeOffset |
   1126         (-offset & 0xffu) |
   1127         (base_reg << 16) |
   1128         (/* IP */ 12 << 12);
   1129     EXPECT_EQ(load_lock_word, GetOutputInsn32(thunk_offset));
   1130     // Verify the gray bit check.
   1131     DCHECK_GE(LockWord::kReadBarrierStateShift, 8u);  // ROR modified immediate.
   1132     uint32_t ror_shift = 7 + (32 - LockWord::kReadBarrierStateShift);
   1133     const uint32_t tst_gray_bit_without_offset =
   1134         0xf0100f00 | (/* IP */ 12 << 16)
   1135                    | (((ror_shift >> 4) & 1) << 26)   // i
   1136                    | (((ror_shift >> 1) & 7) << 12)   // imm3
   1137                    | ((ror_shift & 1) << 7);          // imm8, ROR('1':imm8<7:0>, ror_shift).
   1138     EXPECT_EQ(tst_gray_bit_without_offset, GetOutputInsn32(thunk_offset + 4u));
   1139     EXPECT_EQ(0xd100u, GetOutputInsn16(thunk_offset + 8u) & 0xff00u);  // BNE
   1140     // Verify the fake dependency.
   1141     const uint32_t fake_dependency =
   1142         0xeb000010 |              // ADD Rd, Rn, Rm, LSR 32 (type=01, imm3=000, imm2=00)
   1143         (/* IP */ 12) |           // Rm = IP
   1144         (base_reg << 16) |        // Rn = base_reg
   1145         (base_reg << 8);          // Rd = base_reg
   1146     EXPECT_EQ(fake_dependency, GetOutputInsn32(thunk_offset + 14u));
   1147     // Do not check the rest of the implementation.
   1148 
   1149     // The next thunk follows on the next aligned offset.
   1150     thunk_offset += RoundUp(expected_thunk.size(), kArmAlignment);
   1151   }
   1152 }
   1153 
   1154 TEST_F(Thumb2RelativePatcherTest, BakerGcRootWide) {
   1155   constexpr size_t kMethodCodeSize = 8u;
   1156   constexpr size_t kLiteralOffset = 4u;
   1157   uint32_t method_idx = 0u;
   1158   for (uint32_t root_reg : kBakerValidRegs) {
   1159     ++method_idx;
   1160     uint32_t ldr = kLdrWInsn | (/* offset */ 8) | (/* base_reg */ 0 << 16) | (root_reg << 12);
   1161     const std::vector<uint8_t> raw_code = RawCode({ldr, kBneWPlus0});
   1162     ASSERT_EQ(kMethodCodeSize, raw_code.size());
   1163     ArrayRef<const uint8_t> code(raw_code);
   1164     const LinkerPatch patches[] = {
   1165         LinkerPatch::BakerReadBarrierBranchPatch(
   1166             kLiteralOffset, EncodeBakerReadBarrierGcRootData(root_reg, /* narrow */ false)),
   1167     };
   1168     AddCompiledMethod(MethodRef(method_idx), code, ArrayRef<const LinkerPatch>(patches));
   1169   }
   1170   Link();
   1171 
   1172   // All thunks are at the end.
   1173   uint32_t thunk_offset = GetMethodOffset(method_idx) + RoundUp(kMethodCodeSize, kArmAlignment);
   1174   method_idx = 0u;
   1175   for (uint32_t root_reg : kBakerValidRegs) {
   1176     ++method_idx;
   1177     uint32_t bne = BneWWithOffset(GetMethodOffset(method_idx) + kLiteralOffset, thunk_offset);
   1178     uint32_t ldr = kLdrWInsn | (/* offset */ 8) | (/* base_reg */ 0 << 16) | (root_reg << 12);
   1179     const std::vector<uint8_t> expected_code = RawCode({ldr, bne});
   1180     ASSERT_EQ(kMethodCodeSize, expected_code.size());
   1181     EXPECT_TRUE(CheckLinkedMethod(MethodRef(method_idx), ArrayRef<const uint8_t>(expected_code)));
   1182 
   1183     std::vector<uint8_t> expected_thunk = CompileBakerGcRootThunk(root_reg, /* narrow */ false);
   1184     ASSERT_GT(output_.size(), thunk_offset);
   1185     ASSERT_GE(output_.size() - thunk_offset, expected_thunk.size());
   1186     ArrayRef<const uint8_t> compiled_thunk(output_.data() + thunk_offset,
   1187                                            expected_thunk.size());
   1188     if (ArrayRef<const uint8_t>(expected_thunk) != compiled_thunk) {
   1189       DumpDiff(ArrayRef<const uint8_t>(expected_thunk), compiled_thunk);
   1190       ASSERT_TRUE(false);
   1191     }
   1192 
   1193     // Verify that the fast-path null-check uses the correct register, i.e. root_reg.
   1194     if (root_reg < 8) {
   1195       ASSERT_GE(output_.size() - thunk_offset, 2u);
   1196       ASSERT_EQ(0xb100 | root_reg, GetOutputInsn16(thunk_offset) & 0xfd07u);
   1197     } else {
   1198       ASSERT_GE(output_.size() - thunk_offset, 6u);
   1199       ASSERT_EQ(0xf1b00f00u | (root_reg << 16), GetOutputInsn32(thunk_offset) & 0xfbff8f00u);
   1200       ASSERT_EQ(0xd000u, GetOutputInsn16(thunk_offset + 4u) & 0xff00u);  // BEQ
   1201     }
   1202     // Do not check the rest of the implementation.
   1203 
   1204     // The next thunk follows on the next aligned offset.
   1205     thunk_offset += RoundUp(expected_thunk.size(), kArmAlignment);
   1206   }
   1207 }
   1208 
   1209 TEST_F(Thumb2RelativePatcherTest, BakerGcRootNarrow) {
   1210   constexpr size_t kMethodCodeSize = 6u;
   1211   constexpr size_t kLiteralOffset = 2u;
   1212   uint32_t method_idx = 0u;
   1213   for (uint32_t root_reg : kBakerValidRegsNarrow) {
   1214     ++method_idx;
   1215     uint32_t ldr = kLdrInsn | (/* offset */ 8 << (6 - 2)) | (/* base_reg */ 0 << 3) | root_reg;
   1216     const std::vector<uint8_t> raw_code = RawCode({ldr, kBneWPlus0});
   1217     ASSERT_EQ(kMethodCodeSize, raw_code.size());
   1218     ArrayRef<const uint8_t> code(raw_code);
   1219     const LinkerPatch patches[] = {
   1220         LinkerPatch::BakerReadBarrierBranchPatch(
   1221             kLiteralOffset, EncodeBakerReadBarrierGcRootData(root_reg, /* narrow */ true)),
   1222     };
   1223     AddCompiledMethod(MethodRef(method_idx), code, ArrayRef<const LinkerPatch>(patches));
   1224   }
   1225   Link();
   1226 
   1227   // All thunks are at the end.
   1228   uint32_t thunk_offset = GetMethodOffset(method_idx) + RoundUp(kMethodCodeSize, kArmAlignment);
   1229   method_idx = 0u;
   1230   for (uint32_t root_reg : kBakerValidRegsNarrow) {
   1231     ++method_idx;
   1232     uint32_t bne = BneWWithOffset(GetMethodOffset(method_idx) + kLiteralOffset, thunk_offset);
   1233     uint32_t ldr = kLdrInsn | (/* offset */ 8 << (6 - 2)) | (/* base_reg */ 0 << 3) | root_reg;
   1234     const std::vector<uint8_t> expected_code = RawCode({ldr, bne});
   1235     ASSERT_EQ(kMethodCodeSize, expected_code.size());
   1236     EXPECT_TRUE(CheckLinkedMethod(MethodRef(method_idx), ArrayRef<const uint8_t>(expected_code)));
   1237 
   1238     std::vector<uint8_t> expected_thunk = CompileBakerGcRootThunk(root_reg, /* narrow */ true);
   1239     ASSERT_GT(output_.size(), thunk_offset);
   1240     ASSERT_GE(output_.size() - thunk_offset, expected_thunk.size());
   1241     ArrayRef<const uint8_t> compiled_thunk(output_.data() + thunk_offset,
   1242                                            expected_thunk.size());
   1243     if (ArrayRef<const uint8_t>(expected_thunk) != compiled_thunk) {
   1244       DumpDiff(ArrayRef<const uint8_t>(expected_thunk), compiled_thunk);
   1245       ASSERT_TRUE(false);
   1246     }
   1247 
   1248     // Verify that the fast-path null-check CBZ uses the correct register, i.e. root_reg.
   1249     ASSERT_GE(output_.size() - thunk_offset, 2u);
   1250     ASSERT_EQ(0xb100 | root_reg, GetOutputInsn16(thunk_offset) & 0xfd07u);
   1251     // Do not check the rest of the implementation.
   1252 
   1253     // The next thunk follows on the next aligned offset.
   1254     thunk_offset += RoundUp(expected_thunk.size(), kArmAlignment);
   1255   }
   1256 }
   1257 
   1258 TEST_F(Thumb2RelativePatcherTest, BakerGcRootOffsetBits) {
   1259   // Test 1MiB of patches to the same thunk to stress-test different large offsets.
   1260   // (The low bits are not that important but the location of the high bits is easy to get wrong.)
   1261   std::vector<uint8_t> code;
   1262   code.reserve(1 * MB);
   1263   const size_t num_patches = 1 * MB / 8u;
   1264   std::vector<LinkerPatch> patches;
   1265   patches.reserve(num_patches);
   1266   const uint32_t ldr =
   1267       kLdrWInsn | (/* offset */ 8) | (/* base_reg */ 0 << 16) | (/* root_reg */ 0 << 12);
   1268   uint32_t encoded_data = EncodeBakerReadBarrierGcRootData(/* root_reg */ 0, /* narrow */ false);
   1269   for (size_t i = 0; i != num_patches; ++i) {
   1270     PushBackInsn(&code, ldr);
   1271     PushBackInsn(&code, kBneWPlus0);
   1272     patches.push_back(LinkerPatch::BakerReadBarrierBranchPatch(8u * i + 4u, encoded_data));
   1273   }
   1274   ASSERT_EQ(1 * MB, code.size());
   1275   ASSERT_EQ(num_patches, patches.size());
   1276   AddCompiledMethod(MethodRef(1u),
   1277                     ArrayRef<const uint8_t>(code),
   1278                     ArrayRef<const LinkerPatch>(patches));
   1279   Link();
   1280 
   1281   // The thunk is right after the method code.
   1282   DCHECK_ALIGNED(1 * MB, kArmAlignment);
   1283   std::vector<uint8_t> expected_code;
   1284   for (size_t i = 0; i != num_patches; ++i) {
   1285     PushBackInsn(&expected_code, ldr);
   1286     PushBackInsn(&expected_code, BneWWithOffset(8u * i + 4u, 1 * MB));
   1287     patches.push_back(LinkerPatch::BakerReadBarrierBranchPatch(8u * i + 4u, encoded_data));
   1288   }
   1289   EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
   1290 }
   1291 
   1292 TEST_F(Thumb2RelativePatcherTest, BakerAndMethodCallInteraction) {
   1293   // During development, there was a `DCHECK_LE(MaxNextOffset(), next_thunk.MaxNextOffset());`
   1294   // in `ArmBaseRelativePatcher::ThunkData::MakeSpaceBefore()` which does not necessarily
   1295   // hold when we're reserving thunks of different sizes. This test exposes the situation
   1296   // by using Baker thunks and a method call thunk.
   1297 
   1298   // Add a method call patch that can reach to method 1 offset + 16MiB.
   1299   uint32_t method_idx = 0u;
   1300   constexpr size_t kMethodCallLiteralOffset = 2u;
   1301   constexpr uint32_t kMissingMethodIdx = 2u;
   1302   const std::vector<uint8_t> raw_code1 = RawCode({kNopInsn, kBlPlus0});
   1303   const LinkerPatch method1_patches[] = {
   1304       LinkerPatch::RelativeCodePatch(kMethodCallLiteralOffset, nullptr, 2u),
   1305   };
   1306   ArrayRef<const uint8_t> code1(raw_code1);
   1307   ++method_idx;
   1308   AddCompiledMethod(MethodRef(1u), code1, ArrayRef<const LinkerPatch>(method1_patches));
   1309 
   1310   // Skip kMissingMethodIdx.
   1311   ++method_idx;
   1312   ASSERT_EQ(kMissingMethodIdx, method_idx);
   1313   // Add a method with the right size that the method code for the next one starts 1MiB
   1314   // after code for method 1.
   1315   size_t filler_size =
   1316       1 * MB - RoundUp(raw_code1.size() + sizeof(OatQuickMethodHeader), kArmAlignment)
   1317              - sizeof(OatQuickMethodHeader);
   1318   std::vector<uint8_t> filler_code = GenNops(filler_size / 2u);
   1319   ++method_idx;
   1320   AddCompiledMethod(MethodRef(method_idx), ArrayRef<const uint8_t>(filler_code));
   1321   // Add 14 methods with 1MiB code+header, making the code for the next method start 1MiB
   1322   // before the currently scheduled MaxNextOffset() for the method call thunk.
   1323   for (uint32_t i = 0; i != 14; ++i) {
   1324     filler_size = 1 * MB - sizeof(OatQuickMethodHeader);
   1325     filler_code = GenNops(filler_size / 2u);
   1326     ++method_idx;
   1327     AddCompiledMethod(MethodRef(method_idx), ArrayRef<const uint8_t>(filler_code));
   1328   }
   1329 
   1330   // Add 2 Baker GC root patches to the last method, one that would allow the thunk at
   1331   // 1MiB + kArmAlignment, i.e. kArmAlignment after the method call thunk, and the
   1332   // second that needs it kArmAlignment after that. Given the size of the GC root thunk
   1333   // is more than the space required by the method call thunk plus kArmAlignment,
   1334   // this pushes the first GC root thunk's pending MaxNextOffset() before the method call
   1335   // thunk's pending MaxNextOffset() which needs to be adjusted.
   1336   ASSERT_LT(RoundUp(CompileMethodCallThunk().size(), kArmAlignment) + kArmAlignment,
   1337             CompileBakerGcRootThunk(/* root_reg */ 0, /* narrow */ false).size());
   1338   static_assert(kArmAlignment == 8, "Code below assumes kArmAlignment == 8");
   1339   constexpr size_t kBakerLiteralOffset1 = kArmAlignment + 2u - kPcAdjustment;
   1340   constexpr size_t kBakerLiteralOffset2 = kBakerLiteralOffset1 + kArmAlignment;
   1341   // Use offset = 0, base_reg = 0, the LDR is simply `kLdrWInsn | (root_reg << 12)`.
   1342   const uint32_t ldr1 = kLdrWInsn | (/* root_reg */ 1 << 12);
   1343   const uint32_t ldr2 = kLdrWInsn | (/* root_reg */ 2 << 12);
   1344   const std::vector<uint8_t> last_method_raw_code = RawCode({
   1345       kNopInsn,                                 // Padding before first GC root read barrier.
   1346       ldr1, kBneWPlus0,                         // First GC root LDR with read barrier.
   1347       ldr2, kBneWPlus0,                         // Second GC root LDR with read barrier.
   1348   });
   1349   uint32_t encoded_data1 = EncodeBakerReadBarrierGcRootData(/* root_reg */ 1, /* narrow */ false);
   1350   uint32_t encoded_data2 = EncodeBakerReadBarrierGcRootData(/* root_reg */ 2, /* narrow */ false);
   1351   const LinkerPatch last_method_patches[] = {
   1352       LinkerPatch::BakerReadBarrierBranchPatch(kBakerLiteralOffset1, encoded_data1),
   1353       LinkerPatch::BakerReadBarrierBranchPatch(kBakerLiteralOffset2, encoded_data2),
   1354   };
   1355   ++method_idx;
   1356   AddCompiledMethod(MethodRef(method_idx),
   1357                     ArrayRef<const uint8_t>(last_method_raw_code),
   1358                     ArrayRef<const LinkerPatch>(last_method_patches));
   1359 
   1360   // The main purpose of the test is to check that Link() does not cause a crash.
   1361   Link();
   1362 
   1363   ASSERT_EQ(15 * MB, GetMethodOffset(method_idx) - GetMethodOffset(1u));
   1364 }
   1365 
   1366 }  // namespace linker
   1367 }  // namespace art
   1368