1944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko/*
2944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * Copyright (C) 2016 The Android Open Source Project
3944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko *
4944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * Licensed under the Apache License, Version 2.0 (the "License");
5944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * you may not use this file except in compliance with the License.
6944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * You may obtain a copy of the License at
7944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko *
8944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko *      http://www.apache.org/licenses/LICENSE-2.0
9944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko *
10944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * Unless required by applicable law or agreed to in writing, software
11944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * distributed under the License is distributed on an "AS IS" BASIS,
12944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * See the License for the specific language governing permissions and
14944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * limitations under the License.
15944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko */
16944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
17944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko#include "compiled_method.h"
18944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko#include "gtest/gtest.h"
19944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko#include "multi_oat_relative_patcher.h"
20944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko#include "vector_output_stream.h"
21944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
22944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Markonamespace art {
23944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Markonamespace linker {
24944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
25944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Markostatic const MethodReference kNullMethodRef = MethodReference(nullptr, 0u);
26944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
27944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Markostatic bool EqualRef(MethodReference lhs, MethodReference rhs) {
28944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  return lhs.dex_file == rhs.dex_file && lhs.dex_method_index == rhs.dex_method_index;
29944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko}
30944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
31944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Markoclass MultiOatRelativePatcherTest : public testing::Test {
32944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko protected:
33944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  class MockPatcher : public RelativePatcher {
34944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko   public:
35944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    MockPatcher() { }
36944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
37944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    uint32_t ReserveSpace(uint32_t offset,
38944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko                          const CompiledMethod* compiled_method ATTRIBUTE_UNUSED,
39944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko                          MethodReference method_ref) OVERRIDE {
40944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      last_reserve_offset_ = offset;
41944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      last_reserve_method_ = method_ref;
42944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      offset += next_reserve_adjustment_;
43944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      next_reserve_adjustment_ = 0u;
44944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      return offset;
45944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    }
46944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
47944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    uint32_t ReserveSpaceEnd(uint32_t offset) OVERRIDE {
48944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      last_reserve_offset_ = offset;
49944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      last_reserve_method_ = kNullMethodRef;
50944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      offset += next_reserve_adjustment_;
51944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      next_reserve_adjustment_ = 0u;
52944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      return offset;
53944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    }
54944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
55944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    uint32_t WriteThunks(OutputStream* out, uint32_t offset) OVERRIDE {
56944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      last_write_offset_ = offset;
57944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      if (next_write_alignment_ != 0u) {
58944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko        offset += next_write_alignment_;
59944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko        bool success = WriteCodeAlignment(out, next_write_alignment_);
60944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko        CHECK(success);
61944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko        next_write_alignment_ = 0u;
62944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      }
63944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      if (next_write_call_thunk_ != 0u) {
64944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko        offset += next_write_call_thunk_;
65944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko        std::vector<uint8_t> thunk(next_write_call_thunk_, 'c');
66944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko        bool success = WriteRelCallThunk(out, ArrayRef<const uint8_t>(thunk));
67944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko        CHECK(success);
68944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko        next_write_call_thunk_ = 0u;
69944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      }
70944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      if (next_write_misc_thunk_ != 0u) {
71944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko        offset += next_write_misc_thunk_;
72944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko        std::vector<uint8_t> thunk(next_write_misc_thunk_, 'm');
73944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko        bool success = WriteMiscThunk(out, ArrayRef<const uint8_t>(thunk));
74944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko        CHECK(success);
75944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko        next_write_misc_thunk_ = 0u;
76944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      }
77944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      return offset;
78944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    }
79944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
80944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    void PatchCall(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
81944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko                   uint32_t literal_offset,
82944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko                   uint32_t patch_offset,
83944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko                   uint32_t target_offset) OVERRIDE {
84944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      last_literal_offset_ = literal_offset;
85944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      last_patch_offset_ = patch_offset;
86944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      last_target_offset_ = target_offset;
87944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    }
88944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
89cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko    void PatchPcRelativeReference(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
90cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko                                  const LinkerPatch& patch,
91cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko                                  uint32_t patch_offset,
92cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko                                  uint32_t target_offset) OVERRIDE {
93944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      last_literal_offset_ = patch.LiteralOffset();
94944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      last_patch_offset_ = patch_offset;
95944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      last_target_offset_ = target_offset;
96944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    }
97944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
98944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    uint32_t last_reserve_offset_ = 0u;
99944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    MethodReference last_reserve_method_ = kNullMethodRef;
100944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    uint32_t next_reserve_adjustment_ = 0u;
101944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
102944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    uint32_t last_write_offset_ = 0u;
103944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    uint32_t next_write_alignment_ = 0u;
104944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    uint32_t next_write_call_thunk_ = 0u;
105944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    uint32_t next_write_misc_thunk_ = 0u;
106944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
107944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    uint32_t last_literal_offset_ = 0u;
108944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    uint32_t last_patch_offset_ = 0u;
109944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    uint32_t last_target_offset_ = 0u;
110944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  };
111944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
112944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  MultiOatRelativePatcherTest()
113944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      : instruction_set_features_(InstructionSetFeatures::FromCppDefines()),
114944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko        patcher_(kRuntimeISA, instruction_set_features_.get()) {
115944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    std::unique_ptr<MockPatcher> mock(new MockPatcher());
116944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    mock_ = mock.get();
117944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    patcher_.relative_patcher_ = std::move(mock);
118944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  }
119944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
120944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  std::unique_ptr<const InstructionSetFeatures> instruction_set_features_;
121944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  MultiOatRelativePatcher patcher_;
122944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  MockPatcher* mock_;
123944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko};
124944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
125944da603cde59a4277f3bbc31d860a90842a1a2aVladimir MarkoTEST_F(MultiOatRelativePatcherTest, Offsets) {
126944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  const DexFile* dex_file = reinterpret_cast<const DexFile*>(1);
127944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  MethodReference ref1(dex_file, 1u);
128944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  MethodReference ref2(dex_file, 2u);
129944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  EXPECT_EQ(0u, patcher_.GetOffset(ref1));
130944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  EXPECT_EQ(0u, patcher_.GetOffset(ref2));
131944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
132944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t adjustment1 = 0x1000;
133944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  patcher_.StartOatFile(adjustment1);
134944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  EXPECT_EQ(0u, patcher_.GetOffset(ref1));
135944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  EXPECT_EQ(0u, patcher_.GetOffset(ref2));
136944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
137944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t off1 = 0x1234;
138944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  patcher_.SetOffset(ref1, off1);
139944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  EXPECT_EQ(off1, patcher_.GetOffset(ref1));
140944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  EXPECT_EQ(0u, patcher_.GetOffset(ref2));
141944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
142944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t adjustment2 = 0x30000;
143944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  patcher_.StartOatFile(adjustment2);
144944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  EXPECT_EQ(off1 + adjustment1 - adjustment2, patcher_.GetOffset(ref1));
145944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  EXPECT_EQ(0u, patcher_.GetOffset(ref2));
146944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
147944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t off2 = 0x4321;
148944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  patcher_.SetOffset(ref2, off2);
149944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  EXPECT_EQ(off1 + adjustment1 - adjustment2, patcher_.GetOffset(ref1));
150944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  EXPECT_EQ(off2, patcher_.GetOffset(ref2));
151944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
152944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t adjustment3 = 0x78000;
153944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  patcher_.StartOatFile(adjustment3);
154944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  EXPECT_EQ(off1 + adjustment1 - adjustment3, patcher_.GetOffset(ref1));
155944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  EXPECT_EQ(off2 + adjustment2 - adjustment3, patcher_.GetOffset(ref2));
156944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko}
157944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
158944da603cde59a4277f3bbc31d860a90842a1a2aVladimir MarkoTEST_F(MultiOatRelativePatcherTest, OffsetsInReserve) {
159944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  const DexFile* dex_file = reinterpret_cast<const DexFile*>(1);
160944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  MethodReference ref1(dex_file, 1u);
161944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  MethodReference ref2(dex_file, 2u);
162944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  MethodReference ref3(dex_file, 3u);
163944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  const CompiledMethod* method = reinterpret_cast<const CompiledMethod*>(-1);
164944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
165944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t adjustment1 = 0x1000;
166944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  patcher_.StartOatFile(adjustment1);
167944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
168944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method1_offset = 0x100;
169944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method1_offset_check = patcher_.ReserveSpace(method1_offset, method, ref1);
170944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_EQ(adjustment1 + method1_offset, mock_->last_reserve_offset_);
171944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_TRUE(EqualRef(ref1, mock_->last_reserve_method_));
172944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_EQ(method1_offset, method1_offset_check);
173944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
174944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method2_offset = 0x1230;
175944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method2_reserve_adjustment = 0x10;
176944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  mock_->next_reserve_adjustment_ = method2_reserve_adjustment;
177944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method2_offset_adjusted = patcher_.ReserveSpace(method2_offset, method, ref2);
178944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_EQ(adjustment1 + method2_offset, mock_->last_reserve_offset_);
179944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_TRUE(EqualRef(ref2, mock_->last_reserve_method_));
180944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_EQ(method2_offset + method2_reserve_adjustment, method2_offset_adjusted);
181944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
182944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t end1_offset = 0x4320;
183944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t end1_offset_check = patcher_.ReserveSpaceEnd(end1_offset);
184944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_EQ(adjustment1 + end1_offset, mock_->last_reserve_offset_);
185944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_TRUE(EqualRef(kNullMethodRef, mock_->last_reserve_method_));
186944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_EQ(end1_offset, end1_offset_check);
187944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
188944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t adjustment2 = 0xd000;
189944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  patcher_.StartOatFile(adjustment2);
190944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
191944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method3_offset = 0xf00;
192944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method3_offset_check = patcher_.ReserveSpace(method3_offset, method, ref3);
193944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_EQ(adjustment2 + method3_offset, mock_->last_reserve_offset_);
194944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_TRUE(EqualRef(ref3, mock_->last_reserve_method_));
195944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_EQ(method3_offset, method3_offset_check);
196944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
197944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t end2_offset = 0x2400;
198944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t end2_reserve_adjustment = 0x20;
199944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  mock_->next_reserve_adjustment_ = end2_reserve_adjustment;
200944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t end2_offset_adjusted = patcher_.ReserveSpaceEnd(end2_offset);
201944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_EQ(adjustment2 + end2_offset, mock_->last_reserve_offset_);
202944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_TRUE(EqualRef(kNullMethodRef, mock_->last_reserve_method_));
203944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_EQ(end2_offset + end2_reserve_adjustment, end2_offset_adjusted);
204944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko}
205944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
206944da603cde59a4277f3bbc31d860a90842a1a2aVladimir MarkoTEST_F(MultiOatRelativePatcherTest, Write) {
207944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  std::vector<uint8_t> output;
208944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  VectorOutputStream vos("output", &output);
209944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
210944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t adjustment1 = 0x1000;
211944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  patcher_.StartOatFile(adjustment1);
212944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
213944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method1_offset = 0x100;
214944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method1_offset_check = patcher_.WriteThunks(&vos, method1_offset);
215944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_EQ(adjustment1 + method1_offset, mock_->last_write_offset_);
216944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_EQ(method1_offset, method1_offset_check);
217944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  vos.WriteFully("1", 1);  // Mark method1.
218944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
219944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method2_offset = 0x1230;
220944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method2_alignment_size = 1;
221944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method2_call_thunk_size = 2;
222944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  mock_->next_write_alignment_ = method2_alignment_size;
223944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  mock_->next_write_call_thunk_ = method2_call_thunk_size;
224944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method2_offset_adjusted = patcher_.WriteThunks(&vos, method2_offset);
225944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_EQ(adjustment1 + method2_offset, mock_->last_write_offset_);
226944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_EQ(method2_offset + method2_alignment_size + method2_call_thunk_size,
227944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko            method2_offset_adjusted);
228944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  vos.WriteFully("2", 1);  // Mark method2.
229944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
230944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  EXPECT_EQ(method2_alignment_size, patcher_.CodeAlignmentSize());
231944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  EXPECT_EQ(method2_call_thunk_size, patcher_.RelativeCallThunksSize());
232944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
233944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t adjustment2 = 0xd000;
234944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  patcher_.StartOatFile(adjustment2);
235944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
236944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method3_offset = 0xf00;
237944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method3_alignment_size = 2;
238944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method3_misc_thunk_size = 1;
239944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  mock_->next_write_alignment_ = method3_alignment_size;
240944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  mock_->next_write_misc_thunk_ = method3_misc_thunk_size;
241944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method3_offset_adjusted = patcher_.WriteThunks(&vos, method3_offset);
242944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_EQ(adjustment2 + method3_offset, mock_->last_write_offset_);
243944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_EQ(method3_offset + method3_alignment_size + method3_misc_thunk_size,
244944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko            method3_offset_adjusted);
245944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  vos.WriteFully("3", 1);  // Mark method3.
246944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
247944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  EXPECT_EQ(method3_alignment_size, patcher_.CodeAlignmentSize());
248944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  EXPECT_EQ(method3_misc_thunk_size, patcher_.MiscThunksSize());
249944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
250944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint8_t expected_output[] = {
251944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      '1',
252944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      0, 'c', 'c', '2',
253944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      0, 0, 'm', '3',
254944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  };
255944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  ASSERT_EQ(arraysize(expected_output), output.size());
256944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  for (size_t i = 0; i != arraysize(expected_output); ++i) {
257944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    ASSERT_EQ(expected_output[i], output[i]) << i;
258944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  }
259944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko}
260944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
261944da603cde59a4277f3bbc31d860a90842a1a2aVladimir MarkoTEST_F(MultiOatRelativePatcherTest, Patch) {
262944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  std::vector<uint8_t> code(16);
263944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
264944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t adjustment1 = 0x1000;
265944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  patcher_.StartOatFile(adjustment1);
266944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
267944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method1_literal_offset = 4u;
268944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method1_patch_offset = 0x1234u;
269944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method1_target_offset = 0x8888u;
270944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  patcher_.PatchCall(&code, method1_literal_offset, method1_patch_offset, method1_target_offset);
271944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  DCHECK_EQ(method1_literal_offset, mock_->last_literal_offset_);
272944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  DCHECK_EQ(method1_patch_offset + adjustment1, mock_->last_patch_offset_);
273944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  DCHECK_EQ(method1_target_offset + adjustment1, mock_->last_target_offset_);
274944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
275944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method2_literal_offset = 12u;
276944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method2_patch_offset = 0x7654u;
277944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method2_target_offset = 0xccccu;
278944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  LinkerPatch method2_patch =
279944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      LinkerPatch::DexCacheArrayPatch(method2_literal_offset, nullptr, 0u, 1234u);
280cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko  patcher_.PatchPcRelativeReference(
281944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      &code, method2_patch, method2_patch_offset, method2_target_offset);
282944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  DCHECK_EQ(method2_literal_offset, mock_->last_literal_offset_);
283944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  DCHECK_EQ(method2_patch_offset + adjustment1, mock_->last_patch_offset_);
284944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  DCHECK_EQ(method2_target_offset + adjustment1, mock_->last_target_offset_);
285944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
286944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t adjustment2 = 0xd000;
287944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  patcher_.StartOatFile(adjustment2);
288944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
289944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method3_literal_offset = 8u;
290944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method3_patch_offset = 0x108u;
291944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t method3_target_offset = 0x200u;
292944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  patcher_.PatchCall(&code, method3_literal_offset, method3_patch_offset, method3_target_offset);
293944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  DCHECK_EQ(method3_literal_offset, mock_->last_literal_offset_);
294944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  DCHECK_EQ(method3_patch_offset + adjustment2, mock_->last_patch_offset_);
295944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  DCHECK_EQ(method3_target_offset + adjustment2, mock_->last_target_offset_);
296944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko}
297944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
298944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko}  // namespace linker
299944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko}  // namespace art
300