blob: 6cbca7a6dc482baff52d793219a5e629956a1147 [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
Vladimir Marko9bdf1082016-01-21 12:15:52 +000019#include <unistd.h>
Elliott Hughesa0e18062012-04-13 15:59:59 -070020#include <zlib.h>
21
Vladimir Markoc74658b2015-03-31 10:26:41 +010022#include "arch/arm64/instruction_set_features_arm64.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070023#include "art_method-inl.h"
Ian Rogerse77493c2014-08-20 15:08:45 -070024#include "base/allocator.h"
Brian Carlstromba150c32013-08-27 17:31:03 -070025#include "base/bit_vector.h"
Andreas Gampe542451c2016-07-26 09:02:02 -070026#include "base/enums.h"
Vladimir Marko9bdf1082016-01-21 12:15:52 +000027#include "base/file_magic.h"
Elliott Hughes1aa246d2012-12-13 09:29:36 -080028#include "base/stl_util.h"
Elliott Hughes76160052012-12-12 16:31:20 -080029#include "base/unix_file/fd_file.h"
Brian Carlstrome24fa612011-09-29 00:53:55 -070030#include "class_linker.h"
Mingyao Yang98d1cc82014-05-15 17:02:16 -070031#include "compiled_class.h"
Vladimir Marko20f85592015-03-19 10:07:02 +000032#include "compiled_method.h"
David Srbecky4fda4eb2016-02-05 13:34:46 +000033#include "debug/method_debug_info.h"
Vladimir Markoc7f83202014-01-24 17:55:18 +000034#include "dex/verification_results.h"
David Srbecky4fda4eb2016-02-05 13:34:46 +000035#include "dex_file-inl.h"
Vladimir Marko20f85592015-03-19 10:07:02 +000036#include "driver/compiler_driver.h"
37#include "driver/compiler_options.h"
Vladimir Marko09d09432015-09-08 13:47:48 +010038#include "gc/space/image_space.h"
Ian Rogers1d54e732013-05-02 21:10:01 -070039#include "gc/space/space.h"
Artem Udovichenkod9786b02015-10-14 16:36:55 +030040#include "handle_scope-inl.h"
Vladimir Markof4da6752014-08-01 19:04:18 +010041#include "image_writer.h"
David Brazdil7b49e6c2016-09-01 11:06:18 +010042#include "linker/buffered_output_stream.h"
43#include "linker/file_output_stream.h"
Vladimir Marko944da602016-02-19 12:27:55 +000044#include "linker/multi_oat_relative_patcher.h"
Vladimir Marko131980f2015-12-03 18:29:23 +000045#include "linker/output_stream.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080046#include "mirror/array.h"
47#include "mirror/class_loader.h"
Vladimir Marko3481ba22015-04-13 12:22:36 +010048#include "mirror/dex_cache-inl.h"
Ian Rogers4f6ad8a2013-03-18 15:27:28 -070049#include "mirror/object-inl.h"
Nicolas Geoffray524e7ea2015-10-16 17:13:34 +010050#include "oat_quick_method_header.h"
Brian Carlstrome24fa612011-09-29 00:53:55 -070051#include "os.h"
Elliott Hughesa0e18062012-04-13 15:59:59 -070052#include "safe_map.h"
Mathieu Chartier0795f232016-09-27 18:43:30 -070053#include "scoped_thread_state_change-inl.h"
Artem Udovichenkod9786b02015-10-14 16:36:55 +030054#include "type_lookup_table.h"
Vladimir Marko09d09432015-09-08 13:47:48 +010055#include "utils/dex_cache_arrays_layout-inl.h"
David Brazdil7b49e6c2016-09-01 11:06:18 +010056#include "vdex_file.h"
jeffhaoec014232012-09-05 10:42:25 -070057#include "verifier/method_verifier.h"
David Brazdil5d5a36b2016-09-14 15:34:10 +010058#include "verifier/verifier_deps.h"
Vladimir Marko9bdf1082016-01-21 12:15:52 +000059#include "zip_archive.h"
Brian Carlstrome24fa612011-09-29 00:53:55 -070060
61namespace art {
62
Vladimir Marko9bdf1082016-01-21 12:15:52 +000063namespace { // anonymous namespace
64
65typedef DexFile::Header __attribute__((aligned(1))) UnalignedDexFileHeader;
66
67const UnalignedDexFileHeader* AsUnalignedDexFileHeader(const uint8_t* raw_data) {
68 return reinterpret_cast<const UnalignedDexFileHeader*>(raw_data);
69}
70
Vladimir Markoe079e212016-05-25 12:49:49 +010071class ChecksumUpdatingOutputStream : public OutputStream {
72 public:
73 ChecksumUpdatingOutputStream(OutputStream* out, OatHeader* oat_header)
74 : OutputStream(out->GetLocation()), out_(out), oat_header_(oat_header) { }
75
76 bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE {
77 oat_header_->UpdateChecksum(buffer, byte_count);
78 return out_->WriteFully(buffer, byte_count);
79 }
80
81 off_t Seek(off_t offset, Whence whence) OVERRIDE {
82 return out_->Seek(offset, whence);
83 }
84
85 bool Flush() OVERRIDE {
86 return out_->Flush();
87 }
88
89 private:
90 OutputStream* const out_;
91 OatHeader* const oat_header_;
92};
93
Vladimir Marko0c737df2016-08-01 16:33:16 +010094inline uint32_t CodeAlignmentSize(uint32_t header_offset, const CompiledMethod& compiled_method) {
95 // We want to align the code rather than the preheader.
96 uint32_t unaligned_code_offset = header_offset + sizeof(OatQuickMethodHeader);
97 uint32_t aligned_code_offset = compiled_method.AlignCode(unaligned_code_offset);
98 return aligned_code_offset - unaligned_code_offset;
99}
100
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000101} // anonymous namespace
102
103// Defines the location of the raw dex file to write.
104class OatWriter::DexFileSource {
105 public:
106 explicit DexFileSource(ZipEntry* zip_entry)
107 : type_(kZipEntry), source_(zip_entry) {
108 DCHECK(source_ != nullptr);
109 }
110
111 explicit DexFileSource(File* raw_file)
112 : type_(kRawFile), source_(raw_file) {
113 DCHECK(source_ != nullptr);
114 }
115
116 explicit DexFileSource(const uint8_t* dex_file)
117 : type_(kRawData), source_(dex_file) {
118 DCHECK(source_ != nullptr);
119 }
120
121 bool IsZipEntry() const { return type_ == kZipEntry; }
122 bool IsRawFile() const { return type_ == kRawFile; }
123 bool IsRawData() const { return type_ == kRawData; }
124
125 ZipEntry* GetZipEntry() const {
126 DCHECK(IsZipEntry());
127 DCHECK(source_ != nullptr);
128 return static_cast<ZipEntry*>(const_cast<void*>(source_));
129 }
130
131 File* GetRawFile() const {
132 DCHECK(IsRawFile());
133 DCHECK(source_ != nullptr);
134 return static_cast<File*>(const_cast<void*>(source_));
135 }
136
137 const uint8_t* GetRawData() const {
138 DCHECK(IsRawData());
139 DCHECK(source_ != nullptr);
140 return static_cast<const uint8_t*>(source_);
141 }
142
143 void Clear() {
144 type_ = kNone;
145 source_ = nullptr;
146 }
147
148 private:
149 enum Type {
150 kNone,
151 kZipEntry,
152 kRawFile,
153 kRawData,
154 };
155
156 Type type_;
157 const void* source_;
158};
159
Vladimir Marko49b0f452015-12-10 13:49:19 +0000160class OatWriter::OatClass {
161 public:
162 OatClass(size_t offset,
163 const dchecked_vector<CompiledMethod*>& compiled_methods,
164 uint32_t num_non_null_compiled_methods,
165 mirror::Class::Status status);
166 OatClass(OatClass&& src) = default;
167 size_t GetOatMethodOffsetsOffsetFromOatHeader(size_t class_def_method_index_) const;
168 size_t GetOatMethodOffsetsOffsetFromOatClass(size_t class_def_method_index_) const;
169 size_t SizeOf() const;
170 bool Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const;
171
172 CompiledMethod* GetCompiledMethod(size_t class_def_method_index) const {
173 return compiled_methods_[class_def_method_index];
174 }
175
176 // Offset of start of OatClass from beginning of OatHeader. It is
177 // used to validate file position when writing.
178 size_t offset_;
179
180 // CompiledMethods for each class_def_method_index, or null if no method is available.
181 dchecked_vector<CompiledMethod*> compiled_methods_;
182
183 // Offset from OatClass::offset_ to the OatMethodOffsets for the
184 // class_def_method_index. If 0, it means the corresponding
185 // CompiledMethod entry in OatClass::compiled_methods_ should be
186 // null and that the OatClass::type_ should be kOatClassBitmap.
187 dchecked_vector<uint32_t> oat_method_offsets_offsets_from_oat_class_;
188
189 // Data to write.
190
191 static_assert(mirror::Class::Status::kStatusMax < (1 << 16), "class status won't fit in 16bits");
192 int16_t status_;
193
194 static_assert(OatClassType::kOatClassMax < (1 << 16), "oat_class type won't fit in 16bits");
195 uint16_t type_;
196
197 uint32_t method_bitmap_size_;
198
199 // bit vector indexed by ClassDef method index. When
200 // OatClassType::type_ is kOatClassBitmap, a set bit indicates the
201 // method has an OatMethodOffsets in methods_offsets_, otherwise
202 // the entry was ommited to save space. If OatClassType::type_ is
203 // not is kOatClassBitmap, the bitmap will be null.
204 std::unique_ptr<BitVector> method_bitmap_;
205
206 // OatMethodOffsets and OatMethodHeaders for each CompiledMethod
207 // present in the OatClass. Note that some may be missing if
208 // OatClass::compiled_methods_ contains null values (and
209 // oat_method_offsets_offsets_from_oat_class_ should contain 0
210 // values in this case).
211 dchecked_vector<OatMethodOffsets> method_offsets_;
212 dchecked_vector<OatQuickMethodHeader> method_headers_;
213
214 private:
215 size_t GetMethodOffsetsRawSize() const {
216 return method_offsets_.size() * sizeof(method_offsets_[0]);
217 }
218
219 DISALLOW_COPY_AND_ASSIGN(OatClass);
220};
221
222class OatWriter::OatDexFile {
223 public:
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000224 OatDexFile(const char* dex_file_location,
225 DexFileSource source,
226 CreateTypeLookupTable create_type_lookup_table);
Vladimir Marko49b0f452015-12-10 13:49:19 +0000227 OatDexFile(OatDexFile&& src) = default;
228
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000229 const char* GetLocation() const {
230 return dex_file_location_data_;
231 }
232
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000233 void ReserveClassOffsets(OatWriter* oat_writer);
234
Vladimir Marko49b0f452015-12-10 13:49:19 +0000235 size_t SizeOf() const;
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000236 bool Write(OatWriter* oat_writer, OutputStream* out) const;
237 bool WriteClassOffsets(OatWriter* oat_writer, OutputStream* out);
238
239 // The source of the dex file.
240 DexFileSource source_;
241
242 // Whether to create the type lookup table.
243 CreateTypeLookupTable create_type_lookup_table_;
244
245 // Dex file size. Initialized when writing the dex file.
246 size_t dex_file_size_;
Vladimir Marko49b0f452015-12-10 13:49:19 +0000247
248 // Offset of start of OatDexFile from beginning of OatHeader. It is
249 // used to validate file position when writing.
250 size_t offset_;
251
252 // Data to write.
253 uint32_t dex_file_location_size_;
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000254 const char* dex_file_location_data_;
Vladimir Marko49b0f452015-12-10 13:49:19 +0000255 uint32_t dex_file_location_checksum_;
256 uint32_t dex_file_offset_;
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000257 uint32_t class_offsets_offset_;
Vladimir Marko49b0f452015-12-10 13:49:19 +0000258 uint32_t lookup_table_offset_;
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000259
260 // Data to write to a separate section.
Vladimir Marko49b0f452015-12-10 13:49:19 +0000261 dchecked_vector<uint32_t> class_offsets_;
262
David Sehr9aa352e2016-09-15 18:13:52 -0700263 void InitTypeLookupTable(const DexFile& dex_file, uint8_t* storage) const {
264 lookup_table_.reset(TypeLookupTable::Create(dex_file, storage));
265 }
266
267 TypeLookupTable* GetTypeLookupTable() const {
268 return lookup_table_.get();
269 }
270
Vladimir Marko49b0f452015-12-10 13:49:19 +0000271 private:
David Sehr9aa352e2016-09-15 18:13:52 -0700272 mutable std::unique_ptr<TypeLookupTable> lookup_table_;
Vladimir Marko49b0f452015-12-10 13:49:19 +0000273 size_t GetClassOffsetsRawSize() const {
274 return class_offsets_.size() * sizeof(class_offsets_[0]);
275 }
276
277 DISALLOW_COPY_AND_ASSIGN(OatDexFile);
278};
279
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100280#define DCHECK_OFFSET() \
281 DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out->Seek(0, kSeekCurrent)) \
282 << "file_offset=" << file_offset << " relative_offset=" << relative_offset
283
284#define DCHECK_OFFSET_() \
285 DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \
286 << "file_offset=" << file_offset << " offset_=" << offset_
287
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000288OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings)
289 : write_state_(WriteState::kAddingDexFileSources),
290 timings_(timings),
291 raw_dex_files_(),
292 zip_archives_(),
293 zipped_dex_files_(),
294 zipped_dex_file_locations_(),
295 compiler_driver_(nullptr),
296 image_writer_(nullptr),
Mathieu Chartierda5b28a2015-11-05 08:03:47 -0800297 compiling_boot_image_(compiling_boot_image),
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000298 dex_files_(nullptr),
David Brazdil7b49e6c2016-09-01 11:06:18 +0100299 vdex_size_(0u),
300 vdex_dex_files_offset_(0u),
David Brazdil5d5a36b2016-09-14 15:34:10 +0100301 vdex_verifier_deps_offset_(0u),
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100302 vdex_quickening_info_offset_(0u),
David Brazdil7b49e6c2016-09-01 11:06:18 +0100303 oat_size_(0u),
Vladimir Markoaad75c62016-10-03 08:46:48 +0000304 bss_start_(0u),
Vladimir Marko5c42c292015-02-25 12:02:49 +0000305 bss_size_(0u),
Vladimir Markoaad75c62016-10-03 08:46:48 +0000306 bss_roots_offset_(0u),
307 bss_string_entries_(),
Vladimir Markof4da6752014-08-01 19:04:18 +0100308 oat_data_offset_(0u),
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700309 oat_header_(nullptr),
David Brazdil7b49e6c2016-09-01 11:06:18 +0100310 size_vdex_header_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700311 size_dex_file_alignment_(0),
312 size_executable_offset_alignment_(0),
313 size_oat_header_(0),
Andreas Gampe22f8e5c2014-07-09 11:38:21 -0700314 size_oat_header_key_value_store_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700315 size_dex_file_(0),
David Brazdil5d5a36b2016-09-14 15:34:10 +0100316 size_verifier_deps_(0),
317 size_verifier_deps_alignment_(0),
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100318 size_quickening_info_(0),
319 size_quickening_info_alignment_(0),
Ian Rogers848871b2013-08-05 10:56:33 -0700320 size_interpreter_to_interpreter_bridge_(0),
321 size_interpreter_to_compiled_code_bridge_(0),
322 size_jni_dlsym_lookup_(0),
Andreas Gampe2da88232014-02-27 12:26:20 -0800323 size_quick_generic_jni_trampoline_(0),
Jeff Hao88474b42013-10-23 16:24:40 -0700324 size_quick_imt_conflict_trampoline_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700325 size_quick_resolution_trampoline_(0),
Ian Rogers848871b2013-08-05 10:56:33 -0700326 size_quick_to_interpreter_bridge_(0),
327 size_trampoline_alignment_(0),
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100328 size_method_header_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700329 size_code_(0),
330 size_code_alignment_(0),
Vladimir Markof4da6752014-08-01 19:04:18 +0100331 size_relative_call_thunks_(0),
Vladimir Markoc74658b2015-03-31 10:26:41 +0100332 size_misc_thunks_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700333 size_vmap_table_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700334 size_oat_dex_file_location_size_(0),
335 size_oat_dex_file_location_data_(0),
336 size_oat_dex_file_location_checksum_(0),
337 size_oat_dex_file_offset_(0),
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000338 size_oat_dex_file_class_offsets_offset_(0),
Vladimir Marko49b0f452015-12-10 13:49:19 +0000339 size_oat_dex_file_lookup_table_offset_(0),
Vladimir Marko49b0f452015-12-10 13:49:19 +0000340 size_oat_lookup_table_alignment_(0),
341 size_oat_lookup_table_(0),
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000342 size_oat_class_offsets_alignment_(0),
343 size_oat_class_offsets_(0),
Brian Carlstromba150c32013-08-27 17:31:03 -0700344 size_oat_class_type_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700345 size_oat_class_status_(0),
Brian Carlstromba150c32013-08-27 17:31:03 -0700346 size_oat_class_method_bitmaps_(0),
Vladimir Markof4da6752014-08-01 19:04:18 +0100347 size_oat_class_method_offsets_(0),
Vladimir Marko944da602016-02-19 12:27:55 +0000348 relative_patcher_(nullptr),
349 absolute_patch_locations_() {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000350}
351
352bool OatWriter::AddDexFileSource(const char* filename,
353 const char* location,
354 CreateTypeLookupTable create_type_lookup_table) {
355 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
356 uint32_t magic;
357 std::string error_msg;
Andreas Gampe43e10b02016-07-15 17:17:34 -0700358 File fd = OpenAndReadMagic(filename, &magic, &error_msg);
359 if (fd.Fd() == -1) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000360 PLOG(ERROR) << "Failed to read magic number from dex file: '" << filename << "'";
361 return false;
362 } else if (IsDexMagic(magic)) {
363 // The file is open for reading, not writing, so it's OK to let the File destructor
364 // close it without checking for explicit Close(), so pass checkUsage = false.
Andreas Gampe43e10b02016-07-15 17:17:34 -0700365 raw_dex_files_.emplace_back(new File(fd.Release(), location, /* checkUsage */ false));
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000366 oat_dex_files_.emplace_back(location,
367 DexFileSource(raw_dex_files_.back().get()),
368 create_type_lookup_table);
369 } else if (IsZipMagic(magic)) {
370 if (!AddZippedDexFilesSource(std::move(fd), location, create_type_lookup_table)) {
371 return false;
372 }
373 } else {
374 LOG(ERROR) << "Expected valid zip or dex file: '" << filename << "'";
375 return false;
376 }
377 return true;
378}
379
380// Add dex file source(s) from a zip file specified by a file handle.
Andreas Gampe43e10b02016-07-15 17:17:34 -0700381bool OatWriter::AddZippedDexFilesSource(File&& zip_fd,
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000382 const char* location,
383 CreateTypeLookupTable create_type_lookup_table) {
384 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
385 std::string error_msg;
Andreas Gampe43e10b02016-07-15 17:17:34 -0700386 zip_archives_.emplace_back(ZipArchive::OpenFromFd(zip_fd.Release(), location, &error_msg));
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000387 ZipArchive* zip_archive = zip_archives_.back().get();
388 if (zip_archive == nullptr) {
389 LOG(ERROR) << "Failed to open zip from file descriptor for '" << location << "': "
390 << error_msg;
391 return false;
392 }
393 for (size_t i = 0; ; ++i) {
394 std::string entry_name = DexFile::GetMultiDexClassesDexName(i);
395 std::unique_ptr<ZipEntry> entry(zip_archive->Find(entry_name.c_str(), &error_msg));
396 if (entry == nullptr) {
397 break;
398 }
399 zipped_dex_files_.push_back(std::move(entry));
400 zipped_dex_file_locations_.push_back(DexFile::GetMultiDexLocation(i, location));
401 const char* full_location = zipped_dex_file_locations_.back().c_str();
402 oat_dex_files_.emplace_back(full_location,
403 DexFileSource(zipped_dex_files_.back().get()),
404 create_type_lookup_table);
405 }
406 if (zipped_dex_file_locations_.empty()) {
407 LOG(ERROR) << "No dex files in zip file '" << location << "': " << error_msg;
408 return false;
409 }
410 return true;
411}
412
413// Add dex file source from raw memory.
414bool OatWriter::AddRawDexFileSource(const ArrayRef<const uint8_t>& data,
415 const char* location,
416 uint32_t location_checksum,
417 CreateTypeLookupTable create_type_lookup_table) {
418 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
419 if (data.size() < sizeof(DexFile::Header)) {
420 LOG(ERROR) << "Provided data is shorter than dex file header. size: "
421 << data.size() << " File: " << location;
422 return false;
423 }
424 if (!ValidateDexFileHeader(data.data(), location)) {
425 return false;
426 }
427 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(data.data());
428 if (data.size() < header->file_size_) {
429 LOG(ERROR) << "Truncated dex file data. Data size: " << data.size()
430 << " file size from header: " << header->file_size_ << " File: " << location;
431 return false;
432 }
433
434 oat_dex_files_.emplace_back(location, DexFileSource(data.data()), create_type_lookup_table);
435 oat_dex_files_.back().dex_file_location_checksum_ = location_checksum;
436 return true;
437}
438
439dchecked_vector<const char*> OatWriter::GetSourceLocations() const {
440 dchecked_vector<const char*> locations;
441 locations.reserve(oat_dex_files_.size());
442 for (const OatDexFile& oat_dex_file : oat_dex_files_) {
443 locations.push_back(oat_dex_file.GetLocation());
444 }
445 return locations;
446}
447
448bool OatWriter::WriteAndOpenDexFiles(
David Brazdil7b49e6c2016-09-01 11:06:18 +0100449 File* vdex_file,
450 OutputStream* oat_rodata,
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000451 InstructionSet instruction_set,
452 const InstructionSetFeatures* instruction_set_features,
453 SafeMap<std::string, std::string>* key_value_store,
Andreas Gampe3a2bd292016-01-26 17:23:47 -0800454 bool verify,
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000455 /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map,
456 /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
457 CHECK(write_state_ == WriteState::kAddingDexFileSources);
458
David Brazdil7b49e6c2016-09-01 11:06:18 +0100459 // Record the ELF rodata section offset, i.e. the beginning of the OAT data.
460 if (!RecordOatDataOffset(oat_rodata)) {
461 return false;
462 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000463
464 std::unique_ptr<MemMap> dex_files_map;
465 std::vector<std::unique_ptr<const DexFile>> dex_files;
David Brazdil7b49e6c2016-09-01 11:06:18 +0100466
467 // Initialize VDEX and OAT headers.
468 if (kIsVdexEnabled) {
469 size_vdex_header_ = sizeof(VdexFile::Header);
470 vdex_size_ = size_vdex_header_;
471 }
472 size_t oat_data_offset = InitOatHeader(instruction_set,
473 instruction_set_features,
474 dchecked_integral_cast<uint32_t>(oat_dex_files_.size()),
475 key_value_store);
476 oat_size_ = InitOatDexFiles(oat_data_offset);
477
478 ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, oat_header_.get());
479
480 if (kIsVdexEnabled) {
481 std::unique_ptr<BufferedOutputStream> vdex_out(
482 MakeUnique<BufferedOutputStream>(MakeUnique<FileOutputStream>(vdex_file)));
483
484 // Write DEX files into VDEX, mmap and open them.
485 if (!WriteDexFiles(vdex_out.get(), vdex_file) ||
486 !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
487 return false;
488 }
David Brazdil7b49e6c2016-09-01 11:06:18 +0100489 } else {
490 // Write DEX files into OAT, mmap and open them.
491 if (!WriteDexFiles(oat_rodata, vdex_file) ||
492 !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
493 return false;
494 }
495
496 // Do a bulk checksum update for Dex[]. Doing it piece by piece would be
497 // difficult because we're not using the OutputStream directly.
498 if (!oat_dex_files_.empty()) {
499 size_t size = oat_size_ - oat_dex_files_[0].dex_file_offset_;
500 oat_header_->UpdateChecksum(dex_files_map->Begin(), size);
501 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000502 }
David Brazdil181e1cc2016-09-01 16:38:47 +0000503
David Brazdil7b49e6c2016-09-01 11:06:18 +0100504 // Write TypeLookupTables into OAT.
David Brazdil181e1cc2016-09-01 16:38:47 +0000505 if (!WriteTypeLookupTables(&checksum_updating_rodata, dex_files)) {
506 return false;
507 }
508
David Brazdil7b49e6c2016-09-01 11:06:18 +0100509 // Reserve space for class offsets in OAT and update class_offsets_offset_.
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000510 for (OatDexFile& oat_dex_file : oat_dex_files_) {
511 oat_dex_file.ReserveClassOffsets(this);
512 }
Vladimir Markoe079e212016-05-25 12:49:49 +0100513
David Brazdil7b49e6c2016-09-01 11:06:18 +0100514 // Write OatDexFiles into OAT. Needs to be done last, once offsets are collected.
David Brazdil181e1cc2016-09-01 16:38:47 +0000515 if (!WriteOatDexFiles(&checksum_updating_rodata)) {
516 return false;
David Brazdilb92ba622016-09-01 16:00:30 +0000517 }
518
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000519 *opened_dex_files_map = std::move(dex_files_map);
520 *opened_dex_files = std::move(dex_files);
521 write_state_ = WriteState::kPrepareLayout;
522 return true;
523}
524
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100525void OatWriter::PrepareLayout(linker::MultiOatRelativePatcher* relative_patcher) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000526 CHECK(write_state_ == WriteState::kPrepareLayout);
527
Vladimir Marko944da602016-02-19 12:27:55 +0000528 relative_patcher_ = relative_patcher;
529 SetMultiOatRelativePatcherAdjustment();
530
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000531 if (compiling_boot_image_) {
532 CHECK(image_writer_ != nullptr);
Mathieu Chartierda5b28a2015-11-05 08:03:47 -0800533 }
Vladimir Markob163bb72015-03-31 21:49:49 +0100534 InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000535 CHECK_EQ(instruction_set, oat_header_->GetInstructionSet());
Vladimir Markof4da6752014-08-01 19:04:18 +0100536
David Brazdil7b49e6c2016-09-01 11:06:18 +0100537 uint32_t offset = oat_size_;
Ian Rogersca368cb2013-11-15 15:52:08 -0800538 {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000539 TimingLogger::ScopedTiming split("InitOatClasses", timings_);
Ian Rogersca368cb2013-11-15 15:52:08 -0800540 offset = InitOatClasses(offset);
541 }
542 {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000543 TimingLogger::ScopedTiming split("InitOatMaps", timings_);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100544 offset = InitOatMaps(offset);
545 }
546 {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000547 TimingLogger::ScopedTiming split("InitOatCode", timings_);
Ian Rogersca368cb2013-11-15 15:52:08 -0800548 offset = InitOatCode(offset);
549 }
550 {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000551 TimingLogger::ScopedTiming split("InitOatCodeDexFiles", timings_);
Ian Rogersca368cb2013-11-15 15:52:08 -0800552 offset = InitOatCodeDexFiles(offset);
553 }
David Brazdil7b49e6c2016-09-01 11:06:18 +0100554 oat_size_ = offset;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700555
Mathieu Chartierda5b28a2015-11-05 08:03:47 -0800556 if (!HasBootImage()) {
Vladimir Markoaad75c62016-10-03 08:46:48 +0000557 TimingLogger::ScopedTiming split("InitBssLayout", timings_);
558 InitBssLayout(instruction_set);
Vladimir Marko09d09432015-09-08 13:47:48 +0100559 }
560
Brian Carlstrome24fa612011-09-29 00:53:55 -0700561 CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
Mathieu Chartierda5b28a2015-11-05 08:03:47 -0800562 if (compiling_boot_image_) {
563 CHECK_EQ(image_writer_ != nullptr,
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000564 oat_header_->GetStoreValueByKey(OatHeader::kImageLocationKey) == nullptr);
Mathieu Chartierda5b28a2015-11-05 08:03:47 -0800565 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000566
567 write_state_ = WriteState::kWriteRoData;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700568}
569
Ian Rogers0571d352011-11-03 19:51:38 -0700570OatWriter::~OatWriter() {
Ian Rogers0571d352011-11-03 19:51:38 -0700571}
572
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100573class OatWriter::DexMethodVisitor {
574 public:
575 DexMethodVisitor(OatWriter* writer, size_t offset)
576 : writer_(writer),
577 offset_(offset),
578 dex_file_(nullptr),
579 class_def_index_(DexFile::kDexNoIndex) {
580 }
581
582 virtual bool StartClass(const DexFile* dex_file, size_t class_def_index) {
583 DCHECK(dex_file_ == nullptr);
584 DCHECK_EQ(class_def_index_, DexFile::kDexNoIndex);
585 dex_file_ = dex_file;
586 class_def_index_ = class_def_index;
587 return true;
588 }
589
590 virtual bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) = 0;
591
592 virtual bool EndClass() {
593 if (kIsDebugBuild) {
594 dex_file_ = nullptr;
595 class_def_index_ = DexFile::kDexNoIndex;
596 }
597 return true;
598 }
599
600 size_t GetOffset() const {
601 return offset_;
602 }
603
604 protected:
605 virtual ~DexMethodVisitor() { }
606
607 OatWriter* const writer_;
608
609 // The offset is usually advanced for each visited method by the derived class.
610 size_t offset_;
611
612 // The dex file and class def index are set in StartClass().
613 const DexFile* dex_file_;
614 size_t class_def_index_;
615};
616
617class OatWriter::OatDexMethodVisitor : public DexMethodVisitor {
618 public:
619 OatDexMethodVisitor(OatWriter* writer, size_t offset)
620 : DexMethodVisitor(writer, offset),
621 oat_class_index_(0u),
622 method_offsets_index_(0u) {
623 }
624
625 bool StartClass(const DexFile* dex_file, size_t class_def_index) {
626 DexMethodVisitor::StartClass(dex_file, class_def_index);
627 DCHECK_LT(oat_class_index_, writer_->oat_classes_.size());
628 method_offsets_index_ = 0u;
629 return true;
630 }
631
632 bool EndClass() {
633 ++oat_class_index_;
634 return DexMethodVisitor::EndClass();
635 }
636
637 protected:
638 size_t oat_class_index_;
639 size_t method_offsets_index_;
640};
641
642class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor {
643 public:
644 InitOatClassesMethodVisitor(OatWriter* writer, size_t offset)
645 : DexMethodVisitor(writer, offset),
646 compiled_methods_(),
647 num_non_null_compiled_methods_(0u) {
Vladimir Marko49b0f452015-12-10 13:49:19 +0000648 size_t num_classes = 0u;
649 for (const OatDexFile& oat_dex_file : writer_->oat_dex_files_) {
650 num_classes += oat_dex_file.class_offsets_.size();
651 }
652 writer_->oat_classes_.reserve(num_classes);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100653 compiled_methods_.reserve(256u);
654 }
655
656 bool StartClass(const DexFile* dex_file, size_t class_def_index) {
657 DexMethodVisitor::StartClass(dex_file, class_def_index);
658 compiled_methods_.clear();
659 num_non_null_compiled_methods_ = 0u;
660 return true;
661 }
662
Artem Udovichenkod9786b02015-10-14 16:36:55 +0300663 bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,
664 const ClassDataItemIterator& it) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100665 // Fill in the compiled_methods_ array for methods that have a
666 // CompiledMethod. We track the number of non-null entries in
667 // num_non_null_compiled_methods_ since we only want to allocate
668 // OatMethodOffsets for the compiled methods.
669 uint32_t method_idx = it.GetMemberIndex();
670 CompiledMethod* compiled_method =
671 writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
672 compiled_methods_.push_back(compiled_method);
673 if (compiled_method != nullptr) {
674 ++num_non_null_compiled_methods_;
675 }
676 return true;
677 }
678
679 bool EndClass() {
680 ClassReference class_ref(dex_file_, class_def_index_);
681 CompiledClass* compiled_class = writer_->compiler_driver_->GetCompiledClass(class_ref);
682 mirror::Class::Status status;
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700683 if (compiled_class != nullptr) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100684 status = compiled_class->GetStatus();
685 } else if (writer_->compiler_driver_->GetVerificationResults()->IsClassRejected(class_ref)) {
686 status = mirror::Class::kStatusError;
687 } else {
688 status = mirror::Class::kStatusNotReady;
689 }
690
Vladimir Marko49b0f452015-12-10 13:49:19 +0000691 writer_->oat_classes_.emplace_back(offset_,
692 compiled_methods_,
693 num_non_null_compiled_methods_,
694 status);
695 offset_ += writer_->oat_classes_.back().SizeOf();
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100696 return DexMethodVisitor::EndClass();
697 }
698
699 private:
Vladimir Marko49b0f452015-12-10 13:49:19 +0000700 dchecked_vector<CompiledMethod*> compiled_methods_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100701 size_t num_non_null_compiled_methods_;
702};
703
704class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor {
705 public:
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100706 InitCodeMethodVisitor(OatWriter* writer, size_t offset, size_t quickening_info_offset)
David Srbecky009e2a62015-04-15 02:46:30 +0100707 : OatDexMethodVisitor(writer, offset),
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100708 debuggable_(writer->GetCompilerDriver()->GetCompilerOptions().GetDebuggable()),
709 current_quickening_info_offset_(quickening_info_offset) {
David Srbeckyf8980872015-05-22 17:04:47 +0100710 writer_->absolute_patch_locations_.reserve(
Vladimir Markof4da6752014-08-01 19:04:18 +0100711 writer_->compiler_driver_->GetNonRelativeLinkerPatchCount());
712 }
713
714 bool EndClass() {
715 OatDexMethodVisitor::EndClass();
716 if (oat_class_index_ == writer_->oat_classes_.size()) {
Vladimir Marko71b0ddf2015-04-02 19:45:06 +0100717 offset_ = writer_->relative_patcher_->ReserveSpaceEnd(offset_);
Vladimir Markof4da6752014-08-01 19:04:18 +0100718 }
719 return true;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100720 }
721
722 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700723 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko49b0f452015-12-10 13:49:19 +0000724 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100725 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
726
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100727 if (it.GetMethodCodeItem() != nullptr) {
728 current_quickening_info_offset_ += sizeof(uint32_t);
729 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100730 if (compiled_method != nullptr) {
731 // Derived from CompiledMethod.
732 uint32_t quick_code_offset = 0;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100733
Vladimir Marko35831e82015-09-11 11:59:18 +0100734 ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
735 uint32_t code_size = quick_code.size() * sizeof(uint8_t);
Elliott Hughes956af0f2014-12-11 14:34:28 -0800736 uint32_t thumb_offset = compiled_method->CodeDelta();
Elliott Hughes956af0f2014-12-11 14:34:28 -0800737
David Srbecky009e2a62015-04-15 02:46:30 +0100738 // Deduplicate code arrays if we are not producing debuggable code.
Vladimir Marko9d07e3d2016-03-31 12:02:28 +0100739 bool deduped = true;
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800740 MethodReference method_ref(dex_file_, it.GetMemberIndex());
Nicolas Geoffrayed6195a2015-07-13 17:02:30 +0000741 if (debuggable_) {
Vladimir Marko944da602016-02-19 12:27:55 +0000742 quick_code_offset = writer_->relative_patcher_->GetOffset(method_ref);
743 if (quick_code_offset != 0u) {
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800744 // Duplicate methods, we want the same code for both of them so that the oat writer puts
745 // the same code in both ArtMethods so that we do not get different oat code at runtime.
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800746 } else {
747 quick_code_offset = NewQuickCodeOffset(compiled_method, it, thumb_offset);
Vladimir Marko9d07e3d2016-03-31 12:02:28 +0100748 deduped = false;
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800749 }
Nicolas Geoffrayed6195a2015-07-13 17:02:30 +0000750 } else {
Vladimir Marko9d07e3d2016-03-31 12:02:28 +0100751 quick_code_offset = dedupe_map_.GetOrCreate(
752 compiled_method,
753 [this, &deduped, compiled_method, &it, thumb_offset]() {
754 deduped = false;
755 return NewQuickCodeOffset(compiled_method, it, thumb_offset);
756 });
Elliott Hughes956af0f2014-12-11 14:34:28 -0800757 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100758
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100759 if (code_size != 0) {
Vladimir Marko944da602016-02-19 12:27:55 +0000760 if (writer_->relative_patcher_->GetOffset(method_ref) != 0u) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100761 // TODO: Should this be a hard failure?
762 LOG(WARNING) << "Multiple definitions of "
David Sehr709b0702016-10-13 09:12:37 -0700763 << method_ref.dex_file->PrettyMethod(method_ref.dex_method_index)
Vladimir Marko944da602016-02-19 12:27:55 +0000764 << " offsets " << writer_->relative_patcher_->GetOffset(method_ref)
765 << " " << quick_code_offset;
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100766 } else {
Vladimir Marko944da602016-02-19 12:27:55 +0000767 writer_->relative_patcher_->SetOffset(method_ref, quick_code_offset);
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100768 }
Elliott Hughes956af0f2014-12-11 14:34:28 -0800769 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100770
Elliott Hughes956af0f2014-12-11 14:34:28 -0800771 // Update quick method header.
772 DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size());
773 OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
Elliott Hughes956af0f2014-12-11 14:34:28 -0800774 uint32_t vmap_table_offset = method_header->vmap_table_offset_;
Elliott Hughes956af0f2014-12-11 14:34:28 -0800775 // The code offset was 0 when the mapping/vmap table offset was set, so it's set
776 // to 0-offset and we need to adjust it by code_offset.
777 uint32_t code_offset = quick_code_offset - thumb_offset;
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100778 if (!compiled_method->GetQuickCode().empty()) {
779 // If the code is compiled, we write the offset of the stack map relative
780 // to the code,
781 if (vmap_table_offset != 0u) {
782 vmap_table_offset += code_offset;
783 DCHECK_LT(vmap_table_offset, code_offset);
784 }
785 } else {
786 if (kIsVdexEnabled) {
787 // We write the offset in the .vdex file.
788 DCHECK_EQ(vmap_table_offset, 0u);
789 vmap_table_offset = current_quickening_info_offset_;
790 ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
791 current_quickening_info_offset_ += map.size() * sizeof(map.front());
792 } else {
793 // We write the offset of the quickening info relative to the code.
794 vmap_table_offset += code_offset;
795 DCHECK_LT(vmap_table_offset, code_offset);
796 }
Elliott Hughes956af0f2014-12-11 14:34:28 -0800797 }
Elliott Hughes956af0f2014-12-11 14:34:28 -0800798 uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
799 uint32_t core_spill_mask = compiled_method->GetCoreSpillMask();
800 uint32_t fp_spill_mask = compiled_method->GetFpSpillMask();
Vladimir Marko9d07e3d2016-03-31 12:02:28 +0100801 *method_header = OatQuickMethodHeader(vmap_table_offset,
802 frame_size_in_bytes,
803 core_spill_mask,
804 fp_spill_mask,
805 code_size);
Vladimir Marko7624d252014-05-02 14:40:15 +0100806
Nicolas Geoffrayed6195a2015-07-13 17:02:30 +0000807 if (!deduped) {
Elliott Hughes956af0f2014-12-11 14:34:28 -0800808 // Update offsets. (Checksum is updated when writing.)
809 offset_ += sizeof(*method_header); // Method header is prepended before code.
810 offset_ += code_size;
811 // Record absolute patch locations.
812 if (!compiled_method->GetPatches().empty()) {
813 uintptr_t base_loc = offset_ - code_size - writer_->oat_header_->GetExecutableOffset();
814 for (const LinkerPatch& patch : compiled_method->GetPatches()) {
Vladimir Marko20f85592015-03-19 10:07:02 +0000815 if (!patch.IsPcRelative()) {
David Srbeckyf8980872015-05-22 17:04:47 +0100816 writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset());
Vladimir Markof4da6752014-08-01 19:04:18 +0100817 }
Vladimir Markoaad75c62016-10-03 08:46:48 +0000818 if (patch.GetType() == LinkerPatch::Type::kStringBssEntry) {
819 StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
820 writer_->bss_string_entries_.Overwrite(ref, /* placeholder */ 0u);
821 }
Vladimir Markof4da6752014-08-01 19:04:18 +0100822 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100823 }
Elliott Hughes956af0f2014-12-11 14:34:28 -0800824 }
Alex Light78382fa2014-06-06 15:45:32 -0700825
David Srbecky91cc06c2016-03-07 16:13:58 +0000826 const CompilerOptions& compiler_options = writer_->compiler_driver_->GetCompilerOptions();
David Srbecky197160d2016-03-07 17:33:57 +0000827 // Exclude quickened dex methods (code_size == 0) since they have no native code.
828 if (compiler_options.GenerateAnyDebugInfo() && code_size != 0) {
829 bool has_code_info = method_header->IsOptimized();
Elliott Hughes956af0f2014-12-11 14:34:28 -0800830 // Record debug information for this function if we are doing that.
David Srbecky09c2a6b2016-03-11 17:11:44 +0000831 debug::MethodDebugInfo info = debug::MethodDebugInfo();
832 info.trampoline_name = nullptr;
David Srbecky197160d2016-03-07 17:33:57 +0000833 info.dex_file = dex_file_;
834 info.class_def_index = class_def_index_;
835 info.dex_method_index = it.GetMemberIndex();
836 info.access_flags = it.GetMethodAccessFlags();
837 info.code_item = it.GetMethodCodeItem();
838 info.isa = compiled_method->GetInstructionSet();
839 info.deduped = deduped;
840 info.is_native_debuggable = compiler_options.GetNativeDebuggable();
841 info.is_optimized = method_header->IsOptimized();
842 info.is_code_address_text_relative = true;
843 info.code_address = code_offset - writer_->oat_header_->GetExecutableOffset();
844 info.code_size = code_size;
845 info.frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
846 info.code_info = has_code_info ? compiled_method->GetVmapTable().data() : nullptr;
847 info.cfi = compiled_method->GetCFIInfo();
848 writer_->method_info_.push_back(info);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100849 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100850
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100851 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
852 OatMethodOffsets* offsets = &oat_class->method_offsets_[method_offsets_index_];
853 offsets->code_offset_ = quick_code_offset;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100854 ++method_offsets_index_;
855 }
856
857 return true;
858 }
859
860 private:
Vladimir Marko20f85592015-03-19 10:07:02 +0000861 struct CodeOffsetsKeyComparator {
862 bool operator()(const CompiledMethod* lhs, const CompiledMethod* rhs) const {
Vladimir Marko35831e82015-09-11 11:59:18 +0100863 // Code is deduplicated by CompilerDriver, compare only data pointers.
864 if (lhs->GetQuickCode().data() != rhs->GetQuickCode().data()) {
865 return lhs->GetQuickCode().data() < rhs->GetQuickCode().data();
Vladimir Marko20f85592015-03-19 10:07:02 +0000866 }
867 // If the code is the same, all other fields are likely to be the same as well.
Vladimir Marko35831e82015-09-11 11:59:18 +0100868 if (UNLIKELY(lhs->GetVmapTable().data() != rhs->GetVmapTable().data())) {
869 return lhs->GetVmapTable().data() < rhs->GetVmapTable().data();
Vladimir Marko20f85592015-03-19 10:07:02 +0000870 }
Vladimir Marko35831e82015-09-11 11:59:18 +0100871 if (UNLIKELY(lhs->GetPatches().data() != rhs->GetPatches().data())) {
872 return lhs->GetPatches().data() < rhs->GetPatches().data();
Vladimir Marko20f85592015-03-19 10:07:02 +0000873 }
874 return false;
875 }
876 };
877
David Srbecky009e2a62015-04-15 02:46:30 +0100878 uint32_t NewQuickCodeOffset(CompiledMethod* compiled_method,
879 const ClassDataItemIterator& it,
880 uint32_t thumb_offset) {
881 offset_ = writer_->relative_patcher_->ReserveSpace(
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100882 offset_, compiled_method, MethodReference(dex_file_, it.GetMemberIndex()));
Vladimir Marko0c737df2016-08-01 16:33:16 +0100883 offset_ += CodeAlignmentSize(offset_, *compiled_method);
884 DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader),
David Srbecky009e2a62015-04-15 02:46:30 +0100885 GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
886 return offset_ + sizeof(OatQuickMethodHeader) + thumb_offset;
887 }
888
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100889 // Deduplication is already done on a pointer basis by the compiler driver,
890 // so we can simply compare the pointers to find out if things are duplicated.
Vladimir Marko8a630572014-04-09 18:45:35 +0100891 SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_;
David Srbecky2f6cdb02015-04-11 00:17:53 +0100892
David Srbecky009e2a62015-04-15 02:46:30 +0100893 // Cache of compiler's --debuggable option.
894 const bool debuggable_;
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100895
896 // Offset in the vdex file for the quickening info.
897 uint32_t current_quickening_info_offset_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100898};
899
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100900class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor {
901 public:
902 InitMapMethodVisitor(OatWriter* writer, size_t offset)
903 : OatDexMethodVisitor(writer, offset) {
904 }
905
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700906 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700907 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko49b0f452015-12-10 13:49:19 +0000908 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100909 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
910
911 if (compiled_method != nullptr) {
912 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100913 // If vdex is enabled, we only emit the stack map of compiled code. The quickening info will
914 // be in the vdex file.
915 if (!compiled_method->GetQuickCode().empty() || !kIsVdexEnabled) {
916 DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].vmap_table_offset_, 0u);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100917
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100918 ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
919 uint32_t map_size = map.size() * sizeof(map[0]);
920 if (map_size != 0u) {
921 size_t offset = dedupe_map_.GetOrCreate(
922 map.data(),
923 [this, map_size]() {
924 uint32_t new_offset = offset_;
925 offset_ += map_size;
926 return new_offset;
927 });
928 // Code offset is not initialized yet, so set the map offset to 0u-offset.
929 DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u);
930 oat_class->method_headers_[method_offsets_index_].vmap_table_offset_ = 0u - offset;
931 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100932 }
933 ++method_offsets_index_;
934 }
935
936 return true;
937 }
938
939 private:
940 // Deduplication is already done on a pointer basis by the compiler driver,
941 // so we can simply compare the pointers to find out if things are duplicated.
Vladimir Marko35831e82015-09-11 11:59:18 +0100942 SafeMap<const uint8_t*, uint32_t> dedupe_map_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100943};
944
945class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor {
946 public:
947 InitImageMethodVisitor(OatWriter* writer, size_t offset)
Jeff Haoc7d11882015-02-03 15:08:39 -0800948 : OatDexMethodVisitor(writer, offset),
949 pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100950 }
951
952 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700953 REQUIRES_SHARED(Locks::mutator_lock_) {
Jeff Haodcdc85b2015-12-04 14:06:18 -0800954 const DexFile::TypeId& type_id =
955 dex_file_->GetTypeId(dex_file_->GetClassDef(class_def_index_).class_idx_);
956 const char* class_descriptor = dex_file_->GetTypeDescriptor(type_id);
957 // Skip methods that are not in the image.
958 if (!writer_->GetCompilerDriver()->IsImageClass(class_descriptor)) {
959 return true;
960 }
961
Vladimir Marko49b0f452015-12-10 13:49:19 +0000962 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100963 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
964
Mathieu Chartier957ca1c2014-11-21 16:51:29 -0800965 OatMethodOffsets offsets(0u);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100966 if (compiled_method != nullptr) {
967 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
968 offsets = oat_class->method_offsets_[method_offsets_index_];
969 ++method_offsets_index_;
970 }
971
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100972 ClassLinker* linker = Runtime::Current()->GetClassLinker();
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100973 // Unchecked as we hold mutator_lock_ on entry.
974 ScopedObjectAccessUnchecked soa(Thread::Current());
Mathieu Chartier957ca1c2014-11-21 16:51:29 -0800975 StackHandleScope<1> hs(soa.Self());
Mathieu Chartier673ed3d2015-08-28 14:56:43 -0700976 Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->FindDexCache(
977 Thread::Current(), *dex_file_)));
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800978 ArtMethod* method;
979 if (writer_->HasBootImage()) {
980 const InvokeType invoke_type = it.GetMethodInvokeType(
981 dex_file_->GetClassDef(class_def_index_));
982 method = linker->ResolveMethod<ClassLinker::kNoICCECheckForCache>(
983 *dex_file_,
984 it.GetMemberIndex(),
985 dex_cache,
986 ScopedNullHandle<mirror::ClassLoader>(),
987 nullptr,
988 invoke_type);
989 if (method == nullptr) {
Andreas Gampe3fec9ac2016-09-13 10:47:28 -0700990 LOG(FATAL_WITHOUT_ABORT) << "Unexpected failure to resolve a method: "
David Sehr709b0702016-10-13 09:12:37 -0700991 << dex_file_->PrettyMethod(it.GetMemberIndex(), true);
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800992 soa.Self()->AssertPendingException();
993 mirror::Throwable* exc = soa.Self()->GetException();
994 std::string dump = exc->Dump();
995 LOG(FATAL) << dump;
996 UNREACHABLE();
997 }
998 } else {
999 // Should already have been resolved by the compiler, just peek into the dex cache.
1000 // It may not be resolved if the class failed to verify, in this case, don't set the
1001 // entrypoint. This is not fatal since the dex cache will contain a resolution method.
1002 method = dex_cache->GetResolvedMethod(it.GetMemberIndex(), linker->GetImagePointerSize());
Andreas Gamped9efea62014-07-21 22:56:08 -07001003 }
Mathieu Chartierfbc31082016-01-24 11:59:56 -08001004 if (method != nullptr &&
1005 compiled_method != nullptr &&
1006 compiled_method->GetQuickCode().size() != 0) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001007 method->SetEntryPointFromQuickCompiledCodePtrSize(
1008 reinterpret_cast<void*>(offsets.code_offset_), pointer_size_);
1009 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001010
1011 return true;
1012 }
Jeff Haoc7d11882015-02-03 15:08:39 -08001013
1014 protected:
Andreas Gampe542451c2016-07-26 09:02:02 -07001015 const PointerSize pointer_size_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001016};
1017
1018class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
1019 public:
1020 WriteCodeMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset,
Vladimir Markof4da6752014-08-01 19:04:18 +01001021 size_t relative_offset) SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001022 : OatDexMethodVisitor(writer, relative_offset),
1023 out_(out),
Vladimir Markof4da6752014-08-01 19:04:18 +01001024 file_offset_(file_offset),
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +01001025 soa_(Thread::Current()),
Mathieu Chartier268764d2016-09-13 12:09:38 -07001026 no_thread_suspension_("OatWriter patching"),
Vladimir Markof4da6752014-08-01 19:04:18 +01001027 class_linker_(Runtime::Current()->GetClassLinker()),
1028 dex_cache_(nullptr) {
Vladimir Marko09d09432015-09-08 13:47:48 +01001029 patched_code_.reserve(16 * KB);
Mathieu Chartierda5b28a2015-11-05 08:03:47 -08001030 if (writer_->HasBootImage()) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001031 // If we're creating the image, the address space must be ready so that we can apply patches.
1032 CHECK(writer_->image_writer_->IsImageAddressSpaceReady());
Vladimir Markof4da6752014-08-01 19:04:18 +01001033 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001034 }
1035
Vladimir Markof4da6752014-08-01 19:04:18 +01001036 ~WriteCodeMethodVisitor() UNLOCK_FUNCTION(Locks::mutator_lock_) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001037 }
1038
1039 bool StartClass(const DexFile* dex_file, size_t class_def_index)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001040 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001041 OatDexMethodVisitor::StartClass(dex_file, class_def_index);
1042 if (dex_cache_ == nullptr || dex_cache_->GetDexFile() != dex_file) {
Mathieu Chartier673ed3d2015-08-28 14:56:43 -07001043 dex_cache_ = class_linker_->FindDexCache(Thread::Current(), *dex_file);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001044 DCHECK(dex_cache_ != nullptr);
Vladimir Markof4da6752014-08-01 19:04:18 +01001045 }
1046 return true;
1047 }
1048
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001049 bool EndClass() REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001050 bool result = OatDexMethodVisitor::EndClass();
1051 if (oat_class_index_ == writer_->oat_classes_.size()) {
1052 DCHECK(result); // OatDexMethodVisitor::EndClass() never fails.
Vladimir Marko20f85592015-03-19 10:07:02 +00001053 offset_ = writer_->relative_patcher_->WriteThunks(out_, offset_);
Vladimir Markof4da6752014-08-01 19:04:18 +01001054 if (UNLIKELY(offset_ == 0u)) {
1055 PLOG(ERROR) << "Failed to write final relative call thunks";
1056 result = false;
1057 }
1058 }
1059 return result;
1060 }
1061
1062 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001063 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko49b0f452015-12-10 13:49:19 +00001064 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001065 const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1066
Mathieu Chartier673ed3d2015-08-28 14:56:43 -07001067 // No thread suspension since dex_cache_ that may get invalidated if that occurs.
Mathieu Chartier268764d2016-09-13 12:09:38 -07001068 ScopedAssertNoThreadSuspension tsc(__FUNCTION__);
Mathieu Chartier2cebb242015-04-21 16:50:40 -07001069 if (compiled_method != nullptr) { // ie. not an abstract method
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001070 size_t file_offset = file_offset_;
1071 OutputStream* out = out_;
1072
Vladimir Marko35831e82015-09-11 11:59:18 +01001073 ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
1074 uint32_t code_size = quick_code.size() * sizeof(uint8_t);
Nicolas Geoffrayf0758792015-07-13 11:56:00 +00001075
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001076 // Deduplicate code arrays.
1077 const OatMethodOffsets& method_offsets = oat_class->method_offsets_[method_offsets_index_];
1078 if (method_offsets.code_offset_ > offset_) {
1079 offset_ = writer_->relative_patcher_->WriteThunks(out, offset_);
1080 if (offset_ == 0u) {
1081 ReportWriteFailure("relative call thunk", it);
1082 return false;
Nicolas Geoffrayf0758792015-07-13 11:56:00 +00001083 }
Vladimir Marko0c737df2016-08-01 16:33:16 +01001084 uint32_t alignment_size = CodeAlignmentSize(offset_, *compiled_method);
1085 if (alignment_size != 0) {
1086 if (!writer_->WriteCodeAlignment(out, alignment_size)) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001087 ReportWriteFailure("code alignment padding", it);
1088 return false;
1089 }
Vladimir Marko0c737df2016-08-01 16:33:16 +01001090 offset_ += alignment_size;
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001091 DCHECK_OFFSET_();
1092 }
Vladimir Marko0c737df2016-08-01 16:33:16 +01001093 DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader),
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001094 GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
1095 DCHECK_EQ(method_offsets.code_offset_,
1096 offset_ + sizeof(OatQuickMethodHeader) + compiled_method->CodeDelta())
David Sehr709b0702016-10-13 09:12:37 -07001097 << dex_file_->PrettyMethod(it.GetMemberIndex());
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001098 const OatQuickMethodHeader& method_header =
1099 oat_class->method_headers_[method_offsets_index_];
Vladimir Markoe079e212016-05-25 12:49:49 +01001100 if (!out->WriteFully(&method_header, sizeof(method_header))) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001101 ReportWriteFailure("method header", it);
1102 return false;
1103 }
1104 writer_->size_method_header_ += sizeof(method_header);
1105 offset_ += sizeof(method_header);
Nicolas Geoffrayed6195a2015-07-13 17:02:30 +00001106 DCHECK_OFFSET_();
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001107
1108 if (!compiled_method->GetPatches().empty()) {
Vladimir Marko35831e82015-09-11 11:59:18 +01001109 patched_code_.assign(quick_code.begin(), quick_code.end());
1110 quick_code = ArrayRef<const uint8_t>(patched_code_);
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001111 for (const LinkerPatch& patch : compiled_method->GetPatches()) {
Vladimir Marko944da602016-02-19 12:27:55 +00001112 uint32_t literal_offset = patch.LiteralOffset();
Vladimir Markodb8e62d2016-03-30 16:30:21 +01001113 switch (patch.GetType()) {
1114 case LinkerPatch::Type::kCallRelative: {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001115 // NOTE: Relative calls across oat files are not supported.
1116 uint32_t target_offset = GetTargetOffset(patch);
1117 writer_->relative_patcher_->PatchCall(&patched_code_,
1118 literal_offset,
1119 offset_ + literal_offset,
1120 target_offset);
1121 break;
1122 }
Vladimir Markodb8e62d2016-03-30 16:30:21 +01001123 case LinkerPatch::Type::kDexCacheArray: {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001124 uint32_t target_offset = GetDexCacheOffset(patch);
1125 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1126 patch,
1127 offset_ + literal_offset,
1128 target_offset);
1129 break;
1130 }
Vladimir Markodb8e62d2016-03-30 16:30:21 +01001131 case LinkerPatch::Type::kStringRelative: {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001132 uint32_t target_offset = GetTargetObjectOffset(GetTargetString(patch));
1133 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1134 patch,
1135 offset_ + literal_offset,
1136 target_offset);
1137 break;
1138 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00001139 case LinkerPatch::Type::kStringBssEntry: {
1140 StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
1141 uint32_t target_offset = writer_->bss_string_entries_.Get(ref);
1142 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1143 patch,
1144 offset_ + literal_offset,
1145 target_offset);
1146 break;
1147 }
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01001148 case LinkerPatch::Type::kTypeRelative: {
1149 uint32_t target_offset = GetTargetObjectOffset(GetTargetType(patch));
1150 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1151 patch,
1152 offset_ + literal_offset,
1153 target_offset);
1154 break;
1155 }
Vladimir Markodb8e62d2016-03-30 16:30:21 +01001156 case LinkerPatch::Type::kCall: {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001157 uint32_t target_offset = GetTargetOffset(patch);
1158 PatchCodeAddress(&patched_code_, literal_offset, target_offset);
1159 break;
1160 }
Vladimir Markodb8e62d2016-03-30 16:30:21 +01001161 case LinkerPatch::Type::kMethod: {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001162 ArtMethod* method = GetTargetMethod(patch);
1163 PatchMethodAddress(&patched_code_, literal_offset, method);
1164 break;
1165 }
Vladimir Markodb8e62d2016-03-30 16:30:21 +01001166 case LinkerPatch::Type::kString: {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001167 mirror::String* string = GetTargetString(patch);
1168 PatchObjectAddress(&patched_code_, literal_offset, string);
1169 break;
1170 }
Vladimir Markodb8e62d2016-03-30 16:30:21 +01001171 case LinkerPatch::Type::kType: {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001172 mirror::Class* type = GetTargetType(patch);
1173 PatchObjectAddress(&patched_code_, literal_offset, type);
1174 break;
1175 }
1176 default: {
Vladimir Markodb8e62d2016-03-30 16:30:21 +01001177 DCHECK_EQ(patch.GetType(), LinkerPatch::Type::kRecordPosition);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001178 break;
1179 }
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001180 }
1181 }
1182 }
1183
Vladimir Markoe079e212016-05-25 12:49:49 +01001184 if (!out->WriteFully(quick_code.data(), code_size)) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001185 ReportWriteFailure("method code", it);
1186 return false;
1187 }
1188 writer_->size_code_ += code_size;
1189 offset_ += code_size;
Nicolas Geoffrayf0758792015-07-13 11:56:00 +00001190 }
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001191 DCHECK_OFFSET_();
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001192 ++method_offsets_index_;
1193 }
1194
1195 return true;
1196 }
1197
1198 private:
1199 OutputStream* const out_;
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +01001200 const size_t file_offset_;
1201 const ScopedObjectAccess soa_;
1202 const ScopedAssertNoThreadSuspension no_thread_suspension_;
Vladimir Markof4da6752014-08-01 19:04:18 +01001203 ClassLinker* const class_linker_;
1204 mirror::DexCache* dex_cache_;
1205 std::vector<uint8_t> patched_code_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001206
1207 void ReportWriteFailure(const char* what, const ClassDataItemIterator& it) {
1208 PLOG(ERROR) << "Failed to write " << what << " for "
David Sehr709b0702016-10-13 09:12:37 -07001209 << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001210 }
Vladimir Markof4da6752014-08-01 19:04:18 +01001211
Mathieu Chartiere401d142015-04-22 13:56:20 -07001212 ArtMethod* GetTargetMethod(const LinkerPatch& patch)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001213 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001214 MethodReference ref = patch.TargetMethod();
1215 mirror::DexCache* dex_cache =
Mathieu Chartier673ed3d2015-08-28 14:56:43 -07001216 (dex_file_ == ref.dex_file) ? dex_cache_ : class_linker_->FindDexCache(
1217 Thread::Current(), *ref.dex_file);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001218 ArtMethod* method = dex_cache->GetResolvedMethod(
1219 ref.dex_method_index, class_linker_->GetImagePointerSize());
Vladimir Markof4da6752014-08-01 19:04:18 +01001220 CHECK(method != nullptr);
1221 return method;
1222 }
1223
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001224 uint32_t GetTargetOffset(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko944da602016-02-19 12:27:55 +00001225 uint32_t target_offset = writer_->relative_patcher_->GetOffset(patch.TargetMethod());
1226 // If there's no new compiled code, either we're compiling an app and the target method
1227 // is in the boot image, or we need to point to the correct trampoline.
Vladimir Markof4da6752014-08-01 19:04:18 +01001228 if (UNLIKELY(target_offset == 0)) {
Mathieu Chartiere401d142015-04-22 13:56:20 -07001229 ArtMethod* target = GetTargetMethod(patch);
Vladimir Markof4da6752014-08-01 19:04:18 +01001230 DCHECK(target != nullptr);
Andreas Gampe542451c2016-07-26 09:02:02 -07001231 PointerSize size =
1232 GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet());
Jeff Haoa0acc2d2015-01-27 11:22:04 -08001233 const void* oat_code_offset = target->GetEntryPointFromQuickCompiledCodePtrSize(size);
1234 if (oat_code_offset != 0) {
Vladimir Marko944da602016-02-19 12:27:55 +00001235 DCHECK(!writer_->HasBootImage());
Jeff Haoa0acc2d2015-01-27 11:22:04 -08001236 DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(oat_code_offset));
1237 DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(oat_code_offset));
1238 DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickGenericJniStub(oat_code_offset));
1239 target_offset = PointerToLowMemUInt32(oat_code_offset);
1240 } else {
1241 target_offset = target->IsNative()
1242 ? writer_->oat_header_->GetQuickGenericJniTrampolineOffset()
1243 : writer_->oat_header_->GetQuickToInterpreterBridgeOffset();
1244 }
Vladimir Markof4da6752014-08-01 19:04:18 +01001245 }
1246 return target_offset;
1247 }
1248
Vladimir Marko052164a2016-04-27 13:54:18 +01001249 mirror::DexCache* GetDexCache(const DexFile* target_dex_file)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001250 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko052164a2016-04-27 13:54:18 +01001251 return (target_dex_file == dex_file_)
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001252 ? dex_cache_
Vladimir Marko052164a2016-04-27 13:54:18 +01001253 : class_linker_->FindDexCache(Thread::Current(), *target_dex_file);
1254 }
1255
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001256 mirror::Class* GetTargetType(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko052164a2016-04-27 13:54:18 +01001257 mirror::DexCache* dex_cache = GetDexCache(patch.TargetTypeDexFile());
Vladimir Markof4da6752014-08-01 19:04:18 +01001258 mirror::Class* type = dex_cache->GetResolvedType(patch.TargetTypeIndex());
1259 CHECK(type != nullptr);
1260 return type;
1261 }
1262
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001263 mirror::String* GetTargetString(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07001264 ScopedObjectAccessUnchecked soa(Thread::Current());
1265 StackHandleScope<1> hs(soa.Self());
1266 ClassLinker* linker = Runtime::Current()->GetClassLinker();
1267 Handle<mirror::DexCache> dex_cache(hs.NewHandle(GetDexCache(patch.TargetStringDexFile())));
1268 mirror::String* string = linker->LookupString(*patch.TargetStringDexFile(),
1269 patch.TargetStringIndex(),
1270 dex_cache);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001271 DCHECK(string != nullptr);
1272 DCHECK(writer_->HasBootImage() ||
1273 Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(string));
1274 return string;
1275 }
1276
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001277 uint32_t GetDexCacheOffset(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartierda5b28a2015-11-05 08:03:47 -08001278 if (writer_->HasBootImage()) {
Vladimir Marko944da602016-02-19 12:27:55 +00001279 uintptr_t element = writer_->image_writer_->GetDexCacheArrayElementImageAddress<uintptr_t>(
1280 patch.TargetDexCacheDexFile(), patch.TargetDexCacheElementOffset());
1281 size_t oat_index = writer_->image_writer_->GetOatIndexForDexCache(dex_cache_);
1282 uintptr_t oat_data = writer_->image_writer_->GetOatDataBegin(oat_index);
Vladimir Marko05792b92015-08-03 11:56:49 +01001283 return element - oat_data;
Vladimir Marko20f85592015-03-19 10:07:02 +00001284 } else {
Vladimir Marko09d09432015-09-08 13:47:48 +01001285 size_t start = writer_->dex_cache_arrays_offsets_.Get(patch.TargetDexCacheDexFile());
1286 return start + patch.TargetDexCacheElementOffset();
Vladimir Marko20f85592015-03-19 10:07:02 +00001287 }
1288 }
1289
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001290 uint32_t GetTargetObjectOffset(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001291 DCHECK(writer_->HasBootImage());
1292 object = writer_->image_writer_->GetImageAddress(object);
1293 size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
1294 uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
1295 // TODO: Clean up offset types. The target offset must be treated as signed.
1296 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(object) - oat_data_begin);
1297 }
1298
Vladimir Markof4da6752014-08-01 19:04:18 +01001299 void PatchObjectAddress(std::vector<uint8_t>* code, uint32_t offset, mirror::Object* object)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001300 REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartierda5b28a2015-11-05 08:03:47 -08001301 if (writer_->HasBootImage()) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001302 object = writer_->image_writer_->GetImageAddress(object);
Vladimir Marko09d09432015-09-08 13:47:48 +01001303 } else {
1304 // NOTE: We're using linker patches for app->boot references when the image can
1305 // be relocated and therefore we need to emit .oat_patches. We're not using this
1306 // for app->app references, so check that the object is in the image space.
1307 DCHECK(Runtime::Current()->GetHeap()->FindSpaceFromObject(object, false)->IsImageSpace());
Vladimir Markof4da6752014-08-01 19:04:18 +01001308 }
Vladimir Marko09d09432015-09-08 13:47:48 +01001309 // Note: We only patch targeting Objects in image which is in the low 4gb.
Vladimir Markof4da6752014-08-01 19:04:18 +01001310 uint32_t address = PointerToLowMemUInt32(object);
1311 DCHECK_LE(offset + 4, code->size());
1312 uint8_t* data = &(*code)[offset];
1313 data[0] = address & 0xffu;
1314 data[1] = (address >> 8) & 0xffu;
1315 data[2] = (address >> 16) & 0xffu;
1316 data[3] = (address >> 24) & 0xffu;
1317 }
1318
Mathieu Chartiere401d142015-04-22 13:56:20 -07001319 void PatchMethodAddress(std::vector<uint8_t>* code, uint32_t offset, ArtMethod* method)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001320 REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartierda5b28a2015-11-05 08:03:47 -08001321 if (writer_->HasBootImage()) {
Mathieu Chartiere401d142015-04-22 13:56:20 -07001322 method = writer_->image_writer_->GetImageMethodAddress(method);
Vladimir Marko09d09432015-09-08 13:47:48 +01001323 } else if (kIsDebugBuild) {
1324 // NOTE: We're using linker patches for app->boot references when the image can
1325 // be relocated and therefore we need to emit .oat_patches. We're not using this
1326 // for app->app references, so check that the method is an image method.
Jeff Haodcdc85b2015-12-04 14:06:18 -08001327 std::vector<gc::space::ImageSpace*> image_spaces =
1328 Runtime::Current()->GetHeap()->GetBootImageSpaces();
1329 bool contains_method = false;
1330 for (gc::space::ImageSpace* image_space : image_spaces) {
1331 size_t method_offset = reinterpret_cast<const uint8_t*>(method) - image_space->Begin();
1332 contains_method |=
1333 image_space->GetImageHeader().GetMethodsSection().Contains(method_offset);
1334 }
1335 CHECK(contains_method);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001336 }
Vladimir Marko09d09432015-09-08 13:47:48 +01001337 // Note: We only patch targeting ArtMethods in image which is in the low 4gb.
Mathieu Chartiere401d142015-04-22 13:56:20 -07001338 uint32_t address = PointerToLowMemUInt32(method);
1339 DCHECK_LE(offset + 4, code->size());
1340 uint8_t* data = &(*code)[offset];
1341 data[0] = address & 0xffu;
1342 data[1] = (address >> 8) & 0xffu;
1343 data[2] = (address >> 16) & 0xffu;
1344 data[3] = (address >> 24) & 0xffu;
1345 }
1346
Vladimir Markof4da6752014-08-01 19:04:18 +01001347 void PatchCodeAddress(std::vector<uint8_t>* code, uint32_t offset, uint32_t target_offset)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001348 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko09d09432015-09-08 13:47:48 +01001349 uint32_t address = target_offset;
Mathieu Chartierda5b28a2015-11-05 08:03:47 -08001350 if (writer_->HasBootImage()) {
Vladimir Marko944da602016-02-19 12:27:55 +00001351 size_t oat_index = writer_->image_writer_->GetOatIndexForDexCache(dex_cache_);
1352 // TODO: Clean up offset types.
1353 // The target_offset must be treated as signed for cross-oat patching.
1354 const void* target = reinterpret_cast<const void*>(
1355 writer_->image_writer_->GetOatDataBegin(oat_index) +
1356 static_cast<int32_t>(target_offset));
1357 address = PointerToLowMemUInt32(target);
Vladimir Marko09d09432015-09-08 13:47:48 +01001358 }
Vladimir Markof4da6752014-08-01 19:04:18 +01001359 DCHECK_LE(offset + 4, code->size());
1360 uint8_t* data = &(*code)[offset];
1361 data[0] = address & 0xffu;
1362 data[1] = (address >> 8) & 0xffu;
1363 data[2] = (address >> 16) & 0xffu;
1364 data[3] = (address >> 24) & 0xffu;
1365 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001366};
1367
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001368class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor {
1369 public:
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001370 WriteMapMethodVisitor(OatWriter* writer,
1371 OutputStream* out,
1372 const size_t file_offset,
Mathieu Chartier957ca1c2014-11-21 16:51:29 -08001373 size_t relative_offset)
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001374 : OatDexMethodVisitor(writer, relative_offset),
1375 out_(out),
1376 file_offset_(file_offset) {
1377 }
1378
1379 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) {
Vladimir Marko49b0f452015-12-10 13:49:19 +00001380 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001381 const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1382
Mathieu Chartier2cebb242015-04-21 16:50:40 -07001383 if (compiled_method != nullptr) { // ie. not an abstract method
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001384 size_t file_offset = file_offset_;
1385 OutputStream* out = out_;
1386
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001387 uint32_t map_offset = oat_class->method_headers_[method_offsets_index_].vmap_table_offset_;
1388 uint32_t code_offset = oat_class->method_offsets_[method_offsets_index_].code_offset_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001389 ++method_offsets_index_;
1390
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001391 DCHECK((compiled_method->GetVmapTable().size() == 0u && map_offset == 0u) ||
1392 (compiled_method->GetVmapTable().size() != 0u && map_offset != 0u))
1393 << compiled_method->GetVmapTable().size() << " " << map_offset << " "
David Sehr709b0702016-10-13 09:12:37 -07001394 << dex_file_->PrettyMethod(it.GetMemberIndex());
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001395
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01001396 // If vdex is enabled, only emit the map for compiled code. The quickening info
1397 // is emitted in the vdex already.
1398 if (map_offset != 0u &&
1399 !(kIsVdexEnabled && compiled_method->GetQuickCode().empty())) {
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001400 // Transform map_offset to actual oat data offset.
1401 map_offset = (code_offset - compiled_method->CodeDelta()) - map_offset;
1402 DCHECK_NE(map_offset, 0u);
David Sehr709b0702016-10-13 09:12:37 -07001403 DCHECK_LE(map_offset, offset_) << dex_file_->PrettyMethod(it.GetMemberIndex());
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001404
1405 ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
1406 size_t map_size = map.size() * sizeof(map[0]);
1407 if (map_offset == offset_) {
1408 // Write deduplicated map (code info for Optimizing or transformation info for dex2dex).
Vladimir Markoe079e212016-05-25 12:49:49 +01001409 if (UNLIKELY(!out->WriteFully(map.data(), map_size))) {
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001410 ReportWriteFailure(it);
1411 return false;
1412 }
1413 offset_ += map_size;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001414 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001415 }
1416 DCHECK_OFFSET_();
1417 }
1418
1419 return true;
1420 }
1421
1422 private:
1423 OutputStream* const out_;
1424 size_t const file_offset_;
1425
1426 void ReportWriteFailure(const ClassDataItemIterator& it) {
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001427 PLOG(ERROR) << "Failed to write map for "
David Sehr709b0702016-10-13 09:12:37 -07001428 << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001429 }
1430};
1431
1432// Visit all methods from all classes in all dex files with the specified visitor.
1433bool OatWriter::VisitDexMethods(DexMethodVisitor* visitor) {
1434 for (const DexFile* dex_file : *dex_files_) {
1435 const size_t class_def_count = dex_file->NumClassDefs();
1436 for (size_t class_def_index = 0; class_def_index != class_def_count; ++class_def_index) {
1437 if (UNLIKELY(!visitor->StartClass(dex_file, class_def_index))) {
1438 return false;
1439 }
1440 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
Ian Rogers13735952014-10-08 12:43:28 -07001441 const uint8_t* class_data = dex_file->GetClassData(class_def);
Mathieu Chartier2cebb242015-04-21 16:50:40 -07001442 if (class_data != nullptr) { // ie not an empty class, such as a marker interface
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001443 ClassDataItemIterator it(*dex_file, class_data);
1444 while (it.HasNextStaticField()) {
1445 it.Next();
1446 }
1447 while (it.HasNextInstanceField()) {
1448 it.Next();
1449 }
1450 size_t class_def_method_index = 0u;
1451 while (it.HasNextDirectMethod()) {
1452 if (!visitor->VisitMethod(class_def_method_index, it)) {
1453 return false;
1454 }
1455 ++class_def_method_index;
1456 it.Next();
1457 }
1458 while (it.HasNextVirtualMethod()) {
1459 if (UNLIKELY(!visitor->VisitMethod(class_def_method_index, it))) {
1460 return false;
1461 }
1462 ++class_def_method_index;
1463 it.Next();
1464 }
1465 }
1466 if (UNLIKELY(!visitor->EndClass())) {
1467 return false;
1468 }
1469 }
1470 }
1471 return true;
1472}
1473
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001474size_t OatWriter::InitOatHeader(InstructionSet instruction_set,
1475 const InstructionSetFeatures* instruction_set_features,
1476 uint32_t num_dex_files,
1477 SafeMap<std::string, std::string>* key_value_store) {
1478 TimingLogger::ScopedTiming split("InitOatHeader", timings_);
1479 oat_header_.reset(OatHeader::Create(instruction_set,
1480 instruction_set_features,
1481 num_dex_files,
1482 key_value_store));
1483 size_oat_header_ += sizeof(OatHeader);
1484 size_oat_header_key_value_store_ += oat_header_->GetHeaderSize() - sizeof(OatHeader);
Andreas Gampe22f8e5c2014-07-09 11:38:21 -07001485 return oat_header_->GetHeaderSize();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001486}
1487
1488size_t OatWriter::InitOatDexFiles(size_t offset) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001489 TimingLogger::ScopedTiming split("InitOatDexFiles", timings_);
1490 // Initialize offsets of dex files.
Vladimir Marko49b0f452015-12-10 13:49:19 +00001491 for (OatDexFile& oat_dex_file : oat_dex_files_) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001492 oat_dex_file.offset_ = offset;
1493 offset += oat_dex_file.SizeOf();
Artem Udovichenkod9786b02015-10-14 16:36:55 +03001494 }
1495 return offset;
1496}
1497
Brian Carlstrom389efb02012-01-11 12:06:26 -08001498size_t OatWriter::InitOatClasses(size_t offset) {
Brian Carlstrom389efb02012-01-11 12:06:26 -08001499 // calculate the offsets within OatDexFiles to OatClasses
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001500 InitOatClassesMethodVisitor visitor(this, offset);
1501 bool success = VisitDexMethods(&visitor);
1502 CHECK(success);
1503 offset = visitor.GetOffset();
Brian Carlstromba150c32013-08-27 17:31:03 -07001504
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001505 // Update oat_dex_files_.
1506 auto oat_class_it = oat_classes_.begin();
Vladimir Marko49b0f452015-12-10 13:49:19 +00001507 for (OatDexFile& oat_dex_file : oat_dex_files_) {
1508 for (uint32_t& class_offset : oat_dex_file.class_offsets_) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001509 DCHECK(oat_class_it != oat_classes_.end());
Vladimir Marko49b0f452015-12-10 13:49:19 +00001510 class_offset = oat_class_it->offset_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001511 ++oat_class_it;
Brian Carlstrome24fa612011-09-29 00:53:55 -07001512 }
Brian Carlstrome24fa612011-09-29 00:53:55 -07001513 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001514 CHECK(oat_class_it == oat_classes_.end());
1515
1516 return offset;
1517}
1518
1519size_t OatWriter::InitOatMaps(size_t offset) {
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001520 InitMapMethodVisitor visitor(this, offset);
1521 bool success = VisitDexMethods(&visitor);
1522 DCHECK(success);
1523 offset = visitor.GetOffset();
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001524
Brian Carlstrome24fa612011-09-29 00:53:55 -07001525 return offset;
1526}
1527
1528size_t OatWriter::InitOatCode(size_t offset) {
1529 // calculate the offsets within OatHeader to executable code
1530 size_t old_offset = offset;
Dave Allison50abf0a2014-06-23 13:19:59 -07001531 size_t adjusted_offset = offset;
Brian Carlstrome24fa612011-09-29 00:53:55 -07001532 // required to be on a new page boundary
1533 offset = RoundUp(offset, kPageSize);
1534 oat_header_->SetExecutableOffset(offset);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001535 size_executable_offset_alignment_ = offset - old_offset;
Vladimir Markoaad75c62016-10-03 08:46:48 +00001536 if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001537 InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001538
Ian Rogers848871b2013-08-05 10:56:33 -07001539 #define DO_TRAMPOLINE(field, fn_name) \
1540 offset = CompiledCode::AlignCode(offset, instruction_set); \
Dave Allison50abf0a2014-06-23 13:19:59 -07001541 adjusted_offset = offset + CompiledCode::CodeDelta(instruction_set); \
1542 oat_header_->Set ## fn_name ## Offset(adjusted_offset); \
Chih-Hung Hsiehfba39972016-05-11 11:26:48 -07001543 (field) = compiler_driver_->Create ## fn_name(); \
1544 offset += (field)->size();
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001545
Ian Rogers848871b2013-08-05 10:56:33 -07001546 DO_TRAMPOLINE(jni_dlsym_lookup_, JniDlsymLookup);
Andreas Gampe2da88232014-02-27 12:26:20 -08001547 DO_TRAMPOLINE(quick_generic_jni_trampoline_, QuickGenericJniTrampoline);
Jeff Hao88474b42013-10-23 16:24:40 -07001548 DO_TRAMPOLINE(quick_imt_conflict_trampoline_, QuickImtConflictTrampoline);
Ian Rogers848871b2013-08-05 10:56:33 -07001549 DO_TRAMPOLINE(quick_resolution_trampoline_, QuickResolutionTrampoline);
1550 DO_TRAMPOLINE(quick_to_interpreter_bridge_, QuickToInterpreterBridge);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001551
Ian Rogers848871b2013-08-05 10:56:33 -07001552 #undef DO_TRAMPOLINE
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001553 } else {
Ian Rogers848871b2013-08-05 10:56:33 -07001554 oat_header_->SetInterpreterToInterpreterBridgeOffset(0);
1555 oat_header_->SetInterpreterToCompiledCodeBridgeOffset(0);
1556 oat_header_->SetJniDlsymLookupOffset(0);
Andreas Gampe2da88232014-02-27 12:26:20 -08001557 oat_header_->SetQuickGenericJniTrampolineOffset(0);
Jeff Hao88474b42013-10-23 16:24:40 -07001558 oat_header_->SetQuickImtConflictTrampolineOffset(0);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001559 oat_header_->SetQuickResolutionTrampolineOffset(0);
Ian Rogers848871b2013-08-05 10:56:33 -07001560 oat_header_->SetQuickToInterpreterBridgeOffset(0);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001561 }
Brian Carlstrome24fa612011-09-29 00:53:55 -07001562 return offset;
1563}
1564
1565size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01001566 InitCodeMethodVisitor code_visitor(this, offset, vdex_quickening_info_offset_);
1567 bool success = VisitDexMethods(&code_visitor);
1568 DCHECK(success);
1569 offset = code_visitor.GetOffset();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001570
Mathieu Chartierfbc31082016-01-24 11:59:56 -08001571 if (HasImage()) {
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01001572 InitImageMethodVisitor image_visitor(this, offset);
1573 success = VisitDexMethods(&image_visitor);
1574 DCHECK(success);
1575 offset = image_visitor.GetOffset();
Ian Rogers0571d352011-11-03 19:51:38 -07001576 }
Logan Chien8b977d32012-02-21 19:14:55 +08001577
Brian Carlstrome24fa612011-09-29 00:53:55 -07001578 return offset;
1579}
1580
Vladimir Markoaad75c62016-10-03 08:46:48 +00001581void OatWriter::InitBssLayout(InstructionSet instruction_set) {
1582 DCHECK(!HasBootImage());
1583
1584 // Allocate space for app dex cache arrays in the .bss section.
1585 bss_start_ = RoundUp(oat_size_, kPageSize);
1586 PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set);
1587 bss_size_ = 0u;
1588 for (const DexFile* dex_file : *dex_files_) {
1589 dex_cache_arrays_offsets_.Put(dex_file, bss_start_ + bss_size_);
1590 DexCacheArraysLayout layout(pointer_size, dex_file);
1591 bss_size_ += layout.Size();
1592 }
1593
1594 bss_roots_offset_ = bss_size_;
1595
1596 // Prepare offsets for .bss String entries.
1597 for (auto& entry : bss_string_entries_) {
1598 DCHECK_EQ(entry.second, 0u);
1599 entry.second = bss_start_ + bss_size_;
1600 bss_size_ += sizeof(GcRoot<mirror::String>);
1601 }
1602}
1603
David Srbeckybc90fd02015-04-22 19:40:27 +01001604bool OatWriter::WriteRodata(OutputStream* out) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001605 CHECK(write_state_ == WriteState::kWriteRoData);
1606
Vladimir Markoe079e212016-05-25 12:49:49 +01001607 // Wrap out to update checksum with each write.
1608 ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get());
1609 out = &checksum_updating_out;
1610
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001611 if (!WriteClassOffsets(out)) {
1612 LOG(ERROR) << "Failed to write class offsets to " << out->GetLocation();
Vladimir Markof4da6752014-08-01 19:04:18 +01001613 return false;
1614 }
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001615
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001616 if (!WriteClasses(out)) {
1617 LOG(ERROR) << "Failed to write classes to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001618 return false;
1619 }
1620
Vladimir Markof4da6752014-08-01 19:04:18 +01001621 off_t tables_end_offset = out->Seek(0, kSeekCurrent);
Vladimir Marko49b0f452015-12-10 13:49:19 +00001622 if (tables_end_offset == static_cast<off_t>(-1)) {
David Brazdil181e1cc2016-09-01 16:38:47 +00001623 LOG(ERROR) << "Failed to get oat code position in " << out->GetLocation();
Vladimir Markof4da6752014-08-01 19:04:18 +01001624 return false;
1625 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001626 size_t file_offset = oat_data_offset_;
Vladimir Markof4da6752014-08-01 19:04:18 +01001627 size_t relative_offset = static_cast<size_t>(tables_end_offset) - file_offset;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001628 relative_offset = WriteMaps(out, file_offset, relative_offset);
1629 if (relative_offset == 0) {
1630 LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
1631 return false;
1632 }
1633
David Srbeckybc90fd02015-04-22 19:40:27 +01001634 // Write padding.
1635 off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent);
1636 relative_offset += size_executable_offset_alignment_;
1637 DCHECK_EQ(relative_offset, oat_header_->GetExecutableOffset());
1638 size_t expected_file_offset = file_offset + relative_offset;
1639 if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
1640 PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
1641 << " Expected: " << expected_file_offset << " File: " << out->GetLocation();
1642 return 0;
1643 }
1644 DCHECK_OFFSET();
1645
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001646 write_state_ = WriteState::kWriteText;
David Srbeckybc90fd02015-04-22 19:40:27 +01001647 return true;
1648}
1649
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01001650class OatWriter::WriteQuickeningInfoMethodVisitor : public DexMethodVisitor {
1651 public:
1652 WriteQuickeningInfoMethodVisitor(OatWriter* writer, OutputStream* out, uint32_t offset)
1653 : DexMethodVisitor(writer, offset),
1654 out_(out),
1655 written_bytes_(0u) {}
1656
1657 bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,
1658 const ClassDataItemIterator& it) {
1659 if (it.GetMethodCodeItem() == nullptr) {
1660 // No CodeItem. Native or abstract method.
1661 return true;
1662 }
1663
1664 uint32_t method_idx = it.GetMemberIndex();
1665 CompiledMethod* compiled_method =
1666 writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
1667
1668 uint32_t length = 0;
1669 const uint8_t* data = nullptr;
1670 // VMap only contains quickening info if this method is not compiled.
1671 if (compiled_method != nullptr && compiled_method->GetQuickCode().empty()) {
1672 ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
1673 data = map.data();
1674 length = map.size() * sizeof(map.front());
1675 }
1676
1677 if (!out_->WriteFully(&length, sizeof(length)) ||
1678 !out_->WriteFully(data, length)) {
1679 PLOG(ERROR) << "Failed to write quickening info for "
1680 << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
1681 return false;
1682 }
1683 offset_ += sizeof(length) + length;
1684 written_bytes_ += sizeof(length) + length;
1685 return true;
1686 }
1687
1688 size_t GetNumberOfWrittenBytes() const {
1689 return written_bytes_;
1690 }
1691
1692 private:
1693 OutputStream* const out_;
1694 size_t written_bytes_;
1695};
1696
1697bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) {
1698 if (!kIsVdexEnabled) {
1699 return true;
1700 }
1701
1702 size_t initial_offset = vdex_size_;
1703 size_t start_offset = RoundUp(initial_offset, 4u);
1704
1705 vdex_size_ = start_offset;
1706 vdex_quickening_info_offset_ = vdex_size_;
1707 size_quickening_info_alignment_ = start_offset - initial_offset;
1708
1709 off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet);
1710 if (actual_offset != static_cast<off_t>(start_offset)) {
1711 PLOG(ERROR) << "Failed to seek to quickening info section. Actual: " << actual_offset
1712 << " Expected: " << start_offset
1713 << " Output: " << vdex_out->GetLocation();
1714 return false;
1715 }
1716
1717 WriteQuickeningInfoMethodVisitor visitor(this, vdex_out, start_offset);
1718 if (!VisitDexMethods(&visitor)) {
1719 PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation();
1720 return false;
1721 }
1722
1723 if (!vdex_out->Flush()) {
1724 PLOG(ERROR) << "Failed to flush stream after writing quickening info."
1725 << " File: " << vdex_out->GetLocation();
1726 return false;
1727 }
1728
1729 size_quickening_info_ = visitor.GetNumberOfWrittenBytes();
1730 vdex_size_ += size_quickening_info_;
1731 return true;
1732}
1733
David Brazdil5d5a36b2016-09-14 15:34:10 +01001734bool OatWriter::WriteVerifierDeps(OutputStream* vdex_out, verifier::VerifierDeps* verifier_deps) {
1735 if (!kIsVdexEnabled) {
1736 return true;
1737 }
1738
1739 if (verifier_deps == nullptr) {
1740 // Nothing to write. Record the offset, but no need
1741 // for alignment.
1742 vdex_verifier_deps_offset_ = vdex_size_;
1743 return true;
1744 }
1745
1746 size_t initial_offset = vdex_size_;
1747 size_t start_offset = RoundUp(initial_offset, 4u);
1748
1749 vdex_size_ = start_offset;
1750 vdex_verifier_deps_offset_ = vdex_size_;
1751 size_verifier_deps_alignment_ = start_offset - initial_offset;
1752
1753 off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet);
1754 if (actual_offset != static_cast<off_t>(start_offset)) {
1755 PLOG(ERROR) << "Failed to seek to verifier deps section. Actual: " << actual_offset
1756 << " Expected: " << start_offset
1757 << " Output: " << vdex_out->GetLocation();
1758 return false;
1759 }
1760
1761 std::vector<uint8_t> buffer;
1762 verifier_deps->Encode(&buffer);
1763
1764 if (!vdex_out->WriteFully(buffer.data(), buffer.size())) {
1765 PLOG(ERROR) << "Failed to write verifier deps."
1766 << " File: " << vdex_out->GetLocation();
1767 return false;
1768 }
1769 if (!vdex_out->Flush()) {
1770 PLOG(ERROR) << "Failed to flush stream after writing verifier deps."
1771 << " File: " << vdex_out->GetLocation();
1772 return false;
1773 }
1774
1775 size_verifier_deps_ = buffer.size();
1776 vdex_size_ += size_verifier_deps_;
1777 return true;
1778}
1779
David Srbeckybc90fd02015-04-22 19:40:27 +01001780bool OatWriter::WriteCode(OutputStream* out) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001781 CHECK(write_state_ == WriteState::kWriteText);
1782
Vladimir Markoe079e212016-05-25 12:49:49 +01001783 // Wrap out to update checksum with each write.
1784 ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get());
1785 out = &checksum_updating_out;
1786
Vladimir Marko944da602016-02-19 12:27:55 +00001787 SetMultiOatRelativePatcherAdjustment();
1788
David Srbeckybc90fd02015-04-22 19:40:27 +01001789 const size_t file_offset = oat_data_offset_;
1790 size_t relative_offset = oat_header_->GetExecutableOffset();
1791 DCHECK_OFFSET();
1792
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001793 relative_offset = WriteCode(out, file_offset, relative_offset);
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001794 if (relative_offset == 0) {
Ian Rogers3d504072014-03-01 09:16:49 -08001795 LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001796 return false;
1797 }
1798
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001799 relative_offset = WriteCodeDexFiles(out, file_offset, relative_offset);
1800 if (relative_offset == 0) {
Ian Rogers3d504072014-03-01 09:16:49 -08001801 LOG(ERROR) << "Failed to write oat code for dex files to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001802 return false;
1803 }
1804
Vladimir Markof4da6752014-08-01 19:04:18 +01001805 const off_t oat_end_file_offset = out->Seek(0, kSeekCurrent);
Vladimir Marko49b0f452015-12-10 13:49:19 +00001806 if (oat_end_file_offset == static_cast<off_t>(-1)) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001807 LOG(ERROR) << "Failed to get oat end file offset in " << out->GetLocation();
1808 return false;
1809 }
1810
Ian Rogers4bdbbc82013-06-10 16:02:31 -07001811 if (kIsDebugBuild) {
1812 uint32_t size_total = 0;
1813 #define DO_STAT(x) \
Chih-Hung Hsiehfba39972016-05-11 11:26:48 -07001814 VLOG(compiler) << #x "=" << PrettySize(x) << " (" << (x) << "B)"; \
1815 size_total += (x);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001816
David Brazdil7b49e6c2016-09-01 11:06:18 +01001817 DO_STAT(size_vdex_header_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07001818 DO_STAT(size_dex_file_alignment_);
1819 DO_STAT(size_executable_offset_alignment_);
1820 DO_STAT(size_oat_header_);
Andreas Gampe22f8e5c2014-07-09 11:38:21 -07001821 DO_STAT(size_oat_header_key_value_store_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07001822 DO_STAT(size_dex_file_);
David Brazdil5d5a36b2016-09-14 15:34:10 +01001823 DO_STAT(size_verifier_deps_);
1824 DO_STAT(size_verifier_deps_alignment_);
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01001825 DO_STAT(size_quickening_info_);
1826 DO_STAT(size_quickening_info_alignment_);
Ian Rogers848871b2013-08-05 10:56:33 -07001827 DO_STAT(size_interpreter_to_interpreter_bridge_);
1828 DO_STAT(size_interpreter_to_compiled_code_bridge_);
1829 DO_STAT(size_jni_dlsym_lookup_);
Andreas Gampe2da88232014-02-27 12:26:20 -08001830 DO_STAT(size_quick_generic_jni_trampoline_);
Jeff Hao88474b42013-10-23 16:24:40 -07001831 DO_STAT(size_quick_imt_conflict_trampoline_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07001832 DO_STAT(size_quick_resolution_trampoline_);
Ian Rogers848871b2013-08-05 10:56:33 -07001833 DO_STAT(size_quick_to_interpreter_bridge_);
1834 DO_STAT(size_trampoline_alignment_);
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001835 DO_STAT(size_method_header_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07001836 DO_STAT(size_code_);
1837 DO_STAT(size_code_alignment_);
Vladimir Markof4da6752014-08-01 19:04:18 +01001838 DO_STAT(size_relative_call_thunks_);
Vladimir Markoc74658b2015-03-31 10:26:41 +01001839 DO_STAT(size_misc_thunks_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07001840 DO_STAT(size_vmap_table_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07001841 DO_STAT(size_oat_dex_file_location_size_);
1842 DO_STAT(size_oat_dex_file_location_data_);
1843 DO_STAT(size_oat_dex_file_location_checksum_);
1844 DO_STAT(size_oat_dex_file_offset_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001845 DO_STAT(size_oat_dex_file_class_offsets_offset_);
Vladimir Marko49b0f452015-12-10 13:49:19 +00001846 DO_STAT(size_oat_dex_file_lookup_table_offset_);
Vladimir Marko49b0f452015-12-10 13:49:19 +00001847 DO_STAT(size_oat_lookup_table_alignment_);
1848 DO_STAT(size_oat_lookup_table_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001849 DO_STAT(size_oat_class_offsets_alignment_);
1850 DO_STAT(size_oat_class_offsets_);
Brian Carlstromba150c32013-08-27 17:31:03 -07001851 DO_STAT(size_oat_class_type_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07001852 DO_STAT(size_oat_class_status_);
Brian Carlstromba150c32013-08-27 17:31:03 -07001853 DO_STAT(size_oat_class_method_bitmaps_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07001854 DO_STAT(size_oat_class_method_offsets_);
1855 #undef DO_STAT
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001856
David Brazdil7b49e6c2016-09-01 11:06:18 +01001857 VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)";
1858
1859 CHECK_EQ(vdex_size_ + oat_size_, size_total);
1860 CHECK_EQ(file_offset + size_total - vdex_size_, static_cast<size_t>(oat_end_file_offset));
Ian Rogers4bdbbc82013-06-10 16:02:31 -07001861 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001862
David Brazdil7b49e6c2016-09-01 11:06:18 +01001863 CHECK_EQ(file_offset + oat_size_, static_cast<size_t>(oat_end_file_offset));
1864 CHECK_EQ(oat_size_, relative_offset);
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001865
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001866 write_state_ = WriteState::kWriteHeader;
1867 return true;
1868}
1869
1870bool OatWriter::WriteHeader(OutputStream* out,
1871 uint32_t image_file_location_oat_checksum,
1872 uintptr_t image_file_location_oat_begin,
1873 int32_t image_patch_delta) {
1874 CHECK(write_state_ == WriteState::kWriteHeader);
1875
1876 oat_header_->SetImageFileLocationOatChecksum(image_file_location_oat_checksum);
1877 oat_header_->SetImageFileLocationOatDataBegin(image_file_location_oat_begin);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001878 if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001879 CHECK_EQ(image_patch_delta, 0);
1880 CHECK_EQ(oat_header_->GetImagePatchDelta(), 0);
1881 } else {
1882 CHECK_ALIGNED(image_patch_delta, kPageSize);
1883 oat_header_->SetImagePatchDelta(image_patch_delta);
1884 }
Vladimir Marko49b0f452015-12-10 13:49:19 +00001885 oat_header_->UpdateChecksumWithHeaderData();
1886
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001887 const size_t file_offset = oat_data_offset_;
1888
1889 off_t current_offset = out->Seek(0, kSeekCurrent);
1890 if (current_offset == static_cast<off_t>(-1)) {
1891 PLOG(ERROR) << "Failed to get current offset from " << out->GetLocation();
1892 return false;
1893 }
Vladimir Marko49b0f452015-12-10 13:49:19 +00001894 if (out->Seek(file_offset, kSeekSet) == static_cast<off_t>(-1)) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001895 PLOG(ERROR) << "Failed to seek to oat header position in " << out->GetLocation();
1896 return false;
1897 }
David Srbeckybc90fd02015-04-22 19:40:27 +01001898 DCHECK_EQ(file_offset, static_cast<size_t>(out->Seek(0, kSeekCurrent)));
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001899
1900 // Flush all other data before writing the header.
1901 if (!out->Flush()) {
1902 PLOG(ERROR) << "Failed to flush before writing oat header to " << out->GetLocation();
1903 return false;
1904 }
1905 // Write the header.
1906 size_t header_size = oat_header_->GetHeaderSize();
Vladimir Marko49b0f452015-12-10 13:49:19 +00001907 if (!out->WriteFully(oat_header_.get(), header_size)) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001908 PLOG(ERROR) << "Failed to write oat header to " << out->GetLocation();
1909 return false;
1910 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001911 // Flush the header data.
1912 if (!out->Flush()) {
1913 PLOG(ERROR) << "Failed to flush after writing oat header to " << out->GetLocation();
Vladimir Markof4da6752014-08-01 19:04:18 +01001914 return false;
1915 }
Vladimir Markof4da6752014-08-01 19:04:18 +01001916
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001917 if (out->Seek(current_offset, kSeekSet) == static_cast<off_t>(-1)) {
1918 PLOG(ERROR) << "Failed to seek back after writing oat header to " << out->GetLocation();
1919 return false;
1920 }
1921 DCHECK_EQ(current_offset, out->Seek(0, kSeekCurrent));
1922
1923 write_state_ = WriteState::kDone;
Brian Carlstrome24fa612011-09-29 00:53:55 -07001924 return true;
1925}
1926
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001927bool OatWriter::WriteClassOffsets(OutputStream* out) {
1928 for (OatDexFile& oat_dex_file : oat_dex_files_) {
1929 if (oat_dex_file.class_offsets_offset_ != 0u) {
1930 uint32_t expected_offset = oat_data_offset_ + oat_dex_file.class_offsets_offset_;
1931 off_t actual_offset = out->Seek(expected_offset, kSeekSet);
1932 if (static_cast<uint32_t>(actual_offset) != expected_offset) {
1933 PLOG(ERROR) << "Failed to seek to oat class offsets section. Actual: " << actual_offset
1934 << " Expected: " << expected_offset << " File: " << oat_dex_file.GetLocation();
Vladimir Marko919f5532016-01-20 19:13:01 +00001935 return false;
1936 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001937 if (!oat_dex_file.WriteClassOffsets(this, out)) {
1938 return false;
1939 }
1940 }
1941 }
1942 return true;
1943}
1944
1945bool OatWriter::WriteClasses(OutputStream* out) {
1946 for (OatClass& oat_class : oat_classes_) {
1947 if (!oat_class.Write(this, out, oat_data_offset_)) {
1948 PLOG(ERROR) << "Failed to write oat methods information to " << out->GetLocation();
1949 return false;
Vladimir Marko919f5532016-01-20 19:13:01 +00001950 }
Artem Udovichenkod9786b02015-10-14 16:36:55 +03001951 }
1952 return true;
1953}
1954
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001955size_t OatWriter::WriteMaps(OutputStream* out, const size_t file_offset, size_t relative_offset) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001956 size_t vmap_tables_offset = relative_offset;
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001957 WriteMapMethodVisitor visitor(this, out, file_offset, relative_offset);
1958 if (UNLIKELY(!VisitDexMethods(&visitor))) {
1959 return 0;
1960 }
1961 relative_offset = visitor.GetOffset();
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001962 size_vmap_table_ = relative_offset - vmap_tables_offset;
1963
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001964 return relative_offset;
1965}
1966
1967size_t OatWriter::WriteCode(OutputStream* out, const size_t file_offset, size_t relative_offset) {
Vladimir Markoaad75c62016-10-03 08:46:48 +00001968 if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001969 InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001970
Ian Rogers848871b2013-08-05 10:56:33 -07001971 #define DO_TRAMPOLINE(field) \
1972 do { \
1973 uint32_t aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set); \
1974 uint32_t alignment_padding = aligned_offset - relative_offset; \
Ian Rogers3d504072014-03-01 09:16:49 -08001975 out->Seek(alignment_padding, kSeekCurrent); \
Ian Rogers848871b2013-08-05 10:56:33 -07001976 size_trampoline_alignment_ += alignment_padding; \
Vladimir Markoe079e212016-05-25 12:49:49 +01001977 if (!out->WriteFully((field)->data(), (field)->size())) { \
Ian Rogers3d504072014-03-01 09:16:49 -08001978 PLOG(ERROR) << "Failed to write " # field " to " << out->GetLocation(); \
Ian Rogers848871b2013-08-05 10:56:33 -07001979 return false; \
1980 } \
Chih-Hung Hsiehfba39972016-05-11 11:26:48 -07001981 size_ ## field += (field)->size(); \
1982 relative_offset += alignment_padding + (field)->size(); \
Ian Rogers848871b2013-08-05 10:56:33 -07001983 DCHECK_OFFSET(); \
1984 } while (false)
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001985
Ian Rogers848871b2013-08-05 10:56:33 -07001986 DO_TRAMPOLINE(jni_dlsym_lookup_);
Andreas Gampe2da88232014-02-27 12:26:20 -08001987 DO_TRAMPOLINE(quick_generic_jni_trampoline_);
Jeff Hao88474b42013-10-23 16:24:40 -07001988 DO_TRAMPOLINE(quick_imt_conflict_trampoline_);
Ian Rogers848871b2013-08-05 10:56:33 -07001989 DO_TRAMPOLINE(quick_resolution_trampoline_);
1990 DO_TRAMPOLINE(quick_to_interpreter_bridge_);
1991 #undef DO_TRAMPOLINE
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001992 }
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001993 return relative_offset;
Brian Carlstrome24fa612011-09-29 00:53:55 -07001994}
1995
Ian Rogers3d504072014-03-01 09:16:49 -08001996size_t OatWriter::WriteCodeDexFiles(OutputStream* out,
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001997 const size_t file_offset,
1998 size_t relative_offset) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001999 #define VISIT(VisitorType) \
2000 do { \
2001 VisitorType visitor(this, out, file_offset, relative_offset); \
2002 if (UNLIKELY(!VisitDexMethods(&visitor))) { \
2003 return 0; \
2004 } \
2005 relative_offset = visitor.GetOffset(); \
2006 } while (false)
Brian Carlstrome24fa612011-09-29 00:53:55 -07002007
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002008 VISIT(WriteCodeMethodVisitor);
Brian Carlstrome24fa612011-09-29 00:53:55 -07002009
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002010 #undef VISIT
Brian Carlstrom265091e2013-01-30 14:08:26 -08002011
Vladimir Markob163bb72015-03-31 21:49:49 +01002012 size_code_alignment_ += relative_patcher_->CodeAlignmentSize();
2013 size_relative_call_thunks_ += relative_patcher_->RelativeCallThunksSize();
2014 size_misc_thunks_ += relative_patcher_->MiscThunksSize();
2015
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002016 return relative_offset;
Brian Carlstrome24fa612011-09-29 00:53:55 -07002017}
2018
Vladimir Marko944da602016-02-19 12:27:55 +00002019bool OatWriter::RecordOatDataOffset(OutputStream* out) {
Vladimir Marko49b0f452015-12-10 13:49:19 +00002020 // Get the elf file offset of the oat file.
2021 const off_t raw_file_offset = out->Seek(0, kSeekCurrent);
2022 if (raw_file_offset == static_cast<off_t>(-1)) {
2023 LOG(ERROR) << "Failed to get file offset in " << out->GetLocation();
2024 return false;
2025 }
2026 oat_data_offset_ = static_cast<size_t>(raw_file_offset);
2027 return true;
2028}
2029
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002030bool OatWriter::ReadDexFileHeader(File* file, OatDexFile* oat_dex_file) {
2031 // Read the dex file header and perform minimal verification.
2032 uint8_t raw_header[sizeof(DexFile::Header)];
2033 if (!file->ReadFully(&raw_header, sizeof(DexFile::Header))) {
2034 PLOG(ERROR) << "Failed to read dex file header. Actual: "
2035 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2036 return false;
2037 }
2038 if (!ValidateDexFileHeader(raw_header, oat_dex_file->GetLocation())) {
2039 return false;
2040 }
2041
2042 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_header);
2043 oat_dex_file->dex_file_size_ = header->file_size_;
2044 oat_dex_file->dex_file_location_checksum_ = header->checksum_;
2045 oat_dex_file->class_offsets_.resize(header->class_defs_size_);
2046 return true;
2047}
2048
2049bool OatWriter::ValidateDexFileHeader(const uint8_t* raw_header, const char* location) {
2050 if (!DexFile::IsMagicValid(raw_header)) {
2051 LOG(ERROR) << "Invalid magic number in dex file header. " << " File: " << location;
2052 return false;
2053 }
2054 if (!DexFile::IsVersionValid(raw_header)) {
2055 LOG(ERROR) << "Invalid version number in dex file header. " << " File: " << location;
2056 return false;
2057 }
2058 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_header);
2059 if (header->file_size_ < sizeof(DexFile::Header)) {
2060 LOG(ERROR) << "Dex file header specifies file size insufficient to contain the header."
2061 << " File: " << location;
2062 return false;
2063 }
2064 return true;
2065}
2066
David Brazdil7b49e6c2016-09-01 11:06:18 +01002067bool OatWriter::WriteDexFiles(OutputStream* out, File* file) {
2068 TimingLogger::ScopedTiming split("Write Dex files", timings_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002069
David Brazdil7b49e6c2016-09-01 11:06:18 +01002070 vdex_dex_files_offset_ = vdex_size_;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002071
2072 // Write dex files.
2073 for (OatDexFile& oat_dex_file : oat_dex_files_) {
David Brazdil7b49e6c2016-09-01 11:06:18 +01002074 if (!WriteDexFile(out, file, &oat_dex_file)) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002075 return false;
2076 }
2077 }
2078
2079 // Close sources.
2080 for (OatDexFile& oat_dex_file : oat_dex_files_) {
2081 oat_dex_file.source_.Clear(); // Get rid of the reference, it's about to be invalidated.
2082 }
2083 zipped_dex_files_.clear();
2084 zip_archives_.clear();
2085 raw_dex_files_.clear();
2086 return true;
2087}
2088
David Brazdil7b49e6c2016-09-01 11:06:18 +01002089bool OatWriter::WriteDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file) {
2090 if (!SeekToDexFile(out, file, oat_dex_file)) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002091 return false;
2092 }
2093 if (oat_dex_file->source_.IsZipEntry()) {
David Brazdil7b49e6c2016-09-01 11:06:18 +01002094 if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetZipEntry())) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002095 return false;
2096 }
2097 } else if (oat_dex_file->source_.IsRawFile()) {
David Brazdil7b49e6c2016-09-01 11:06:18 +01002098 if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetRawFile())) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002099 return false;
2100 }
2101 } else {
2102 DCHECK(oat_dex_file->source_.IsRawData());
David Brazdil7b49e6c2016-09-01 11:06:18 +01002103 if (!WriteDexFile(out, oat_dex_file, oat_dex_file->source_.GetRawData())) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002104 return false;
2105 }
2106 }
2107
2108 // Update current size and account for the written data.
David Brazdil7b49e6c2016-09-01 11:06:18 +01002109 if (kIsVdexEnabled) {
2110 DCHECK_EQ(vdex_size_, oat_dex_file->dex_file_offset_);
2111 vdex_size_ += oat_dex_file->dex_file_size_;
2112 } else {
2113 DCHECK_EQ(oat_size_, oat_dex_file->dex_file_offset_);
2114 oat_size_ += oat_dex_file->dex_file_size_;
2115 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002116 size_dex_file_ += oat_dex_file->dex_file_size_;
2117 return true;
2118}
2119
2120bool OatWriter::SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file) {
2121 // Dex files are required to be 4 byte aligned.
David Brazdil7b49e6c2016-09-01 11:06:18 +01002122 size_t initial_offset = kIsVdexEnabled ? vdex_size_ : oat_size_;
2123 size_t start_offset = RoundUp(initial_offset, 4);
2124 size_t file_offset = kIsVdexEnabled ? start_offset : (oat_data_offset_ + start_offset);
2125 size_dex_file_alignment_ += start_offset - initial_offset;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002126
2127 // Seek to the start of the dex file and flush any pending operations in the stream.
2128 // Verify that, after flushing the stream, the file is at the same offset as the stream.
David Brazdil7b49e6c2016-09-01 11:06:18 +01002129 off_t actual_offset = out->Seek(file_offset, kSeekSet);
2130 if (actual_offset != static_cast<off_t>(file_offset)) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002131 PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
David Brazdil7b49e6c2016-09-01 11:06:18 +01002132 << " Expected: " << file_offset
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002133 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2134 return false;
2135 }
2136 if (!out->Flush()) {
2137 PLOG(ERROR) << "Failed to flush before writing dex file."
2138 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2139 return false;
2140 }
2141 actual_offset = lseek(file->Fd(), 0, SEEK_CUR);
David Brazdil7b49e6c2016-09-01 11:06:18 +01002142 if (actual_offset != static_cast<off_t>(file_offset)) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002143 PLOG(ERROR) << "Stream/file position mismatch! Actual: " << actual_offset
David Brazdil7b49e6c2016-09-01 11:06:18 +01002144 << " Expected: " << file_offset
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002145 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2146 return false;
2147 }
2148
David Brazdil7b49e6c2016-09-01 11:06:18 +01002149 if (kIsVdexEnabled) {
2150 vdex_size_ = start_offset;
2151 } else {
2152 oat_size_ = start_offset;
2153 }
2154 oat_dex_file->dex_file_offset_ = start_offset;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002155 return true;
2156}
2157
David Brazdil7b49e6c2016-09-01 11:06:18 +01002158bool OatWriter::WriteDexFile(OutputStream* out,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002159 File* file,
2160 OatDexFile* oat_dex_file,
2161 ZipEntry* dex_file) {
David Brazdil7b49e6c2016-09-01 11:06:18 +01002162 size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_;
2163 DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002164
2165 // Extract the dex file and get the extracted size.
2166 std::string error_msg;
2167 if (!dex_file->ExtractToFile(*file, &error_msg)) {
2168 LOG(ERROR) << "Failed to extract dex file from ZIP entry: " << error_msg
2169 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2170 return false;
2171 }
2172 if (file->Flush() != 0) {
2173 PLOG(ERROR) << "Failed to flush dex file from ZIP entry."
2174 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2175 return false;
2176 }
2177 off_t extracted_end = lseek(file->Fd(), 0, SEEK_CUR);
2178 if (extracted_end == static_cast<off_t>(-1)) {
2179 PLOG(ERROR) << "Failed get end offset after writing dex file from ZIP entry."
2180 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2181 return false;
2182 }
2183 if (extracted_end < static_cast<off_t>(start_offset)) {
2184 LOG(ERROR) << "Dex file end position is before start position! End: " << extracted_end
2185 << " Start: " << start_offset
2186 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2187 return false;
2188 }
2189 uint64_t extracted_size = static_cast<uint64_t>(extracted_end - start_offset);
2190 if (extracted_size < sizeof(DexFile::Header)) {
2191 LOG(ERROR) << "Extracted dex file is shorter than dex file header. size: "
2192 << extracted_size << " File: " << oat_dex_file->GetLocation();
2193 return false;
2194 }
2195
2196 // Read the dex file header and extract required data to OatDexFile.
2197 off_t actual_offset = lseek(file->Fd(), start_offset, SEEK_SET);
2198 if (actual_offset != static_cast<off_t>(start_offset)) {
2199 PLOG(ERROR) << "Failed to seek back to dex file header. Actual: " << actual_offset
2200 << " Expected: " << start_offset
2201 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2202 return false;
2203 }
2204 if (!ReadDexFileHeader(file, oat_dex_file)) {
2205 return false;
2206 }
2207 if (extracted_size < oat_dex_file->dex_file_size_) {
2208 LOG(ERROR) << "Extracted truncated dex file. Extracted size: " << extracted_size
2209 << " file size from header: " << oat_dex_file->dex_file_size_
2210 << " File: " << oat_dex_file->GetLocation();
2211 return false;
2212 }
2213
2214 // Override the checksum from header with the CRC from ZIP entry.
2215 oat_dex_file->dex_file_location_checksum_ = dex_file->GetCrc32();
2216
2217 // Seek both file and stream to the end offset.
2218 size_t end_offset = start_offset + oat_dex_file->dex_file_size_;
2219 actual_offset = lseek(file->Fd(), end_offset, SEEK_SET);
2220 if (actual_offset != static_cast<off_t>(end_offset)) {
2221 PLOG(ERROR) << "Failed to seek to end of dex file. Actual: " << actual_offset
2222 << " Expected: " << end_offset
2223 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2224 return false;
2225 }
David Brazdil7b49e6c2016-09-01 11:06:18 +01002226 actual_offset = out->Seek(end_offset, kSeekSet);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002227 if (actual_offset != static_cast<off_t>(end_offset)) {
2228 PLOG(ERROR) << "Failed to seek stream to end of dex file. Actual: " << actual_offset
2229 << " Expected: " << end_offset << " File: " << oat_dex_file->GetLocation();
2230 return false;
2231 }
David Brazdil7b49e6c2016-09-01 11:06:18 +01002232 if (!out->Flush()) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002233 PLOG(ERROR) << "Failed to flush stream after seeking over dex file."
2234 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2235 return false;
2236 }
2237
2238 // If we extracted more than the size specified in the header, truncate the file.
2239 if (extracted_size > oat_dex_file->dex_file_size_) {
2240 if (file->SetLength(end_offset) != 0) {
2241 PLOG(ERROR) << "Failed to truncate excessive dex file length."
David Brazdil7b49e6c2016-09-01 11:06:18 +01002242 << " File: " << oat_dex_file->GetLocation()
2243 << " Output: " << file->GetPath();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002244 return false;
2245 }
2246 }
2247
2248 return true;
2249}
2250
David Brazdil7b49e6c2016-09-01 11:06:18 +01002251bool OatWriter::WriteDexFile(OutputStream* out,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002252 File* file,
2253 OatDexFile* oat_dex_file,
2254 File* dex_file) {
David Brazdil7b49e6c2016-09-01 11:06:18 +01002255 size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_;
2256 DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002257
2258 off_t input_offset = lseek(dex_file->Fd(), 0, SEEK_SET);
2259 if (input_offset != static_cast<off_t>(0)) {
2260 PLOG(ERROR) << "Failed to seek to dex file header. Actual: " << input_offset
2261 << " Expected: 0"
2262 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2263 return false;
2264 }
2265 if (!ReadDexFileHeader(dex_file, oat_dex_file)) {
2266 return false;
2267 }
2268
2269 // Copy the input dex file using sendfile().
2270 if (!file->Copy(dex_file, 0, oat_dex_file->dex_file_size_)) {
2271 PLOG(ERROR) << "Failed to copy dex file to oat file."
2272 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2273 return false;
2274 }
2275 if (file->Flush() != 0) {
2276 PLOG(ERROR) << "Failed to flush dex file."
2277 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2278 return false;
2279 }
2280
2281 // Check file position and seek the stream to the end offset.
2282 size_t end_offset = start_offset + oat_dex_file->dex_file_size_;
2283 off_t actual_offset = lseek(file->Fd(), 0, SEEK_CUR);
2284 if (actual_offset != static_cast<off_t>(end_offset)) {
2285 PLOG(ERROR) << "Unexpected file position after copying dex file. Actual: " << actual_offset
2286 << " Expected: " << end_offset
2287 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2288 return false;
2289 }
David Brazdil7b49e6c2016-09-01 11:06:18 +01002290 actual_offset = out->Seek(end_offset, kSeekSet);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002291 if (actual_offset != static_cast<off_t>(end_offset)) {
2292 PLOG(ERROR) << "Failed to seek stream to end of dex file. Actual: " << actual_offset
2293 << " Expected: " << end_offset << " File: " << oat_dex_file->GetLocation();
2294 return false;
2295 }
David Brazdil7b49e6c2016-09-01 11:06:18 +01002296 if (!out->Flush()) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002297 PLOG(ERROR) << "Failed to flush stream after seeking over dex file."
2298 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2299 return false;
2300 }
2301
2302 return true;
2303}
2304
David Brazdil7b49e6c2016-09-01 11:06:18 +01002305bool OatWriter::WriteDexFile(OutputStream* out,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002306 OatDexFile* oat_dex_file,
2307 const uint8_t* dex_file) {
2308 // Note: The raw data has already been checked to contain the header
2309 // and all the data that the header specifies as the file size.
2310 DCHECK(dex_file != nullptr);
2311 DCHECK(ValidateDexFileHeader(dex_file, oat_dex_file->GetLocation()));
2312 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(dex_file);
2313
David Brazdil7b49e6c2016-09-01 11:06:18 +01002314 if (!out->WriteFully(dex_file, header->file_size_)) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002315 PLOG(ERROR) << "Failed to write dex file " << oat_dex_file->GetLocation()
David Brazdil7b49e6c2016-09-01 11:06:18 +01002316 << " to " << out->GetLocation();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002317 return false;
2318 }
David Brazdil7b49e6c2016-09-01 11:06:18 +01002319 if (!out->Flush()) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002320 PLOG(ERROR) << "Failed to flush stream after writing dex file."
2321 << " File: " << oat_dex_file->GetLocation();
2322 return false;
2323 }
2324
2325 // Update dex file size and resize class offsets in the OatDexFile.
2326 // Note: For raw data, the checksum is passed directly to AddRawDexFileSource().
2327 oat_dex_file->dex_file_size_ = header->file_size_;
2328 oat_dex_file->class_offsets_.resize(header->class_defs_size_);
2329 return true;
2330}
2331
2332bool OatWriter::WriteOatDexFiles(OutputStream* rodata) {
2333 TimingLogger::ScopedTiming split("WriteOatDexFiles", timings_);
2334
David Brazdil181e1cc2016-09-01 16:38:47 +00002335 off_t initial_offset = rodata->Seek(0, kSeekCurrent);
2336 if (initial_offset == static_cast<off_t>(-1)) {
2337 LOG(ERROR) << "Failed to get current position in " << rodata->GetLocation();
2338 return false;
2339 }
2340
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002341 // Seek to the start of OatDexFiles, i.e. to the end of the OatHeader. If there are
2342 // no OatDexFiles, no data is actually written to .rodata before WriteHeader() and
2343 // this Seek() ensures that we reserve the space for OatHeader in .rodata.
2344 DCHECK(oat_dex_files_.empty() || oat_dex_files_[0u].offset_ == oat_header_->GetHeaderSize());
2345 uint32_t expected_offset = oat_data_offset_ + oat_header_->GetHeaderSize();
2346 off_t actual_offset = rodata->Seek(expected_offset, kSeekSet);
2347 if (static_cast<uint32_t>(actual_offset) != expected_offset) {
2348 PLOG(ERROR) << "Failed to seek to OatDexFile table section. Actual: " << actual_offset
2349 << " Expected: " << expected_offset << " File: " << rodata->GetLocation();
2350 return false;
2351 }
2352
2353 for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
2354 OatDexFile* oat_dex_file = &oat_dex_files_[i];
2355
2356 DCHECK_EQ(oat_data_offset_ + oat_dex_file->offset_,
2357 static_cast<size_t>(rodata->Seek(0, kSeekCurrent)));
2358
2359 // Write OatDexFile.
2360 if (!oat_dex_file->Write(this, rodata)) {
2361 PLOG(ERROR) << "Failed to write oat dex information to " << rodata->GetLocation();
2362 return false;
2363 }
2364 }
2365
David Brazdil181e1cc2016-09-01 16:38:47 +00002366 // Seek back to the initial position.
2367 if (rodata->Seek(initial_offset, kSeekSet) != initial_offset) {
2368 PLOG(ERROR) << "Failed to seek to initial position. Actual: " << actual_offset
2369 << " Expected: " << initial_offset << " File: " << rodata->GetLocation();
2370 return false;
2371 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002372
David Brazdilb92ba622016-09-01 16:00:30 +00002373 return true;
2374}
2375
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002376bool OatWriter::OpenDexFiles(
2377 File* file,
Andreas Gampe3a2bd292016-01-26 17:23:47 -08002378 bool verify,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002379 /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map,
2380 /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
2381 TimingLogger::ScopedTiming split("OpenDexFiles", timings_);
2382
2383 if (oat_dex_files_.empty()) {
2384 // Nothing to do.
2385 return true;
2386 }
2387
2388 size_t map_offset = oat_dex_files_[0].dex_file_offset_;
David Brazdil7b49e6c2016-09-01 11:06:18 +01002389 size_t length = kIsVdexEnabled ? (vdex_size_ - map_offset) : (oat_size_ - map_offset);
2390
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002391 std::string error_msg;
David Brazdil7b49e6c2016-09-01 11:06:18 +01002392 std::unique_ptr<MemMap> dex_files_map(MemMap::MapFile(
2393 length,
2394 PROT_READ | PROT_WRITE,
2395 MAP_SHARED,
2396 file->Fd(),
2397 kIsVdexEnabled ? map_offset : (oat_data_offset_ + map_offset),
2398 /* low_4gb */ false,
2399 file->GetPath().c_str(),
2400 &error_msg));
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002401 if (dex_files_map == nullptr) {
2402 LOG(ERROR) << "Failed to mmap() dex files from oat file. File: " << file->GetPath()
2403 << " error: " << error_msg;
2404 return false;
2405 }
2406 std::vector<std::unique_ptr<const DexFile>> dex_files;
2407 for (OatDexFile& oat_dex_file : oat_dex_files_) {
2408 // Make sure no one messed with input files while we were copying data.
2409 // At the very least we need consistent file size and number of class definitions.
2410 const uint8_t* raw_dex_file =
2411 dex_files_map->Begin() + oat_dex_file.dex_file_offset_ - map_offset;
2412 if (!ValidateDexFileHeader(raw_dex_file, oat_dex_file.GetLocation())) {
2413 // Note: ValidateDexFileHeader() already logged an error message.
2414 LOG(ERROR) << "Failed to verify written dex file header!"
2415 << " Output: " << file->GetPath() << " ~ " << std::hex << map_offset
2416 << " ~ " << static_cast<const void*>(raw_dex_file);
2417 return false;
2418 }
2419 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
2420 if (header->file_size_ != oat_dex_file.dex_file_size_) {
2421 LOG(ERROR) << "File size mismatch in written dex file header! Expected: "
2422 << oat_dex_file.dex_file_size_ << " Actual: " << header->file_size_
2423 << " Output: " << file->GetPath();
2424 return false;
2425 }
2426 if (header->class_defs_size_ != oat_dex_file.class_offsets_.size()) {
2427 LOG(ERROR) << "Class defs size mismatch in written dex file header! Expected: "
2428 << oat_dex_file.class_offsets_.size() << " Actual: " << header->class_defs_size_
2429 << " Output: " << file->GetPath();
2430 return false;
2431 }
2432
2433 // Now, open the dex file.
2434 dex_files.emplace_back(DexFile::Open(raw_dex_file,
2435 oat_dex_file.dex_file_size_,
2436 oat_dex_file.GetLocation(),
2437 oat_dex_file.dex_file_location_checksum_,
2438 /* oat_dex_file */ nullptr,
Andreas Gampe3a2bd292016-01-26 17:23:47 -08002439 verify,
Aart Bik37d6a3b2016-06-21 18:30:10 -07002440 verify,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002441 &error_msg));
2442 if (dex_files.back() == nullptr) {
Andreas Gampe3a2bd292016-01-26 17:23:47 -08002443 LOG(ERROR) << "Failed to open dex file from oat file. File: " << oat_dex_file.GetLocation()
2444 << " Error: " << error_msg;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002445 return false;
2446 }
2447 }
2448
2449 *opened_dex_files_map = std::move(dex_files_map);
2450 *opened_dex_files = std::move(dex_files);
2451 return true;
2452}
2453
2454bool OatWriter::WriteTypeLookupTables(
David Brazdil7b49e6c2016-09-01 11:06:18 +01002455 OutputStream* oat_rodata,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002456 const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files) {
2457 TimingLogger::ScopedTiming split("WriteTypeLookupTables", timings_);
2458
David Brazdil7b49e6c2016-09-01 11:06:18 +01002459 uint32_t expected_offset = oat_data_offset_ + oat_size_;
2460 off_t actual_offset = oat_rodata->Seek(expected_offset, kSeekSet);
2461 if (static_cast<uint32_t>(actual_offset) != expected_offset) {
2462 PLOG(ERROR) << "Failed to seek to TypeLookupTable section. Actual: " << actual_offset
2463 << " Expected: " << expected_offset << " File: " << oat_rodata->GetLocation();
2464 return false;
2465 }
2466
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002467 DCHECK_EQ(opened_dex_files.size(), oat_dex_files_.size());
2468 for (size_t i = 0, size = opened_dex_files.size(); i != size; ++i) {
2469 OatDexFile* oat_dex_file = &oat_dex_files_[i];
David Brazdil181e1cc2016-09-01 16:38:47 +00002470 DCHECK_EQ(oat_dex_file->lookup_table_offset_, 0u);
2471
2472 if (oat_dex_file->create_type_lookup_table_ != CreateTypeLookupTable::kCreate ||
2473 oat_dex_file->class_offsets_.empty()) {
2474 continue;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002475 }
David Brazdil181e1cc2016-09-01 16:38:47 +00002476
2477 size_t table_size = TypeLookupTable::RawDataLength(oat_dex_file->class_offsets_.size());
2478 if (table_size == 0u) {
2479 continue;
2480 }
2481
2482 // Create the lookup table. When `nullptr` is given as the storage buffer,
David Sehr9aa352e2016-09-15 18:13:52 -07002483 // TypeLookupTable allocates its own and OatDexFile takes ownership.
2484 oat_dex_file->InitTypeLookupTable(*opened_dex_files[i], /* storage */ nullptr);
2485 TypeLookupTable* table = oat_dex_file->GetTypeLookupTable();
David Brazdil181e1cc2016-09-01 16:38:47 +00002486
2487 // Type tables are required to be 4 byte aligned.
David Brazdil7b49e6c2016-09-01 11:06:18 +01002488 size_t initial_offset = oat_size_;
2489 size_t rodata_offset = RoundUp(initial_offset, 4);
2490 size_t padding_size = rodata_offset - initial_offset;
David Brazdil181e1cc2016-09-01 16:38:47 +00002491
2492 if (padding_size != 0u) {
2493 std::vector<uint8_t> buffer(padding_size, 0u);
David Brazdil7b49e6c2016-09-01 11:06:18 +01002494 if (!oat_rodata->WriteFully(buffer.data(), padding_size)) {
David Brazdil181e1cc2016-09-01 16:38:47 +00002495 PLOG(ERROR) << "Failed to write lookup table alignment padding."
2496 << " File: " << oat_dex_file->GetLocation()
David Brazdil7b49e6c2016-09-01 11:06:18 +01002497 << " Output: " << oat_rodata->GetLocation();
David Brazdil181e1cc2016-09-01 16:38:47 +00002498 return false;
2499 }
2500 }
2501
2502 DCHECK_EQ(oat_data_offset_ + rodata_offset,
David Brazdil7b49e6c2016-09-01 11:06:18 +01002503 static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent)));
David Brazdil181e1cc2016-09-01 16:38:47 +00002504 DCHECK_EQ(table_size, table->RawDataLength());
2505
David Brazdil7b49e6c2016-09-01 11:06:18 +01002506 if (!oat_rodata->WriteFully(table->RawData(), table_size)) {
David Brazdil181e1cc2016-09-01 16:38:47 +00002507 PLOG(ERROR) << "Failed to write lookup table."
2508 << " File: " << oat_dex_file->GetLocation()
David Brazdil7b49e6c2016-09-01 11:06:18 +01002509 << " Output: " << oat_rodata->GetLocation();
David Brazdil181e1cc2016-09-01 16:38:47 +00002510 return false;
2511 }
2512
2513 oat_dex_file->lookup_table_offset_ = rodata_offset;
2514
David Brazdil7b49e6c2016-09-01 11:06:18 +01002515 oat_size_ += padding_size + table_size;
David Brazdil181e1cc2016-09-01 16:38:47 +00002516 size_oat_lookup_table_ += table_size;
2517 size_oat_lookup_table_alignment_ += padding_size;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002518 }
2519
David Brazdil7b49e6c2016-09-01 11:06:18 +01002520 if (!oat_rodata->Flush()) {
David Brazdil181e1cc2016-09-01 16:38:47 +00002521 PLOG(ERROR) << "Failed to flush stream after writing type lookup tables."
David Brazdil7b49e6c2016-09-01 11:06:18 +01002522 << " File: " << oat_rodata->GetLocation();
2523 return false;
2524 }
2525
2526 return true;
2527}
2528
2529bool OatWriter::WriteVdexHeader(OutputStream* vdex_out) {
David Brazdil5d5a36b2016-09-14 15:34:10 +01002530 if (!kIsVdexEnabled) {
2531 return true;
2532 }
David Brazdil7b49e6c2016-09-01 11:06:18 +01002533 off_t actual_offset = vdex_out->Seek(0, kSeekSet);
2534 if (actual_offset != 0) {
2535 PLOG(ERROR) << "Failed to seek to the beginning of vdex file. Actual: " << actual_offset
2536 << " File: " << vdex_out->GetLocation();
2537 return false;
2538 }
2539
David Brazdil5d5a36b2016-09-14 15:34:10 +01002540 DCHECK_NE(vdex_dex_files_offset_, 0u);
2541 DCHECK_NE(vdex_verifier_deps_offset_, 0u);
2542
2543 size_t dex_section_size = vdex_verifier_deps_offset_ - vdex_dex_files_offset_;
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002544 size_t verifier_deps_section_size = vdex_quickening_info_offset_ - vdex_verifier_deps_offset_;
2545 size_t quickening_info_section_size = vdex_size_ - vdex_quickening_info_offset_;
David Brazdil5d5a36b2016-09-14 15:34:10 +01002546
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002547 VdexFile::Header vdex_header(
2548 dex_section_size, verifier_deps_section_size, quickening_info_section_size);
David Brazdil7b49e6c2016-09-01 11:06:18 +01002549 if (!vdex_out->WriteFully(&vdex_header, sizeof(VdexFile::Header))) {
2550 PLOG(ERROR) << "Failed to write vdex header. File: " << vdex_out->GetLocation();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002551 return false;
2552 }
2553
David Brazdil5d5a36b2016-09-14 15:34:10 +01002554 if (!vdex_out->Flush()) {
2555 PLOG(ERROR) << "Failed to flush stream after writing to vdex file."
2556 << " File: " << vdex_out->GetLocation();
2557 return false;
2558 }
2559
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002560 return true;
2561}
2562
Vladimir Markof4da6752014-08-01 19:04:18 +01002563bool OatWriter::WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta) {
2564 static const uint8_t kPadding[] = {
2565 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u
2566 };
2567 DCHECK_LE(aligned_code_delta, sizeof(kPadding));
Vladimir Markoe079e212016-05-25 12:49:49 +01002568 if (UNLIKELY(!out->WriteFully(kPadding, aligned_code_delta))) {
Vladimir Markof4da6752014-08-01 19:04:18 +01002569 return false;
2570 }
2571 size_code_alignment_ += aligned_code_delta;
2572 return true;
2573}
2574
Vladimir Marko944da602016-02-19 12:27:55 +00002575void OatWriter::SetMultiOatRelativePatcherAdjustment() {
2576 DCHECK(dex_files_ != nullptr);
2577 DCHECK(relative_patcher_ != nullptr);
2578 DCHECK_NE(oat_data_offset_, 0u);
2579 if (image_writer_ != nullptr && !dex_files_->empty()) {
2580 // The oat data begin may not be initialized yet but the oat file offset is ready.
2581 size_t oat_index = image_writer_->GetOatIndexForDexFile(dex_files_->front());
2582 size_t elf_file_offset = image_writer_->GetOatFileOffset(oat_index);
2583 relative_patcher_->StartOatFile(elf_file_offset + oat_data_offset_);
Vladimir Markob163bb72015-03-31 21:49:49 +01002584 }
2585}
2586
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002587OatWriter::OatDexFile::OatDexFile(const char* dex_file_location,
2588 DexFileSource source,
2589 CreateTypeLookupTable create_type_lookup_table)
2590 : source_(source),
2591 create_type_lookup_table_(create_type_lookup_table),
2592 dex_file_size_(0),
2593 offset_(0),
2594 dex_file_location_size_(strlen(dex_file_location)),
2595 dex_file_location_data_(dex_file_location),
2596 dex_file_location_checksum_(0u),
2597 dex_file_offset_(0u),
2598 class_offsets_offset_(0u),
2599 lookup_table_offset_(0u),
2600 class_offsets_() {
Brian Carlstrome24fa612011-09-29 00:53:55 -07002601}
2602
2603size_t OatWriter::OatDexFile::SizeOf() const {
2604 return sizeof(dex_file_location_size_)
2605 + dex_file_location_size_
Brian Carlstrom5b332c82012-02-01 15:02:31 -08002606 + sizeof(dex_file_location_checksum_)
Brian Carlstrom89521892011-12-07 22:05:07 -08002607 + sizeof(dex_file_offset_)
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002608 + sizeof(class_offsets_offset_)
2609 + sizeof(lookup_table_offset_);
Brian Carlstrome24fa612011-09-29 00:53:55 -07002610}
2611
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002612void OatWriter::OatDexFile::ReserveClassOffsets(OatWriter* oat_writer) {
2613 DCHECK_EQ(class_offsets_offset_, 0u);
2614 if (!class_offsets_.empty()) {
2615 // Class offsets are required to be 4 byte aligned.
David Brazdil7b49e6c2016-09-01 11:06:18 +01002616 size_t initial_offset = oat_writer->oat_size_;
2617 size_t offset = RoundUp(initial_offset, 4);
2618 oat_writer->size_oat_class_offsets_alignment_ += offset - initial_offset;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002619 class_offsets_offset_ = offset;
David Brazdil7b49e6c2016-09-01 11:06:18 +01002620 oat_writer->oat_size_ = offset + GetClassOffsetsRawSize();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002621 }
2622}
2623
2624bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream* out) const {
2625 const size_t file_offset = oat_writer->oat_data_offset_;
Brian Carlstrom265091e2013-01-30 14:08:26 -08002626 DCHECK_OFFSET_();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002627
Vladimir Markoe079e212016-05-25 12:49:49 +01002628 if (!out->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08002629 PLOG(ERROR) << "Failed to write dex file location length to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07002630 return false;
2631 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002632 oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002633
Vladimir Markoe079e212016-05-25 12:49:49 +01002634 if (!out->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
Ian Rogers3d504072014-03-01 09:16:49 -08002635 PLOG(ERROR) << "Failed to write dex file location data to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07002636 return false;
2637 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002638 oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002639
Vladimir Markoe079e212016-05-25 12:49:49 +01002640 if (!out->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08002641 PLOG(ERROR) << "Failed to write dex file location checksum to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07002642 return false;
2643 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002644 oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002645
Vladimir Markoe079e212016-05-25 12:49:49 +01002646 if (!out->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08002647 PLOG(ERROR) << "Failed to write dex file offset to " << out->GetLocation();
Brian Carlstrom89521892011-12-07 22:05:07 -08002648 return false;
2649 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002650 oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002651
Vladimir Markoe079e212016-05-25 12:49:49 +01002652 if (!out->WriteFully(&class_offsets_offset_, sizeof(class_offsets_offset_))) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002653 PLOG(ERROR) << "Failed to write class offsets offset to " << out->GetLocation();
2654 return false;
2655 }
2656 oat_writer->size_oat_dex_file_class_offsets_offset_ += sizeof(class_offsets_offset_);
2657
Vladimir Markoe079e212016-05-25 12:49:49 +01002658 if (!out->WriteFully(&lookup_table_offset_, sizeof(lookup_table_offset_))) {
Artem Udovichenkod9786b02015-10-14 16:36:55 +03002659 PLOG(ERROR) << "Failed to write lookup table offset to " << out->GetLocation();
2660 return false;
2661 }
Vladimir Marko49b0f452015-12-10 13:49:19 +00002662 oat_writer->size_oat_dex_file_lookup_table_offset_ += sizeof(lookup_table_offset_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002663
2664 return true;
2665}
2666
2667bool OatWriter::OatDexFile::WriteClassOffsets(OatWriter* oat_writer, OutputStream* out) {
Vladimir Markoe079e212016-05-25 12:49:49 +01002668 if (!out->WriteFully(class_offsets_.data(), GetClassOffsetsRawSize())) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002669 PLOG(ERROR) << "Failed to write oat class offsets for " << GetLocation()
2670 << " to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07002671 return false;
2672 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002673 oat_writer->size_oat_class_offsets_ += GetClassOffsetsRawSize();
Brian Carlstrome24fa612011-09-29 00:53:55 -07002674 return true;
2675}
2676
Brian Carlstromba150c32013-08-27 17:31:03 -07002677OatWriter::OatClass::OatClass(size_t offset,
Vladimir Marko49b0f452015-12-10 13:49:19 +00002678 const dchecked_vector<CompiledMethod*>& compiled_methods,
Brian Carlstromba150c32013-08-27 17:31:03 -07002679 uint32_t num_non_null_compiled_methods,
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002680 mirror::Class::Status status)
2681 : compiled_methods_(compiled_methods) {
2682 uint32_t num_methods = compiled_methods.size();
Brian Carlstromba150c32013-08-27 17:31:03 -07002683 CHECK_LE(num_non_null_compiled_methods, num_methods);
2684
Brian Carlstrom265091e2013-01-30 14:08:26 -08002685 offset_ = offset;
Brian Carlstromba150c32013-08-27 17:31:03 -07002686 oat_method_offsets_offsets_from_oat_class_.resize(num_methods);
2687
2688 // Since both kOatClassNoneCompiled and kOatClassAllCompiled could
2689 // apply when there are 0 methods, we just arbitrarily say that 0
2690 // methods means kOatClassNoneCompiled and that we won't use
2691 // kOatClassAllCompiled unless there is at least one compiled
2692 // method. This means in an interpretter only system, we can assert
2693 // that all classes are kOatClassNoneCompiled.
2694 if (num_non_null_compiled_methods == 0) {
2695 type_ = kOatClassNoneCompiled;
2696 } else if (num_non_null_compiled_methods == num_methods) {
2697 type_ = kOatClassAllCompiled;
2698 } else {
2699 type_ = kOatClassSomeCompiled;
2700 }
2701
Brian Carlstrom0755ec52012-01-11 15:19:46 -08002702 status_ = status;
Brian Carlstromba150c32013-08-27 17:31:03 -07002703 method_offsets_.resize(num_non_null_compiled_methods);
Vladimir Marko8a630572014-04-09 18:45:35 +01002704 method_headers_.resize(num_non_null_compiled_methods);
Brian Carlstromba150c32013-08-27 17:31:03 -07002705
2706 uint32_t oat_method_offsets_offset_from_oat_class = sizeof(type_) + sizeof(status_);
2707 if (type_ == kOatClassSomeCompiled) {
Vladimir Marko49b0f452015-12-10 13:49:19 +00002708 method_bitmap_.reset(new BitVector(num_methods, false, Allocator::GetMallocAllocator()));
Brian Carlstromba150c32013-08-27 17:31:03 -07002709 method_bitmap_size_ = method_bitmap_->GetSizeOf();
2710 oat_method_offsets_offset_from_oat_class += sizeof(method_bitmap_size_);
2711 oat_method_offsets_offset_from_oat_class += method_bitmap_size_;
2712 } else {
Mathieu Chartier2cebb242015-04-21 16:50:40 -07002713 method_bitmap_ = nullptr;
Brian Carlstromba150c32013-08-27 17:31:03 -07002714 method_bitmap_size_ = 0;
2715 }
2716
2717 for (size_t i = 0; i < num_methods; i++) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002718 CompiledMethod* compiled_method = compiled_methods_[i];
Mathieu Chartier2cebb242015-04-21 16:50:40 -07002719 if (compiled_method == nullptr) {
Brian Carlstromba150c32013-08-27 17:31:03 -07002720 oat_method_offsets_offsets_from_oat_class_[i] = 0;
2721 } else {
2722 oat_method_offsets_offsets_from_oat_class_[i] = oat_method_offsets_offset_from_oat_class;
2723 oat_method_offsets_offset_from_oat_class += sizeof(OatMethodOffsets);
2724 if (type_ == kOatClassSomeCompiled) {
2725 method_bitmap_->SetBit(i);
2726 }
2727 }
2728 }
Brian Carlstrome24fa612011-09-29 00:53:55 -07002729}
2730
Brian Carlstrom265091e2013-01-30 14:08:26 -08002731size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatHeader(
2732 size_t class_def_method_index_) const {
Brian Carlstromba150c32013-08-27 17:31:03 -07002733 uint32_t method_offset = GetOatMethodOffsetsOffsetFromOatClass(class_def_method_index_);
2734 if (method_offset == 0) {
2735 return 0;
2736 }
2737 return offset_ + method_offset;
Brian Carlstrom265091e2013-01-30 14:08:26 -08002738}
2739
2740size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatClass(
2741 size_t class_def_method_index_) const {
Brian Carlstromba150c32013-08-27 17:31:03 -07002742 return oat_method_offsets_offsets_from_oat_class_[class_def_method_index_];
Brian Carlstrom265091e2013-01-30 14:08:26 -08002743}
2744
2745size_t OatWriter::OatClass::SizeOf() const {
Brian Carlstromba150c32013-08-27 17:31:03 -07002746 return sizeof(status_)
2747 + sizeof(type_)
2748 + ((method_bitmap_size_ == 0) ? 0 : sizeof(method_bitmap_size_))
2749 + method_bitmap_size_
2750 + (sizeof(method_offsets_[0]) * method_offsets_.size());
Brian Carlstrome24fa612011-09-29 00:53:55 -07002751}
2752
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002753bool OatWriter::OatClass::Write(OatWriter* oat_writer,
Ian Rogers3d504072014-03-01 09:16:49 -08002754 OutputStream* out,
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002755 const size_t file_offset) const {
Brian Carlstrom265091e2013-01-30 14:08:26 -08002756 DCHECK_OFFSET_();
Vladimir Markoe079e212016-05-25 12:49:49 +01002757 if (!out->WriteFully(&status_, sizeof(status_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08002758 PLOG(ERROR) << "Failed to write class status to " << out->GetLocation();
Brian Carlstrom0755ec52012-01-11 15:19:46 -08002759 return false;
2760 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002761 oat_writer->size_oat_class_status_ += sizeof(status_);
Vladimir Marko49b0f452015-12-10 13:49:19 +00002762
Vladimir Markoe079e212016-05-25 12:49:49 +01002763 if (!out->WriteFully(&type_, sizeof(type_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08002764 PLOG(ERROR) << "Failed to write oat class type to " << out->GetLocation();
Brian Carlstromba150c32013-08-27 17:31:03 -07002765 return false;
2766 }
2767 oat_writer->size_oat_class_type_ += sizeof(type_);
Vladimir Marko49b0f452015-12-10 13:49:19 +00002768
Brian Carlstromba150c32013-08-27 17:31:03 -07002769 if (method_bitmap_size_ != 0) {
2770 CHECK_EQ(kOatClassSomeCompiled, type_);
Vladimir Markoe079e212016-05-25 12:49:49 +01002771 if (!out->WriteFully(&method_bitmap_size_, sizeof(method_bitmap_size_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08002772 PLOG(ERROR) << "Failed to write method bitmap size to " << out->GetLocation();
Brian Carlstromba150c32013-08-27 17:31:03 -07002773 return false;
2774 }
2775 oat_writer->size_oat_class_method_bitmaps_ += sizeof(method_bitmap_size_);
Vladimir Marko49b0f452015-12-10 13:49:19 +00002776
Vladimir Markoe079e212016-05-25 12:49:49 +01002777 if (!out->WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_size_)) {
Ian Rogers3d504072014-03-01 09:16:49 -08002778 PLOG(ERROR) << "Failed to write method bitmap to " << out->GetLocation();
Brian Carlstromba150c32013-08-27 17:31:03 -07002779 return false;
2780 }
2781 oat_writer->size_oat_class_method_bitmaps_ += method_bitmap_size_;
2782 }
Vladimir Marko49b0f452015-12-10 13:49:19 +00002783
Vladimir Markoe079e212016-05-25 12:49:49 +01002784 if (!out->WriteFully(method_offsets_.data(), GetMethodOffsetsRawSize())) {
Ian Rogers3d504072014-03-01 09:16:49 -08002785 PLOG(ERROR) << "Failed to write method offsets to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07002786 return false;
2787 }
Vladimir Marko49b0f452015-12-10 13:49:19 +00002788 oat_writer->size_oat_class_method_offsets_ += GetMethodOffsetsRawSize();
Brian Carlstrome24fa612011-09-29 00:53:55 -07002789 return true;
2790}
2791
Brian Carlstrome24fa612011-09-29 00:53:55 -07002792} // namespace art