blob: be52f40a0be1a3b7913ebc2c137bab2760e26876 [file] [log] [blame]
Elliott Hughes2faa5f12012-01-30 14:42:07 -08001/*
2 * Copyright (C) 2011 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 */
Brian Carlstrome24fa612011-09-29 00:53:55 -070016
17#include "oat_writer.h"
18
Elliott Hughesa0e18062012-04-13 15:59:59 -070019#include <zlib.h>
20
Ian Rogerse77493c2014-08-20 15:08:45 -070021#include "base/allocator.h"
Brian Carlstromba150c32013-08-27 17:31:03 -070022#include "base/bit_vector.h"
Elliott Hughes1aa246d2012-12-13 09:29:36 -080023#include "base/stl_util.h"
Elliott Hughes76160052012-12-12 16:31:20 -080024#include "base/unix_file/fd_file.h"
Brian Carlstrome24fa612011-09-29 00:53:55 -070025#include "class_linker.h"
Mingyao Yang98d1cc82014-05-15 17:02:16 -070026#include "compiled_class.h"
Ian Rogers4f6ad8a2013-03-18 15:27:28 -070027#include "dex_file-inl.h"
Vladimir Markoc7f83202014-01-24 17:55:18 +000028#include "dex/verification_results.h"
Ian Rogers1d54e732013-05-02 21:10:01 -070029#include "gc/space/space.h"
Vladimir Markof4da6752014-08-01 19:04:18 +010030#include "image_writer.h"
Brian Carlstromea46f952013-07-30 01:26:50 -070031#include "mirror/art_method-inl.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080032#include "mirror/array.h"
33#include "mirror/class_loader.h"
Ian Rogers4f6ad8a2013-03-18 15:27:28 -070034#include "mirror/object-inl.h"
Brian Carlstrome24fa612011-09-29 00:53:55 -070035#include "os.h"
Brian Carlstromcd60ac72013-01-20 17:09:51 -080036#include "output_stream.h"
Elliott Hughesa0e18062012-04-13 15:59:59 -070037#include "safe_map.h"
Ian Rogers00f7d0e2012-07-19 15:28:27 -070038#include "scoped_thread_state_change.h"
Mathieu Chartiereb8167a2014-05-07 15:43:14 -070039#include "handle_scope-inl.h"
Vladimir Markof4da6752014-08-01 19:04:18 +010040#include "utils/arm/assembler_thumb2.h"
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +010041#include "utils/arm64/assembler_arm64.h"
jeffhaoec014232012-09-05 10:42:25 -070042#include "verifier/method_verifier.h"
Brian Carlstrome24fa612011-09-29 00:53:55 -070043
44namespace art {
45
Vladimir Markof4da6752014-08-01 19:04:18 +010046class OatWriter::RelativeCallPatcher {
47 public:
48 virtual ~RelativeCallPatcher() { }
49
50 // Reserve space for relative call thunks if needed, return adjusted offset.
51 // After all methods have been processed it's call one last time with compiled_method == nullptr.
52 virtual uint32_t ReserveSpace(uint32_t offset, const CompiledMethod* compiled_method) = 0;
53
54 // Write relative call thunks if needed, return adjusted offset.
55 virtual uint32_t WriteThunks(OutputStream* out, uint32_t offset) = 0;
56
57 // Patch method code. The input displacement is relative to the patched location,
58 // the patcher may need to adjust it if the correct base is different.
59 virtual void Patch(std::vector<uint8_t>* code, uint32_t literal_offset, uint32_t patch_offset,
60 uint32_t target_offset) = 0;
61
62 protected:
63 RelativeCallPatcher() { }
64
65 private:
66 DISALLOW_COPY_AND_ASSIGN(RelativeCallPatcher);
67};
68
69class OatWriter::NoRelativeCallPatcher FINAL : public RelativeCallPatcher {
70 public:
71 NoRelativeCallPatcher() { }
72
73 uint32_t ReserveSpace(uint32_t offset, const CompiledMethod* compiled_method) OVERRIDE {
74 return offset; // No space reserved; no patches expected.
75 }
76
77 uint32_t WriteThunks(OutputStream* out, uint32_t offset) OVERRIDE {
78 return offset; // No thunks added; no patches expected.
79 }
80
81 void Patch(std::vector<uint8_t>* code, uint32_t literal_offset, uint32_t patch_offset,
82 uint32_t target_offset) OVERRIDE {
83 LOG(FATAL) << "Unexpected relative patch.";
84 }
85
86 private:
87 DISALLOW_COPY_AND_ASSIGN(NoRelativeCallPatcher);
88};
89
90class OatWriter::X86RelativeCallPatcher FINAL : public RelativeCallPatcher {
91 public:
92 X86RelativeCallPatcher() { }
93
94 uint32_t ReserveSpace(uint32_t offset, const CompiledMethod* compiled_method) OVERRIDE {
95 return offset; // No space reserved; no limit on relative call distance.
96 }
97
98 uint32_t WriteThunks(OutputStream* out, uint32_t offset) OVERRIDE {
99 return offset; // No thunks added; no limit on relative call distance.
100 }
101
102 void Patch(std::vector<uint8_t>* code, uint32_t literal_offset, uint32_t patch_offset,
103 uint32_t target_offset) OVERRIDE {
104 DCHECK_LE(literal_offset + 4u, code->size());
105 // Unsigned arithmetic with its well-defined overflow behavior is just fine here.
106 uint32_t displacement = target_offset - patch_offset;
107 displacement -= kPcDisplacement; // The base PC is at the end of the 4-byte patch.
108
109 typedef __attribute__((__aligned__(1))) int32_t unaligned_int32_t;
110 reinterpret_cast<unaligned_int32_t*>(&(*code)[literal_offset])[0] = displacement;
111 }
112
113 private:
114 // PC displacement from patch location; x86 PC for relative calls points to the next
115 // instruction and the patch location is 4 bytes earlier.
116 static constexpr int32_t kPcDisplacement = 4;
117
118 DISALLOW_COPY_AND_ASSIGN(X86RelativeCallPatcher);
119};
120
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +0100121class OatWriter::ArmBaseRelativeCallPatcher : public RelativeCallPatcher {
Vladimir Markof4da6752014-08-01 19:04:18 +0100122 public:
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +0100123 ArmBaseRelativeCallPatcher(OatWriter* writer,
124 InstructionSet instruction_set, std::vector<uint8_t> thunk_code,
125 uint32_t max_positive_displacement, uint32_t max_negative_displacement)
126 : writer_(writer), instruction_set_(instruction_set), thunk_code_(thunk_code),
127 max_positive_displacement_(max_positive_displacement),
128 max_negative_displacement_(max_negative_displacement),
Vladimir Markof4da6752014-08-01 19:04:18 +0100129 thunk_locations_(), current_thunk_to_write_(0u), unprocessed_patches_() {
130 }
131
132 uint32_t ReserveSpace(uint32_t offset, const CompiledMethod* compiled_method) OVERRIDE {
133 // NOTE: The final thunk can be reserved from InitCodeMethodVisitor::EndClass() while it
134 // may be written early by WriteCodeMethodVisitor::VisitMethod() for a deduplicated chunk
135 // of code. To avoid any alignment discrepancies for the final chunk, we always align the
136 // offset after reserving of writing any chunk.
137 if (UNLIKELY(compiled_method == nullptr)) {
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +0100138 uint32_t aligned_offset = CompiledMethod::AlignCode(offset, instruction_set_);
Vladimir Markof4da6752014-08-01 19:04:18 +0100139 bool needs_thunk = ReserveSpaceProcessPatches(aligned_offset);
140 if (needs_thunk) {
141 thunk_locations_.push_back(aligned_offset);
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +0100142 offset = CompiledMethod::AlignCode(aligned_offset + thunk_code_.size(), instruction_set_);
Vladimir Markof4da6752014-08-01 19:04:18 +0100143 }
144 return offset;
145 }
146 DCHECK(compiled_method->GetQuickCode() != nullptr);
147 uint32_t quick_code_size = compiled_method->GetQuickCode()->size();
148 uint32_t quick_code_offset = compiled_method->AlignCode(offset) + sizeof(OatQuickMethodHeader);
149 uint32_t next_aligned_offset = compiled_method->AlignCode(quick_code_offset + quick_code_size);
150 if (!unprocessed_patches_.empty() &&
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +0100151 next_aligned_offset - unprocessed_patches_.front().second > max_positive_displacement_) {
Vladimir Markof4da6752014-08-01 19:04:18 +0100152 bool needs_thunk = ReserveSpaceProcessPatches(next_aligned_offset);
153 if (needs_thunk) {
154 // A single thunk will cover all pending patches.
155 unprocessed_patches_.clear();
156 uint32_t thunk_location = compiled_method->AlignCode(offset);
157 thunk_locations_.push_back(thunk_location);
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +0100158 offset = CompiledMethod::AlignCode(thunk_location + thunk_code_.size(), instruction_set_);
Vladimir Markof4da6752014-08-01 19:04:18 +0100159 }
160 }
161 for (const LinkerPatch& patch : compiled_method->GetPatches()) {
162 if (patch.Type() == kLinkerPatchCallRelative) {
163 unprocessed_patches_.emplace_back(patch.TargetMethod(),
164 quick_code_offset + patch.LiteralOffset());
165 }
166 }
167 return offset;
168 }
169
170 uint32_t WriteThunks(OutputStream* out, uint32_t offset) OVERRIDE {
171 if (current_thunk_to_write_ == thunk_locations_.size()) {
172 return offset;
173 }
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +0100174 uint32_t aligned_offset = CompiledMethod::AlignCode(offset, instruction_set_);
Vladimir Markof4da6752014-08-01 19:04:18 +0100175 if (UNLIKELY(aligned_offset == thunk_locations_[current_thunk_to_write_])) {
176 ++current_thunk_to_write_;
177 uint32_t aligned_code_delta = aligned_offset - offset;
178 if (aligned_code_delta != 0u && !writer_->WriteCodeAlignment(out, aligned_code_delta)) {
179 return 0u;
180 }
181 if (!out->WriteFully(thunk_code_.data(), thunk_code_.size())) {
182 return 0u;
183 }
184 writer_->size_relative_call_thunks_ += thunk_code_.size();
185 uint32_t thunk_end_offset = aligned_offset + thunk_code_.size();
186 // Align after writing chunk, see the ReserveSpace() above.
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +0100187 offset = CompiledMethod::AlignCode(thunk_end_offset, instruction_set_);
Vladimir Markof4da6752014-08-01 19:04:18 +0100188 aligned_code_delta = offset - thunk_end_offset;
189 if (aligned_code_delta != 0u && !writer_->WriteCodeAlignment(out, aligned_code_delta)) {
190 return 0u;
191 }
192 }
193 return offset;
194 }
195
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +0100196 protected:
197 uint32_t CalculateDisplacement(uint32_t patch_offset, uint32_t target_offset) {
Vladimir Markof4da6752014-08-01 19:04:18 +0100198 // Unsigned arithmetic with its well-defined overflow behavior is just fine here.
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +0100199 uint32_t displacement = target_offset - patch_offset;
Vladimir Markof4da6752014-08-01 19:04:18 +0100200 // NOTE: With unsigned arithmetic we do mean to use && rather than || below.
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +0100201 if (displacement > max_positive_displacement_ && displacement < -max_negative_displacement_) {
Vladimir Markof4da6752014-08-01 19:04:18 +0100202 // Unwritten thunks have higher offsets, check if it's within range.
203 DCHECK(current_thunk_to_write_ == thunk_locations_.size() ||
204 thunk_locations_[current_thunk_to_write_] > patch_offset);
205 if (current_thunk_to_write_ != thunk_locations_.size() &&
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +0100206 thunk_locations_[current_thunk_to_write_] - patch_offset < max_positive_displacement_) {
Vladimir Markof4da6752014-08-01 19:04:18 +0100207 displacement = thunk_locations_[current_thunk_to_write_] - patch_offset;
208 } else {
209 // We must have a previous thunk then.
210 DCHECK_NE(current_thunk_to_write_, 0u);
211 DCHECK_LT(thunk_locations_[current_thunk_to_write_ - 1], patch_offset);
212 displacement = thunk_locations_[current_thunk_to_write_ - 1] - patch_offset;
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +0100213 DCHECK(displacement >= -max_negative_displacement_);
Vladimir Markof4da6752014-08-01 19:04:18 +0100214 }
215 }
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +0100216 return displacement;
217 }
218
219 private:
220 bool ReserveSpaceProcessPatches(uint32_t next_aligned_offset) {
221 // Process as many patches as possible, stop only on unresolved targets or calls too far back.
222 while (!unprocessed_patches_.empty()) {
223 uint32_t patch_offset = unprocessed_patches_.front().second;
224 auto it = writer_->method_offset_map_.find(unprocessed_patches_.front().first);
225 if (it == writer_->method_offset_map_.end()) {
226 // If still unresolved, check if we have a thunk within range.
227 DCHECK(thunk_locations_.empty() || thunk_locations_.back() <= patch_offset);
228 if (thunk_locations_.empty() ||
229 patch_offset - thunk_locations_.back() > max_negative_displacement_) {
230 return next_aligned_offset - patch_offset > max_positive_displacement_;
231 }
232 } else if (it->second >= patch_offset) {
233 DCHECK_LE(it->second - patch_offset, max_positive_displacement_);
234 } else {
235 // When calling back, check if we have a thunk that's closer than the actual target.
236 uint32_t target_offset = (thunk_locations_.empty() || it->second > thunk_locations_.back())
237 ? it->second
238 : thunk_locations_.back();
239 DCHECK_GT(patch_offset, target_offset);
240 if (patch_offset - target_offset > max_negative_displacement_) {
241 return true;
242 }
243 }
244 unprocessed_patches_.pop_front();
245 }
246 return false;
247 }
248
249 OatWriter* const writer_;
250 const InstructionSet instruction_set_;
251 const std::vector<uint8_t> thunk_code_;
252 const uint32_t max_positive_displacement_;
253 const uint32_t max_negative_displacement_;
254 std::vector<uint32_t> thunk_locations_;
255 size_t current_thunk_to_write_;
256
257 // ReserveSpace() tracks unprocessed patches.
258 typedef std::pair<MethodReference, uint32_t> UnprocessedPatch;
259 std::deque<UnprocessedPatch> unprocessed_patches_;
260
261 DISALLOW_COPY_AND_ASSIGN(ArmBaseRelativeCallPatcher);
262};
263
264class OatWriter::Thumb2RelativeCallPatcher FINAL : public ArmBaseRelativeCallPatcher {
265 public:
266 explicit Thumb2RelativeCallPatcher(OatWriter* writer)
267 : ArmBaseRelativeCallPatcher(writer, kThumb2, CompileThunkCode(),
268 kMaxPositiveDisplacement, kMaxNegativeDisplacement) {
269 }
270
271 void Patch(std::vector<uint8_t>* code, uint32_t literal_offset, uint32_t patch_offset,
272 uint32_t target_offset) OVERRIDE {
273 DCHECK_LE(literal_offset + 4u, code->size());
274 DCHECK_EQ(literal_offset & 1u, 0u);
275 DCHECK_EQ(patch_offset & 1u, 0u);
276 DCHECK_EQ(target_offset & 1u, 1u); // Thumb2 mode bit.
277 uint32_t displacement = CalculateDisplacement(patch_offset, target_offset & ~1u);
Vladimir Markof4da6752014-08-01 19:04:18 +0100278 displacement -= kPcDisplacement; // The base PC is at the end of the 4-byte patch.
279 DCHECK_EQ(displacement & 1u, 0u);
280 DCHECK((displacement >> 24) == 0u || (displacement >> 24) == 255u); // 25-bit signed.
281 uint32_t signbit = (displacement >> 31) & 0x1;
282 uint32_t i1 = (displacement >> 23) & 0x1;
283 uint32_t i2 = (displacement >> 22) & 0x1;
284 uint32_t imm10 = (displacement >> 12) & 0x03ff;
285 uint32_t imm11 = (displacement >> 1) & 0x07ff;
286 uint32_t j1 = i1 ^ (signbit ^ 1);
287 uint32_t j2 = i2 ^ (signbit ^ 1);
288 uint32_t value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) | imm11;
289 value |= 0xf000d000; // BL
290
291 uint8_t* addr = &(*code)[literal_offset];
292 // Check that we're just overwriting an existing BL.
293 DCHECK_EQ(addr[1] & 0xf8, 0xf0);
294 DCHECK_EQ(addr[3] & 0xd0, 0xd0);
295 // Write the new BL.
296 addr[0] = (value >> 16) & 0xff;
297 addr[1] = (value >> 24) & 0xff;
298 addr[2] = (value >> 0) & 0xff;
299 addr[3] = (value >> 8) & 0xff;
300 }
301
302 private:
Vladimir Markof4da6752014-08-01 19:04:18 +0100303 static std::vector<uint8_t> CompileThunkCode() {
304 // The thunk just uses the entry point in the ArtMethod. This works even for calls
305 // to the generic JNI and interpreter trampolines.
306 arm::Thumb2Assembler assembler;
307 assembler.LoadFromOffset(
308 arm::kLoadWord, arm::PC, arm::R0,
309 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value());
310 assembler.bkpt(0);
311 std::vector<uint8_t> thunk_code(assembler.CodeSize());
312 MemoryRegion code(thunk_code.data(), thunk_code.size());
313 assembler.FinalizeInstructions(code);
314 return thunk_code;
315 }
316
317 // PC displacement from patch location; Thumb2 PC is always at instruction address + 4.
318 static constexpr int32_t kPcDisplacement = 4;
319
320 // Maximum positive and negative displacement measured from the patch location.
321 // (Signed 25 bit displacement with the last bit 0 has range [-2^24, 2^24-2] measured from
322 // the Thumb2 PC pointing right after the BL, i.e. 4 bytes later than the patch location.)
323 static constexpr uint32_t kMaxPositiveDisplacement = (1u << 24) - 2 + kPcDisplacement;
324 static constexpr uint32_t kMaxNegativeDisplacement = (1u << 24) - kPcDisplacement;
325
Vladimir Markof4da6752014-08-01 19:04:18 +0100326 DISALLOW_COPY_AND_ASSIGN(Thumb2RelativeCallPatcher);
327};
328
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +0100329class OatWriter::Arm64RelativeCallPatcher FINAL : public ArmBaseRelativeCallPatcher {
330 public:
331 explicit Arm64RelativeCallPatcher(OatWriter* writer)
332 : ArmBaseRelativeCallPatcher(writer, kArm64, CompileThunkCode(),
333 kMaxPositiveDisplacement, kMaxNegativeDisplacement) {
334 }
335
336 void Patch(std::vector<uint8_t>* code, uint32_t literal_offset, uint32_t patch_offset,
337 uint32_t target_offset) OVERRIDE {
338 DCHECK_LE(literal_offset + 4u, code->size());
339 DCHECK_EQ(literal_offset & 3u, 0u);
340 DCHECK_EQ(patch_offset & 3u, 0u);
341 DCHECK_EQ(target_offset & 3u, 0u);
342 uint32_t displacement = CalculateDisplacement(patch_offset, target_offset & ~1u);
343 DCHECK_EQ(displacement & 3u, 0u);
344 DCHECK((displacement >> 27) == 0u || (displacement >> 27) == 31u); // 28-bit signed.
345 uint32_t value = (displacement & 0x0fffffffu) >> 2;
346 value |= 0x94000000; // BL
347
348 uint8_t* addr = &(*code)[literal_offset];
349 // Check that we're just overwriting an existing BL.
350 DCHECK_EQ(addr[3] & 0xfc, 0x94);
351 // Write the new BL.
352 addr[0] = (value >> 0) & 0xff;
353 addr[1] = (value >> 8) & 0xff;
354 addr[2] = (value >> 16) & 0xff;
355 addr[3] = (value >> 24) & 0xff;
356 }
357
358 private:
359 static std::vector<uint8_t> CompileThunkCode() {
360 // The thunk just uses the entry point in the ArtMethod. This works even for calls
361 // to the generic JNI and interpreter trampolines.
362 arm64::Arm64Assembler assembler;
363 Offset offset(mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value());
364 assembler.JumpTo(ManagedRegister(arm64::X0), offset, ManagedRegister(arm64::IP0));
365 std::vector<uint8_t> thunk_code(assembler.CodeSize());
366 MemoryRegion code(thunk_code.data(), thunk_code.size());
367 assembler.FinalizeInstructions(code);
368 return thunk_code;
369 }
370
371 // Maximum positive and negative displacement measured from the patch location.
372 // (Signed 28 bit displacement with the last bit 0 has range [-2^27, 2^27-4] measured from
373 // the ARM64 PC pointing to the BL.)
374 static constexpr uint32_t kMaxPositiveDisplacement = (1u << 27) - 4u;
375 static constexpr uint32_t kMaxNegativeDisplacement = (1u << 27);
376
377 DISALLOW_COPY_AND_ASSIGN(Arm64RelativeCallPatcher);
378};
379
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100380#define DCHECK_OFFSET() \
381 DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out->Seek(0, kSeekCurrent)) \
382 << "file_offset=" << file_offset << " relative_offset=" << relative_offset
383
384#define DCHECK_OFFSET_() \
385 DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \
386 << "file_offset=" << file_offset << " offset_=" << offset_
387
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700388OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
Brian Carlstrom28db0122012-10-18 16:20:41 -0700389 uint32_t image_file_location_oat_checksum,
Ian Rogersef7d42f2014-01-06 12:55:46 -0800390 uintptr_t image_file_location_oat_begin,
Alex Lighta59dd802014-07-02 16:28:08 -0700391 int32_t image_patch_delta,
Ian Rogersca368cb2013-11-15 15:52:08 -0800392 const CompilerDriver* compiler,
Vladimir Markof4da6752014-08-01 19:04:18 +0100393 ImageWriter* image_writer,
Andreas Gampe22f8e5c2014-07-09 11:38:21 -0700394 TimingLogger* timings,
395 SafeMap<std::string, std::string>* key_value_store)
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700396 : compiler_driver_(compiler),
Vladimir Markof4da6752014-08-01 19:04:18 +0100397 image_writer_(image_writer),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700398 dex_files_(&dex_files),
Vladimir Markof4da6752014-08-01 19:04:18 +0100399 size_(0u),
400 oat_data_offset_(0u),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700401 image_file_location_oat_checksum_(image_file_location_oat_checksum),
402 image_file_location_oat_begin_(image_file_location_oat_begin),
Alex Lighta59dd802014-07-02 16:28:08 -0700403 image_patch_delta_(image_patch_delta),
Andreas Gampe22f8e5c2014-07-09 11:38:21 -0700404 key_value_store_(key_value_store),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700405 oat_header_(NULL),
406 size_dex_file_alignment_(0),
407 size_executable_offset_alignment_(0),
408 size_oat_header_(0),
Andreas Gampe22f8e5c2014-07-09 11:38:21 -0700409 size_oat_header_key_value_store_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700410 size_dex_file_(0),
Ian Rogers848871b2013-08-05 10:56:33 -0700411 size_interpreter_to_interpreter_bridge_(0),
412 size_interpreter_to_compiled_code_bridge_(0),
413 size_jni_dlsym_lookup_(0),
Jeff Hao88474b42013-10-23 16:24:40 -0700414 size_portable_imt_conflict_trampoline_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700415 size_portable_resolution_trampoline_(0),
Ian Rogers848871b2013-08-05 10:56:33 -0700416 size_portable_to_interpreter_bridge_(0),
Andreas Gampe2da88232014-02-27 12:26:20 -0800417 size_quick_generic_jni_trampoline_(0),
Jeff Hao88474b42013-10-23 16:24:40 -0700418 size_quick_imt_conflict_trampoline_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700419 size_quick_resolution_trampoline_(0),
Ian Rogers848871b2013-08-05 10:56:33 -0700420 size_quick_to_interpreter_bridge_(0),
421 size_trampoline_alignment_(0),
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100422 size_method_header_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700423 size_code_(0),
424 size_code_alignment_(0),
Vladimir Markof4da6752014-08-01 19:04:18 +0100425 size_relative_call_thunks_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700426 size_mapping_table_(0),
427 size_vmap_table_(0),
428 size_gc_map_(0),
429 size_oat_dex_file_location_size_(0),
430 size_oat_dex_file_location_data_(0),
431 size_oat_dex_file_location_checksum_(0),
432 size_oat_dex_file_offset_(0),
433 size_oat_dex_file_methods_offsets_(0),
Brian Carlstromba150c32013-08-27 17:31:03 -0700434 size_oat_class_type_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700435 size_oat_class_status_(0),
Brian Carlstromba150c32013-08-27 17:31:03 -0700436 size_oat_class_method_bitmaps_(0),
Vladimir Markof4da6752014-08-01 19:04:18 +0100437 size_oat_class_method_offsets_(0),
438 method_offset_map_() {
Andreas Gampe22f8e5c2014-07-09 11:38:21 -0700439 CHECK(key_value_store != nullptr);
440
Vladimir Markof4da6752014-08-01 19:04:18 +0100441 switch (compiler_driver_->GetInstructionSet()) {
442 case kX86:
443 case kX86_64:
444 relative_call_patcher_.reset(new X86RelativeCallPatcher);
445 break;
446 case kArm:
447 // Fall through: we generate Thumb2 code for "arm".
448 case kThumb2:
449 relative_call_patcher_.reset(new Thumb2RelativeCallPatcher(this));
450 break;
451 case kArm64:
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +0100452 relative_call_patcher_.reset(new Arm64RelativeCallPatcher(this));
453 break;
Vladimir Markof4da6752014-08-01 19:04:18 +0100454 default:
455 relative_call_patcher_.reset(new NoRelativeCallPatcher);
456 break;
457 }
458
Ian Rogersca368cb2013-11-15 15:52:08 -0800459 size_t offset;
460 {
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700461 TimingLogger::ScopedTiming split("InitOatHeader", timings);
Ian Rogersca368cb2013-11-15 15:52:08 -0800462 offset = InitOatHeader();
463 }
464 {
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700465 TimingLogger::ScopedTiming split("InitOatDexFiles", timings);
Ian Rogersca368cb2013-11-15 15:52:08 -0800466 offset = InitOatDexFiles(offset);
467 }
468 {
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700469 TimingLogger::ScopedTiming split("InitDexFiles", timings);
Ian Rogersca368cb2013-11-15 15:52:08 -0800470 offset = InitDexFiles(offset);
471 }
472 {
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700473 TimingLogger::ScopedTiming split("InitOatClasses", timings);
Ian Rogersca368cb2013-11-15 15:52:08 -0800474 offset = InitOatClasses(offset);
475 }
476 {
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700477 TimingLogger::ScopedTiming split("InitOatMaps", timings);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100478 offset = InitOatMaps(offset);
479 }
480 {
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700481 TimingLogger::ScopedTiming split("InitOatCode", timings);
Ian Rogersca368cb2013-11-15 15:52:08 -0800482 offset = InitOatCode(offset);
483 }
484 {
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700485 TimingLogger::ScopedTiming split("InitOatCodeDexFiles", timings);
Ian Rogersca368cb2013-11-15 15:52:08 -0800486 offset = InitOatCodeDexFiles(offset);
487 }
Brian Carlstromc50d8e12013-07-23 22:35:16 -0700488 size_ = offset;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700489
490 CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
Vladimir Markof4da6752014-08-01 19:04:18 +0100491 CHECK_EQ(compiler->IsImage(), image_writer_ != nullptr);
Andreas Gampe22f8e5c2014-07-09 11:38:21 -0700492 CHECK_EQ(compiler->IsImage(),
493 key_value_store_->find(OatHeader::kImageLocationKey) == key_value_store_->end());
Alex Lighta59dd802014-07-02 16:28:08 -0700494 CHECK_ALIGNED(image_patch_delta_, kPageSize);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700495}
496
Ian Rogers0571d352011-11-03 19:51:38 -0700497OatWriter::~OatWriter() {
498 delete oat_header_;
499 STLDeleteElements(&oat_dex_files_);
Brian Carlstrom389efb02012-01-11 12:06:26 -0800500 STLDeleteElements(&oat_classes_);
Ian Rogers0571d352011-11-03 19:51:38 -0700501}
502
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100503struct OatWriter::GcMapDataAccess {
504 static const std::vector<uint8_t>* GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100505 return compiled_method->GetGcMap();
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100506 }
507
508 static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE {
509 return oat_class->method_offsets_[method_offsets_index].gc_map_offset_;
510 }
511
512 static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset)
513 ALWAYS_INLINE {
514 oat_class->method_offsets_[method_offsets_index].gc_map_offset_ = offset;
515 }
516
517 static const char* Name() ALWAYS_INLINE {
518 return "GC map";
519 }
520};
521
522struct OatWriter::MappingTableDataAccess {
523 static const std::vector<uint8_t>* GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
524 return &compiled_method->GetMappingTable();
525 }
526
527 static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE {
Vladimir Marko8a630572014-04-09 18:45:35 +0100528 uint32_t offset = oat_class->method_headers_[method_offsets_index].mapping_table_offset_;
529 return offset == 0u ? 0u :
530 (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100531 }
532
533 static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset)
534 ALWAYS_INLINE {
Vladimir Marko8a630572014-04-09 18:45:35 +0100535 oat_class->method_headers_[method_offsets_index].mapping_table_offset_ =
536 (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100537 }
538
539 static const char* Name() ALWAYS_INLINE {
540 return "mapping table";
541 }
542};
543
544struct OatWriter::VmapTableDataAccess {
545 static const std::vector<uint8_t>* GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
546 return &compiled_method->GetVmapTable();
547 }
548
549 static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE {
Vladimir Marko8a630572014-04-09 18:45:35 +0100550 uint32_t offset = oat_class->method_headers_[method_offsets_index].vmap_table_offset_;
551 return offset == 0u ? 0u :
552 (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100553 }
554
555 static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset)
556 ALWAYS_INLINE {
Vladimir Marko8a630572014-04-09 18:45:35 +0100557 oat_class->method_headers_[method_offsets_index].vmap_table_offset_ =
558 (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100559 }
560
561 static const char* Name() ALWAYS_INLINE {
562 return "vmap table";
563 }
564};
565
566class OatWriter::DexMethodVisitor {
567 public:
568 DexMethodVisitor(OatWriter* writer, size_t offset)
569 : writer_(writer),
570 offset_(offset),
571 dex_file_(nullptr),
572 class_def_index_(DexFile::kDexNoIndex) {
573 }
574
575 virtual bool StartClass(const DexFile* dex_file, size_t class_def_index) {
576 DCHECK(dex_file_ == nullptr);
577 DCHECK_EQ(class_def_index_, DexFile::kDexNoIndex);
578 dex_file_ = dex_file;
579 class_def_index_ = class_def_index;
580 return true;
581 }
582
583 virtual bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) = 0;
584
585 virtual bool EndClass() {
586 if (kIsDebugBuild) {
587 dex_file_ = nullptr;
588 class_def_index_ = DexFile::kDexNoIndex;
589 }
590 return true;
591 }
592
593 size_t GetOffset() const {
594 return offset_;
595 }
596
597 protected:
598 virtual ~DexMethodVisitor() { }
599
600 OatWriter* const writer_;
601
602 // The offset is usually advanced for each visited method by the derived class.
603 size_t offset_;
604
605 // The dex file and class def index are set in StartClass().
606 const DexFile* dex_file_;
607 size_t class_def_index_;
608};
609
610class OatWriter::OatDexMethodVisitor : public DexMethodVisitor {
611 public:
612 OatDexMethodVisitor(OatWriter* writer, size_t offset)
613 : DexMethodVisitor(writer, offset),
614 oat_class_index_(0u),
615 method_offsets_index_(0u) {
616 }
617
618 bool StartClass(const DexFile* dex_file, size_t class_def_index) {
619 DexMethodVisitor::StartClass(dex_file, class_def_index);
620 DCHECK_LT(oat_class_index_, writer_->oat_classes_.size());
621 method_offsets_index_ = 0u;
622 return true;
623 }
624
625 bool EndClass() {
626 ++oat_class_index_;
627 return DexMethodVisitor::EndClass();
628 }
629
630 protected:
631 size_t oat_class_index_;
632 size_t method_offsets_index_;
633};
634
635class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor {
636 public:
637 InitOatClassesMethodVisitor(OatWriter* writer, size_t offset)
638 : DexMethodVisitor(writer, offset),
639 compiled_methods_(),
640 num_non_null_compiled_methods_(0u) {
641 compiled_methods_.reserve(256u);
642 }
643
644 bool StartClass(const DexFile* dex_file, size_t class_def_index) {
645 DexMethodVisitor::StartClass(dex_file, class_def_index);
646 compiled_methods_.clear();
647 num_non_null_compiled_methods_ = 0u;
648 return true;
649 }
650
651 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) {
652 // Fill in the compiled_methods_ array for methods that have a
653 // CompiledMethod. We track the number of non-null entries in
654 // num_non_null_compiled_methods_ since we only want to allocate
655 // OatMethodOffsets for the compiled methods.
656 uint32_t method_idx = it.GetMemberIndex();
657 CompiledMethod* compiled_method =
658 writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
659 compiled_methods_.push_back(compiled_method);
660 if (compiled_method != nullptr) {
661 ++num_non_null_compiled_methods_;
662 }
663 return true;
664 }
665
666 bool EndClass() {
667 ClassReference class_ref(dex_file_, class_def_index_);
668 CompiledClass* compiled_class = writer_->compiler_driver_->GetCompiledClass(class_ref);
669 mirror::Class::Status status;
670 if (compiled_class != NULL) {
671 status = compiled_class->GetStatus();
672 } else if (writer_->compiler_driver_->GetVerificationResults()->IsClassRejected(class_ref)) {
673 status = mirror::Class::kStatusError;
674 } else {
675 status = mirror::Class::kStatusNotReady;
676 }
677
678 OatClass* oat_class = new OatClass(offset_, compiled_methods_,
679 num_non_null_compiled_methods_, status);
680 writer_->oat_classes_.push_back(oat_class);
Vladimir Markof4da6752014-08-01 19:04:18 +0100681 oat_class->UpdateChecksum(writer_->oat_header_);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100682 offset_ += oat_class->SizeOf();
683 return DexMethodVisitor::EndClass();
684 }
685
686 private:
687 std::vector<CompiledMethod*> compiled_methods_;
688 size_t num_non_null_compiled_methods_;
689};
690
691class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor {
692 public:
693 InitCodeMethodVisitor(OatWriter* writer, size_t offset)
694 : OatDexMethodVisitor(writer, offset) {
Vladimir Markof4da6752014-08-01 19:04:18 +0100695 writer_->absolute_patch_locations_.reserve(
696 writer_->compiler_driver_->GetNonRelativeLinkerPatchCount());
697 }
698
699 bool EndClass() {
700 OatDexMethodVisitor::EndClass();
701 if (oat_class_index_ == writer_->oat_classes_.size()) {
702 offset_ = writer_->relative_call_patcher_->ReserveSpace(offset_, nullptr);
703 }
704 return true;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100705 }
706
707 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it)
708 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
709 OatClass* oat_class = writer_->oat_classes_[oat_class_index_];
710 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
711
712 if (compiled_method != nullptr) {
713 // Derived from CompiledMethod.
714 uint32_t quick_code_offset = 0;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100715
716 const std::vector<uint8_t>* portable_code = compiled_method->GetPortableCode();
717 const std::vector<uint8_t>* quick_code = compiled_method->GetQuickCode();
718 if (portable_code != nullptr) {
719 CHECK(quick_code == nullptr);
720 size_t oat_method_offsets_offset =
721 oat_class->GetOatMethodOffsetsOffsetFromOatHeader(class_def_method_index);
722 compiled_method->AddOatdataOffsetToCompliledCodeOffset(
723 oat_method_offsets_offset + OFFSETOF_MEMBER(OatMethodOffsets, code_offset_));
724 } else {
725 CHECK(quick_code != nullptr);
Vladimir Markof4da6752014-08-01 19:04:18 +0100726 offset_ = writer_->relative_call_patcher_->ReserveSpace(offset_, compiled_method);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100727 offset_ = compiled_method->AlignCode(offset_);
728 DCHECK_ALIGNED_PARAM(offset_,
729 GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
730 uint32_t code_size = quick_code->size() * sizeof(uint8_t);
731 CHECK_NE(code_size, 0U);
732 uint32_t thumb_offset = compiled_method->CodeDelta();
Vladimir Marko7624d252014-05-02 14:40:15 +0100733 quick_code_offset = offset_ + sizeof(OatQuickMethodHeader) + thumb_offset;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100734
Alex Light78382fa2014-06-06 15:45:32 -0700735 bool deduped = false;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100736
737 // Deduplicate code arrays.
Vladimir Markobd72fc12014-07-09 16:06:40 +0100738 auto lb = dedupe_map_.lower_bound(compiled_method);
739 if (lb != dedupe_map_.end() && !dedupe_map_.key_comp()(compiled_method, lb->first)) {
740 quick_code_offset = lb->second;
Alex Light78382fa2014-06-06 15:45:32 -0700741 deduped = true;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100742 } else {
Vladimir Markobd72fc12014-07-09 16:06:40 +0100743 dedupe_map_.PutBefore(lb, compiled_method, quick_code_offset);
Vladimir Marko7624d252014-05-02 14:40:15 +0100744 }
745
Vladimir Markof4da6752014-08-01 19:04:18 +0100746 MethodReference method_ref(dex_file_, it.GetMemberIndex());
747 auto method_lb = writer_->method_offset_map_.lower_bound(method_ref);
748 if (method_lb != writer_->method_offset_map_.end() &&
749 !writer_->method_offset_map_.key_comp()(method_ref, method_lb->first)) {
750 // TODO: Should this be a hard failure?
751 LOG(WARNING) << "Multiple definitions of "
752 << PrettyMethod(method_ref.dex_method_index, *method_ref.dex_file)
753 << ((method_lb->second != quick_code_offset) ? "; OFFSET MISMATCH" : "");
754 } else {
755 writer_->method_offset_map_.PutBefore(method_lb, method_ref, quick_code_offset);
756 }
757
Vladimir Marko7624d252014-05-02 14:40:15 +0100758 // Update quick method header.
759 DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size());
760 OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
761 uint32_t mapping_table_offset = method_header->mapping_table_offset_;
762 uint32_t vmap_table_offset = method_header->vmap_table_offset_;
763 // The code offset was 0 when the mapping/vmap table offset was set, so it's set
764 // to 0-offset and we need to adjust it by code_offset.
765 uint32_t code_offset = quick_code_offset - thumb_offset;
766 if (mapping_table_offset != 0u) {
767 mapping_table_offset += code_offset;
768 DCHECK_LT(mapping_table_offset, code_offset);
769 }
770 if (vmap_table_offset != 0u) {
771 vmap_table_offset += code_offset;
772 DCHECK_LT(vmap_table_offset, code_offset);
773 }
774 uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
775 uint32_t core_spill_mask = compiled_method->GetCoreSpillMask();
776 uint32_t fp_spill_mask = compiled_method->GetFpSpillMask();
777 *method_header = OatQuickMethodHeader(mapping_table_offset, vmap_table_offset,
778 frame_size_in_bytes, core_spill_mask, fp_spill_mask,
779 code_size);
780
Vladimir Markobd72fc12014-07-09 16:06:40 +0100781 if (!deduped) {
Vladimir Markof4da6752014-08-01 19:04:18 +0100782 // Update offsets. (Checksum is updated when writing.)
Vladimir Marko8a630572014-04-09 18:45:35 +0100783 offset_ += sizeof(*method_header); // Method header is prepended before code.
Vladimir Marko8a630572014-04-09 18:45:35 +0100784 offset_ += code_size;
Vladimir Markof4da6752014-08-01 19:04:18 +0100785 // Record absolute patch locations.
786 if (!compiled_method->GetPatches().empty()) {
787 uintptr_t base_loc = offset_ - code_size - writer_->oat_header_->GetExecutableOffset();
788 for (const LinkerPatch& patch : compiled_method->GetPatches()) {
789 if (patch.Type() != kLinkerPatchCallRelative) {
790 writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset());
791 }
792 }
793 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100794 }
Alex Light78382fa2014-06-06 15:45:32 -0700795
Andreas Gampe79273802014-08-05 20:21:05 -0700796 if (writer_->compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols()) {
797 // Record debug information for this function if we are doing that.
Alex Light78382fa2014-06-06 15:45:32 -0700798
Alex Light78382fa2014-06-06 15:45:32 -0700799 std::string name = PrettyMethod(it.GetMemberIndex(), *dex_file_, true);
800 if (deduped) {
Andreas Gampe79273802014-08-05 20:21:05 -0700801 // TODO We should place the DEDUPED tag on the first instance of a deduplicated symbol
802 // so that it will show up in a debuggerd crash report.
Alex Light78382fa2014-06-06 15:45:32 -0700803 name += " [ DEDUPED ]";
804 }
Andreas Gampe79273802014-08-05 20:21:05 -0700805
806 const uint32_t quick_code_start = quick_code_offset -
807 writer_->oat_header_->GetExecutableOffset();
Yevgeny Roubane3ea8382014-08-08 16:29:38 +0700808 const DexFile::CodeItem *code_item = it.GetMethodCodeItem();
Andreas Gampe79273802014-08-05 20:21:05 -0700809 writer_->method_info_.push_back(DebugInfo(name,
Yevgeny Roubane3ea8382014-08-08 16:29:38 +0700810 dex_file_->GetSourceFile(dex_file_->GetClassDef(class_def_index_)),
811 quick_code_start, quick_code_start + code_size,
812 code_item == nullptr ? nullptr : dex_file_->GetDebugInfoStream(code_item),
813 compiled_method));
Alex Light78382fa2014-06-06 15:45:32 -0700814 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100815 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100816
817 if (kIsDebugBuild) {
818 // We expect GC maps except when the class hasn't been verified or the method is native.
819 const CompilerDriver* compiler_driver = writer_->compiler_driver_;
820 ClassReference class_ref(dex_file_, class_def_index_);
821 CompiledClass* compiled_class = compiler_driver->GetCompiledClass(class_ref);
822 mirror::Class::Status status;
823 if (compiled_class != NULL) {
824 status = compiled_class->GetStatus();
825 } else if (compiler_driver->GetVerificationResults()->IsClassRejected(class_ref)) {
826 status = mirror::Class::kStatusError;
827 } else {
828 status = mirror::Class::kStatusNotReady;
829 }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100830 std::vector<uint8_t> const * gc_map = compiled_method->GetGcMap();
831 if (gc_map != nullptr) {
832 size_t gc_map_size = gc_map->size() * sizeof(gc_map[0]);
Andreas Gampe51829322014-08-25 15:05:04 -0700833 bool is_native = it.MemberIsNative();
Nicolas Geoffray39468442014-09-02 15:17:15 +0100834 CHECK(gc_map_size != 0 || is_native || status < mirror::Class::kStatusVerified)
835 << gc_map << " " << gc_map_size << " " << (is_native ? "true" : "false") << " "
836 << (status < mirror::Class::kStatusVerified) << " " << status << " "
837 << PrettyMethod(it.GetMemberIndex(), *dex_file_);
838 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100839 }
840
841 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
842 OatMethodOffsets* offsets = &oat_class->method_offsets_[method_offsets_index_];
843 offsets->code_offset_ = quick_code_offset;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100844 ++method_offsets_index_;
845 }
846
847 return true;
848 }
849
850 private:
851 // Deduplication is already done on a pointer basis by the compiler driver,
852 // so we can simply compare the pointers to find out if things are duplicated.
Vladimir Marko8a630572014-04-09 18:45:35 +0100853 SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100854};
855
856template <typename DataAccess>
857class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor {
858 public:
859 InitMapMethodVisitor(OatWriter* writer, size_t offset)
860 : OatDexMethodVisitor(writer, offset) {
861 }
862
863 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it)
864 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
865 OatClass* oat_class = writer_->oat_classes_[oat_class_index_];
866 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
867
868 if (compiled_method != nullptr) {
869 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
870 DCHECK_EQ(DataAccess::GetOffset(oat_class, method_offsets_index_), 0u);
871
872 const std::vector<uint8_t>* map = DataAccess::GetData(compiled_method);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100873 uint32_t map_size = map == nullptr ? 0 : map->size() * sizeof((*map)[0]);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100874 if (map_size != 0u) {
Vladimir Markobd72fc12014-07-09 16:06:40 +0100875 auto lb = dedupe_map_.lower_bound(map);
876 if (lb != dedupe_map_.end() && !dedupe_map_.key_comp()(map, lb->first)) {
877 DataAccess::SetOffset(oat_class, method_offsets_index_, lb->second);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100878 } else {
879 DataAccess::SetOffset(oat_class, method_offsets_index_, offset_);
Vladimir Markobd72fc12014-07-09 16:06:40 +0100880 dedupe_map_.PutBefore(lb, map, offset_);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100881 offset_ += map_size;
882 writer_->oat_header_->UpdateChecksum(&(*map)[0], map_size);
883 }
884 }
885 ++method_offsets_index_;
886 }
887
888 return true;
889 }
890
891 private:
892 // Deduplication is already done on a pointer basis by the compiler driver,
893 // so we can simply compare the pointers to find out if things are duplicated.
894 SafeMap<const std::vector<uint8_t>*, uint32_t> dedupe_map_;
895};
896
897class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor {
898 public:
899 InitImageMethodVisitor(OatWriter* writer, size_t offset)
900 : OatDexMethodVisitor(writer, offset) {
901 }
902
903 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it)
904 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
905 OatClass* oat_class = writer_->oat_classes_[oat_class_index_];
906 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
907
Vladimir Marko7624d252014-05-02 14:40:15 +0100908 OatMethodOffsets offsets(0u, 0u);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100909 if (compiled_method != nullptr) {
910 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
911 offsets = oat_class->method_offsets_[method_offsets_index_];
912 ++method_offsets_index_;
913 }
914
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100915 ClassLinker* linker = Runtime::Current()->GetClassLinker();
916 InvokeType invoke_type = it.GetMethodInvokeType(dex_file_->GetClassDef(class_def_index_));
917 // Unchecked as we hold mutator_lock_ on entry.
918 ScopedObjectAccessUnchecked soa(Thread::Current());
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700919 StackHandleScope<2> hs(soa.Self());
920 Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->FindDexCache(*dex_file_)));
Vladimir Marko7624d252014-05-02 14:40:15 +0100921 mirror::ArtMethod* method = linker->ResolveMethod(*dex_file_, it.GetMemberIndex(), dex_cache,
Mathieu Chartier0cd81352014-05-22 16:48:55 -0700922 NullHandle<mirror::ClassLoader>(),
923 NullHandle<mirror::ArtMethod>(),
924 invoke_type);
Andreas Gamped9efea62014-07-21 22:56:08 -0700925 if (method == nullptr) {
926 LOG(ERROR) << "Unexpected failure to resolve a method: "
927 << PrettyMethod(it.GetMemberIndex(), *dex_file_, true);
928 soa.Self()->AssertPendingException();
929 mirror::Throwable* exc = soa.Self()->GetException(nullptr);
930 std::string dump = exc->Dump();
931 LOG(FATAL) << dump;
932 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100933 // Portable code offsets are set by ElfWriterMclinker::FixupCompiledCodeOffset after linking.
934 method->SetQuickOatCodeOffset(offsets.code_offset_);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100935 method->SetOatNativeGcMapOffset(offsets.gc_map_offset_);
936
937 return true;
938 }
939};
940
941class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
942 public:
943 WriteCodeMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset,
Vladimir Markof4da6752014-08-01 19:04:18 +0100944 size_t relative_offset) SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100945 : OatDexMethodVisitor(writer, relative_offset),
946 out_(out),
Vladimir Markof4da6752014-08-01 19:04:18 +0100947 file_offset_(file_offset),
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +0100948 soa_(Thread::Current()),
949 no_thread_suspension_(soa_.Self(), "OatWriter patching"),
Vladimir Markof4da6752014-08-01 19:04:18 +0100950 class_linker_(Runtime::Current()->GetClassLinker()),
951 dex_cache_(nullptr) {
952 if (writer_->image_writer_ != nullptr) {
953 // If we're creating the image, the address space must be ready so that we can apply patches.
954 CHECK(writer_->image_writer_->IsImageAddressSpaceReady());
955 patched_code_.reserve(16 * KB);
956 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100957 }
958
Vladimir Markof4da6752014-08-01 19:04:18 +0100959 ~WriteCodeMethodVisitor() UNLOCK_FUNCTION(Locks::mutator_lock_) {
Vladimir Markof4da6752014-08-01 19:04:18 +0100960 }
961
962 bool StartClass(const DexFile* dex_file, size_t class_def_index)
963 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
964 OatDexMethodVisitor::StartClass(dex_file, class_def_index);
965 if (dex_cache_ == nullptr || dex_cache_->GetDexFile() != dex_file) {
966 dex_cache_ = class_linker_->FindDexCache(*dex_file);
967 }
968 return true;
969 }
970
971 bool EndClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
972 bool result = OatDexMethodVisitor::EndClass();
973 if (oat_class_index_ == writer_->oat_classes_.size()) {
974 DCHECK(result); // OatDexMethodVisitor::EndClass() never fails.
975 offset_ = writer_->relative_call_patcher_->WriteThunks(out_, offset_);
976 if (UNLIKELY(offset_ == 0u)) {
977 PLOG(ERROR) << "Failed to write final relative call thunks";
978 result = false;
979 }
980 }
981 return result;
982 }
983
984 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it)
985 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100986 OatClass* oat_class = writer_->oat_classes_[oat_class_index_];
987 const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
988
989 if (compiled_method != NULL) { // ie. not an abstract method
990 size_t file_offset = file_offset_;
991 OutputStream* out = out_;
992
993 const std::vector<uint8_t>* quick_code = compiled_method->GetQuickCode();
994 if (quick_code != nullptr) {
995 CHECK(compiled_method->GetPortableCode() == nullptr);
Vladimir Markof4da6752014-08-01 19:04:18 +0100996 offset_ = writer_->relative_call_patcher_->WriteThunks(out, offset_);
997 if (offset_ == 0u) {
998 ReportWriteFailure("relative call thunk", it);
999 return false;
1000 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001001 uint32_t aligned_offset = compiled_method->AlignCode(offset_);
1002 uint32_t aligned_code_delta = aligned_offset - offset_;
1003 if (aligned_code_delta != 0) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001004 if (!writer_->WriteCodeAlignment(out, aligned_code_delta)) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001005 ReportWriteFailure("code alignment padding", it);
1006 return false;
1007 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001008 offset_ += aligned_code_delta;
1009 DCHECK_OFFSET_();
1010 }
1011 DCHECK_ALIGNED_PARAM(offset_,
1012 GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
1013 uint32_t code_size = quick_code->size() * sizeof(uint8_t);
1014 CHECK_NE(code_size, 0U);
1015
1016 // Deduplicate code arrays.
1017 const OatMethodOffsets& method_offsets = oat_class->method_offsets_[method_offsets_index_];
1018 DCHECK(method_offsets.code_offset_ < offset_ || method_offsets.code_offset_ ==
Vladimir Marko7624d252014-05-02 14:40:15 +01001019 offset_ + sizeof(OatQuickMethodHeader) + compiled_method->CodeDelta())
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001020 << PrettyMethod(it.GetMemberIndex(), *dex_file_);
1021 if (method_offsets.code_offset_ >= offset_) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001022 const OatQuickMethodHeader& method_header =
1023 oat_class->method_headers_[method_offsets_index_];
1024 writer_->oat_header_->UpdateChecksum(&method_header, sizeof(method_header));
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001025 if (!out->WriteFully(&method_header, sizeof(method_header))) {
1026 ReportWriteFailure("method header", it);
1027 return false;
1028 }
1029 writer_->size_method_header_ += sizeof(method_header);
1030 offset_ += sizeof(method_header);
1031 DCHECK_OFFSET_();
Vladimir Markof4da6752014-08-01 19:04:18 +01001032
1033 if (!compiled_method->GetPatches().empty()) {
1034 patched_code_ = *quick_code;
1035 quick_code = &patched_code_;
1036 for (const LinkerPatch& patch : compiled_method->GetPatches()) {
1037 if (patch.Type() == kLinkerPatchCallRelative) {
1038 // NOTE: Relative calls across oat files are not supported.
1039 uint32_t target_offset = GetTargetOffset(patch);
1040 uint32_t literal_offset = patch.LiteralOffset();
1041 writer_->relative_call_patcher_->Patch(&patched_code_, literal_offset,
1042 offset_ + literal_offset, target_offset);
1043 } else if (patch.Type() == kLinkerPatchCall) {
1044 uint32_t target_offset = GetTargetOffset(patch);
1045 PatchCodeAddress(&patched_code_, patch.LiteralOffset(), target_offset);
1046 } else if (patch.Type() == kLinkerPatchMethod) {
1047 mirror::ArtMethod* method = GetTargetMethod(patch);
1048 PatchObjectAddress(&patched_code_, patch.LiteralOffset(), method);
1049 } else if (patch.Type() == kLinkerPatchType) {
1050 mirror::Class* type = GetTargetType(patch);
1051 PatchObjectAddress(&patched_code_, patch.LiteralOffset(), type);
1052 }
1053 }
1054 }
1055
1056 writer_->oat_header_->UpdateChecksum(&(*quick_code)[0], code_size);
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001057 if (!out->WriteFully(&(*quick_code)[0], code_size)) {
1058 ReportWriteFailure("method code", it);
1059 return false;
1060 }
1061 writer_->size_code_ += code_size;
1062 offset_ += code_size;
1063 }
1064 DCHECK_OFFSET_();
1065 }
1066 ++method_offsets_index_;
1067 }
1068
1069 return true;
1070 }
1071
1072 private:
1073 OutputStream* const out_;
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +01001074 const size_t file_offset_;
1075 const ScopedObjectAccess soa_;
1076 const ScopedAssertNoThreadSuspension no_thread_suspension_;
Vladimir Markof4da6752014-08-01 19:04:18 +01001077 ClassLinker* const class_linker_;
1078 mirror::DexCache* dex_cache_;
1079 std::vector<uint8_t> patched_code_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001080
1081 void ReportWriteFailure(const char* what, const ClassDataItemIterator& it) {
1082 PLOG(ERROR) << "Failed to write " << what << " for "
1083 << PrettyMethod(it.GetMemberIndex(), *dex_file_) << " to " << out_->GetLocation();
1084 }
Vladimir Markof4da6752014-08-01 19:04:18 +01001085
1086 mirror::ArtMethod* GetTargetMethod(const LinkerPatch& patch)
1087 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
1088 MethodReference ref = patch.TargetMethod();
1089 mirror::DexCache* dex_cache =
1090 (dex_file_ == ref.dex_file) ? dex_cache_ : class_linker_->FindDexCache(*ref.dex_file);
1091 mirror::ArtMethod* method = dex_cache->GetResolvedMethod(ref.dex_method_index);
1092 CHECK(method != nullptr);
1093 return method;
1094 }
1095
1096 uint32_t GetTargetOffset(const LinkerPatch& patch) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
1097 auto target_it = writer_->method_offset_map_.find(patch.TargetMethod());
1098 uint32_t target_offset =
1099 (target_it != writer_->method_offset_map_.end()) ? target_it->second : 0u;
1100 // If there's no compiled code, point to the correct trampoline.
1101 if (UNLIKELY(target_offset == 0)) {
1102 mirror::ArtMethod* target = GetTargetMethod(patch);
1103 DCHECK(target != nullptr);
1104 DCHECK_EQ(target->GetQuickOatCodeOffset(), 0u);
1105 target_offset = target->IsNative()
1106 ? writer_->oat_header_->GetQuickGenericJniTrampolineOffset()
1107 : writer_->oat_header_->GetQuickToInterpreterBridgeOffset();
1108 }
1109 return target_offset;
1110 }
1111
1112 mirror::Class* GetTargetType(const LinkerPatch& patch)
1113 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
1114 mirror::DexCache* dex_cache = (dex_file_ == patch.TargetTypeDexFile())
1115 ? dex_cache_ : class_linker_->FindDexCache(*patch.TargetTypeDexFile());
1116 mirror::Class* type = dex_cache->GetResolvedType(patch.TargetTypeIndex());
1117 CHECK(type != nullptr);
1118 return type;
1119 }
1120
1121 void PatchObjectAddress(std::vector<uint8_t>* code, uint32_t offset, mirror::Object* object)
1122 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
1123 // NOTE: Direct method pointers across oat files don't use linker patches. However, direct
1124 // type pointers across oat files do. (TODO: Investigate why.)
1125 if (writer_->image_writer_ != nullptr) {
1126 object = writer_->image_writer_->GetImageAddress(object);
1127 }
1128 uint32_t address = PointerToLowMemUInt32(object);
1129 DCHECK_LE(offset + 4, code->size());
1130 uint8_t* data = &(*code)[offset];
1131 data[0] = address & 0xffu;
1132 data[1] = (address >> 8) & 0xffu;
1133 data[2] = (address >> 16) & 0xffu;
1134 data[3] = (address >> 24) & 0xffu;
1135 }
1136
1137 void PatchCodeAddress(std::vector<uint8_t>* code, uint32_t offset, uint32_t target_offset)
1138 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
1139 // NOTE: Direct calls across oat files don't use linker patches.
1140 DCHECK(writer_->image_writer_ != nullptr);
1141 uint32_t address = PointerToLowMemUInt32(writer_->image_writer_->GetOatFileBegin() +
1142 writer_->oat_data_offset_ + target_offset);
1143 DCHECK_LE(offset + 4, code->size());
1144 uint8_t* data = &(*code)[offset];
1145 data[0] = address & 0xffu;
1146 data[1] = (address >> 8) & 0xffu;
1147 data[2] = (address >> 16) & 0xffu;
1148 data[3] = (address >> 24) & 0xffu;
1149 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001150};
1151
1152template <typename DataAccess>
1153class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor {
1154 public:
1155 WriteMapMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset,
1156 size_t relative_offset)
1157 : OatDexMethodVisitor(writer, relative_offset),
1158 out_(out),
1159 file_offset_(file_offset) {
1160 }
1161
1162 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) {
1163 OatClass* oat_class = writer_->oat_classes_[oat_class_index_];
1164 const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1165
1166 if (compiled_method != NULL) { // ie. not an abstract method
1167 size_t file_offset = file_offset_;
1168 OutputStream* out = out_;
1169
1170 uint32_t map_offset = DataAccess::GetOffset(oat_class, method_offsets_index_);
1171 ++method_offsets_index_;
1172
1173 // Write deduplicated map.
1174 const std::vector<uint8_t>* map = DataAccess::GetData(compiled_method);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001175 size_t map_size = map == nullptr ? 0 : map->size() * sizeof((*map)[0]);
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001176 DCHECK((map_size == 0u && map_offset == 0u) ||
1177 (map_size != 0u && map_offset != 0u && map_offset <= offset_))
1178 << PrettyMethod(it.GetMemberIndex(), *dex_file_);
1179 if (map_size != 0u && map_offset == offset_) {
1180 if (UNLIKELY(!out->WriteFully(&(*map)[0], map_size))) {
1181 ReportWriteFailure(it);
1182 return false;
1183 }
1184 offset_ += map_size;
1185 }
1186 DCHECK_OFFSET_();
1187 }
1188
1189 return true;
1190 }
1191
1192 private:
1193 OutputStream* const out_;
1194 size_t const file_offset_;
1195
1196 void ReportWriteFailure(const ClassDataItemIterator& it) {
1197 PLOG(ERROR) << "Failed to write " << DataAccess::Name() << " for "
1198 << PrettyMethod(it.GetMemberIndex(), *dex_file_) << " to " << out_->GetLocation();
1199 }
1200};
1201
1202// Visit all methods from all classes in all dex files with the specified visitor.
1203bool OatWriter::VisitDexMethods(DexMethodVisitor* visitor) {
1204 for (const DexFile* dex_file : *dex_files_) {
1205 const size_t class_def_count = dex_file->NumClassDefs();
1206 for (size_t class_def_index = 0; class_def_index != class_def_count; ++class_def_index) {
1207 if (UNLIKELY(!visitor->StartClass(dex_file, class_def_index))) {
1208 return false;
1209 }
1210 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
Ian Rogers13735952014-10-08 12:43:28 -07001211 const uint8_t* class_data = dex_file->GetClassData(class_def);
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001212 if (class_data != NULL) { // ie not an empty class, such as a marker interface
1213 ClassDataItemIterator it(*dex_file, class_data);
1214 while (it.HasNextStaticField()) {
1215 it.Next();
1216 }
1217 while (it.HasNextInstanceField()) {
1218 it.Next();
1219 }
1220 size_t class_def_method_index = 0u;
1221 while (it.HasNextDirectMethod()) {
1222 if (!visitor->VisitMethod(class_def_method_index, it)) {
1223 return false;
1224 }
1225 ++class_def_method_index;
1226 it.Next();
1227 }
1228 while (it.HasNextVirtualMethod()) {
1229 if (UNLIKELY(!visitor->VisitMethod(class_def_method_index, it))) {
1230 return false;
1231 }
1232 ++class_def_method_index;
1233 it.Next();
1234 }
1235 }
1236 if (UNLIKELY(!visitor->EndClass())) {
1237 return false;
1238 }
1239 }
1240 }
1241 return true;
1242}
1243
Brian Carlstrom81f3ca12012-03-17 00:27:35 -07001244size_t OatWriter::InitOatHeader() {
Andreas Gampe22f8e5c2014-07-09 11:38:21 -07001245 oat_header_ = OatHeader::Create(compiler_driver_->GetInstructionSet(),
1246 compiler_driver_->GetInstructionSetFeatures(),
1247 dex_files_,
1248 image_file_location_oat_checksum_,
1249 image_file_location_oat_begin_,
1250 key_value_store_);
1251
1252 return oat_header_->GetHeaderSize();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001253}
1254
1255size_t OatWriter::InitOatDexFiles(size_t offset) {
1256 // create the OatDexFiles
1257 for (size_t i = 0; i != dex_files_->size(); ++i) {
1258 const DexFile* dex_file = (*dex_files_)[i];
1259 CHECK(dex_file != NULL);
Brian Carlstrom265091e2013-01-30 14:08:26 -08001260 OatDexFile* oat_dex_file = new OatDexFile(offset, *dex_file);
Brian Carlstrome24fa612011-09-29 00:53:55 -07001261 oat_dex_files_.push_back(oat_dex_file);
1262 offset += oat_dex_file->SizeOf();
1263 }
1264 return offset;
1265}
1266
Brian Carlstrom89521892011-12-07 22:05:07 -08001267size_t OatWriter::InitDexFiles(size_t offset) {
1268 // calculate the offsets within OatDexFiles to the DexFiles
1269 for (size_t i = 0; i != dex_files_->size(); ++i) {
1270 // dex files are required to be 4 byte aligned
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001271 size_t original_offset = offset;
Brian Carlstrom89521892011-12-07 22:05:07 -08001272 offset = RoundUp(offset, 4);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001273 size_dex_file_alignment_ += offset - original_offset;
Brian Carlstrom89521892011-12-07 22:05:07 -08001274
1275 // set offset in OatDexFile to DexFile
1276 oat_dex_files_[i]->dex_file_offset_ = offset;
1277
1278 const DexFile* dex_file = (*dex_files_)[i];
1279 offset += dex_file->GetHeader().file_size_;
1280 }
1281 return offset;
1282}
1283
Brian Carlstrom389efb02012-01-11 12:06:26 -08001284size_t OatWriter::InitOatClasses(size_t offset) {
Brian Carlstrom389efb02012-01-11 12:06:26 -08001285 // calculate the offsets within OatDexFiles to OatClasses
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001286 InitOatClassesMethodVisitor visitor(this, offset);
1287 bool success = VisitDexMethods(&visitor);
1288 CHECK(success);
1289 offset = visitor.GetOffset();
Brian Carlstromba150c32013-08-27 17:31:03 -07001290
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001291 // Update oat_dex_files_.
1292 auto oat_class_it = oat_classes_.begin();
1293 for (OatDexFile* oat_dex_file : oat_dex_files_) {
1294 for (uint32_t& offset : oat_dex_file->methods_offsets_) {
1295 DCHECK(oat_class_it != oat_classes_.end());
1296 offset = (*oat_class_it)->offset_;
1297 ++oat_class_it;
Brian Carlstrome24fa612011-09-29 00:53:55 -07001298 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001299 oat_dex_file->UpdateChecksum(oat_header_);
Brian Carlstrome24fa612011-09-29 00:53:55 -07001300 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001301 CHECK(oat_class_it == oat_classes_.end());
1302
1303 return offset;
1304}
1305
1306size_t OatWriter::InitOatMaps(size_t offset) {
1307 #define VISIT(VisitorType) \
1308 do { \
1309 VisitorType visitor(this, offset); \
1310 bool success = VisitDexMethods(&visitor); \
1311 DCHECK(success); \
1312 offset = visitor.GetOffset(); \
1313 } while (false)
1314
1315 VISIT(InitMapMethodVisitor<GcMapDataAccess>);
1316 VISIT(InitMapMethodVisitor<MappingTableDataAccess>);
1317 VISIT(InitMapMethodVisitor<VmapTableDataAccess>);
1318
1319 #undef VISIT
1320
Brian Carlstrome24fa612011-09-29 00:53:55 -07001321 return offset;
1322}
1323
1324size_t OatWriter::InitOatCode(size_t offset) {
1325 // calculate the offsets within OatHeader to executable code
1326 size_t old_offset = offset;
Dave Allison50abf0a2014-06-23 13:19:59 -07001327 size_t adjusted_offset = offset;
Brian Carlstrome24fa612011-09-29 00:53:55 -07001328 // required to be on a new page boundary
1329 offset = RoundUp(offset, kPageSize);
1330 oat_header_->SetExecutableOffset(offset);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001331 size_executable_offset_alignment_ = offset - old_offset;
1332 if (compiler_driver_->IsImage()) {
Alex Lighta59dd802014-07-02 16:28:08 -07001333 CHECK_EQ(image_patch_delta_, 0);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001334 InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001335
Ian Rogers848871b2013-08-05 10:56:33 -07001336 #define DO_TRAMPOLINE(field, fn_name) \
1337 offset = CompiledCode::AlignCode(offset, instruction_set); \
Dave Allison50abf0a2014-06-23 13:19:59 -07001338 adjusted_offset = offset + CompiledCode::CodeDelta(instruction_set); \
1339 oat_header_->Set ## fn_name ## Offset(adjusted_offset); \
Ian Rogers848871b2013-08-05 10:56:33 -07001340 field.reset(compiler_driver_->Create ## fn_name()); \
1341 offset += field->size();
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001342
Ian Rogers848871b2013-08-05 10:56:33 -07001343 DO_TRAMPOLINE(interpreter_to_interpreter_bridge_, InterpreterToInterpreterBridge);
1344 DO_TRAMPOLINE(interpreter_to_compiled_code_bridge_, InterpreterToCompiledCodeBridge);
1345 DO_TRAMPOLINE(jni_dlsym_lookup_, JniDlsymLookup);
Jeff Hao88474b42013-10-23 16:24:40 -07001346 DO_TRAMPOLINE(portable_imt_conflict_trampoline_, PortableImtConflictTrampoline);
Ian Rogers848871b2013-08-05 10:56:33 -07001347 DO_TRAMPOLINE(portable_resolution_trampoline_, PortableResolutionTrampoline);
1348 DO_TRAMPOLINE(portable_to_interpreter_bridge_, PortableToInterpreterBridge);
Andreas Gampe2da88232014-02-27 12:26:20 -08001349 DO_TRAMPOLINE(quick_generic_jni_trampoline_, QuickGenericJniTrampoline);
Jeff Hao88474b42013-10-23 16:24:40 -07001350 DO_TRAMPOLINE(quick_imt_conflict_trampoline_, QuickImtConflictTrampoline);
Ian Rogers848871b2013-08-05 10:56:33 -07001351 DO_TRAMPOLINE(quick_resolution_trampoline_, QuickResolutionTrampoline);
1352 DO_TRAMPOLINE(quick_to_interpreter_bridge_, QuickToInterpreterBridge);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001353
Ian Rogers848871b2013-08-05 10:56:33 -07001354 #undef DO_TRAMPOLINE
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001355 } else {
Ian Rogers848871b2013-08-05 10:56:33 -07001356 oat_header_->SetInterpreterToInterpreterBridgeOffset(0);
1357 oat_header_->SetInterpreterToCompiledCodeBridgeOffset(0);
1358 oat_header_->SetJniDlsymLookupOffset(0);
Jeff Hao88474b42013-10-23 16:24:40 -07001359 oat_header_->SetPortableImtConflictTrampolineOffset(0);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001360 oat_header_->SetPortableResolutionTrampolineOffset(0);
Ian Rogers848871b2013-08-05 10:56:33 -07001361 oat_header_->SetPortableToInterpreterBridgeOffset(0);
Andreas Gampe2da88232014-02-27 12:26:20 -08001362 oat_header_->SetQuickGenericJniTrampolineOffset(0);
Jeff Hao88474b42013-10-23 16:24:40 -07001363 oat_header_->SetQuickImtConflictTrampolineOffset(0);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001364 oat_header_->SetQuickResolutionTrampolineOffset(0);
Ian Rogers848871b2013-08-05 10:56:33 -07001365 oat_header_->SetQuickToInterpreterBridgeOffset(0);
Alex Lighta59dd802014-07-02 16:28:08 -07001366 oat_header_->SetImagePatchDelta(image_patch_delta_);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001367 }
Brian Carlstrome24fa612011-09-29 00:53:55 -07001368 return offset;
1369}
1370
1371size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001372 #define VISIT(VisitorType) \
1373 do { \
1374 VisitorType visitor(this, offset); \
1375 bool success = VisitDexMethods(&visitor); \
1376 DCHECK(success); \
1377 offset = visitor.GetOffset(); \
1378 } while (false)
Brian Carlstrome24fa612011-09-29 00:53:55 -07001379
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001380 VISIT(InitCodeMethodVisitor);
Ian Rogers1212a022013-03-04 10:48:41 -08001381 if (compiler_driver_->IsImage()) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001382 VISIT(InitImageMethodVisitor);
Ian Rogers0571d352011-11-03 19:51:38 -07001383 }
Logan Chien8b977d32012-02-21 19:14:55 +08001384
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001385 #undef VISIT
1386
Brian Carlstrome24fa612011-09-29 00:53:55 -07001387 return offset;
1388}
1389
Ian Rogers3d504072014-03-01 09:16:49 -08001390bool OatWriter::Write(OutputStream* out) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001391 const off_t raw_file_offset = out->Seek(0, kSeekCurrent);
1392 if (raw_file_offset == (off_t) -1) {
1393 LOG(ERROR) << "Failed to get file offset in " << out->GetLocation();
1394 return false;
1395 }
1396 const size_t file_offset = static_cast<size_t>(raw_file_offset);
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001397
Vladimir Markof4da6752014-08-01 19:04:18 +01001398 // Reserve space for header. It will be written last - after updating the checksum.
Andreas Gampe22f8e5c2014-07-09 11:38:21 -07001399 size_t header_size = oat_header_->GetHeaderSize();
Vladimir Markof4da6752014-08-01 19:04:18 +01001400 if (out->Seek(header_size, kSeekCurrent) == (off_t) -1) {
1401 PLOG(ERROR) << "Failed to reserve space for oat header in " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001402 return false;
1403 }
Andreas Gampe22f8e5c2014-07-09 11:38:21 -07001404 size_oat_header_ += sizeof(OatHeader);
1405 size_oat_header_key_value_store_ += oat_header_->GetHeaderSize() - sizeof(OatHeader);
Brian Carlstrom81f3ca12012-03-17 00:27:35 -07001406
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001407 if (!WriteTables(out, file_offset)) {
Ian Rogers3d504072014-03-01 09:16:49 -08001408 LOG(ERROR) << "Failed to write oat tables to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001409 return false;
1410 }
1411
Vladimir Markof4da6752014-08-01 19:04:18 +01001412 off_t tables_end_offset = out->Seek(0, kSeekCurrent);
1413 if (tables_end_offset == (off_t) -1) {
1414 LOG(ERROR) << "Failed to seek to oat code position in " << out->GetLocation();
1415 return false;
1416 }
1417 size_t relative_offset = static_cast<size_t>(tables_end_offset) - file_offset;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001418 relative_offset = WriteMaps(out, file_offset, relative_offset);
1419 if (relative_offset == 0) {
1420 LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
1421 return false;
1422 }
1423
1424 relative_offset = WriteCode(out, file_offset, relative_offset);
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001425 if (relative_offset == 0) {
Ian Rogers3d504072014-03-01 09:16:49 -08001426 LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001427 return false;
1428 }
1429
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001430 relative_offset = WriteCodeDexFiles(out, file_offset, relative_offset);
1431 if (relative_offset == 0) {
Ian Rogers3d504072014-03-01 09:16:49 -08001432 LOG(ERROR) << "Failed to write oat code for dex files to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001433 return false;
1434 }
1435
Vladimir Markof4da6752014-08-01 19:04:18 +01001436 const off_t oat_end_file_offset = out->Seek(0, kSeekCurrent);
1437 if (oat_end_file_offset == (off_t) -1) {
1438 LOG(ERROR) << "Failed to get oat end file offset in " << out->GetLocation();
1439 return false;
1440 }
1441
Ian Rogers4bdbbc82013-06-10 16:02:31 -07001442 if (kIsDebugBuild) {
1443 uint32_t size_total = 0;
1444 #define DO_STAT(x) \
Anwar Ghuloum75a43f12013-08-13 17:22:14 -07001445 VLOG(compiler) << #x "=" << PrettySize(x) << " (" << x << "B)"; \
Ian Rogers4bdbbc82013-06-10 16:02:31 -07001446 size_total += x;
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001447
Ian Rogers4bdbbc82013-06-10 16:02:31 -07001448 DO_STAT(size_dex_file_alignment_);
1449 DO_STAT(size_executable_offset_alignment_);
1450 DO_STAT(size_oat_header_);
Andreas Gampe22f8e5c2014-07-09 11:38:21 -07001451 DO_STAT(size_oat_header_key_value_store_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07001452 DO_STAT(size_dex_file_);
Ian Rogers848871b2013-08-05 10:56:33 -07001453 DO_STAT(size_interpreter_to_interpreter_bridge_);
1454 DO_STAT(size_interpreter_to_compiled_code_bridge_);
1455 DO_STAT(size_jni_dlsym_lookup_);
Jeff Hao88474b42013-10-23 16:24:40 -07001456 DO_STAT(size_portable_imt_conflict_trampoline_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07001457 DO_STAT(size_portable_resolution_trampoline_);
Ian Rogers848871b2013-08-05 10:56:33 -07001458 DO_STAT(size_portable_to_interpreter_bridge_);
Andreas Gampe2da88232014-02-27 12:26:20 -08001459 DO_STAT(size_quick_generic_jni_trampoline_);
Jeff Hao88474b42013-10-23 16:24:40 -07001460 DO_STAT(size_quick_imt_conflict_trampoline_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07001461 DO_STAT(size_quick_resolution_trampoline_);
Ian Rogers848871b2013-08-05 10:56:33 -07001462 DO_STAT(size_quick_to_interpreter_bridge_);
1463 DO_STAT(size_trampoline_alignment_);
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001464 DO_STAT(size_method_header_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07001465 DO_STAT(size_code_);
1466 DO_STAT(size_code_alignment_);
Vladimir Markof4da6752014-08-01 19:04:18 +01001467 DO_STAT(size_relative_call_thunks_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07001468 DO_STAT(size_mapping_table_);
1469 DO_STAT(size_vmap_table_);
1470 DO_STAT(size_gc_map_);
1471 DO_STAT(size_oat_dex_file_location_size_);
1472 DO_STAT(size_oat_dex_file_location_data_);
1473 DO_STAT(size_oat_dex_file_location_checksum_);
1474 DO_STAT(size_oat_dex_file_offset_);
1475 DO_STAT(size_oat_dex_file_methods_offsets_);
Brian Carlstromba150c32013-08-27 17:31:03 -07001476 DO_STAT(size_oat_class_type_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07001477 DO_STAT(size_oat_class_status_);
Brian Carlstromba150c32013-08-27 17:31:03 -07001478 DO_STAT(size_oat_class_method_bitmaps_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07001479 DO_STAT(size_oat_class_method_offsets_);
1480 #undef DO_STAT
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001481
Anwar Ghuloum75a43f12013-08-13 17:22:14 -07001482 VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)"; \
Vladimir Markof4da6752014-08-01 19:04:18 +01001483 CHECK_EQ(file_offset + size_total, static_cast<size_t>(oat_end_file_offset));
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001484 CHECK_EQ(size_, size_total);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07001485 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001486
Vladimir Markof4da6752014-08-01 19:04:18 +01001487 CHECK_EQ(file_offset + size_, static_cast<size_t>(oat_end_file_offset));
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001488 CHECK_EQ(size_, relative_offset);
1489
Vladimir Markof4da6752014-08-01 19:04:18 +01001490 // Write the header now that the checksum is final.
1491 if (out->Seek(file_offset, kSeekSet) == (off_t) -1) {
1492 PLOG(ERROR) << "Failed to seek to oat header position in " << out->GetLocation();
1493 return false;
1494 }
1495 DCHECK_EQ(raw_file_offset, out->Seek(0, kSeekCurrent));
1496 if (!out->WriteFully(oat_header_, header_size)) {
1497 PLOG(ERROR) << "Failed to write oat header to " << out->GetLocation();
1498 return false;
1499 }
1500 if (out->Seek(oat_end_file_offset, kSeekSet) == (off_t) -1) {
1501 PLOG(ERROR) << "Failed to seek to end after writing oat header to " << out->GetLocation();
1502 return false;
1503 }
1504 DCHECK_EQ(oat_end_file_offset, out->Seek(0, kSeekCurrent));
1505
Brian Carlstrome24fa612011-09-29 00:53:55 -07001506 return true;
1507}
1508
Ian Rogers3d504072014-03-01 09:16:49 -08001509bool OatWriter::WriteTables(OutputStream* out, const size_t file_offset) {
Brian Carlstrome24fa612011-09-29 00:53:55 -07001510 for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001511 if (!oat_dex_files_[i]->Write(this, out, file_offset)) {
Ian Rogers3d504072014-03-01 09:16:49 -08001512 PLOG(ERROR) << "Failed to write oat dex information to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001513 return false;
1514 }
1515 }
Brian Carlstrom89521892011-12-07 22:05:07 -08001516 for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001517 uint32_t expected_offset = file_offset + oat_dex_files_[i]->dex_file_offset_;
Ian Rogers3d504072014-03-01 09:16:49 -08001518 off_t actual_offset = out->Seek(expected_offset, kSeekSet);
Brian Carlstrom89521892011-12-07 22:05:07 -08001519 if (static_cast<uint32_t>(actual_offset) != expected_offset) {
1520 const DexFile* dex_file = (*dex_files_)[i];
1521 PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
1522 << " Expected: " << expected_offset << " File: " << dex_file->GetLocation();
1523 return false;
1524 }
1525 const DexFile* dex_file = (*dex_files_)[i];
Ian Rogers3d504072014-03-01 09:16:49 -08001526 if (!out->WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) {
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001527 PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation()
Ian Rogers3d504072014-03-01 09:16:49 -08001528 << " to " << out->GetLocation();
Brian Carlstrom89521892011-12-07 22:05:07 -08001529 return false;
1530 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001531 size_dex_file_ += dex_file->GetHeader().file_size_;
Brian Carlstrom89521892011-12-07 22:05:07 -08001532 }
Brian Carlstrom389efb02012-01-11 12:06:26 -08001533 for (size_t i = 0; i != oat_classes_.size(); ++i) {
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001534 if (!oat_classes_[i]->Write(this, out, file_offset)) {
Ian Rogers3d504072014-03-01 09:16:49 -08001535 PLOG(ERROR) << "Failed to write oat methods information to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001536 return false;
1537 }
1538 }
1539 return true;
1540}
1541
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001542size_t OatWriter::WriteMaps(OutputStream* out, const size_t file_offset, size_t relative_offset) {
1543 #define VISIT(VisitorType) \
1544 do { \
1545 VisitorType visitor(this, out, file_offset, relative_offset); \
1546 if (UNLIKELY(!VisitDexMethods(&visitor))) { \
1547 return 0; \
1548 } \
1549 relative_offset = visitor.GetOffset(); \
1550 } while (false)
1551
1552 size_t gc_maps_offset = relative_offset;
1553 VISIT(WriteMapMethodVisitor<GcMapDataAccess>);
1554 size_gc_map_ = relative_offset - gc_maps_offset;
1555
1556 size_t mapping_tables_offset = relative_offset;
1557 VISIT(WriteMapMethodVisitor<MappingTableDataAccess>);
1558 size_mapping_table_ = relative_offset - mapping_tables_offset;
1559
1560 size_t vmap_tables_offset = relative_offset;
1561 VISIT(WriteMapMethodVisitor<VmapTableDataAccess>);
1562 size_vmap_table_ = relative_offset - vmap_tables_offset;
1563
1564 #undef VISIT
1565
1566 return relative_offset;
1567}
1568
1569size_t OatWriter::WriteCode(OutputStream* out, const size_t file_offset, size_t relative_offset) {
Ian Rogers3d504072014-03-01 09:16:49 -08001570 off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent);
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001571 relative_offset += size_executable_offset_alignment_;
1572 DCHECK_EQ(relative_offset, oat_header_->GetExecutableOffset());
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001573 size_t expected_file_offset = file_offset + relative_offset;
1574 if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001575 PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
Ian Rogers3d504072014-03-01 09:16:49 -08001576 << " Expected: " << expected_file_offset << " File: " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001577 return 0;
1578 }
Brian Carlstrom265091e2013-01-30 14:08:26 -08001579 DCHECK_OFFSET();
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001580 if (compiler_driver_->IsImage()) {
1581 InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001582
Ian Rogers848871b2013-08-05 10:56:33 -07001583 #define DO_TRAMPOLINE(field) \
1584 do { \
1585 uint32_t aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set); \
1586 uint32_t alignment_padding = aligned_offset - relative_offset; \
Ian Rogers3d504072014-03-01 09:16:49 -08001587 out->Seek(alignment_padding, kSeekCurrent); \
Ian Rogers848871b2013-08-05 10:56:33 -07001588 size_trampoline_alignment_ += alignment_padding; \
Ian Rogers3d504072014-03-01 09:16:49 -08001589 if (!out->WriteFully(&(*field)[0], field->size())) { \
1590 PLOG(ERROR) << "Failed to write " # field " to " << out->GetLocation(); \
Ian Rogers848871b2013-08-05 10:56:33 -07001591 return false; \
1592 } \
1593 size_ ## field += field->size(); \
1594 relative_offset += alignment_padding + field->size(); \
1595 DCHECK_OFFSET(); \
1596 } while (false)
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001597
Ian Rogers848871b2013-08-05 10:56:33 -07001598 DO_TRAMPOLINE(interpreter_to_interpreter_bridge_);
1599 DO_TRAMPOLINE(interpreter_to_compiled_code_bridge_);
1600 DO_TRAMPOLINE(jni_dlsym_lookup_);
Jeff Hao88474b42013-10-23 16:24:40 -07001601 DO_TRAMPOLINE(portable_imt_conflict_trampoline_);
Ian Rogers848871b2013-08-05 10:56:33 -07001602 DO_TRAMPOLINE(portable_resolution_trampoline_);
1603 DO_TRAMPOLINE(portable_to_interpreter_bridge_);
Andreas Gampe2da88232014-02-27 12:26:20 -08001604 DO_TRAMPOLINE(quick_generic_jni_trampoline_);
Jeff Hao88474b42013-10-23 16:24:40 -07001605 DO_TRAMPOLINE(quick_imt_conflict_trampoline_);
Ian Rogers848871b2013-08-05 10:56:33 -07001606 DO_TRAMPOLINE(quick_resolution_trampoline_);
1607 DO_TRAMPOLINE(quick_to_interpreter_bridge_);
1608 #undef DO_TRAMPOLINE
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001609 }
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001610 return relative_offset;
Brian Carlstrome24fa612011-09-29 00:53:55 -07001611}
1612
Ian Rogers3d504072014-03-01 09:16:49 -08001613size_t OatWriter::WriteCodeDexFiles(OutputStream* out,
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001614 const size_t file_offset,
1615 size_t relative_offset) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001616 #define VISIT(VisitorType) \
1617 do { \
1618 VisitorType visitor(this, out, file_offset, relative_offset); \
1619 if (UNLIKELY(!VisitDexMethods(&visitor))) { \
1620 return 0; \
1621 } \
1622 relative_offset = visitor.GetOffset(); \
1623 } while (false)
Brian Carlstrome24fa612011-09-29 00:53:55 -07001624
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001625 VISIT(WriteCodeMethodVisitor);
Brian Carlstrome24fa612011-09-29 00:53:55 -07001626
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001627 #undef VISIT
Brian Carlstrom265091e2013-01-30 14:08:26 -08001628
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001629 return relative_offset;
Brian Carlstrome24fa612011-09-29 00:53:55 -07001630}
1631
Vladimir Markof4da6752014-08-01 19:04:18 +01001632bool OatWriter::WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta) {
1633 static const uint8_t kPadding[] = {
1634 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u
1635 };
1636 DCHECK_LE(aligned_code_delta, sizeof(kPadding));
1637 if (UNLIKELY(!out->WriteFully(kPadding, aligned_code_delta))) {
1638 return false;
1639 }
1640 size_code_alignment_ += aligned_code_delta;
1641 return true;
1642}
1643
Brian Carlstrom265091e2013-01-30 14:08:26 -08001644OatWriter::OatDexFile::OatDexFile(size_t offset, const DexFile& dex_file) {
1645 offset_ = offset;
Elliott Hughes95572412011-12-13 18:14:20 -08001646 const std::string& location(dex_file.GetLocation());
Brian Carlstrome24fa612011-09-29 00:53:55 -07001647 dex_file_location_size_ = location.size();
1648 dex_file_location_data_ = reinterpret_cast<const uint8_t*>(location.data());
Brian Carlstrom5b332c82012-02-01 15:02:31 -08001649 dex_file_location_checksum_ = dex_file.GetLocationChecksum();
Brian Carlstrom89521892011-12-07 22:05:07 -08001650 dex_file_offset_ = 0;
Brian Carlstrom6e3b1d92012-01-11 01:36:32 -08001651 methods_offsets_.resize(dex_file.NumClassDefs());
Brian Carlstrome24fa612011-09-29 00:53:55 -07001652}
1653
1654size_t OatWriter::OatDexFile::SizeOf() const {
1655 return sizeof(dex_file_location_size_)
1656 + dex_file_location_size_
Brian Carlstrom5b332c82012-02-01 15:02:31 -08001657 + sizeof(dex_file_location_checksum_)
Brian Carlstrom89521892011-12-07 22:05:07 -08001658 + sizeof(dex_file_offset_)
Brian Carlstrom6e3b1d92012-01-11 01:36:32 -08001659 + (sizeof(methods_offsets_[0]) * methods_offsets_.size());
Brian Carlstrome24fa612011-09-29 00:53:55 -07001660}
1661
Ian Rogers3d504072014-03-01 09:16:49 -08001662void OatWriter::OatDexFile::UpdateChecksum(OatHeader* oat_header) const {
1663 oat_header->UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
1664 oat_header->UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
1665 oat_header->UpdateChecksum(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_));
1666 oat_header->UpdateChecksum(&dex_file_offset_, sizeof(dex_file_offset_));
1667 oat_header->UpdateChecksum(&methods_offsets_[0],
Brian Carlstrom6e3b1d92012-01-11 01:36:32 -08001668 sizeof(methods_offsets_[0]) * methods_offsets_.size());
Brian Carlstrome24fa612011-09-29 00:53:55 -07001669}
1670
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001671bool OatWriter::OatDexFile::Write(OatWriter* oat_writer,
Ian Rogers3d504072014-03-01 09:16:49 -08001672 OutputStream* out,
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001673 const size_t file_offset) const {
Brian Carlstrom265091e2013-01-30 14:08:26 -08001674 DCHECK_OFFSET_();
Ian Rogers3d504072014-03-01 09:16:49 -08001675 if (!out->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
1676 PLOG(ERROR) << "Failed to write dex file location length to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001677 return false;
1678 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001679 oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
Ian Rogers3d504072014-03-01 09:16:49 -08001680 if (!out->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
1681 PLOG(ERROR) << "Failed to write dex file location data to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001682 return false;
1683 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001684 oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
Ian Rogers3d504072014-03-01 09:16:49 -08001685 if (!out->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
1686 PLOG(ERROR) << "Failed to write dex file location checksum to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001687 return false;
1688 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001689 oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
Ian Rogers3d504072014-03-01 09:16:49 -08001690 if (!out->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
1691 PLOG(ERROR) << "Failed to write dex file offset to " << out->GetLocation();
Brian Carlstrom89521892011-12-07 22:05:07 -08001692 return false;
1693 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001694 oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
Ian Rogers3d504072014-03-01 09:16:49 -08001695 if (!out->WriteFully(&methods_offsets_[0],
Brian Carlstromcd60ac72013-01-20 17:09:51 -08001696 sizeof(methods_offsets_[0]) * methods_offsets_.size())) {
Ian Rogers3d504072014-03-01 09:16:49 -08001697 PLOG(ERROR) << "Failed to write methods offsets to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001698 return false;
1699 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001700 oat_writer->size_oat_dex_file_methods_offsets_ +=
1701 sizeof(methods_offsets_[0]) * methods_offsets_.size();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001702 return true;
1703}
1704
Brian Carlstromba150c32013-08-27 17:31:03 -07001705OatWriter::OatClass::OatClass(size_t offset,
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001706 const std::vector<CompiledMethod*>& compiled_methods,
Brian Carlstromba150c32013-08-27 17:31:03 -07001707 uint32_t num_non_null_compiled_methods,
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001708 mirror::Class::Status status)
1709 : compiled_methods_(compiled_methods) {
1710 uint32_t num_methods = compiled_methods.size();
Brian Carlstromba150c32013-08-27 17:31:03 -07001711 CHECK_LE(num_non_null_compiled_methods, num_methods);
1712
Brian Carlstrom265091e2013-01-30 14:08:26 -08001713 offset_ = offset;
Brian Carlstromba150c32013-08-27 17:31:03 -07001714 oat_method_offsets_offsets_from_oat_class_.resize(num_methods);
1715
1716 // Since both kOatClassNoneCompiled and kOatClassAllCompiled could
1717 // apply when there are 0 methods, we just arbitrarily say that 0
1718 // methods means kOatClassNoneCompiled and that we won't use
1719 // kOatClassAllCompiled unless there is at least one compiled
1720 // method. This means in an interpretter only system, we can assert
1721 // that all classes are kOatClassNoneCompiled.
1722 if (num_non_null_compiled_methods == 0) {
1723 type_ = kOatClassNoneCompiled;
1724 } else if (num_non_null_compiled_methods == num_methods) {
1725 type_ = kOatClassAllCompiled;
1726 } else {
1727 type_ = kOatClassSomeCompiled;
1728 }
1729
Brian Carlstrom0755ec52012-01-11 15:19:46 -08001730 status_ = status;
Brian Carlstromba150c32013-08-27 17:31:03 -07001731 method_offsets_.resize(num_non_null_compiled_methods);
Vladimir Marko8a630572014-04-09 18:45:35 +01001732 method_headers_.resize(num_non_null_compiled_methods);
Brian Carlstromba150c32013-08-27 17:31:03 -07001733
1734 uint32_t oat_method_offsets_offset_from_oat_class = sizeof(type_) + sizeof(status_);
1735 if (type_ == kOatClassSomeCompiled) {
1736 method_bitmap_ = new BitVector(num_methods, false, Allocator::GetMallocAllocator());
1737 method_bitmap_size_ = method_bitmap_->GetSizeOf();
1738 oat_method_offsets_offset_from_oat_class += sizeof(method_bitmap_size_);
1739 oat_method_offsets_offset_from_oat_class += method_bitmap_size_;
1740 } else {
1741 method_bitmap_ = NULL;
1742 method_bitmap_size_ = 0;
1743 }
1744
1745 for (size_t i = 0; i < num_methods; i++) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001746 CompiledMethod* compiled_method = compiled_methods_[i];
Brian Carlstromba150c32013-08-27 17:31:03 -07001747 if (compiled_method == NULL) {
1748 oat_method_offsets_offsets_from_oat_class_[i] = 0;
1749 } else {
1750 oat_method_offsets_offsets_from_oat_class_[i] = oat_method_offsets_offset_from_oat_class;
1751 oat_method_offsets_offset_from_oat_class += sizeof(OatMethodOffsets);
1752 if (type_ == kOatClassSomeCompiled) {
1753 method_bitmap_->SetBit(i);
1754 }
1755 }
1756 }
Brian Carlstrome24fa612011-09-29 00:53:55 -07001757}
1758
Brian Carlstromba150c32013-08-27 17:31:03 -07001759OatWriter::OatClass::~OatClass() {
Mathieu Chartier661974a2014-01-09 11:23:53 -08001760 delete method_bitmap_;
Brian Carlstromba150c32013-08-27 17:31:03 -07001761}
1762
Brian Carlstrom265091e2013-01-30 14:08:26 -08001763size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatHeader(
1764 size_t class_def_method_index_) const {
Brian Carlstromba150c32013-08-27 17:31:03 -07001765 uint32_t method_offset = GetOatMethodOffsetsOffsetFromOatClass(class_def_method_index_);
1766 if (method_offset == 0) {
1767 return 0;
1768 }
1769 return offset_ + method_offset;
Brian Carlstrom265091e2013-01-30 14:08:26 -08001770}
1771
1772size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatClass(
1773 size_t class_def_method_index_) const {
Brian Carlstromba150c32013-08-27 17:31:03 -07001774 return oat_method_offsets_offsets_from_oat_class_[class_def_method_index_];
Brian Carlstrom265091e2013-01-30 14:08:26 -08001775}
1776
1777size_t OatWriter::OatClass::SizeOf() const {
Brian Carlstromba150c32013-08-27 17:31:03 -07001778 return sizeof(status_)
1779 + sizeof(type_)
1780 + ((method_bitmap_size_ == 0) ? 0 : sizeof(method_bitmap_size_))
1781 + method_bitmap_size_
1782 + (sizeof(method_offsets_[0]) * method_offsets_.size());
Brian Carlstrome24fa612011-09-29 00:53:55 -07001783}
1784
Ian Rogers3d504072014-03-01 09:16:49 -08001785void OatWriter::OatClass::UpdateChecksum(OatHeader* oat_header) const {
1786 oat_header->UpdateChecksum(&status_, sizeof(status_));
1787 oat_header->UpdateChecksum(&type_, sizeof(type_));
Brian Carlstromba150c32013-08-27 17:31:03 -07001788 if (method_bitmap_size_ != 0) {
1789 CHECK_EQ(kOatClassSomeCompiled, type_);
Ian Rogers3d504072014-03-01 09:16:49 -08001790 oat_header->UpdateChecksum(&method_bitmap_size_, sizeof(method_bitmap_size_));
1791 oat_header->UpdateChecksum(method_bitmap_->GetRawStorage(), method_bitmap_size_);
Brian Carlstromba150c32013-08-27 17:31:03 -07001792 }
Ian Rogers3d504072014-03-01 09:16:49 -08001793 oat_header->UpdateChecksum(&method_offsets_[0],
1794 sizeof(method_offsets_[0]) * method_offsets_.size());
Brian Carlstrome24fa612011-09-29 00:53:55 -07001795}
1796
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001797bool OatWriter::OatClass::Write(OatWriter* oat_writer,
Ian Rogers3d504072014-03-01 09:16:49 -08001798 OutputStream* out,
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001799 const size_t file_offset) const {
Brian Carlstrom265091e2013-01-30 14:08:26 -08001800 DCHECK_OFFSET_();
Ian Rogers3d504072014-03-01 09:16:49 -08001801 if (!out->WriteFully(&status_, sizeof(status_))) {
1802 PLOG(ERROR) << "Failed to write class status to " << out->GetLocation();
Brian Carlstrom0755ec52012-01-11 15:19:46 -08001803 return false;
1804 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001805 oat_writer->size_oat_class_status_ += sizeof(status_);
Ian Rogers3d504072014-03-01 09:16:49 -08001806 if (!out->WriteFully(&type_, sizeof(type_))) {
1807 PLOG(ERROR) << "Failed to write oat class type to " << out->GetLocation();
Brian Carlstromba150c32013-08-27 17:31:03 -07001808 return false;
1809 }
1810 oat_writer->size_oat_class_type_ += sizeof(type_);
1811 if (method_bitmap_size_ != 0) {
1812 CHECK_EQ(kOatClassSomeCompiled, type_);
Ian Rogers3d504072014-03-01 09:16:49 -08001813 if (!out->WriteFully(&method_bitmap_size_, sizeof(method_bitmap_size_))) {
1814 PLOG(ERROR) << "Failed to write method bitmap size to " << out->GetLocation();
Brian Carlstromba150c32013-08-27 17:31:03 -07001815 return false;
1816 }
1817 oat_writer->size_oat_class_method_bitmaps_ += sizeof(method_bitmap_size_);
Ian Rogers3d504072014-03-01 09:16:49 -08001818 if (!out->WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_size_)) {
1819 PLOG(ERROR) << "Failed to write method bitmap to " << out->GetLocation();
Brian Carlstromba150c32013-08-27 17:31:03 -07001820 return false;
1821 }
1822 oat_writer->size_oat_class_method_bitmaps_ += method_bitmap_size_;
1823 }
Ian Rogers3d504072014-03-01 09:16:49 -08001824 if (!out->WriteFully(&method_offsets_[0],
Brian Carlstromcd60ac72013-01-20 17:09:51 -08001825 sizeof(method_offsets_[0]) * method_offsets_.size())) {
Ian Rogers3d504072014-03-01 09:16:49 -08001826 PLOG(ERROR) << "Failed to write method offsets to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001827 return false;
1828 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001829 oat_writer->size_oat_class_method_offsets_ += sizeof(method_offsets_[0]) * method_offsets_.size();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001830 return true;
1831}
1832
Brian Carlstrome24fa612011-09-29 00:53:55 -07001833} // namespace art