blob: a33081e0337bd78700282734d9d272a7c262823d [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"
Vladimir Marko0eb882b2017-05-15 13:39:18 +010025#include "base/bit_vector-inl.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"
Vladimir Marko20f85592015-03-19 10:07:02 +000031#include "compiled_method.h"
David Srbecky4fda4eb2016-02-05 13:34:46 +000032#include "debug/method_debug_info.h"
Vladimir Markoc7f83202014-01-24 17:55:18 +000033#include "dex/verification_results.h"
David Srbecky4fda4eb2016-02-05 13:34:46 +000034#include "dex_file-inl.h"
Jeff Hao608f2ce2016-10-19 11:17:11 -070035#include "dexlayout.h"
Andreas Gamped482e732017-04-24 17:59:09 -070036#include "driver/compiler_driver-inl.h"
Vladimir Marko20f85592015-03-19 10:07:02 +000037#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 Marko0eb882b2017-05-15 13:39:18 +010044#include "linker/method_bss_mapping_encoder.h"
Vladimir Marko944da602016-02-19 12:27:55 +000045#include "linker/multi_oat_relative_patcher.h"
Vladimir Marko131980f2015-12-03 18:29:23 +000046#include "linker/output_stream.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080047#include "mirror/array.h"
48#include "mirror/class_loader.h"
Vladimir Marko3481ba22015-04-13 12:22:36 +010049#include "mirror/dex_cache-inl.h"
Ian Rogers4f6ad8a2013-03-18 15:27:28 -070050#include "mirror/object-inl.h"
Nicolas Geoffray524e7ea2015-10-16 17:13:34 +010051#include "oat_quick_method_header.h"
Brian Carlstrome24fa612011-09-29 00:53:55 -070052#include "os.h"
Elliott Hughesa0e18062012-04-13 15:59:59 -070053#include "safe_map.h"
Mathieu Chartier0795f232016-09-27 18:43:30 -070054#include "scoped_thread_state_change-inl.h"
Artem Udovichenkod9786b02015-10-14 16:36:55 +030055#include "type_lookup_table.h"
Vladimir Marko09d09432015-09-08 13:47:48 +010056#include "utils/dex_cache_arrays_layout-inl.h"
David Brazdil7b49e6c2016-09-01 11:06:18 +010057#include "vdex_file.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
Mathieu Chartier120aa282017-08-05 16:03:03 -070065// If we write dex layout info in the oat file.
66static constexpr bool kWriteDexLayoutInfo = true;
67
Vladimir Marko9bdf1082016-01-21 12:15:52 +000068typedef DexFile::Header __attribute__((aligned(1))) UnalignedDexFileHeader;
69
70const UnalignedDexFileHeader* AsUnalignedDexFileHeader(const uint8_t* raw_data) {
71 return reinterpret_cast<const UnalignedDexFileHeader*>(raw_data);
72}
73
Vladimir Markoe079e212016-05-25 12:49:49 +010074class ChecksumUpdatingOutputStream : public OutputStream {
75 public:
76 ChecksumUpdatingOutputStream(OutputStream* out, OatHeader* oat_header)
77 : OutputStream(out->GetLocation()), out_(out), oat_header_(oat_header) { }
78
79 bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE {
80 oat_header_->UpdateChecksum(buffer, byte_count);
81 return out_->WriteFully(buffer, byte_count);
82 }
83
84 off_t Seek(off_t offset, Whence whence) OVERRIDE {
85 return out_->Seek(offset, whence);
86 }
87
88 bool Flush() OVERRIDE {
89 return out_->Flush();
90 }
91
92 private:
93 OutputStream* const out_;
94 OatHeader* const oat_header_;
95};
96
Vladimir Marko0c737df2016-08-01 16:33:16 +010097inline uint32_t CodeAlignmentSize(uint32_t header_offset, const CompiledMethod& compiled_method) {
98 // We want to align the code rather than the preheader.
99 uint32_t unaligned_code_offset = header_offset + sizeof(OatQuickMethodHeader);
100 uint32_t aligned_code_offset = compiled_method.AlignCode(unaligned_code_offset);
101 return aligned_code_offset - unaligned_code_offset;
102}
103
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000104} // anonymous namespace
105
106// Defines the location of the raw dex file to write.
107class OatWriter::DexFileSource {
108 public:
Mathieu Chartier497d5262017-02-28 20:17:30 -0800109 enum Type {
110 kNone,
111 kZipEntry,
112 kRawFile,
113 kRawData,
114 };
115
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000116 explicit DexFileSource(ZipEntry* zip_entry)
117 : type_(kZipEntry), source_(zip_entry) {
118 DCHECK(source_ != nullptr);
119 }
120
121 explicit DexFileSource(File* raw_file)
122 : type_(kRawFile), source_(raw_file) {
123 DCHECK(source_ != nullptr);
124 }
125
126 explicit DexFileSource(const uint8_t* dex_file)
127 : type_(kRawData), source_(dex_file) {
128 DCHECK(source_ != nullptr);
129 }
130
Mathieu Chartier497d5262017-02-28 20:17:30 -0800131 Type GetType() const { return type_; }
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000132 bool IsZipEntry() const { return type_ == kZipEntry; }
133 bool IsRawFile() const { return type_ == kRawFile; }
134 bool IsRawData() const { return type_ == kRawData; }
135
136 ZipEntry* GetZipEntry() const {
137 DCHECK(IsZipEntry());
138 DCHECK(source_ != nullptr);
139 return static_cast<ZipEntry*>(const_cast<void*>(source_));
140 }
141
142 File* GetRawFile() const {
143 DCHECK(IsRawFile());
144 DCHECK(source_ != nullptr);
145 return static_cast<File*>(const_cast<void*>(source_));
146 }
147
148 const uint8_t* GetRawData() const {
149 DCHECK(IsRawData());
150 DCHECK(source_ != nullptr);
151 return static_cast<const uint8_t*>(source_);
152 }
153
154 void Clear() {
155 type_ = kNone;
156 source_ = nullptr;
157 }
158
159 private:
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000160 Type type_;
161 const void* source_;
162};
163
Mathieu Chartier3957bff2017-07-16 13:55:27 -0700164// OatClassHeader is the header only part of the oat class that is required even when compilation
165// is not enabled.
166class OatWriter::OatClassHeader {
167 public:
168 OatClassHeader(uint32_t offset,
169 uint32_t num_non_null_compiled_methods,
170 uint32_t num_methods,
171 mirror::Class::Status status)
172 : status_(status),
173 offset_(offset) {
174 // We just arbitrarily say that 0 methods means kOatClassNoneCompiled and that we won't use
175 // kOatClassAllCompiled unless there is at least one compiled method. This means in an
176 // interpreter only system, we can assert that all classes are kOatClassNoneCompiled.
177 if (num_non_null_compiled_methods == 0) {
178 type_ = kOatClassNoneCompiled;
179 } else if (num_non_null_compiled_methods == num_methods) {
180 type_ = kOatClassAllCompiled;
181 } else {
182 type_ = kOatClassSomeCompiled;
183 }
184 }
185
186 bool Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const;
187
188 static size_t SizeOf() {
189 return sizeof(status_) + sizeof(type_);
190 }
191
192 // Data to write.
193 static_assert(mirror::Class::Status::kStatusMax < (1 << 16), "class status won't fit in 16bits");
194 int16_t status_;
195
196 static_assert(OatClassType::kOatClassMax < (1 << 16), "oat_class type won't fit in 16bits");
197 uint16_t type_;
198
199 // Offset of start of OatClass from beginning of OatHeader. It is
200 // used to validate file position when writing.
201 uint32_t offset_;
202};
203
204// The actual oat class body contains the information about compiled methods. It is only required
205// for compiler filters that have any compilation.
Vladimir Marko49b0f452015-12-10 13:49:19 +0000206class OatWriter::OatClass {
207 public:
Mathieu Chartier3957bff2017-07-16 13:55:27 -0700208 OatClass(const dchecked_vector<CompiledMethod*>& compiled_methods,
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100209 uint32_t compiled_methods_with_code,
Mathieu Chartier3957bff2017-07-16 13:55:27 -0700210 uint16_t oat_class_type);
Vladimir Marko49b0f452015-12-10 13:49:19 +0000211 OatClass(OatClass&& src) = default;
Vladimir Marko49b0f452015-12-10 13:49:19 +0000212 size_t SizeOf() const;
Mathieu Chartier3957bff2017-07-16 13:55:27 -0700213 bool Write(OatWriter* oat_writer, OutputStream* out) const;
Vladimir Marko49b0f452015-12-10 13:49:19 +0000214
215 CompiledMethod* GetCompiledMethod(size_t class_def_method_index) const {
216 return compiled_methods_[class_def_method_index];
217 }
218
Vladimir Marko49b0f452015-12-10 13:49:19 +0000219 // CompiledMethods for each class_def_method_index, or null if no method is available.
220 dchecked_vector<CompiledMethod*> compiled_methods_;
221
222 // Offset from OatClass::offset_ to the OatMethodOffsets for the
223 // class_def_method_index. If 0, it means the corresponding
224 // CompiledMethod entry in OatClass::compiled_methods_ should be
225 // null and that the OatClass::type_ should be kOatClassBitmap.
226 dchecked_vector<uint32_t> oat_method_offsets_offsets_from_oat_class_;
227
228 // Data to write.
Vladimir Marko49b0f452015-12-10 13:49:19 +0000229 uint32_t method_bitmap_size_;
230
231 // bit vector indexed by ClassDef method index. When
232 // OatClassType::type_ is kOatClassBitmap, a set bit indicates the
233 // method has an OatMethodOffsets in methods_offsets_, otherwise
234 // the entry was ommited to save space. If OatClassType::type_ is
235 // not is kOatClassBitmap, the bitmap will be null.
236 std::unique_ptr<BitVector> method_bitmap_;
237
238 // OatMethodOffsets and OatMethodHeaders for each CompiledMethod
239 // present in the OatClass. Note that some may be missing if
240 // OatClass::compiled_methods_ contains null values (and
241 // oat_method_offsets_offsets_from_oat_class_ should contain 0
242 // values in this case).
243 dchecked_vector<OatMethodOffsets> method_offsets_;
244 dchecked_vector<OatQuickMethodHeader> method_headers_;
245
246 private:
247 size_t GetMethodOffsetsRawSize() const {
248 return method_offsets_.size() * sizeof(method_offsets_[0]);
249 }
250
251 DISALLOW_COPY_AND_ASSIGN(OatClass);
252};
253
254class OatWriter::OatDexFile {
255 public:
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000256 OatDexFile(const char* dex_file_location,
257 DexFileSource source,
258 CreateTypeLookupTable create_type_lookup_table);
Vladimir Marko49b0f452015-12-10 13:49:19 +0000259 OatDexFile(OatDexFile&& src) = default;
260
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000261 const char* GetLocation() const {
262 return dex_file_location_data_;
263 }
264
Vladimir Marko49b0f452015-12-10 13:49:19 +0000265 size_t SizeOf() const;
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000266 bool Write(OatWriter* oat_writer, OutputStream* out) const;
267 bool WriteClassOffsets(OatWriter* oat_writer, OutputStream* out);
268
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100269 size_t GetClassOffsetsRawSize() const {
270 return class_offsets_.size() * sizeof(class_offsets_[0]);
271 }
272
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000273 // The source of the dex file.
274 DexFileSource source_;
275
276 // Whether to create the type lookup table.
277 CreateTypeLookupTable create_type_lookup_table_;
278
279 // Dex file size. Initialized when writing the dex file.
280 size_t dex_file_size_;
Vladimir Marko49b0f452015-12-10 13:49:19 +0000281
282 // Offset of start of OatDexFile from beginning of OatHeader. It is
283 // used to validate file position when writing.
284 size_t offset_;
285
286 // Data to write.
287 uint32_t dex_file_location_size_;
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000288 const char* dex_file_location_data_;
Vladimir Marko49b0f452015-12-10 13:49:19 +0000289 uint32_t dex_file_location_checksum_;
290 uint32_t dex_file_offset_;
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000291 uint32_t class_offsets_offset_;
Vladimir Marko49b0f452015-12-10 13:49:19 +0000292 uint32_t lookup_table_offset_;
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100293 uint32_t method_bss_mapping_offset_;
Mathieu Chartier120aa282017-08-05 16:03:03 -0700294 uint32_t dex_sections_layout_offset_;
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000295
296 // Data to write to a separate section.
Vladimir Marko49b0f452015-12-10 13:49:19 +0000297 dchecked_vector<uint32_t> class_offsets_;
298
Mathieu Chartier120aa282017-08-05 16:03:03 -0700299 // Dex section layout info to serialize.
300 DexLayoutSections dex_sections_layout_;
301
Vladimir Marko49b0f452015-12-10 13:49:19 +0000302 private:
Vladimir Marko49b0f452015-12-10 13:49:19 +0000303 DISALLOW_COPY_AND_ASSIGN(OatDexFile);
304};
305
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100306#define DCHECK_OFFSET() \
307 DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out->Seek(0, kSeekCurrent)) \
308 << "file_offset=" << file_offset << " relative_offset=" << relative_offset
309
310#define DCHECK_OFFSET_() \
311 DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \
312 << "file_offset=" << file_offset << " offset_=" << offset_
313
Jeff Hao608f2ce2016-10-19 11:17:11 -0700314OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings, ProfileCompilationInfo* info)
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000315 : write_state_(WriteState::kAddingDexFileSources),
316 timings_(timings),
317 raw_dex_files_(),
318 zip_archives_(),
319 zipped_dex_files_(),
320 zipped_dex_file_locations_(),
321 compiler_driver_(nullptr),
322 image_writer_(nullptr),
Mathieu Chartierda5b28a2015-11-05 08:03:47 -0800323 compiling_boot_image_(compiling_boot_image),
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000324 dex_files_(nullptr),
David Brazdil7b49e6c2016-09-01 11:06:18 +0100325 vdex_size_(0u),
326 vdex_dex_files_offset_(0u),
David Brazdil5d5a36b2016-09-14 15:34:10 +0100327 vdex_verifier_deps_offset_(0u),
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100328 vdex_quickening_info_offset_(0u),
David Brazdil7b49e6c2016-09-01 11:06:18 +0100329 oat_size_(0u),
Vladimir Markoaad75c62016-10-03 08:46:48 +0000330 bss_start_(0u),
Vladimir Marko5c42c292015-02-25 12:02:49 +0000331 bss_size_(0u),
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100332 bss_methods_offset_(0u),
Vladimir Markoaad75c62016-10-03 08:46:48 +0000333 bss_roots_offset_(0u),
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100334 bss_method_entry_references_(),
335 bss_method_entries_(),
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000336 bss_type_entries_(),
Vladimir Markoaad75c62016-10-03 08:46:48 +0000337 bss_string_entries_(),
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +0100338 map_boot_image_tables_to_bss_(false),
Vladimir Markof4da6752014-08-01 19:04:18 +0100339 oat_data_offset_(0u),
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700340 oat_header_(nullptr),
David Brazdil7b49e6c2016-09-01 11:06:18 +0100341 size_vdex_header_(0),
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000342 size_vdex_checksums_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700343 size_dex_file_alignment_(0),
344 size_executable_offset_alignment_(0),
345 size_oat_header_(0),
Andreas Gampe22f8e5c2014-07-09 11:38:21 -0700346 size_oat_header_key_value_store_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700347 size_dex_file_(0),
David Brazdil5d5a36b2016-09-14 15:34:10 +0100348 size_verifier_deps_(0),
349 size_verifier_deps_alignment_(0),
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100350 size_quickening_info_(0),
351 size_quickening_info_alignment_(0),
Ian Rogers848871b2013-08-05 10:56:33 -0700352 size_interpreter_to_interpreter_bridge_(0),
353 size_interpreter_to_compiled_code_bridge_(0),
354 size_jni_dlsym_lookup_(0),
Andreas Gampe2da88232014-02-27 12:26:20 -0800355 size_quick_generic_jni_trampoline_(0),
Jeff Hao88474b42013-10-23 16:24:40 -0700356 size_quick_imt_conflict_trampoline_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700357 size_quick_resolution_trampoline_(0),
Ian Rogers848871b2013-08-05 10:56:33 -0700358 size_quick_to_interpreter_bridge_(0),
359 size_trampoline_alignment_(0),
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100360 size_method_header_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700361 size_code_(0),
362 size_code_alignment_(0),
Vladimir Markof4da6752014-08-01 19:04:18 +0100363 size_relative_call_thunks_(0),
Vladimir Markoc74658b2015-03-31 10:26:41 +0100364 size_misc_thunks_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700365 size_vmap_table_(0),
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700366 size_method_info_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700367 size_oat_dex_file_location_size_(0),
368 size_oat_dex_file_location_data_(0),
369 size_oat_dex_file_location_checksum_(0),
370 size_oat_dex_file_offset_(0),
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000371 size_oat_dex_file_class_offsets_offset_(0),
Vladimir Marko49b0f452015-12-10 13:49:19 +0000372 size_oat_dex_file_lookup_table_offset_(0),
Mathieu Chartier120aa282017-08-05 16:03:03 -0700373 size_oat_dex_file_dex_layout_sections_offset_(0),
374 size_oat_dex_file_dex_layout_sections_(0),
375 size_oat_dex_file_dex_layout_sections_alignment_(0),
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100376 size_oat_dex_file_method_bss_mapping_offset_(0),
Vladimir Marko49b0f452015-12-10 13:49:19 +0000377 size_oat_lookup_table_alignment_(0),
378 size_oat_lookup_table_(0),
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000379 size_oat_class_offsets_alignment_(0),
380 size_oat_class_offsets_(0),
Brian Carlstromba150c32013-08-27 17:31:03 -0700381 size_oat_class_type_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700382 size_oat_class_status_(0),
Brian Carlstromba150c32013-08-27 17:31:03 -0700383 size_oat_class_method_bitmaps_(0),
Vladimir Markof4da6752014-08-01 19:04:18 +0100384 size_oat_class_method_offsets_(0),
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100385 size_method_bss_mappings_(0u),
Vladimir Marko944da602016-02-19 12:27:55 +0000386 relative_patcher_(nullptr),
Jeff Hao608f2ce2016-10-19 11:17:11 -0700387 absolute_patch_locations_(),
388 profile_compilation_info_(info) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000389}
390
391bool OatWriter::AddDexFileSource(const char* filename,
392 const char* location,
393 CreateTypeLookupTable create_type_lookup_table) {
394 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
395 uint32_t magic;
396 std::string error_msg;
Andreas Gampe43e10b02016-07-15 17:17:34 -0700397 File fd = OpenAndReadMagic(filename, &magic, &error_msg);
398 if (fd.Fd() == -1) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000399 PLOG(ERROR) << "Failed to read magic number from dex file: '" << filename << "'";
400 return false;
401 } else if (IsDexMagic(magic)) {
402 // The file is open for reading, not writing, so it's OK to let the File destructor
403 // close it without checking for explicit Close(), so pass checkUsage = false.
Andreas Gampe43e10b02016-07-15 17:17:34 -0700404 raw_dex_files_.emplace_back(new File(fd.Release(), location, /* checkUsage */ false));
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000405 oat_dex_files_.emplace_back(location,
406 DexFileSource(raw_dex_files_.back().get()),
407 create_type_lookup_table);
408 } else if (IsZipMagic(magic)) {
409 if (!AddZippedDexFilesSource(std::move(fd), location, create_type_lookup_table)) {
410 return false;
411 }
412 } else {
413 LOG(ERROR) << "Expected valid zip or dex file: '" << filename << "'";
414 return false;
415 }
416 return true;
417}
418
419// Add dex file source(s) from a zip file specified by a file handle.
Andreas Gampe43e10b02016-07-15 17:17:34 -0700420bool OatWriter::AddZippedDexFilesSource(File&& zip_fd,
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000421 const char* location,
422 CreateTypeLookupTable create_type_lookup_table) {
423 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
424 std::string error_msg;
Andreas Gampe43e10b02016-07-15 17:17:34 -0700425 zip_archives_.emplace_back(ZipArchive::OpenFromFd(zip_fd.Release(), location, &error_msg));
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000426 ZipArchive* zip_archive = zip_archives_.back().get();
427 if (zip_archive == nullptr) {
428 LOG(ERROR) << "Failed to open zip from file descriptor for '" << location << "': "
429 << error_msg;
430 return false;
431 }
432 for (size_t i = 0; ; ++i) {
433 std::string entry_name = DexFile::GetMultiDexClassesDexName(i);
434 std::unique_ptr<ZipEntry> entry(zip_archive->Find(entry_name.c_str(), &error_msg));
435 if (entry == nullptr) {
436 break;
437 }
438 zipped_dex_files_.push_back(std::move(entry));
439 zipped_dex_file_locations_.push_back(DexFile::GetMultiDexLocation(i, location));
440 const char* full_location = zipped_dex_file_locations_.back().c_str();
441 oat_dex_files_.emplace_back(full_location,
442 DexFileSource(zipped_dex_files_.back().get()),
443 create_type_lookup_table);
444 }
445 if (zipped_dex_file_locations_.empty()) {
446 LOG(ERROR) << "No dex files in zip file '" << location << "': " << error_msg;
447 return false;
448 }
449 return true;
450}
451
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000452// Add dex file source(s) from a vdex file specified by a file handle.
453bool OatWriter::AddVdexDexFilesSource(const VdexFile& vdex_file,
454 const char* location,
455 CreateTypeLookupTable create_type_lookup_table) {
456 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
457 const uint8_t* current_dex_data = nullptr;
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000458 for (size_t i = 0; i < vdex_file.GetHeader().GetNumberOfDexFiles(); ++i) {
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000459 current_dex_data = vdex_file.GetNextDexFileData(current_dex_data);
460 if (current_dex_data == nullptr) {
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000461 LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
462 return false;
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000463 }
464 if (!DexFile::IsMagicValid(current_dex_data)) {
465 LOG(ERROR) << "Invalid magic in vdex file created from " << location;
466 return false;
467 }
468 // We used `zipped_dex_file_locations_` to keep the strings in memory.
469 zipped_dex_file_locations_.push_back(DexFile::GetMultiDexLocation(i, location));
470 const char* full_location = zipped_dex_file_locations_.back().c_str();
471 oat_dex_files_.emplace_back(full_location,
472 DexFileSource(current_dex_data),
473 create_type_lookup_table);
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000474 oat_dex_files_.back().dex_file_location_checksum_ = vdex_file.GetLocationChecksum(i);
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000475 }
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000476
477 if (vdex_file.GetNextDexFileData(current_dex_data) != nullptr) {
478 LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
479 return false;
480 }
481
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000482 if (oat_dex_files_.empty()) {
483 LOG(ERROR) << "No dex files in vdex file created from " << location;
484 return false;
485 }
486 return true;
487}
488
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000489// Add dex file source from raw memory.
490bool OatWriter::AddRawDexFileSource(const ArrayRef<const uint8_t>& data,
491 const char* location,
492 uint32_t location_checksum,
493 CreateTypeLookupTable create_type_lookup_table) {
494 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
495 if (data.size() < sizeof(DexFile::Header)) {
496 LOG(ERROR) << "Provided data is shorter than dex file header. size: "
497 << data.size() << " File: " << location;
498 return false;
499 }
500 if (!ValidateDexFileHeader(data.data(), location)) {
501 return false;
502 }
503 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(data.data());
504 if (data.size() < header->file_size_) {
505 LOG(ERROR) << "Truncated dex file data. Data size: " << data.size()
506 << " file size from header: " << header->file_size_ << " File: " << location;
507 return false;
508 }
509
510 oat_dex_files_.emplace_back(location, DexFileSource(data.data()), create_type_lookup_table);
511 oat_dex_files_.back().dex_file_location_checksum_ = location_checksum;
512 return true;
513}
514
Calin Juravle1ce70852017-06-28 10:59:03 -0700515dchecked_vector<std::string> OatWriter::GetSourceLocations() const {
516 dchecked_vector<std::string> locations;
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000517 locations.reserve(oat_dex_files_.size());
518 for (const OatDexFile& oat_dex_file : oat_dex_files_) {
519 locations.push_back(oat_dex_file.GetLocation());
520 }
521 return locations;
522}
523
Mathieu Chartier3957bff2017-07-16 13:55:27 -0700524bool OatWriter::MayHaveCompiledMethods() const {
525 return CompilerFilter::IsAnyCompilationEnabled(
526 GetCompilerDriver()->GetCompilerOptions().GetCompilerFilter());
527}
528
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000529bool OatWriter::WriteAndOpenDexFiles(
David Brazdil7b49e6c2016-09-01 11:06:18 +0100530 File* vdex_file,
531 OutputStream* oat_rodata,
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000532 InstructionSet instruction_set,
533 const InstructionSetFeatures* instruction_set_features,
534 SafeMap<std::string, std::string>* key_value_store,
Andreas Gampe3a2bd292016-01-26 17:23:47 -0800535 bool verify,
Nicolas Geoffray81f57d12016-12-20 13:17:09 +0000536 bool update_input_vdex,
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000537 /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map,
538 /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
539 CHECK(write_state_ == WriteState::kAddingDexFileSources);
540
David Brazdil7b49e6c2016-09-01 11:06:18 +0100541 // Record the ELF rodata section offset, i.e. the beginning of the OAT data.
542 if (!RecordOatDataOffset(oat_rodata)) {
543 return false;
544 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000545
546 std::unique_ptr<MemMap> dex_files_map;
547 std::vector<std::unique_ptr<const DexFile>> dex_files;
David Brazdil7b49e6c2016-09-01 11:06:18 +0100548
549 // Initialize VDEX and OAT headers.
550 if (kIsVdexEnabled) {
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000551 // Reserve space for Vdex header and checksums.
552 vdex_size_ = sizeof(VdexFile::Header) + oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum);
David Brazdil7b49e6c2016-09-01 11:06:18 +0100553 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100554 oat_size_ = InitOatHeader(instruction_set,
555 instruction_set_features,
556 dchecked_integral_cast<uint32_t>(oat_dex_files_.size()),
557 key_value_store);
David Brazdil7b49e6c2016-09-01 11:06:18 +0100558
559 ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, oat_header_.get());
560
561 if (kIsVdexEnabled) {
Andreas Gampe8bdda5a2017-06-08 15:30:36 -0700562 std::unique_ptr<BufferedOutputStream> vdex_out =
563 std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file));
David Brazdil7b49e6c2016-09-01 11:06:18 +0100564 // Write DEX files into VDEX, mmap and open them.
Nicolas Geoffray81f57d12016-12-20 13:17:09 +0000565 if (!WriteDexFiles(vdex_out.get(), vdex_file, update_input_vdex) ||
David Brazdil7b49e6c2016-09-01 11:06:18 +0100566 !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
567 return false;
568 }
David Brazdil7b49e6c2016-09-01 11:06:18 +0100569 } else {
Nicolas Geoffray81f57d12016-12-20 13:17:09 +0000570 DCHECK(!update_input_vdex);
David Brazdil7b49e6c2016-09-01 11:06:18 +0100571 // Write DEX files into OAT, mmap and open them.
Nicolas Geoffray81f57d12016-12-20 13:17:09 +0000572 if (!WriteDexFiles(oat_rodata, vdex_file, update_input_vdex) ||
David Brazdil7b49e6c2016-09-01 11:06:18 +0100573 !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
574 return false;
575 }
576
577 // Do a bulk checksum update for Dex[]. Doing it piece by piece would be
578 // difficult because we're not using the OutputStream directly.
579 if (!oat_dex_files_.empty()) {
580 size_t size = oat_size_ - oat_dex_files_[0].dex_file_offset_;
581 oat_header_->UpdateChecksum(dex_files_map->Begin(), size);
582 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000583 }
David Brazdil181e1cc2016-09-01 16:38:47 +0000584
Mathieu Chartier120aa282017-08-05 16:03:03 -0700585 // Write type lookup tables into the oat file.
David Brazdil181e1cc2016-09-01 16:38:47 +0000586 if (!WriteTypeLookupTables(&checksum_updating_rodata, dex_files)) {
587 return false;
588 }
589
Mathieu Chartier120aa282017-08-05 16:03:03 -0700590 // Write dex layout sections into the oat file.
591 if (!WriteDexLayoutSections(&checksum_updating_rodata, dex_files)) {
592 return false;
593 }
594
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000595 *opened_dex_files_map = std::move(dex_files_map);
596 *opened_dex_files = std::move(dex_files);
597 write_state_ = WriteState::kPrepareLayout;
598 return true;
599}
600
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100601void OatWriter::PrepareLayout(linker::MultiOatRelativePatcher* relative_patcher) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000602 CHECK(write_state_ == WriteState::kPrepareLayout);
603
Vladimir Marko944da602016-02-19 12:27:55 +0000604 relative_patcher_ = relative_patcher;
605 SetMultiOatRelativePatcherAdjustment();
606
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000607 if (compiling_boot_image_) {
608 CHECK(image_writer_ != nullptr);
Mathieu Chartierda5b28a2015-11-05 08:03:47 -0800609 }
Vladimir Markob163bb72015-03-31 21:49:49 +0100610 InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000611 CHECK_EQ(instruction_set, oat_header_->GetInstructionSet());
Vladimir Markof4da6752014-08-01 19:04:18 +0100612
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100613 {
614 TimingLogger::ScopedTiming split("InitBssLayout", timings_);
615 InitBssLayout(instruction_set);
616 }
617
David Brazdil7b49e6c2016-09-01 11:06:18 +0100618 uint32_t offset = oat_size_;
Ian Rogersca368cb2013-11-15 15:52:08 -0800619 {
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100620 TimingLogger::ScopedTiming split("InitClassOffsets", timings_);
621 offset = InitClassOffsets(offset);
622 }
623 {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000624 TimingLogger::ScopedTiming split("InitOatClasses", timings_);
Ian Rogersca368cb2013-11-15 15:52:08 -0800625 offset = InitOatClasses(offset);
626 }
627 {
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100628 TimingLogger::ScopedTiming split("InitMethodBssMappings", timings_);
629 offset = InitMethodBssMappings(offset);
630 }
631 {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000632 TimingLogger::ScopedTiming split("InitOatMaps", timings_);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100633 offset = InitOatMaps(offset);
634 }
635 {
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100636 TimingLogger::ScopedTiming split("InitOatDexFiles", timings_);
637 oat_header_->SetOatDexFilesOffset(offset);
638 offset = InitOatDexFiles(offset);
639 }
640 {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000641 TimingLogger::ScopedTiming split("InitOatCode", timings_);
Ian Rogersca368cb2013-11-15 15:52:08 -0800642 offset = InitOatCode(offset);
643 }
644 {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000645 TimingLogger::ScopedTiming split("InitOatCodeDexFiles", timings_);
Ian Rogersca368cb2013-11-15 15:52:08 -0800646 offset = InitOatCodeDexFiles(offset);
647 }
David Brazdil7b49e6c2016-09-01 11:06:18 +0100648 oat_size_ = offset;
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100649 bss_start_ = (bss_size_ != 0u) ? RoundUp(oat_size_, kPageSize) : 0u;
Vladimir Marko09d09432015-09-08 13:47:48 +0100650
Brian Carlstrome24fa612011-09-29 00:53:55 -0700651 CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
Mathieu Chartierda5b28a2015-11-05 08:03:47 -0800652 if (compiling_boot_image_) {
653 CHECK_EQ(image_writer_ != nullptr,
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000654 oat_header_->GetStoreValueByKey(OatHeader::kImageLocationKey) == nullptr);
Mathieu Chartierda5b28a2015-11-05 08:03:47 -0800655 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000656
657 write_state_ = WriteState::kWriteRoData;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700658}
659
Ian Rogers0571d352011-11-03 19:51:38 -0700660OatWriter::~OatWriter() {
Ian Rogers0571d352011-11-03 19:51:38 -0700661}
662
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100663class OatWriter::DexMethodVisitor {
664 public:
665 DexMethodVisitor(OatWriter* writer, size_t offset)
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100666 : writer_(writer),
667 offset_(offset),
668 dex_file_(nullptr),
669 class_def_index_(DexFile::kDexNoIndex) {}
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100670
671 virtual bool StartClass(const DexFile* dex_file, size_t class_def_index) {
672 DCHECK(dex_file_ == nullptr);
673 DCHECK_EQ(class_def_index_, DexFile::kDexNoIndex);
674 dex_file_ = dex_file;
675 class_def_index_ = class_def_index;
676 return true;
677 }
678
679 virtual bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) = 0;
680
681 virtual bool EndClass() {
682 if (kIsDebugBuild) {
683 dex_file_ = nullptr;
684 class_def_index_ = DexFile::kDexNoIndex;
685 }
686 return true;
687 }
688
689 size_t GetOffset() const {
690 return offset_;
691 }
692
693 protected:
694 virtual ~DexMethodVisitor() { }
695
696 OatWriter* const writer_;
697
698 // The offset is usually advanced for each visited method by the derived class.
699 size_t offset_;
700
701 // The dex file and class def index are set in StartClass().
702 const DexFile* dex_file_;
703 size_t class_def_index_;
704};
705
706class OatWriter::OatDexMethodVisitor : public DexMethodVisitor {
707 public:
708 OatDexMethodVisitor(OatWriter* writer, size_t offset)
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100709 : DexMethodVisitor(writer, offset),
710 oat_class_index_(0u),
711 method_offsets_index_(0u) {}
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100712
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100713 bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE {
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100714 DexMethodVisitor::StartClass(dex_file, class_def_index);
Mathieu Chartier3957bff2017-07-16 13:55:27 -0700715 if (kIsDebugBuild && writer_->MayHaveCompiledMethods()) {
716 // There are no oat classes if there aren't any compiled methods.
717 CHECK_LT(oat_class_index_, writer_->oat_classes_.size());
718 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100719 method_offsets_index_ = 0u;
720 return true;
721 }
722
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100723 bool EndClass() OVERRIDE {
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100724 ++oat_class_index_;
725 return DexMethodVisitor::EndClass();
726 }
727
728 protected:
729 size_t oat_class_index_;
730 size_t method_offsets_index_;
731};
732
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100733static bool HasCompiledCode(const CompiledMethod* method) {
734 // The dextodexcompiler puts the quickening info table into the CompiledMethod
735 // for simplicity. For such methods, we will emit an OatQuickMethodHeader
736 // only when vdex is disabled.
737 return method != nullptr && (!method->GetQuickCode().empty() || !kIsVdexEnabled);
738}
739
740static bool HasQuickeningInfo(const CompiledMethod* method) {
741 return method != nullptr && method->GetQuickCode().empty() && !method->GetVmapTable().empty();
742}
743
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100744class OatWriter::InitBssLayoutMethodVisitor : public DexMethodVisitor {
745 public:
746 explicit InitBssLayoutMethodVisitor(OatWriter* writer)
747 : DexMethodVisitor(writer, /* offset */ 0u) {}
748
749 bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,
750 const ClassDataItemIterator& it) OVERRIDE {
751 // Look for patches with .bss references and prepare maps with placeholders for their offsets.
752 CompiledMethod* compiled_method = writer_->compiler_driver_->GetCompiledMethod(
753 MethodReference(dex_file_, it.GetMemberIndex()));
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100754 if (HasCompiledCode(compiled_method)) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100755 for (const LinkerPatch& patch : compiled_method->GetPatches()) {
756 if (patch.GetType() == LinkerPatch::Type::kMethodBssEntry) {
757 MethodReference target_method = patch.TargetMethod();
758 auto refs_it = writer_->bss_method_entry_references_.find(target_method.dex_file);
759 if (refs_it == writer_->bss_method_entry_references_.end()) {
760 refs_it = writer_->bss_method_entry_references_.Put(
761 target_method.dex_file,
762 BitVector(target_method.dex_file->NumMethodIds(),
763 /* expandable */ false,
764 Allocator::GetMallocAllocator()));
765 refs_it->second.ClearAllBits();
766 }
767 refs_it->second.SetBit(target_method.dex_method_index);
768 writer_->bss_method_entries_.Overwrite(target_method, /* placeholder */ 0u);
769 } else if (patch.GetType() == LinkerPatch::Type::kTypeBssEntry) {
770 TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex());
771 writer_->bss_type_entries_.Overwrite(ref, /* placeholder */ 0u);
772 } else if (patch.GetType() == LinkerPatch::Type::kStringBssEntry) {
773 StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
774 writer_->bss_string_entries_.Overwrite(ref, /* placeholder */ 0u);
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +0100775 } else if (patch.GetType() == LinkerPatch::Type::kStringInternTable) {
776 writer_->map_boot_image_tables_to_bss_ = true;
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100777 }
778 }
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100779 } else {
780 DCHECK(compiled_method == nullptr || compiled_method->GetPatches().empty());
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100781 }
782 return true;
783 }
784};
785
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100786class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor {
787 public:
788 InitOatClassesMethodVisitor(OatWriter* writer, size_t offset)
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100789 : DexMethodVisitor(writer, offset),
790 compiled_methods_(),
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100791 compiled_methods_with_code_(0u) {
Vladimir Marko49b0f452015-12-10 13:49:19 +0000792 size_t num_classes = 0u;
793 for (const OatDexFile& oat_dex_file : writer_->oat_dex_files_) {
794 num_classes += oat_dex_file.class_offsets_.size();
795 }
Mathieu Chartier3957bff2017-07-16 13:55:27 -0700796 // If we aren't compiling only reserve headers.
797 writer_->oat_class_headers_.reserve(num_classes);
798 if (writer->MayHaveCompiledMethods()) {
799 writer->oat_classes_.reserve(num_classes);
800 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100801 compiled_methods_.reserve(256u);
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100802 // If there are any classes, the class offsets allocation aligns the offset.
803 DCHECK(num_classes == 0u || IsAligned<4u>(offset));
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100804 }
805
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100806 bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE {
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100807 DexMethodVisitor::StartClass(dex_file, class_def_index);
808 compiled_methods_.clear();
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100809 compiled_methods_with_code_ = 0u;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100810 return true;
811 }
812
Artem Udovichenkod9786b02015-10-14 16:36:55 +0300813 bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100814 const ClassDataItemIterator& it) OVERRIDE {
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100815 // Fill in the compiled_methods_ array for methods that have a
816 // CompiledMethod. We track the number of non-null entries in
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100817 // compiled_methods_with_code_ since we only want to allocate
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100818 // OatMethodOffsets for the compiled methods.
819 uint32_t method_idx = it.GetMemberIndex();
820 CompiledMethod* compiled_method =
821 writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
822 compiled_methods_.push_back(compiled_method);
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100823 if (HasCompiledCode(compiled_method)) {
824 ++compiled_methods_with_code_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100825 }
826 return true;
827 }
828
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100829 bool EndClass() OVERRIDE {
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100830 ClassReference class_ref(dex_file_, class_def_index_);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100831 mirror::Class::Status status;
Andreas Gampebb846102017-05-11 21:03:35 -0700832 bool found = writer_->compiler_driver_->GetCompiledClass(class_ref, &status);
833 if (!found) {
Mathieu Chartier0733dc82017-07-17 14:05:28 -0700834 VerificationResults* results = writer_->compiler_driver_->GetVerificationResults();
835 if (results != nullptr && results->IsClassRejected(class_ref)) {
Andreas Gampebb846102017-05-11 21:03:35 -0700836 // The oat class status is used only for verification of resolved classes,
837 // so use kStatusErrorResolved whether the class was resolved or unresolved
838 // during compile-time verification.
839 status = mirror::Class::kStatusErrorResolved;
840 } else {
841 status = mirror::Class::kStatusNotReady;
842 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100843 }
844
Mathieu Chartier3957bff2017-07-16 13:55:27 -0700845 writer_->oat_class_headers_.emplace_back(offset_,
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100846 compiled_methods_with_code_,
Mathieu Chartier3957bff2017-07-16 13:55:27 -0700847 compiled_methods_.size(),
848 status);
849 OatClassHeader& header = writer_->oat_class_headers_.back();
850 offset_ += header.SizeOf();
851 if (writer_->MayHaveCompiledMethods()) {
852 writer_->oat_classes_.emplace_back(compiled_methods_,
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100853 compiled_methods_with_code_,
Mathieu Chartier3957bff2017-07-16 13:55:27 -0700854 header.type_);
855 offset_ += writer_->oat_classes_.back().SizeOf();
856 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100857 return DexMethodVisitor::EndClass();
858 }
859
860 private:
Vladimir Marko49b0f452015-12-10 13:49:19 +0000861 dchecked_vector<CompiledMethod*> compiled_methods_;
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100862 size_t compiled_methods_with_code_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100863};
864
865class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor {
866 public:
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100867 InitCodeMethodVisitor(OatWriter* writer, size_t offset)
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100868 : OatDexMethodVisitor(writer, offset),
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100869 debuggable_(writer->GetCompilerDriver()->GetCompilerOptions().GetDebuggable()) {
David Srbeckyf8980872015-05-22 17:04:47 +0100870 writer_->absolute_patch_locations_.reserve(
Vladimir Markof4da6752014-08-01 19:04:18 +0100871 writer_->compiler_driver_->GetNonRelativeLinkerPatchCount());
872 }
873
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100874 bool EndClass() OVERRIDE {
Vladimir Markof4da6752014-08-01 19:04:18 +0100875 OatDexMethodVisitor::EndClass();
876 if (oat_class_index_ == writer_->oat_classes_.size()) {
Vladimir Marko71b0ddf2015-04-02 19:45:06 +0100877 offset_ = writer_->relative_patcher_->ReserveSpaceEnd(offset_);
Vladimir Markof4da6752014-08-01 19:04:18 +0100878 }
879 return true;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100880 }
881
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100882 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700883 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko49b0f452015-12-10 13:49:19 +0000884 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100885 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
886
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100887 if (HasCompiledCode(compiled_method)) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100888 // Derived from CompiledMethod.
889 uint32_t quick_code_offset = 0;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100890
Vladimir Marko35831e82015-09-11 11:59:18 +0100891 ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
892 uint32_t code_size = quick_code.size() * sizeof(uint8_t);
Elliott Hughes956af0f2014-12-11 14:34:28 -0800893 uint32_t thumb_offset = compiled_method->CodeDelta();
Elliott Hughes956af0f2014-12-11 14:34:28 -0800894
David Srbecky009e2a62015-04-15 02:46:30 +0100895 // Deduplicate code arrays if we are not producing debuggable code.
Vladimir Marko9d07e3d2016-03-31 12:02:28 +0100896 bool deduped = true;
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800897 MethodReference method_ref(dex_file_, it.GetMemberIndex());
Nicolas Geoffrayed6195a2015-07-13 17:02:30 +0000898 if (debuggable_) {
Vladimir Marko944da602016-02-19 12:27:55 +0000899 quick_code_offset = writer_->relative_patcher_->GetOffset(method_ref);
900 if (quick_code_offset != 0u) {
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800901 // Duplicate methods, we want the same code for both of them so that the oat writer puts
902 // the same code in both ArtMethods so that we do not get different oat code at runtime.
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800903 } else {
904 quick_code_offset = NewQuickCodeOffset(compiled_method, it, thumb_offset);
Vladimir Marko9d07e3d2016-03-31 12:02:28 +0100905 deduped = false;
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800906 }
Nicolas Geoffrayed6195a2015-07-13 17:02:30 +0000907 } else {
Vladimir Marko9d07e3d2016-03-31 12:02:28 +0100908 quick_code_offset = dedupe_map_.GetOrCreate(
909 compiled_method,
910 [this, &deduped, compiled_method, &it, thumb_offset]() {
911 deduped = false;
912 return NewQuickCodeOffset(compiled_method, it, thumb_offset);
913 });
Elliott Hughes956af0f2014-12-11 14:34:28 -0800914 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100915
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100916 if (code_size != 0) {
Vladimir Marko944da602016-02-19 12:27:55 +0000917 if (writer_->relative_patcher_->GetOffset(method_ref) != 0u) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100918 // TODO: Should this be a hard failure?
919 LOG(WARNING) << "Multiple definitions of "
David Sehr709b0702016-10-13 09:12:37 -0700920 << method_ref.dex_file->PrettyMethod(method_ref.dex_method_index)
Vladimir Marko944da602016-02-19 12:27:55 +0000921 << " offsets " << writer_->relative_patcher_->GetOffset(method_ref)
922 << " " << quick_code_offset;
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100923 } else {
Vladimir Marko944da602016-02-19 12:27:55 +0000924 writer_->relative_patcher_->SetOffset(method_ref, quick_code_offset);
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100925 }
Elliott Hughes956af0f2014-12-11 14:34:28 -0800926 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100927
Elliott Hughes956af0f2014-12-11 14:34:28 -0800928 // Update quick method header.
929 DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size());
930 OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
Mingyao Yang063fc772016-08-02 11:02:54 -0700931 uint32_t vmap_table_offset = method_header->GetVmapTableOffset();
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700932 uint32_t method_info_offset = method_header->GetMethodInfoOffset();
Elliott Hughes956af0f2014-12-11 14:34:28 -0800933 // The code offset was 0 when the mapping/vmap table offset was set, so it's set
934 // to 0-offset and we need to adjust it by code_offset.
935 uint32_t code_offset = quick_code_offset - thumb_offset;
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100936 if (!compiled_method->GetQuickCode().empty()) {
937 // If the code is compiled, we write the offset of the stack map relative
938 // to the code,
939 if (vmap_table_offset != 0u) {
940 vmap_table_offset += code_offset;
941 DCHECK_LT(vmap_table_offset, code_offset);
942 }
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700943 if (method_info_offset != 0u) {
944 method_info_offset += code_offset;
945 DCHECK_LT(method_info_offset, code_offset);
946 }
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100947 } else {
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100948 CHECK(!kIsVdexEnabled);
949 // We write the offset of the quickening info relative to the code.
950 vmap_table_offset += code_offset;
951 DCHECK_LT(vmap_table_offset, code_offset);
Elliott Hughes956af0f2014-12-11 14:34:28 -0800952 }
Elliott Hughes956af0f2014-12-11 14:34:28 -0800953 uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
954 uint32_t core_spill_mask = compiled_method->GetCoreSpillMask();
955 uint32_t fp_spill_mask = compiled_method->GetFpSpillMask();
Vladimir Marko9d07e3d2016-03-31 12:02:28 +0100956 *method_header = OatQuickMethodHeader(vmap_table_offset,
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700957 method_info_offset,
Vladimir Marko9d07e3d2016-03-31 12:02:28 +0100958 frame_size_in_bytes,
959 core_spill_mask,
960 fp_spill_mask,
961 code_size);
Vladimir Marko7624d252014-05-02 14:40:15 +0100962
Nicolas Geoffrayed6195a2015-07-13 17:02:30 +0000963 if (!deduped) {
Elliott Hughes956af0f2014-12-11 14:34:28 -0800964 // Update offsets. (Checksum is updated when writing.)
965 offset_ += sizeof(*method_header); // Method header is prepended before code.
966 offset_ += code_size;
967 // Record absolute patch locations.
968 if (!compiled_method->GetPatches().empty()) {
969 uintptr_t base_loc = offset_ - code_size - writer_->oat_header_->GetExecutableOffset();
970 for (const LinkerPatch& patch : compiled_method->GetPatches()) {
Vladimir Marko20f85592015-03-19 10:07:02 +0000971 if (!patch.IsPcRelative()) {
David Srbeckyf8980872015-05-22 17:04:47 +0100972 writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset());
Vladimir Markof4da6752014-08-01 19:04:18 +0100973 }
974 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100975 }
Elliott Hughes956af0f2014-12-11 14:34:28 -0800976 }
Alex Light78382fa2014-06-06 15:45:32 -0700977
David Srbecky91cc06c2016-03-07 16:13:58 +0000978 const CompilerOptions& compiler_options = writer_->compiler_driver_->GetCompilerOptions();
David Srbecky197160d2016-03-07 17:33:57 +0000979 // Exclude quickened dex methods (code_size == 0) since they have no native code.
980 if (compiler_options.GenerateAnyDebugInfo() && code_size != 0) {
981 bool has_code_info = method_header->IsOptimized();
Elliott Hughes956af0f2014-12-11 14:34:28 -0800982 // Record debug information for this function if we are doing that.
David Srbecky09c2a6b2016-03-11 17:11:44 +0000983 debug::MethodDebugInfo info = debug::MethodDebugInfo();
984 info.trampoline_name = nullptr;
David Srbecky197160d2016-03-07 17:33:57 +0000985 info.dex_file = dex_file_;
986 info.class_def_index = class_def_index_;
987 info.dex_method_index = it.GetMemberIndex();
988 info.access_flags = it.GetMethodAccessFlags();
989 info.code_item = it.GetMethodCodeItem();
990 info.isa = compiled_method->GetInstructionSet();
991 info.deduped = deduped;
992 info.is_native_debuggable = compiler_options.GetNativeDebuggable();
993 info.is_optimized = method_header->IsOptimized();
994 info.is_code_address_text_relative = true;
995 info.code_address = code_offset - writer_->oat_header_->GetExecutableOffset();
996 info.code_size = code_size;
997 info.frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
998 info.code_info = has_code_info ? compiled_method->GetVmapTable().data() : nullptr;
999 info.cfi = compiled_method->GetCFIInfo();
1000 writer_->method_info_.push_back(info);
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001001 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001002
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001003 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1004 OatMethodOffsets* offsets = &oat_class->method_offsets_[method_offsets_index_];
1005 offsets->code_offset_ = quick_code_offset;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001006 ++method_offsets_index_;
1007 }
1008
1009 return true;
1010 }
1011
1012 private:
Vladimir Marko20f85592015-03-19 10:07:02 +00001013 struct CodeOffsetsKeyComparator {
1014 bool operator()(const CompiledMethod* lhs, const CompiledMethod* rhs) const {
Vladimir Marko35831e82015-09-11 11:59:18 +01001015 // Code is deduplicated by CompilerDriver, compare only data pointers.
1016 if (lhs->GetQuickCode().data() != rhs->GetQuickCode().data()) {
1017 return lhs->GetQuickCode().data() < rhs->GetQuickCode().data();
Vladimir Marko20f85592015-03-19 10:07:02 +00001018 }
1019 // If the code is the same, all other fields are likely to be the same as well.
Vladimir Marko35831e82015-09-11 11:59:18 +01001020 if (UNLIKELY(lhs->GetVmapTable().data() != rhs->GetVmapTable().data())) {
1021 return lhs->GetVmapTable().data() < rhs->GetVmapTable().data();
Vladimir Marko20f85592015-03-19 10:07:02 +00001022 }
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001023 if (UNLIKELY(lhs->GetMethodInfo().data() != rhs->GetMethodInfo().data())) {
1024 return lhs->GetMethodInfo().data() < rhs->GetMethodInfo().data();
1025 }
Vladimir Marko35831e82015-09-11 11:59:18 +01001026 if (UNLIKELY(lhs->GetPatches().data() != rhs->GetPatches().data())) {
1027 return lhs->GetPatches().data() < rhs->GetPatches().data();
Vladimir Marko20f85592015-03-19 10:07:02 +00001028 }
1029 return false;
1030 }
1031 };
1032
David Srbecky009e2a62015-04-15 02:46:30 +01001033 uint32_t NewQuickCodeOffset(CompiledMethod* compiled_method,
1034 const ClassDataItemIterator& it,
1035 uint32_t thumb_offset) {
1036 offset_ = writer_->relative_patcher_->ReserveSpace(
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001037 offset_, compiled_method, MethodReference(dex_file_, it.GetMemberIndex()));
Vladimir Marko0c737df2016-08-01 16:33:16 +01001038 offset_ += CodeAlignmentSize(offset_, *compiled_method);
1039 DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader),
David Srbecky009e2a62015-04-15 02:46:30 +01001040 GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
1041 return offset_ + sizeof(OatQuickMethodHeader) + thumb_offset;
1042 }
1043
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001044 // Deduplication is already done on a pointer basis by the compiler driver,
1045 // so we can simply compare the pointers to find out if things are duplicated.
Vladimir Marko8a630572014-04-09 18:45:35 +01001046 SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_;
David Srbecky2f6cdb02015-04-11 00:17:53 +01001047
David Srbecky009e2a62015-04-15 02:46:30 +01001048 // Cache of compiler's --debuggable option.
1049 const bool debuggable_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001050};
1051
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001052class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor {
1053 public:
1054 InitMapMethodVisitor(OatWriter* writer, size_t offset)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001055 : OatDexMethodVisitor(writer, offset) {}
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001056
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001057 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001058 OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko49b0f452015-12-10 13:49:19 +00001059 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001060 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1061
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01001062 if (HasCompiledCode(compiled_method)) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001063 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01001064 DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].GetVmapTableOffset(), 0u);
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001065
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01001066 ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
1067 uint32_t map_size = map.size() * sizeof(map[0]);
1068 if (map_size != 0u) {
1069 size_t offset = dedupe_map_.GetOrCreate(
1070 map.data(),
1071 [this, map_size]() {
1072 uint32_t new_offset = offset_;
1073 offset_ += map_size;
1074 return new_offset;
1075 });
1076 // Code offset is not initialized yet, so set the map offset to 0u-offset.
1077 DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u);
1078 oat_class->method_headers_[method_offsets_index_].SetVmapTableOffset(0u - offset);
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001079 }
1080 ++method_offsets_index_;
1081 }
1082
1083 return true;
1084 }
1085
1086 private:
1087 // Deduplication is already done on a pointer basis by the compiler driver,
1088 // so we can simply compare the pointers to find out if things are duplicated.
Vladimir Marko35831e82015-09-11 11:59:18 +01001089 SafeMap<const uint8_t*, uint32_t> dedupe_map_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001090};
1091
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001092class OatWriter::InitMethodInfoVisitor : public OatDexMethodVisitor {
1093 public:
1094 InitMethodInfoVisitor(OatWriter* writer, size_t offset) : OatDexMethodVisitor(writer, offset) {}
1095
1096 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001097 OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001098 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1099 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1100
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01001101 if (HasCompiledCode(compiled_method)) {
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001102 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1103 DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].GetMethodInfoOffset(), 0u);
1104 ArrayRef<const uint8_t> map = compiled_method->GetMethodInfo();
1105 const uint32_t map_size = map.size() * sizeof(map[0]);
1106 if (map_size != 0u) {
1107 size_t offset = dedupe_map_.GetOrCreate(
1108 map.data(),
1109 [this, map_size]() {
1110 uint32_t new_offset = offset_;
1111 offset_ += map_size;
1112 return new_offset;
1113 });
1114 // Code offset is not initialized yet, so set the map offset to 0u-offset.
1115 DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u);
1116 oat_class->method_headers_[method_offsets_index_].SetMethodInfoOffset(0u - offset);
1117 }
1118 ++method_offsets_index_;
1119 }
1120
1121 return true;
1122 }
1123
1124 private:
1125 // Deduplication is already done on a pointer basis by the compiler driver,
1126 // so we can simply compare the pointers to find out if things are duplicated.
1127 SafeMap<const uint8_t*, uint32_t> dedupe_map_;
1128};
1129
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001130class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor {
1131 public:
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001132 InitImageMethodVisitor(OatWriter* writer,
1133 size_t offset,
1134 const std::vector<const DexFile*>* dex_files)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001135 : OatDexMethodVisitor(writer, offset),
1136 pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())),
Vladimir Marko07bfbac2017-07-06 14:55:02 +01001137 class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr),
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001138 dex_files_(dex_files),
1139 class_linker_(Runtime::Current()->GetClassLinker()) {}
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001140
1141 // Handle copied methods here. Copy pointer to quick code from
1142 // an origin method to a copied method only if they are
1143 // in the same oat file. If the origin and the copied methods are
1144 // in different oat files don't touch the copied method.
1145 // References to other oat files are not supported yet.
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001146 bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001147 REQUIRES_SHARED(Locks::mutator_lock_) {
1148 OatDexMethodVisitor::StartClass(dex_file, class_def_index);
1149 // Skip classes that are not in the image.
1150 if (!IsImageClass()) {
1151 return true;
1152 }
Vladimir Marko07bfbac2017-07-06 14:55:02 +01001153 ObjPtr<mirror::DexCache> dex_cache = class_linker_->FindDexCache(Thread::Current(), *dex_file);
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001154 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
1155 mirror::Class* klass = dex_cache->GetResolvedType(class_def.class_idx_);
1156 if (klass != nullptr) {
1157 for (ArtMethod& method : klass->GetCopiedMethods(pointer_size_)) {
1158 // Find origin method. Declaring class and dex_method_idx
1159 // in the copied method should be the same as in the origin
1160 // method.
1161 mirror::Class* declaring_class = method.GetDeclaringClass();
Vladimir Markoba118822017-06-12 15:41:56 +01001162 ArtMethod* origin = declaring_class->FindClassMethod(
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001163 declaring_class->GetDexCache(),
1164 method.GetDexMethodIndex(),
1165 pointer_size_);
1166 CHECK(origin != nullptr);
Vladimir Markoba118822017-06-12 15:41:56 +01001167 CHECK(!origin->IsDirect());
1168 CHECK(origin->GetDeclaringClass() == declaring_class);
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001169 if (IsInOatFile(&declaring_class->GetDexFile())) {
1170 const void* code_ptr =
1171 origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
1172 if (code_ptr == nullptr) {
1173 methods_to_process_.push_back(std::make_pair(&method, origin));
1174 } else {
1175 method.SetEntryPointFromQuickCompiledCodePtrSize(
1176 code_ptr, pointer_size_);
1177 }
1178 }
1179 }
1180 }
1181 return true;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001182 }
1183
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001184 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001185 REQUIRES_SHARED(Locks::mutator_lock_) {
Jeff Haodcdc85b2015-12-04 14:06:18 -08001186 // Skip methods that are not in the image.
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001187 if (!IsImageClass()) {
Jeff Haodcdc85b2015-12-04 14:06:18 -08001188 return true;
1189 }
1190
Vladimir Marko49b0f452015-12-10 13:49:19 +00001191 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001192 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1193
Mathieu Chartier957ca1c2014-11-21 16:51:29 -08001194 OatMethodOffsets offsets(0u);
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01001195 if (HasCompiledCode(compiled_method)) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001196 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1197 offsets = oat_class->method_offsets_[method_offsets_index_];
1198 ++method_offsets_index_;
1199 }
1200
Vladimir Marko07bfbac2017-07-06 14:55:02 +01001201 Thread* self = Thread::Current();
1202 ObjPtr<mirror::DexCache> dex_cache = class_linker_->FindDexCache(self, *dex_file_);
Mathieu Chartierfbc31082016-01-24 11:59:56 -08001203 ArtMethod* method;
1204 if (writer_->HasBootImage()) {
1205 const InvokeType invoke_type = it.GetMethodInvokeType(
1206 dex_file_->GetClassDef(class_def_index_));
Vladimir Marko07bfbac2017-07-06 14:55:02 +01001207 // Unchecked as we hold mutator_lock_ on entry.
1208 ScopedObjectAccessUnchecked soa(self);
1209 StackHandleScope<1> hs(self);
Vladimir Markoba118822017-06-12 15:41:56 +01001210 method = class_linker_->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
Mathieu Chartierfbc31082016-01-24 11:59:56 -08001211 *dex_file_,
1212 it.GetMemberIndex(),
Vladimir Marko07bfbac2017-07-06 14:55:02 +01001213 hs.NewHandle(dex_cache),
Mathieu Chartierfbc31082016-01-24 11:59:56 -08001214 ScopedNullHandle<mirror::ClassLoader>(),
1215 nullptr,
1216 invoke_type);
1217 if (method == nullptr) {
Andreas Gampe3fec9ac2016-09-13 10:47:28 -07001218 LOG(FATAL_WITHOUT_ABORT) << "Unexpected failure to resolve a method: "
David Sehr709b0702016-10-13 09:12:37 -07001219 << dex_file_->PrettyMethod(it.GetMemberIndex(), true);
Vladimir Marko07bfbac2017-07-06 14:55:02 +01001220 self->AssertPendingException();
1221 mirror::Throwable* exc = self->GetException();
Mathieu Chartierfbc31082016-01-24 11:59:56 -08001222 std::string dump = exc->Dump();
1223 LOG(FATAL) << dump;
1224 UNREACHABLE();
1225 }
1226 } else {
Vladimir Marko07bfbac2017-07-06 14:55:02 +01001227 // Should already have been resolved by the compiler.
Mathieu Chartierfbc31082016-01-24 11:59:56 -08001228 // It may not be resolved if the class failed to verify, in this case, don't set the
Vladimir Marko07bfbac2017-07-06 14:55:02 +01001229 // entrypoint. This is not fatal since we shall use a resolution method.
1230 method = class_linker_->LookupResolvedMethod(it.GetMemberIndex(), dex_cache, class_loader_);
Andreas Gamped9efea62014-07-21 22:56:08 -07001231 }
Mathieu Chartierfbc31082016-01-24 11:59:56 -08001232 if (method != nullptr &&
1233 compiled_method != nullptr &&
1234 compiled_method->GetQuickCode().size() != 0) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001235 method->SetEntryPointFromQuickCompiledCodePtrSize(
1236 reinterpret_cast<void*>(offsets.code_offset_), pointer_size_);
1237 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001238
1239 return true;
1240 }
Jeff Haoc7d11882015-02-03 15:08:39 -08001241
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001242 // Check whether current class is image class
1243 bool IsImageClass() {
1244 const DexFile::TypeId& type_id =
1245 dex_file_->GetTypeId(dex_file_->GetClassDef(class_def_index_).class_idx_);
1246 const char* class_descriptor = dex_file_->GetTypeDescriptor(type_id);
1247 return writer_->GetCompilerDriver()->IsImageClass(class_descriptor);
1248 }
1249
1250 // Check whether specified dex file is in the compiled oat file.
1251 bool IsInOatFile(const DexFile* dex_file) {
1252 return ContainsElement(*dex_files_, dex_file);
1253 }
1254
1255 // Assign a pointer to quick code for copied methods
1256 // not handled in the method StartClass
1257 void Postprocess() {
1258 for (std::pair<ArtMethod*, ArtMethod*>& p : methods_to_process_) {
1259 ArtMethod* method = p.first;
1260 ArtMethod* origin = p.second;
1261 const void* code_ptr =
1262 origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
1263 if (code_ptr != nullptr) {
1264 method->SetEntryPointFromQuickCompiledCodePtrSize(code_ptr, pointer_size_);
1265 }
1266 }
1267 }
1268
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001269 private:
Andreas Gampe542451c2016-07-26 09:02:02 -07001270 const PointerSize pointer_size_;
Vladimir Marko07bfbac2017-07-06 14:55:02 +01001271 ObjPtr<mirror::ClassLoader> class_loader_;
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001272 const std::vector<const DexFile*>* dex_files_;
1273 ClassLinker* const class_linker_;
1274 std::vector<std::pair<ArtMethod*, ArtMethod*>> methods_to_process_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001275};
1276
1277class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
1278 public:
1279 WriteCodeMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset,
Vladimir Markof4da6752014-08-01 19:04:18 +01001280 size_t relative_offset) SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001281 : OatDexMethodVisitor(writer, relative_offset),
1282 pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())),
1283 class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr),
1284 out_(out),
1285 file_offset_(file_offset),
1286 soa_(Thread::Current()),
1287 no_thread_suspension_("OatWriter patching"),
1288 class_linker_(Runtime::Current()->GetClassLinker()),
1289 dex_cache_(nullptr) {
Vladimir Marko09d09432015-09-08 13:47:48 +01001290 patched_code_.reserve(16 * KB);
Mathieu Chartierda5b28a2015-11-05 08:03:47 -08001291 if (writer_->HasBootImage()) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001292 // If we're creating the image, the address space must be ready so that we can apply patches.
1293 CHECK(writer_->image_writer_->IsImageAddressSpaceReady());
Vladimir Markof4da6752014-08-01 19:04:18 +01001294 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001295 }
1296
Vladimir Markof4da6752014-08-01 19:04:18 +01001297 ~WriteCodeMethodVisitor() UNLOCK_FUNCTION(Locks::mutator_lock_) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001298 }
1299
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001300 bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001301 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001302 OatDexMethodVisitor::StartClass(dex_file, class_def_index);
Mathieu Chartier72041a02017-07-14 18:23:25 -07001303 if (writer_->GetCompilerDriver()->GetCompilerOptions().IsAotCompilationEnabled()) {
1304 // Only need to set the dex cache if we have compilation. Other modes might have unloaded it.
1305 if (dex_cache_ == nullptr || dex_cache_->GetDexFile() != dex_file) {
1306 dex_cache_ = class_linker_->FindDexCache(Thread::Current(), *dex_file);
1307 DCHECK(dex_cache_ != nullptr);
1308 }
Vladimir Markof4da6752014-08-01 19:04:18 +01001309 }
1310 return true;
1311 }
1312
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001313 bool EndClass() OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001314 bool result = OatDexMethodVisitor::EndClass();
1315 if (oat_class_index_ == writer_->oat_classes_.size()) {
1316 DCHECK(result); // OatDexMethodVisitor::EndClass() never fails.
Vladimir Marko20f85592015-03-19 10:07:02 +00001317 offset_ = writer_->relative_patcher_->WriteThunks(out_, offset_);
Vladimir Markof4da6752014-08-01 19:04:18 +01001318 if (UNLIKELY(offset_ == 0u)) {
1319 PLOG(ERROR) << "Failed to write final relative call thunks";
1320 result = false;
1321 }
1322 }
1323 return result;
1324 }
1325
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001326 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001327 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko49b0f452015-12-10 13:49:19 +00001328 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001329 const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1330
Mathieu Chartier673ed3d2015-08-28 14:56:43 -07001331 // No thread suspension since dex_cache_ that may get invalidated if that occurs.
Mathieu Chartier268764d2016-09-13 12:09:38 -07001332 ScopedAssertNoThreadSuspension tsc(__FUNCTION__);
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01001333 if (HasCompiledCode(compiled_method)) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001334 size_t file_offset = file_offset_;
1335 OutputStream* out = out_;
1336
Vladimir Marko35831e82015-09-11 11:59:18 +01001337 ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
1338 uint32_t code_size = quick_code.size() * sizeof(uint8_t);
Nicolas Geoffrayf0758792015-07-13 11:56:00 +00001339
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001340 // Deduplicate code arrays.
1341 const OatMethodOffsets& method_offsets = oat_class->method_offsets_[method_offsets_index_];
1342 if (method_offsets.code_offset_ > offset_) {
1343 offset_ = writer_->relative_patcher_->WriteThunks(out, offset_);
1344 if (offset_ == 0u) {
1345 ReportWriteFailure("relative call thunk", it);
1346 return false;
Nicolas Geoffrayf0758792015-07-13 11:56:00 +00001347 }
Vladimir Marko0c737df2016-08-01 16:33:16 +01001348 uint32_t alignment_size = CodeAlignmentSize(offset_, *compiled_method);
1349 if (alignment_size != 0) {
1350 if (!writer_->WriteCodeAlignment(out, alignment_size)) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001351 ReportWriteFailure("code alignment padding", it);
1352 return false;
1353 }
Vladimir Marko0c737df2016-08-01 16:33:16 +01001354 offset_ += alignment_size;
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001355 DCHECK_OFFSET_();
1356 }
Vladimir Marko0c737df2016-08-01 16:33:16 +01001357 DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader),
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001358 GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
1359 DCHECK_EQ(method_offsets.code_offset_,
1360 offset_ + sizeof(OatQuickMethodHeader) + compiled_method->CodeDelta())
David Sehr709b0702016-10-13 09:12:37 -07001361 << dex_file_->PrettyMethod(it.GetMemberIndex());
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001362 const OatQuickMethodHeader& method_header =
1363 oat_class->method_headers_[method_offsets_index_];
Vladimir Markoe079e212016-05-25 12:49:49 +01001364 if (!out->WriteFully(&method_header, sizeof(method_header))) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001365 ReportWriteFailure("method header", it);
1366 return false;
1367 }
1368 writer_->size_method_header_ += sizeof(method_header);
1369 offset_ += sizeof(method_header);
Nicolas Geoffrayed6195a2015-07-13 17:02:30 +00001370 DCHECK_OFFSET_();
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001371
1372 if (!compiled_method->GetPatches().empty()) {
Vladimir Marko35831e82015-09-11 11:59:18 +01001373 patched_code_.assign(quick_code.begin(), quick_code.end());
1374 quick_code = ArrayRef<const uint8_t>(patched_code_);
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001375 for (const LinkerPatch& patch : compiled_method->GetPatches()) {
Vladimir Marko944da602016-02-19 12:27:55 +00001376 uint32_t literal_offset = patch.LiteralOffset();
Vladimir Markodb8e62d2016-03-30 16:30:21 +01001377 switch (patch.GetType()) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001378 case LinkerPatch::Type::kMethodBssEntry: {
1379 uint32_t target_offset =
1380 writer_->bss_start_ + writer_->bss_method_entries_.Get(patch.TargetMethod());
1381 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1382 patch,
1383 offset_ + literal_offset,
1384 target_offset);
1385 break;
1386 }
Vladimir Markodb8e62d2016-03-30 16:30:21 +01001387 case LinkerPatch::Type::kCallRelative: {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001388 // NOTE: Relative calls across oat files are not supported.
1389 uint32_t target_offset = GetTargetOffset(patch);
1390 writer_->relative_patcher_->PatchCall(&patched_code_,
1391 literal_offset,
1392 offset_ + literal_offset,
1393 target_offset);
1394 break;
1395 }
Vladimir Markodb8e62d2016-03-30 16:30:21 +01001396 case LinkerPatch::Type::kStringRelative: {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001397 uint32_t target_offset = GetTargetObjectOffset(GetTargetString(patch));
1398 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1399 patch,
1400 offset_ + literal_offset,
1401 target_offset);
1402 break;
1403 }
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001404 case LinkerPatch::Type::kStringInternTable: {
1405 uint32_t target_offset = GetInternTableEntryOffset(patch);
1406 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1407 patch,
1408 offset_ + literal_offset,
1409 target_offset);
1410 break;
1411 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00001412 case LinkerPatch::Type::kStringBssEntry: {
1413 StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001414 uint32_t target_offset =
1415 writer_->bss_start_ + writer_->bss_string_entries_.Get(ref);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001416 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1417 patch,
1418 offset_ + literal_offset,
1419 target_offset);
1420 break;
1421 }
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01001422 case LinkerPatch::Type::kTypeRelative: {
1423 uint32_t target_offset = GetTargetObjectOffset(GetTargetType(patch));
1424 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1425 patch,
1426 offset_ + literal_offset,
1427 target_offset);
1428 break;
1429 }
Vladimir Marko6bec91c2017-01-09 15:03:12 +00001430 case LinkerPatch::Type::kTypeBssEntry: {
1431 TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex());
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001432 uint32_t target_offset = writer_->bss_start_ + writer_->bss_type_entries_.Get(ref);
Vladimir Marko6bec91c2017-01-09 15:03:12 +00001433 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1434 patch,
1435 offset_ + literal_offset,
1436 target_offset);
1437 break;
1438 }
Vladimir Markodb8e62d2016-03-30 16:30:21 +01001439 case LinkerPatch::Type::kCall: {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001440 uint32_t target_offset = GetTargetOffset(patch);
1441 PatchCodeAddress(&patched_code_, literal_offset, target_offset);
1442 break;
1443 }
Vladimir Marko65979462017-05-19 17:25:12 +01001444 case LinkerPatch::Type::kMethodRelative: {
1445 uint32_t target_offset = GetTargetMethodOffset(GetTargetMethod(patch));
1446 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1447 patch,
1448 offset_ + literal_offset,
1449 target_offset);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001450 break;
1451 }
Vladimir Markof4f2daa2017-03-20 18:26:59 +00001452 case LinkerPatch::Type::kBakerReadBarrierBranch: {
1453 writer_->relative_patcher_->PatchBakerReadBarrierBranch(&patched_code_,
1454 patch,
1455 offset_ + literal_offset);
1456 break;
1457 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001458 default: {
Richard Uhlerc52f3032017-03-02 13:45:45 +00001459 DCHECK(false) << "Unexpected linker patch type: " << patch.GetType();
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001460 break;
1461 }
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001462 }
1463 }
1464 }
1465
Vladimir Markoe079e212016-05-25 12:49:49 +01001466 if (!out->WriteFully(quick_code.data(), code_size)) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001467 ReportWriteFailure("method code", it);
1468 return false;
1469 }
1470 writer_->size_code_ += code_size;
1471 offset_ += code_size;
Nicolas Geoffrayf0758792015-07-13 11:56:00 +00001472 }
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001473 DCHECK_OFFSET_();
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001474 ++method_offsets_index_;
1475 }
1476
1477 return true;
1478 }
1479
1480 private:
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001481 const PointerSize pointer_size_;
Vladimir Marko8d6768d2017-03-14 10:13:21 +00001482 ObjPtr<mirror::ClassLoader> class_loader_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001483 OutputStream* const out_;
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +01001484 const size_t file_offset_;
1485 const ScopedObjectAccess soa_;
1486 const ScopedAssertNoThreadSuspension no_thread_suspension_;
Vladimir Markof4da6752014-08-01 19:04:18 +01001487 ClassLinker* const class_linker_;
Vladimir Markocd556b02017-02-03 11:47:34 +00001488 ObjPtr<mirror::DexCache> dex_cache_;
Vladimir Markof4da6752014-08-01 19:04:18 +01001489 std::vector<uint8_t> patched_code_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001490
1491 void ReportWriteFailure(const char* what, const ClassDataItemIterator& it) {
1492 PLOG(ERROR) << "Failed to write " << what << " for "
David Sehr709b0702016-10-13 09:12:37 -07001493 << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001494 }
Vladimir Markof4da6752014-08-01 19:04:18 +01001495
Mathieu Chartiere401d142015-04-22 13:56:20 -07001496 ArtMethod* GetTargetMethod(const LinkerPatch& patch)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001497 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001498 MethodReference ref = patch.TargetMethod();
Vladimir Markocd556b02017-02-03 11:47:34 +00001499 ObjPtr<mirror::DexCache> dex_cache =
Mathieu Chartier673ed3d2015-08-28 14:56:43 -07001500 (dex_file_ == ref.dex_file) ? dex_cache_ : class_linker_->FindDexCache(
1501 Thread::Current(), *ref.dex_file);
Vladimir Marko07bfbac2017-07-06 14:55:02 +01001502 ArtMethod* method =
1503 class_linker_->LookupResolvedMethod(ref.dex_method_index, dex_cache, class_loader_);
Vladimir Markof4da6752014-08-01 19:04:18 +01001504 CHECK(method != nullptr);
1505 return method;
1506 }
1507
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001508 uint32_t GetTargetOffset(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko944da602016-02-19 12:27:55 +00001509 uint32_t target_offset = writer_->relative_patcher_->GetOffset(patch.TargetMethod());
1510 // If there's no new compiled code, either we're compiling an app and the target method
1511 // is in the boot image, or we need to point to the correct trampoline.
Vladimir Markof4da6752014-08-01 19:04:18 +01001512 if (UNLIKELY(target_offset == 0)) {
Mathieu Chartiere401d142015-04-22 13:56:20 -07001513 ArtMethod* target = GetTargetMethod(patch);
Vladimir Markof4da6752014-08-01 19:04:18 +01001514 DCHECK(target != nullptr);
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001515 const void* oat_code_offset =
1516 target->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
Jeff Haoa0acc2d2015-01-27 11:22:04 -08001517 if (oat_code_offset != 0) {
Vladimir Marko944da602016-02-19 12:27:55 +00001518 DCHECK(!writer_->HasBootImage());
Jeff Haoa0acc2d2015-01-27 11:22:04 -08001519 DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(oat_code_offset));
1520 DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(oat_code_offset));
1521 DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickGenericJniStub(oat_code_offset));
1522 target_offset = PointerToLowMemUInt32(oat_code_offset);
1523 } else {
1524 target_offset = target->IsNative()
1525 ? writer_->oat_header_->GetQuickGenericJniTrampolineOffset()
1526 : writer_->oat_header_->GetQuickToInterpreterBridgeOffset();
1527 }
Vladimir Markof4da6752014-08-01 19:04:18 +01001528 }
1529 return target_offset;
1530 }
1531
Vladimir Markocd556b02017-02-03 11:47:34 +00001532 ObjPtr<mirror::DexCache> GetDexCache(const DexFile* target_dex_file)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001533 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko052164a2016-04-27 13:54:18 +01001534 return (target_dex_file == dex_file_)
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001535 ? dex_cache_
Vladimir Marko052164a2016-04-27 13:54:18 +01001536 : class_linker_->FindDexCache(Thread::Current(), *target_dex_file);
1537 }
1538
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001539 mirror::Class* GetTargetType(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko8d6768d2017-03-14 10:13:21 +00001540 DCHECK(writer_->HasImage());
Vladimir Markocd556b02017-02-03 11:47:34 +00001541 ObjPtr<mirror::DexCache> dex_cache = GetDexCache(patch.TargetTypeDexFile());
Vladimir Marko8d6768d2017-03-14 10:13:21 +00001542 ObjPtr<mirror::Class> type =
1543 ClassLinker::LookupResolvedType(patch.TargetTypeIndex(), dex_cache, class_loader_);
Vladimir Markof4da6752014-08-01 19:04:18 +01001544 CHECK(type != nullptr);
Vladimir Marko8d6768d2017-03-14 10:13:21 +00001545 return type.Ptr();
Vladimir Markof4da6752014-08-01 19:04:18 +01001546 }
1547
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001548 mirror::String* GetTargetString(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07001549 ClassLinker* linker = Runtime::Current()->GetClassLinker();
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07001550 mirror::String* string = linker->LookupString(*patch.TargetStringDexFile(),
1551 patch.TargetStringIndex(),
Vladimir Markof25cc732017-03-16 16:18:15 +00001552 GetDexCache(patch.TargetStringDexFile()));
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001553 DCHECK(string != nullptr);
1554 DCHECK(writer_->HasBootImage() ||
1555 Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(string));
1556 return string;
1557 }
1558
Vladimir Marko65979462017-05-19 17:25:12 +01001559 uint32_t GetTargetMethodOffset(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
1560 DCHECK(writer_->HasBootImage());
1561 method = writer_->image_writer_->GetImageMethodAddress(method);
1562 size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
1563 uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
1564 // TODO: Clean up offset types. The target offset must be treated as signed.
1565 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(method) - oat_data_begin);
1566 }
1567
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001568 uint32_t GetTargetObjectOffset(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001569 DCHECK(writer_->HasBootImage());
1570 object = writer_->image_writer_->GetImageAddress(object);
1571 size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
1572 uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
1573 // TODO: Clean up offset types. The target offset must be treated as signed.
1574 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(object) - oat_data_begin);
1575 }
1576
Vladimir Markof4da6752014-08-01 19:04:18 +01001577 void PatchObjectAddress(std::vector<uint8_t>* code, uint32_t offset, mirror::Object* object)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001578 REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartierda5b28a2015-11-05 08:03:47 -08001579 if (writer_->HasBootImage()) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001580 object = writer_->image_writer_->GetImageAddress(object);
Vladimir Marko09d09432015-09-08 13:47:48 +01001581 } else {
1582 // NOTE: We're using linker patches for app->boot references when the image can
1583 // be relocated and therefore we need to emit .oat_patches. We're not using this
1584 // for app->app references, so check that the object is in the image space.
1585 DCHECK(Runtime::Current()->GetHeap()->FindSpaceFromObject(object, false)->IsImageSpace());
Vladimir Markof4da6752014-08-01 19:04:18 +01001586 }
Vladimir Marko09d09432015-09-08 13:47:48 +01001587 // Note: We only patch targeting Objects in image which is in the low 4gb.
Vladimir Markof4da6752014-08-01 19:04:18 +01001588 uint32_t address = PointerToLowMemUInt32(object);
1589 DCHECK_LE(offset + 4, code->size());
1590 uint8_t* data = &(*code)[offset];
1591 data[0] = address & 0xffu;
1592 data[1] = (address >> 8) & 0xffu;
1593 data[2] = (address >> 16) & 0xffu;
1594 data[3] = (address >> 24) & 0xffu;
1595 }
1596
1597 void PatchCodeAddress(std::vector<uint8_t>* code, uint32_t offset, uint32_t target_offset)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001598 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko09d09432015-09-08 13:47:48 +01001599 uint32_t address = target_offset;
Mathieu Chartierda5b28a2015-11-05 08:03:47 -08001600 if (writer_->HasBootImage()) {
Vladimir Marko944da602016-02-19 12:27:55 +00001601 size_t oat_index = writer_->image_writer_->GetOatIndexForDexCache(dex_cache_);
1602 // TODO: Clean up offset types.
1603 // The target_offset must be treated as signed for cross-oat patching.
1604 const void* target = reinterpret_cast<const void*>(
1605 writer_->image_writer_->GetOatDataBegin(oat_index) +
1606 static_cast<int32_t>(target_offset));
1607 address = PointerToLowMemUInt32(target);
Vladimir Marko09d09432015-09-08 13:47:48 +01001608 }
Vladimir Markof4da6752014-08-01 19:04:18 +01001609 DCHECK_LE(offset + 4, code->size());
1610 uint8_t* data = &(*code)[offset];
1611 data[0] = address & 0xffu;
1612 data[1] = (address >> 8) & 0xffu;
1613 data[2] = (address >> 16) & 0xffu;
1614 data[3] = (address >> 24) & 0xffu;
1615 }
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001616
1617 // Calculate the offset of the InternTable slot (GcRoot<String>) when mmapped to the .bss.
1618 uint32_t GetInternTableEntryOffset(const LinkerPatch& patch)
1619 REQUIRES_SHARED(Locks::mutator_lock_) {
1620 DCHECK(!writer_->HasBootImage());
1621 const uint8_t* string_root = writer_->LookupBootImageInternTableSlot(
1622 *patch.TargetStringDexFile(), patch.TargetStringIndex());
1623 DCHECK(string_root != nullptr);
1624 uint32_t base_offset = writer_->bss_start_;
1625 for (gc::space::ImageSpace* space : Runtime::Current()->GetHeap()->GetBootImageSpaces()) {
1626 const uint8_t* const_tables_begin =
1627 space->Begin() + space->GetImageHeader().GetBootImageConstantTablesOffset();
1628 size_t offset = static_cast<size_t>(string_root - const_tables_begin);
1629 if (offset < space->GetImageHeader().GetBootImageConstantTablesSize()) {
1630 DCHECK_LE(base_offset + offset, writer_->bss_start_ + writer_->bss_methods_offset_);
1631 return base_offset + offset;
1632 }
1633 base_offset += space->GetImageHeader().GetBootImageConstantTablesSize();
1634 }
1635 LOG(FATAL) << "Didn't find boot image string in boot image intern tables!";
1636 UNREACHABLE();
1637 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001638};
1639
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001640class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor {
1641 public:
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001642 WriteMapMethodVisitor(OatWriter* writer,
1643 OutputStream* out,
1644 const size_t file_offset,
Mathieu Chartier957ca1c2014-11-21 16:51:29 -08001645 size_t relative_offset)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001646 : OatDexMethodVisitor(writer, relative_offset),
1647 out_(out),
1648 file_offset_(file_offset) {}
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001649
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001650 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE {
Vladimir Marko49b0f452015-12-10 13:49:19 +00001651 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001652 const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1653
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01001654 if (HasCompiledCode(compiled_method)) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001655 size_t file_offset = file_offset_;
1656 OutputStream* out = out_;
1657
Mingyao Yang063fc772016-08-02 11:02:54 -07001658 uint32_t map_offset = oat_class->method_headers_[method_offsets_index_].GetVmapTableOffset();
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001659 uint32_t code_offset = oat_class->method_offsets_[method_offsets_index_].code_offset_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001660 ++method_offsets_index_;
1661
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001662 DCHECK((compiled_method->GetVmapTable().size() == 0u && map_offset == 0u) ||
1663 (compiled_method->GetVmapTable().size() != 0u && map_offset != 0u))
1664 << compiled_method->GetVmapTable().size() << " " << map_offset << " "
David Sehr709b0702016-10-13 09:12:37 -07001665 << dex_file_->PrettyMethod(it.GetMemberIndex());
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001666
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01001667 // If vdex is enabled, only emit the map for compiled code. The quickening info
1668 // is emitted in the vdex already.
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01001669 if (map_offset != 0u) {
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001670 // Transform map_offset to actual oat data offset.
1671 map_offset = (code_offset - compiled_method->CodeDelta()) - map_offset;
1672 DCHECK_NE(map_offset, 0u);
David Sehr709b0702016-10-13 09:12:37 -07001673 DCHECK_LE(map_offset, offset_) << dex_file_->PrettyMethod(it.GetMemberIndex());
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001674
1675 ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
1676 size_t map_size = map.size() * sizeof(map[0]);
1677 if (map_offset == offset_) {
1678 // Write deduplicated map (code info for Optimizing or transformation info for dex2dex).
Vladimir Markoe079e212016-05-25 12:49:49 +01001679 if (UNLIKELY(!out->WriteFully(map.data(), map_size))) {
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001680 ReportWriteFailure(it);
1681 return false;
1682 }
1683 offset_ += map_size;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001684 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001685 }
1686 DCHECK_OFFSET_();
1687 }
1688
1689 return true;
1690 }
1691
1692 private:
1693 OutputStream* const out_;
1694 size_t const file_offset_;
1695
1696 void ReportWriteFailure(const ClassDataItemIterator& it) {
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001697 PLOG(ERROR) << "Failed to write map for "
David Sehr709b0702016-10-13 09:12:37 -07001698 << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001699 }
1700};
1701
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001702class OatWriter::WriteMethodInfoVisitor : public OatDexMethodVisitor {
1703 public:
1704 WriteMethodInfoVisitor(OatWriter* writer,
1705 OutputStream* out,
1706 const size_t file_offset,
1707 size_t relative_offset)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001708 : OatDexMethodVisitor(writer, relative_offset),
1709 out_(out),
1710 file_offset_(file_offset) {}
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001711
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001712 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE {
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001713 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1714 const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1715
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01001716 if (HasCompiledCode(compiled_method)) {
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001717 size_t file_offset = file_offset_;
1718 OutputStream* out = out_;
1719 uint32_t map_offset = oat_class->method_headers_[method_offsets_index_].GetMethodInfoOffset();
1720 uint32_t code_offset = oat_class->method_offsets_[method_offsets_index_].code_offset_;
1721 ++method_offsets_index_;
1722 DCHECK((compiled_method->GetMethodInfo().size() == 0u && map_offset == 0u) ||
1723 (compiled_method->GetMethodInfo().size() != 0u && map_offset != 0u))
1724 << compiled_method->GetMethodInfo().size() << " " << map_offset << " "
1725 << dex_file_->PrettyMethod(it.GetMemberIndex());
1726 if (map_offset != 0u) {
1727 // Transform map_offset to actual oat data offset.
1728 map_offset = (code_offset - compiled_method->CodeDelta()) - map_offset;
1729 DCHECK_NE(map_offset, 0u);
1730 DCHECK_LE(map_offset, offset_) << dex_file_->PrettyMethod(it.GetMemberIndex());
1731
1732 ArrayRef<const uint8_t> map = compiled_method->GetMethodInfo();
1733 size_t map_size = map.size() * sizeof(map[0]);
1734 if (map_offset == offset_) {
1735 // Write deduplicated map (code info for Optimizing or transformation info for dex2dex).
1736 if (UNLIKELY(!out->WriteFully(map.data(), map_size))) {
1737 ReportWriteFailure(it);
1738 return false;
1739 }
1740 offset_ += map_size;
1741 }
1742 }
1743 DCHECK_OFFSET_();
1744 }
1745
1746 return true;
1747 }
1748
1749 private:
1750 OutputStream* const out_;
1751 size_t const file_offset_;
1752
1753 void ReportWriteFailure(const ClassDataItemIterator& it) {
1754 PLOG(ERROR) << "Failed to write map for "
1755 << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
1756 }
1757};
1758
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001759// Visit all methods from all classes in all dex files with the specified visitor.
1760bool OatWriter::VisitDexMethods(DexMethodVisitor* visitor) {
1761 for (const DexFile* dex_file : *dex_files_) {
1762 const size_t class_def_count = dex_file->NumClassDefs();
1763 for (size_t class_def_index = 0; class_def_index != class_def_count; ++class_def_index) {
1764 if (UNLIKELY(!visitor->StartClass(dex_file, class_def_index))) {
1765 return false;
1766 }
Mathieu Chartier3957bff2017-07-16 13:55:27 -07001767 if (MayHaveCompiledMethods()) {
Nicolas Geoffray60ca9492016-12-20 21:15:00 +00001768 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
1769 const uint8_t* class_data = dex_file->GetClassData(class_def);
1770 if (class_data != nullptr) { // ie not an empty class, such as a marker interface
1771 ClassDataItemIterator it(*dex_file, class_data);
Mathieu Chartiere17cf242017-06-19 11:05:51 -07001772 it.SkipAllFields();
Nicolas Geoffray60ca9492016-12-20 21:15:00 +00001773 size_t class_def_method_index = 0u;
1774 while (it.HasNextDirectMethod()) {
1775 if (!visitor->VisitMethod(class_def_method_index, it)) {
1776 return false;
1777 }
1778 ++class_def_method_index;
1779 it.Next();
1780 }
1781 while (it.HasNextVirtualMethod()) {
1782 if (UNLIKELY(!visitor->VisitMethod(class_def_method_index, it))) {
1783 return false;
1784 }
1785 ++class_def_method_index;
1786 it.Next();
1787 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001788 }
1789 }
1790 if (UNLIKELY(!visitor->EndClass())) {
1791 return false;
1792 }
1793 }
1794 }
1795 return true;
1796}
1797
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001798size_t OatWriter::InitOatHeader(InstructionSet instruction_set,
1799 const InstructionSetFeatures* instruction_set_features,
1800 uint32_t num_dex_files,
1801 SafeMap<std::string, std::string>* key_value_store) {
1802 TimingLogger::ScopedTiming split("InitOatHeader", timings_);
1803 oat_header_.reset(OatHeader::Create(instruction_set,
1804 instruction_set_features,
1805 num_dex_files,
1806 key_value_store));
1807 size_oat_header_ += sizeof(OatHeader);
1808 size_oat_header_key_value_store_ += oat_header_->GetHeaderSize() - sizeof(OatHeader);
Andreas Gampe22f8e5c2014-07-09 11:38:21 -07001809 return oat_header_->GetHeaderSize();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001810}
1811
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001812size_t OatWriter::InitClassOffsets(size_t offset) {
1813 // Reserve space for class offsets in OAT and update class_offsets_offset_.
Vladimir Marko49b0f452015-12-10 13:49:19 +00001814 for (OatDexFile& oat_dex_file : oat_dex_files_) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001815 DCHECK_EQ(oat_dex_file.class_offsets_offset_, 0u);
1816 if (!oat_dex_file.class_offsets_.empty()) {
1817 // Class offsets are required to be 4 byte aligned.
1818 offset = RoundUp(offset, 4u);
1819 oat_dex_file.class_offsets_offset_ = offset;
1820 offset += oat_dex_file.GetClassOffsetsRawSize();
1821 DCHECK_ALIGNED(offset, 4u);
1822 }
Artem Udovichenkod9786b02015-10-14 16:36:55 +03001823 }
1824 return offset;
1825}
1826
Brian Carlstrom389efb02012-01-11 12:06:26 -08001827size_t OatWriter::InitOatClasses(size_t offset) {
Brian Carlstrom389efb02012-01-11 12:06:26 -08001828 // calculate the offsets within OatDexFiles to OatClasses
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001829 InitOatClassesMethodVisitor visitor(this, offset);
1830 bool success = VisitDexMethods(&visitor);
1831 CHECK(success);
1832 offset = visitor.GetOffset();
Brian Carlstromba150c32013-08-27 17:31:03 -07001833
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001834 // Update oat_dex_files_.
Mathieu Chartier3957bff2017-07-16 13:55:27 -07001835 auto oat_class_it = oat_class_headers_.begin();
Vladimir Marko49b0f452015-12-10 13:49:19 +00001836 for (OatDexFile& oat_dex_file : oat_dex_files_) {
1837 for (uint32_t& class_offset : oat_dex_file.class_offsets_) {
Mathieu Chartier3957bff2017-07-16 13:55:27 -07001838 DCHECK(oat_class_it != oat_class_headers_.end());
Vladimir Marko49b0f452015-12-10 13:49:19 +00001839 class_offset = oat_class_it->offset_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001840 ++oat_class_it;
Brian Carlstrome24fa612011-09-29 00:53:55 -07001841 }
Brian Carlstrome24fa612011-09-29 00:53:55 -07001842 }
Mathieu Chartier3957bff2017-07-16 13:55:27 -07001843 CHECK(oat_class_it == oat_class_headers_.end());
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001844
1845 return offset;
1846}
1847
1848size_t OatWriter::InitOatMaps(size_t offset) {
Mathieu Chartier3957bff2017-07-16 13:55:27 -07001849 if (!MayHaveCompiledMethods()) {
Nicolas Geoffray60ca9492016-12-20 21:15:00 +00001850 return offset;
1851 }
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001852 {
1853 InitMapMethodVisitor visitor(this, offset);
1854 bool success = VisitDexMethods(&visitor);
1855 DCHECK(success);
1856 offset = visitor.GetOffset();
1857 }
1858 {
1859 InitMethodInfoVisitor visitor(this, offset);
1860 bool success = VisitDexMethods(&visitor);
1861 DCHECK(success);
1862 offset = visitor.GetOffset();
1863 }
Brian Carlstrome24fa612011-09-29 00:53:55 -07001864 return offset;
1865}
1866
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001867size_t OatWriter::InitMethodBssMappings(size_t offset) {
1868 size_t number_of_dex_files = 0u;
1869 for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
1870 const DexFile* dex_file = (*dex_files_)[i];
1871 auto it = bss_method_entry_references_.find(dex_file);
1872 if (it != bss_method_entry_references_.end()) {
1873 const BitVector& method_indexes = it->second;
1874 ++number_of_dex_files;
1875 // If there are any classes, the class offsets allocation aligns the offset
1876 // and we cannot have method bss mappings without class offsets.
1877 static_assert(alignof(MethodBssMapping) == 4u, "MethodBssMapping alignment check.");
1878 DCHECK_ALIGNED(offset, 4u);
1879 oat_dex_files_[i].method_bss_mapping_offset_ = offset;
1880
1881 linker::MethodBssMappingEncoder encoder(
1882 GetInstructionSetPointerSize(oat_header_->GetInstructionSet()));
1883 size_t number_of_entries = 0u;
1884 bool first_index = true;
1885 for (uint32_t method_index : method_indexes.Indexes()) {
1886 uint32_t bss_offset = bss_method_entries_.Get(MethodReference(dex_file, method_index));
1887 if (first_index || !encoder.TryMerge(method_index, bss_offset)) {
1888 encoder.Reset(method_index, bss_offset);
1889 ++number_of_entries;
1890 first_index = false;
1891 }
1892 }
1893 DCHECK_NE(number_of_entries, 0u);
1894 offset += MethodBssMapping::ComputeSize(number_of_entries);
1895 }
1896 }
1897 // Check that all dex files targeted by method bss entries are in `*dex_files_`.
1898 CHECK_EQ(number_of_dex_files, bss_method_entry_references_.size());
1899 return offset;
1900}
1901
1902size_t OatWriter::InitOatDexFiles(size_t offset) {
1903 // Initialize offsets of oat dex files.
1904 for (OatDexFile& oat_dex_file : oat_dex_files_) {
1905 oat_dex_file.offset_ = offset;
1906 offset += oat_dex_file.SizeOf();
1907 }
1908 return offset;
1909}
1910
Brian Carlstrome24fa612011-09-29 00:53:55 -07001911size_t OatWriter::InitOatCode(size_t offset) {
1912 // calculate the offsets within OatHeader to executable code
1913 size_t old_offset = offset;
Dave Allison50abf0a2014-06-23 13:19:59 -07001914 size_t adjusted_offset = offset;
Brian Carlstrome24fa612011-09-29 00:53:55 -07001915 // required to be on a new page boundary
1916 offset = RoundUp(offset, kPageSize);
1917 oat_header_->SetExecutableOffset(offset);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001918 size_executable_offset_alignment_ = offset - old_offset;
Vladimir Markoaad75c62016-10-03 08:46:48 +00001919 if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001920 InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001921
Ian Rogers848871b2013-08-05 10:56:33 -07001922 #define DO_TRAMPOLINE(field, fn_name) \
1923 offset = CompiledCode::AlignCode(offset, instruction_set); \
Dave Allison50abf0a2014-06-23 13:19:59 -07001924 adjusted_offset = offset + CompiledCode::CodeDelta(instruction_set); \
1925 oat_header_->Set ## fn_name ## Offset(adjusted_offset); \
Chih-Hung Hsiehfba39972016-05-11 11:26:48 -07001926 (field) = compiler_driver_->Create ## fn_name(); \
1927 offset += (field)->size();
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001928
Ian Rogers848871b2013-08-05 10:56:33 -07001929 DO_TRAMPOLINE(jni_dlsym_lookup_, JniDlsymLookup);
Andreas Gampe2da88232014-02-27 12:26:20 -08001930 DO_TRAMPOLINE(quick_generic_jni_trampoline_, QuickGenericJniTrampoline);
Jeff Hao88474b42013-10-23 16:24:40 -07001931 DO_TRAMPOLINE(quick_imt_conflict_trampoline_, QuickImtConflictTrampoline);
Ian Rogers848871b2013-08-05 10:56:33 -07001932 DO_TRAMPOLINE(quick_resolution_trampoline_, QuickResolutionTrampoline);
1933 DO_TRAMPOLINE(quick_to_interpreter_bridge_, QuickToInterpreterBridge);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001934
Ian Rogers848871b2013-08-05 10:56:33 -07001935 #undef DO_TRAMPOLINE
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001936 } else {
Ian Rogers848871b2013-08-05 10:56:33 -07001937 oat_header_->SetInterpreterToInterpreterBridgeOffset(0);
1938 oat_header_->SetInterpreterToCompiledCodeBridgeOffset(0);
1939 oat_header_->SetJniDlsymLookupOffset(0);
Andreas Gampe2da88232014-02-27 12:26:20 -08001940 oat_header_->SetQuickGenericJniTrampolineOffset(0);
Jeff Hao88474b42013-10-23 16:24:40 -07001941 oat_header_->SetQuickImtConflictTrampolineOffset(0);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001942 oat_header_->SetQuickResolutionTrampolineOffset(0);
Ian Rogers848871b2013-08-05 10:56:33 -07001943 oat_header_->SetQuickToInterpreterBridgeOffset(0);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001944 }
Brian Carlstrome24fa612011-09-29 00:53:55 -07001945 return offset;
1946}
1947
1948size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
Nicolas Geoffray49cda062017-04-21 13:08:25 +01001949 if (!compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
Nicolas Geoffray60ca9492016-12-20 21:15:00 +00001950 return offset;
1951 }
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01001952 InitCodeMethodVisitor code_visitor(this, offset);
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01001953 bool success = VisitDexMethods(&code_visitor);
1954 DCHECK(success);
1955 offset = code_visitor.GetOffset();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001956
Mathieu Chartierfbc31082016-01-24 11:59:56 -08001957 if (HasImage()) {
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001958 InitImageMethodVisitor image_visitor(this, offset, dex_files_);
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01001959 success = VisitDexMethods(&image_visitor);
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001960 image_visitor.Postprocess();
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01001961 DCHECK(success);
1962 offset = image_visitor.GetOffset();
Ian Rogers0571d352011-11-03 19:51:38 -07001963 }
Logan Chien8b977d32012-02-21 19:14:55 +08001964
Brian Carlstrome24fa612011-09-29 00:53:55 -07001965 return offset;
1966}
1967
Vladimir Markoaad75c62016-10-03 08:46:48 +00001968void OatWriter::InitBssLayout(InstructionSet instruction_set) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001969 {
1970 InitBssLayoutMethodVisitor visitor(this);
1971 bool success = VisitDexMethods(&visitor);
1972 DCHECK(success);
1973 }
1974
1975 DCHECK_EQ(bss_size_, 0u);
Vladimir Marko1998cd02017-01-13 13:02:58 +00001976 if (HasBootImage()) {
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001977 DCHECK(!map_boot_image_tables_to_bss_);
Vladimir Marko1998cd02017-01-13 13:02:58 +00001978 DCHECK(bss_string_entries_.empty());
Vladimir Marko0f3c7002017-09-07 14:15:56 +01001979 }
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001980 if (!map_boot_image_tables_to_bss_ &&
1981 bss_method_entries_.empty() &&
Vladimir Marko0f3c7002017-09-07 14:15:56 +01001982 bss_type_entries_.empty() &&
1983 bss_string_entries_.empty()) {
1984 // Nothing to put to the .bss section.
1985 return;
Vladimir Marko1998cd02017-01-13 13:02:58 +00001986 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00001987
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001988 // Allocate space for boot image tables in the .bss section.
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001989 PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set);
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001990 if (map_boot_image_tables_to_bss_) {
1991 for (gc::space::ImageSpace* space : Runtime::Current()->GetHeap()->GetBootImageSpaces()) {
1992 bss_size_ += space->GetImageHeader().GetBootImageConstantTablesSize();
1993 }
1994 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00001995
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001996 bss_methods_offset_ = bss_size_;
1997
1998 // Prepare offsets for .bss ArtMethod entries.
1999 for (auto& entry : bss_method_entries_) {
2000 DCHECK_EQ(entry.second, 0u);
2001 entry.second = bss_size_;
2002 bss_size_ += static_cast<size_t>(pointer_size);
2003 }
2004
Vladimir Markoaad75c62016-10-03 08:46:48 +00002005 bss_roots_offset_ = bss_size_;
2006
Vladimir Marko6bec91c2017-01-09 15:03:12 +00002007 // Prepare offsets for .bss Class entries.
2008 for (auto& entry : bss_type_entries_) {
2009 DCHECK_EQ(entry.second, 0u);
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002010 entry.second = bss_size_;
Vladimir Marko6bec91c2017-01-09 15:03:12 +00002011 bss_size_ += sizeof(GcRoot<mirror::Class>);
2012 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00002013 // Prepare offsets for .bss String entries.
2014 for (auto& entry : bss_string_entries_) {
2015 DCHECK_EQ(entry.second, 0u);
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002016 entry.second = bss_size_;
Vladimir Markoaad75c62016-10-03 08:46:48 +00002017 bss_size_ += sizeof(GcRoot<mirror::String>);
2018 }
2019}
2020
David Srbeckybc90fd02015-04-22 19:40:27 +01002021bool OatWriter::WriteRodata(OutputStream* out) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002022 CHECK(write_state_ == WriteState::kWriteRoData);
2023
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002024 size_t file_offset = oat_data_offset_;
2025 off_t current_offset = out->Seek(0, kSeekCurrent);
2026 if (current_offset == static_cast<off_t>(-1)) {
2027 PLOG(ERROR) << "Failed to retrieve current position in " << out->GetLocation();
2028 }
2029 DCHECK_GE(static_cast<size_t>(current_offset), file_offset + oat_header_->GetHeaderSize());
2030 size_t relative_offset = current_offset - file_offset;
2031
Vladimir Markoe079e212016-05-25 12:49:49 +01002032 // Wrap out to update checksum with each write.
2033 ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get());
2034 out = &checksum_updating_out;
2035
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002036 relative_offset = WriteClassOffsets(out, file_offset, relative_offset);
2037 if (relative_offset == 0) {
2038 PLOG(ERROR) << "Failed to write class offsets to " << out->GetLocation();
Vladimir Markof4da6752014-08-01 19:04:18 +01002039 return false;
2040 }
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002041
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002042 relative_offset = WriteClasses(out, file_offset, relative_offset);
2043 if (relative_offset == 0) {
2044 PLOG(ERROR) << "Failed to write classes to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07002045 return false;
2046 }
2047
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002048 relative_offset = WriteMethodBssMappings(out, file_offset, relative_offset);
2049 if (relative_offset == 0) {
2050 PLOG(ERROR) << "Failed to write method bss mappings to " << out->GetLocation();
Vladimir Markof4da6752014-08-01 19:04:18 +01002051 return false;
2052 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002053
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002054 relative_offset = WriteMaps(out, file_offset, relative_offset);
2055 if (relative_offset == 0) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002056 PLOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
2057 return false;
2058 }
2059
2060 relative_offset = WriteOatDexFiles(out, file_offset, relative_offset);
2061 if (relative_offset == 0) {
2062 PLOG(ERROR) << "Failed to write oat dex information to " << out->GetLocation();
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002063 return false;
2064 }
2065
David Srbeckybc90fd02015-04-22 19:40:27 +01002066 // Write padding.
2067 off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent);
2068 relative_offset += size_executable_offset_alignment_;
2069 DCHECK_EQ(relative_offset, oat_header_->GetExecutableOffset());
2070 size_t expected_file_offset = file_offset + relative_offset;
2071 if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
2072 PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
2073 << " Expected: " << expected_file_offset << " File: " << out->GetLocation();
2074 return 0;
2075 }
2076 DCHECK_OFFSET();
2077
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002078 write_state_ = WriteState::kWriteText;
David Srbeckybc90fd02015-04-22 19:40:27 +01002079 return true;
2080}
2081
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002082class OatWriter::WriteQuickeningInfoMethodVisitor : public DexMethodVisitor {
2083 public:
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01002084 WriteQuickeningInfoMethodVisitor(OatWriter* writer,
2085 OutputStream* out,
2086 uint32_t offset,
2087 SafeMap<const uint8_t*, uint32_t>* offset_map)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002088 : DexMethodVisitor(writer, offset),
2089 out_(out),
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01002090 written_bytes_(0u),
2091 offset_map_(offset_map) {}
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002092
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01002093 bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED, const ClassDataItemIterator& it)
2094 OVERRIDE {
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002095 uint32_t method_idx = it.GetMemberIndex();
2096 CompiledMethod* compiled_method =
2097 writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
2098
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01002099 if (HasQuickeningInfo(compiled_method)) {
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002100 ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01002101 // Deduplication is already done on a pointer basis by the compiler driver,
2102 // so we can simply compare the pointers to find out if things are duplicated.
2103 if (offset_map_->find(map.data()) == offset_map_->end()) {
2104 uint32_t length = map.size() * sizeof(map.front());
2105 offset_map_->Put(map.data(), written_bytes_);
2106 if (!out_->WriteFully(&length, sizeof(length)) ||
2107 !out_->WriteFully(map.data(), length)) {
2108 PLOG(ERROR) << "Failed to write quickening info for "
2109 << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to "
2110 << out_->GetLocation();
2111 return false;
2112 }
2113 written_bytes_ += sizeof(length) + length;
2114 offset_ += sizeof(length) + length;
2115 }
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002116 }
2117
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002118 return true;
2119 }
2120
2121 size_t GetNumberOfWrittenBytes() const {
2122 return written_bytes_;
2123 }
2124
2125 private:
2126 OutputStream* const out_;
2127 size_t written_bytes_;
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01002128 // Maps quickening map to its offset in the file.
2129 SafeMap<const uint8_t*, uint32_t>* offset_map_;
2130};
2131
2132class OatWriter::WriteQuickeningIndicesMethodVisitor {
2133 public:
2134 WriteQuickeningIndicesMethodVisitor(OutputStream* out,
2135 uint32_t indices_offset,
2136 const SafeMap<const uint8_t*, uint32_t>& offset_map,
2137 std::vector<uint32_t>* dex_files_offset)
2138 : out_(out),
2139 indices_offset_(indices_offset),
2140 written_bytes_(0u),
2141 dex_files_offset_(dex_files_offset),
2142 offset_map_(offset_map) {}
2143
2144 bool VisitDexMethods(const std::vector<const DexFile*>& dex_files, const CompilerDriver& driver) {
2145 for (const DexFile* dex_file : dex_files) {
2146 // Record the offset for this current dex file. It will be written in the vdex file
2147 // later.
2148 dex_files_offset_->push_back(indices_offset_ + GetNumberOfWrittenBytes());
2149 const size_t class_def_count = dex_file->NumClassDefs();
2150 for (size_t class_def_index = 0; class_def_index != class_def_count; ++class_def_index) {
2151 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
2152 const uint8_t* class_data = dex_file->GetClassData(class_def);
2153 if (class_data == nullptr) {
2154 continue;
2155 }
2156 for (ClassDataItemIterator class_it(*dex_file, class_data);
2157 class_it.HasNext();
2158 class_it.Next()) {
2159 if (!class_it.IsAtMethod()) {
2160 continue;
2161 }
2162 uint32_t method_idx = class_it.GetMemberIndex();
2163 CompiledMethod* compiled_method =
2164 driver.GetCompiledMethod(MethodReference(dex_file, method_idx));
2165 if (HasQuickeningInfo(compiled_method)) {
2166 uint32_t code_item_offset = class_it.GetMethodCodeItemOffset();
2167 uint32_t offset = offset_map_.Get(compiled_method->GetVmapTable().data());
2168 if (!out_->WriteFully(&code_item_offset, sizeof(code_item_offset)) ||
2169 !out_->WriteFully(&offset, sizeof(offset))) {
2170 PLOG(ERROR) << "Failed to write quickening info for "
2171 << dex_file->PrettyMethod(method_idx) << " to "
2172 << out_->GetLocation();
2173 return false;
2174 }
2175 written_bytes_ += sizeof(code_item_offset) + sizeof(offset);
2176 }
2177 }
2178 }
2179 }
2180 return true;
2181 }
2182
2183 size_t GetNumberOfWrittenBytes() const {
2184 return written_bytes_;
2185 }
2186
2187 private:
2188 OutputStream* const out_;
2189 const uint32_t indices_offset_;
2190 size_t written_bytes_;
2191 std::vector<uint32_t>* dex_files_offset_;
2192 // Maps quickening map to its offset in the file.
2193 const SafeMap<const uint8_t*, uint32_t>& offset_map_;
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002194};
2195
2196bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) {
2197 if (!kIsVdexEnabled) {
2198 return true;
2199 }
2200
2201 size_t initial_offset = vdex_size_;
2202 size_t start_offset = RoundUp(initial_offset, 4u);
2203
2204 vdex_size_ = start_offset;
2205 vdex_quickening_info_offset_ = vdex_size_;
2206 size_quickening_info_alignment_ = start_offset - initial_offset;
2207
2208 off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet);
2209 if (actual_offset != static_cast<off_t>(start_offset)) {
2210 PLOG(ERROR) << "Failed to seek to quickening info section. Actual: " << actual_offset
2211 << " Expected: " << start_offset
2212 << " Output: " << vdex_out->GetLocation();
2213 return false;
2214 }
2215
Nicolas Geoffray49cda062017-04-21 13:08:25 +01002216 if (compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01002217 std::vector<uint32_t> dex_files_indices;
2218 SafeMap<const uint8_t*, uint32_t> offset_map;
2219 WriteQuickeningInfoMethodVisitor visitor1(this, vdex_out, start_offset, &offset_map);
2220 if (!VisitDexMethods(&visitor1)) {
2221 PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation();
2222 return false;
2223 }
2224
2225 WriteQuickeningIndicesMethodVisitor visitor2(vdex_out,
2226 visitor1.GetNumberOfWrittenBytes(),
2227 offset_map,
2228 &dex_files_indices);
2229 if (!visitor2.VisitDexMethods(*dex_files_, *compiler_driver_)) {
2230 PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation();
2231 return false;
2232 }
2233
2234 DCHECK_EQ(dex_files_->size(), dex_files_indices.size());
2235 if (!vdex_out->WriteFully(
2236 dex_files_indices.data(), sizeof(dex_files_indices[0]) * dex_files_indices.size())) {
Nicolas Geoffray60ca9492016-12-20 21:15:00 +00002237 PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation();
2238 return false;
2239 }
2240
2241 if (!vdex_out->Flush()) {
2242 PLOG(ERROR) << "Failed to flush stream after writing quickening info."
2243 << " File: " << vdex_out->GetLocation();
2244 return false;
2245 }
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01002246 size_quickening_info_ = visitor1.GetNumberOfWrittenBytes() +
2247 visitor2.GetNumberOfWrittenBytes() +
2248 dex_files_->size() * sizeof(uint32_t);
Nicolas Geoffray60ca9492016-12-20 21:15:00 +00002249 } else {
2250 // We know we did not quicken.
2251 size_quickening_info_ = 0;
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002252 }
2253
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002254 vdex_size_ += size_quickening_info_;
2255 return true;
2256}
2257
David Brazdil5d5a36b2016-09-14 15:34:10 +01002258bool OatWriter::WriteVerifierDeps(OutputStream* vdex_out, verifier::VerifierDeps* verifier_deps) {
2259 if (!kIsVdexEnabled) {
2260 return true;
2261 }
2262
2263 if (verifier_deps == nullptr) {
2264 // Nothing to write. Record the offset, but no need
2265 // for alignment.
2266 vdex_verifier_deps_offset_ = vdex_size_;
2267 return true;
2268 }
2269
2270 size_t initial_offset = vdex_size_;
2271 size_t start_offset = RoundUp(initial_offset, 4u);
2272
2273 vdex_size_ = start_offset;
2274 vdex_verifier_deps_offset_ = vdex_size_;
2275 size_verifier_deps_alignment_ = start_offset - initial_offset;
2276
2277 off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet);
2278 if (actual_offset != static_cast<off_t>(start_offset)) {
2279 PLOG(ERROR) << "Failed to seek to verifier deps section. Actual: " << actual_offset
2280 << " Expected: " << start_offset
2281 << " Output: " << vdex_out->GetLocation();
2282 return false;
2283 }
2284
2285 std::vector<uint8_t> buffer;
Nicolas Geoffrayd01f60c2016-10-28 14:45:48 +01002286 verifier_deps->Encode(*dex_files_, &buffer);
David Brazdil5d5a36b2016-09-14 15:34:10 +01002287
2288 if (!vdex_out->WriteFully(buffer.data(), buffer.size())) {
2289 PLOG(ERROR) << "Failed to write verifier deps."
2290 << " File: " << vdex_out->GetLocation();
2291 return false;
2292 }
2293 if (!vdex_out->Flush()) {
2294 PLOG(ERROR) << "Failed to flush stream after writing verifier deps."
2295 << " File: " << vdex_out->GetLocation();
2296 return false;
2297 }
2298
2299 size_verifier_deps_ = buffer.size();
2300 vdex_size_ += size_verifier_deps_;
2301 return true;
2302}
2303
David Srbeckybc90fd02015-04-22 19:40:27 +01002304bool OatWriter::WriteCode(OutputStream* out) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002305 CHECK(write_state_ == WriteState::kWriteText);
2306
Vladimir Markoe079e212016-05-25 12:49:49 +01002307 // Wrap out to update checksum with each write.
2308 ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get());
2309 out = &checksum_updating_out;
2310
Vladimir Marko944da602016-02-19 12:27:55 +00002311 SetMultiOatRelativePatcherAdjustment();
2312
David Srbeckybc90fd02015-04-22 19:40:27 +01002313 const size_t file_offset = oat_data_offset_;
2314 size_t relative_offset = oat_header_->GetExecutableOffset();
2315 DCHECK_OFFSET();
2316
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002317 relative_offset = WriteCode(out, file_offset, relative_offset);
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002318 if (relative_offset == 0) {
Ian Rogers3d504072014-03-01 09:16:49 -08002319 LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07002320 return false;
2321 }
2322
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002323 relative_offset = WriteCodeDexFiles(out, file_offset, relative_offset);
2324 if (relative_offset == 0) {
Ian Rogers3d504072014-03-01 09:16:49 -08002325 LOG(ERROR) << "Failed to write oat code for dex files to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07002326 return false;
2327 }
2328
Vladimir Markof4da6752014-08-01 19:04:18 +01002329 const off_t oat_end_file_offset = out->Seek(0, kSeekCurrent);
Vladimir Marko49b0f452015-12-10 13:49:19 +00002330 if (oat_end_file_offset == static_cast<off_t>(-1)) {
Vladimir Markof4da6752014-08-01 19:04:18 +01002331 LOG(ERROR) << "Failed to get oat end file offset in " << out->GetLocation();
2332 return false;
2333 }
2334
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002335 if (kIsDebugBuild) {
2336 uint32_t size_total = 0;
2337 #define DO_STAT(x) \
Chih-Hung Hsiehfba39972016-05-11 11:26:48 -07002338 VLOG(compiler) << #x "=" << PrettySize(x) << " (" << (x) << "B)"; \
2339 size_total += (x);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002340
David Brazdil7b49e6c2016-09-01 11:06:18 +01002341 DO_STAT(size_vdex_header_);
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +00002342 DO_STAT(size_vdex_checksums_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002343 DO_STAT(size_dex_file_alignment_);
2344 DO_STAT(size_executable_offset_alignment_);
2345 DO_STAT(size_oat_header_);
Andreas Gampe22f8e5c2014-07-09 11:38:21 -07002346 DO_STAT(size_oat_header_key_value_store_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002347 DO_STAT(size_dex_file_);
David Brazdil5d5a36b2016-09-14 15:34:10 +01002348 DO_STAT(size_verifier_deps_);
2349 DO_STAT(size_verifier_deps_alignment_);
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002350 DO_STAT(size_quickening_info_);
2351 DO_STAT(size_quickening_info_alignment_);
Ian Rogers848871b2013-08-05 10:56:33 -07002352 DO_STAT(size_interpreter_to_interpreter_bridge_);
2353 DO_STAT(size_interpreter_to_compiled_code_bridge_);
2354 DO_STAT(size_jni_dlsym_lookup_);
Andreas Gampe2da88232014-02-27 12:26:20 -08002355 DO_STAT(size_quick_generic_jni_trampoline_);
Jeff Hao88474b42013-10-23 16:24:40 -07002356 DO_STAT(size_quick_imt_conflict_trampoline_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002357 DO_STAT(size_quick_resolution_trampoline_);
Ian Rogers848871b2013-08-05 10:56:33 -07002358 DO_STAT(size_quick_to_interpreter_bridge_);
2359 DO_STAT(size_trampoline_alignment_);
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002360 DO_STAT(size_method_header_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002361 DO_STAT(size_code_);
2362 DO_STAT(size_code_alignment_);
Vladimir Markof4da6752014-08-01 19:04:18 +01002363 DO_STAT(size_relative_call_thunks_);
Vladimir Markoc74658b2015-03-31 10:26:41 +01002364 DO_STAT(size_misc_thunks_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002365 DO_STAT(size_vmap_table_);
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07002366 DO_STAT(size_method_info_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002367 DO_STAT(size_oat_dex_file_location_size_);
2368 DO_STAT(size_oat_dex_file_location_data_);
2369 DO_STAT(size_oat_dex_file_location_checksum_);
2370 DO_STAT(size_oat_dex_file_offset_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002371 DO_STAT(size_oat_dex_file_class_offsets_offset_);
Vladimir Marko49b0f452015-12-10 13:49:19 +00002372 DO_STAT(size_oat_dex_file_lookup_table_offset_);
Mathieu Chartier120aa282017-08-05 16:03:03 -07002373 DO_STAT(size_oat_dex_file_dex_layout_sections_offset_);
2374 DO_STAT(size_oat_dex_file_dex_layout_sections_);
2375 DO_STAT(size_oat_dex_file_dex_layout_sections_alignment_);
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002376 DO_STAT(size_oat_dex_file_method_bss_mapping_offset_);
Vladimir Marko49b0f452015-12-10 13:49:19 +00002377 DO_STAT(size_oat_lookup_table_alignment_);
2378 DO_STAT(size_oat_lookup_table_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002379 DO_STAT(size_oat_class_offsets_alignment_);
2380 DO_STAT(size_oat_class_offsets_);
Brian Carlstromba150c32013-08-27 17:31:03 -07002381 DO_STAT(size_oat_class_type_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002382 DO_STAT(size_oat_class_status_);
Brian Carlstromba150c32013-08-27 17:31:03 -07002383 DO_STAT(size_oat_class_method_bitmaps_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002384 DO_STAT(size_oat_class_method_offsets_);
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002385 DO_STAT(size_method_bss_mappings_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002386 #undef DO_STAT
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002387
David Brazdil7b49e6c2016-09-01 11:06:18 +01002388 VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)";
2389
2390 CHECK_EQ(vdex_size_ + oat_size_, size_total);
2391 CHECK_EQ(file_offset + size_total - vdex_size_, static_cast<size_t>(oat_end_file_offset));
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002392 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002393
David Brazdil7b49e6c2016-09-01 11:06:18 +01002394 CHECK_EQ(file_offset + oat_size_, static_cast<size_t>(oat_end_file_offset));
2395 CHECK_EQ(oat_size_, relative_offset);
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002396
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002397 write_state_ = WriteState::kWriteHeader;
2398 return true;
2399}
2400
2401bool OatWriter::WriteHeader(OutputStream* out,
2402 uint32_t image_file_location_oat_checksum,
2403 uintptr_t image_file_location_oat_begin,
2404 int32_t image_patch_delta) {
2405 CHECK(write_state_ == WriteState::kWriteHeader);
2406
2407 oat_header_->SetImageFileLocationOatChecksum(image_file_location_oat_checksum);
2408 oat_header_->SetImageFileLocationOatDataBegin(image_file_location_oat_begin);
Vladimir Markoaad75c62016-10-03 08:46:48 +00002409 if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002410 CHECK_EQ(image_patch_delta, 0);
2411 CHECK_EQ(oat_header_->GetImagePatchDelta(), 0);
2412 } else {
2413 CHECK_ALIGNED(image_patch_delta, kPageSize);
2414 oat_header_->SetImagePatchDelta(image_patch_delta);
2415 }
Vladimir Marko49b0f452015-12-10 13:49:19 +00002416 oat_header_->UpdateChecksumWithHeaderData();
2417
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002418 const size_t file_offset = oat_data_offset_;
2419
2420 off_t current_offset = out->Seek(0, kSeekCurrent);
2421 if (current_offset == static_cast<off_t>(-1)) {
2422 PLOG(ERROR) << "Failed to get current offset from " << out->GetLocation();
2423 return false;
2424 }
Vladimir Marko49b0f452015-12-10 13:49:19 +00002425 if (out->Seek(file_offset, kSeekSet) == static_cast<off_t>(-1)) {
Vladimir Markof4da6752014-08-01 19:04:18 +01002426 PLOG(ERROR) << "Failed to seek to oat header position in " << out->GetLocation();
2427 return false;
2428 }
David Srbeckybc90fd02015-04-22 19:40:27 +01002429 DCHECK_EQ(file_offset, static_cast<size_t>(out->Seek(0, kSeekCurrent)));
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002430
2431 // Flush all other data before writing the header.
2432 if (!out->Flush()) {
2433 PLOG(ERROR) << "Failed to flush before writing oat header to " << out->GetLocation();
2434 return false;
2435 }
2436 // Write the header.
2437 size_t header_size = oat_header_->GetHeaderSize();
Vladimir Marko49b0f452015-12-10 13:49:19 +00002438 if (!out->WriteFully(oat_header_.get(), header_size)) {
Vladimir Markof4da6752014-08-01 19:04:18 +01002439 PLOG(ERROR) << "Failed to write oat header to " << out->GetLocation();
2440 return false;
2441 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002442 // Flush the header data.
2443 if (!out->Flush()) {
2444 PLOG(ERROR) << "Failed to flush after writing oat header to " << out->GetLocation();
Vladimir Markof4da6752014-08-01 19:04:18 +01002445 return false;
2446 }
Vladimir Markof4da6752014-08-01 19:04:18 +01002447
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002448 if (out->Seek(current_offset, kSeekSet) == static_cast<off_t>(-1)) {
2449 PLOG(ERROR) << "Failed to seek back after writing oat header to " << out->GetLocation();
2450 return false;
2451 }
2452 DCHECK_EQ(current_offset, out->Seek(0, kSeekCurrent));
2453
2454 write_state_ = WriteState::kDone;
Brian Carlstrome24fa612011-09-29 00:53:55 -07002455 return true;
2456}
2457
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002458size_t OatWriter::WriteClassOffsets(OutputStream* out, size_t file_offset, size_t relative_offset) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002459 for (OatDexFile& oat_dex_file : oat_dex_files_) {
2460 if (oat_dex_file.class_offsets_offset_ != 0u) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002461 // Class offsets are required to be 4 byte aligned.
2462 if (UNLIKELY(!IsAligned<4u>(relative_offset))) {
2463 size_t padding_size = RoundUp(relative_offset, 4u) - relative_offset;
2464 if (!WriteUpTo16BytesAlignment(out, padding_size, &size_oat_class_offsets_alignment_)) {
2465 return 0u;
2466 }
2467 relative_offset += padding_size;
Vladimir Marko919f5532016-01-20 19:13:01 +00002468 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002469 DCHECK_OFFSET();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002470 if (!oat_dex_file.WriteClassOffsets(this, out)) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002471 return 0u;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002472 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002473 relative_offset += oat_dex_file.GetClassOffsetsRawSize();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002474 }
2475 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002476 return relative_offset;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002477}
2478
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002479size_t OatWriter::WriteClasses(OutputStream* out, size_t file_offset, size_t relative_offset) {
Mathieu Chartier3957bff2017-07-16 13:55:27 -07002480 const bool may_have_compiled = MayHaveCompiledMethods();
2481 if (may_have_compiled) {
2482 CHECK_EQ(oat_class_headers_.size(), oat_classes_.size());
2483 }
2484 for (size_t i = 0; i < oat_class_headers_.size(); ++i) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002485 // If there are any classes, the class offsets allocation aligns the offset.
2486 DCHECK_ALIGNED(relative_offset, 4u);
2487 DCHECK_OFFSET();
Mathieu Chartier3957bff2017-07-16 13:55:27 -07002488 if (!oat_class_headers_[i].Write(this, out, oat_data_offset_)) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002489 return 0u;
Vladimir Marko919f5532016-01-20 19:13:01 +00002490 }
Mathieu Chartier3957bff2017-07-16 13:55:27 -07002491 relative_offset += oat_class_headers_[i].SizeOf();
2492 if (may_have_compiled) {
2493 if (!oat_classes_[i].Write(this, out)) {
2494 return 0u;
2495 }
2496 relative_offset += oat_classes_[i].SizeOf();
2497 }
Artem Udovichenkod9786b02015-10-14 16:36:55 +03002498 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002499 return relative_offset;
Artem Udovichenkod9786b02015-10-14 16:36:55 +03002500}
2501
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002502size_t OatWriter::WriteMaps(OutputStream* out, size_t file_offset, size_t relative_offset) {
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07002503 {
2504 size_t vmap_tables_offset = relative_offset;
2505 WriteMapMethodVisitor visitor(this, out, file_offset, relative_offset);
2506 if (UNLIKELY(!VisitDexMethods(&visitor))) {
2507 return 0;
2508 }
2509 relative_offset = visitor.GetOffset();
2510 size_vmap_table_ = relative_offset - vmap_tables_offset;
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01002511 }
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07002512 {
2513 size_t method_infos_offset = relative_offset;
2514 WriteMethodInfoVisitor visitor(this, out, file_offset, relative_offset);
2515 if (UNLIKELY(!VisitDexMethods(&visitor))) {
2516 return 0;
2517 }
2518 relative_offset = visitor.GetOffset();
2519 size_method_info_ = relative_offset - method_infos_offset;
2520 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002521
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002522 return relative_offset;
2523}
2524
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002525size_t OatWriter::WriteMethodBssMappings(OutputStream* out,
2526 size_t file_offset,
2527 size_t relative_offset) {
2528 TimingLogger::ScopedTiming split("WriteMethodBssMappings", timings_);
2529
2530 for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
2531 const DexFile* dex_file = (*dex_files_)[i];
2532 OatDexFile* oat_dex_file = &oat_dex_files_[i];
2533 auto it = bss_method_entry_references_.find(dex_file);
2534 if (it != bss_method_entry_references_.end()) {
2535 const BitVector& method_indexes = it->second;
2536 // If there are any classes, the class offsets allocation aligns the offset
2537 // and we cannot have method bss mappings without class offsets.
2538 static_assert(alignof(MethodBssMapping) == sizeof(uint32_t),
2539 "MethodBssMapping alignment check.");
2540 DCHECK_ALIGNED(relative_offset, sizeof(uint32_t));
2541
2542 linker::MethodBssMappingEncoder encoder(
2543 GetInstructionSetPointerSize(oat_header_->GetInstructionSet()));
2544 // Allocate a sufficiently large MethodBssMapping.
2545 size_t number_of_method_indexes = method_indexes.NumSetBits();
2546 DCHECK_NE(number_of_method_indexes, 0u);
2547 size_t max_mappings_size = MethodBssMapping::ComputeSize(number_of_method_indexes);
2548 DCHECK_ALIGNED(max_mappings_size, sizeof(uint32_t));
2549 std::unique_ptr<uint32_t[]> storage(new uint32_t[max_mappings_size / sizeof(uint32_t)]);
2550 MethodBssMapping* mappings = new(storage.get()) MethodBssMapping(number_of_method_indexes);
2551 mappings->ClearPadding();
2552 // Encode the MethodBssMapping.
2553 auto init_it = mappings->begin();
2554 bool first_index = true;
2555 for (uint32_t method_index : method_indexes.Indexes()) {
2556 size_t bss_offset = bss_method_entries_.Get(MethodReference(dex_file, method_index));
2557 if (first_index) {
2558 first_index = false;
2559 encoder.Reset(method_index, bss_offset);
2560 } else if (!encoder.TryMerge(method_index, bss_offset)) {
2561 *init_it = encoder.GetEntry();
2562 ++init_it;
2563 encoder.Reset(method_index, bss_offset);
2564 }
2565 }
2566 // Store the last entry and shrink the mapping to the actual size.
2567 *init_it = encoder.GetEntry();
2568 ++init_it;
2569 DCHECK(init_it <= mappings->end());
2570 mappings->SetSize(std::distance(mappings->begin(), init_it));
2571 size_t mappings_size = MethodBssMapping::ComputeSize(mappings->size());
2572
2573 DCHECK_EQ(relative_offset, oat_dex_file->method_bss_mapping_offset_);
2574 DCHECK_OFFSET();
2575 if (!out->WriteFully(storage.get(), mappings_size)) {
2576 return 0u;
2577 }
2578 size_method_bss_mappings_ += mappings_size;
2579 relative_offset += mappings_size;
2580 } else {
2581 DCHECK_EQ(0u, oat_dex_file->method_bss_mapping_offset_);
2582 }
2583 }
2584 return relative_offset;
2585}
2586
2587size_t OatWriter::WriteOatDexFiles(OutputStream* out, size_t file_offset, size_t relative_offset) {
2588 TimingLogger::ScopedTiming split("WriteOatDexFiles", timings_);
2589
2590 for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
2591 OatDexFile* oat_dex_file = &oat_dex_files_[i];
2592 DCHECK_EQ(relative_offset, oat_dex_file->offset_);
2593 DCHECK_OFFSET();
2594
2595 // Write OatDexFile.
2596 if (!oat_dex_file->Write(this, out)) {
2597 return 0u;
2598 }
2599 relative_offset += oat_dex_file->SizeOf();
2600 }
2601
2602 return relative_offset;
2603}
2604
2605size_t OatWriter::WriteCode(OutputStream* out, size_t file_offset, size_t relative_offset) {
Vladimir Markoaad75c62016-10-03 08:46:48 +00002606 if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002607 InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002608
Ian Rogers848871b2013-08-05 10:56:33 -07002609 #define DO_TRAMPOLINE(field) \
2610 do { \
2611 uint32_t aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set); \
2612 uint32_t alignment_padding = aligned_offset - relative_offset; \
Ian Rogers3d504072014-03-01 09:16:49 -08002613 out->Seek(alignment_padding, kSeekCurrent); \
Ian Rogers848871b2013-08-05 10:56:33 -07002614 size_trampoline_alignment_ += alignment_padding; \
Vladimir Markoe079e212016-05-25 12:49:49 +01002615 if (!out->WriteFully((field)->data(), (field)->size())) { \
Ian Rogers3d504072014-03-01 09:16:49 -08002616 PLOG(ERROR) << "Failed to write " # field " to " << out->GetLocation(); \
Ian Rogers848871b2013-08-05 10:56:33 -07002617 return false; \
2618 } \
Chih-Hung Hsiehfba39972016-05-11 11:26:48 -07002619 size_ ## field += (field)->size(); \
2620 relative_offset += alignment_padding + (field)->size(); \
Ian Rogers848871b2013-08-05 10:56:33 -07002621 DCHECK_OFFSET(); \
2622 } while (false)
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002623
Ian Rogers848871b2013-08-05 10:56:33 -07002624 DO_TRAMPOLINE(jni_dlsym_lookup_);
Andreas Gampe2da88232014-02-27 12:26:20 -08002625 DO_TRAMPOLINE(quick_generic_jni_trampoline_);
Jeff Hao88474b42013-10-23 16:24:40 -07002626 DO_TRAMPOLINE(quick_imt_conflict_trampoline_);
Ian Rogers848871b2013-08-05 10:56:33 -07002627 DO_TRAMPOLINE(quick_resolution_trampoline_);
2628 DO_TRAMPOLINE(quick_to_interpreter_bridge_);
2629 #undef DO_TRAMPOLINE
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002630 }
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002631 return relative_offset;
Brian Carlstrome24fa612011-09-29 00:53:55 -07002632}
2633
Ian Rogers3d504072014-03-01 09:16:49 -08002634size_t OatWriter::WriteCodeDexFiles(OutputStream* out,
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002635 size_t file_offset,
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002636 size_t relative_offset) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002637 #define VISIT(VisitorType) \
2638 do { \
2639 VisitorType visitor(this, out, file_offset, relative_offset); \
2640 if (UNLIKELY(!VisitDexMethods(&visitor))) { \
2641 return 0; \
2642 } \
2643 relative_offset = visitor.GetOffset(); \
2644 } while (false)
Brian Carlstrome24fa612011-09-29 00:53:55 -07002645
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002646 VISIT(WriteCodeMethodVisitor);
Brian Carlstrome24fa612011-09-29 00:53:55 -07002647
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002648 #undef VISIT
Brian Carlstrom265091e2013-01-30 14:08:26 -08002649
Vladimir Markob163bb72015-03-31 21:49:49 +01002650 size_code_alignment_ += relative_patcher_->CodeAlignmentSize();
2651 size_relative_call_thunks_ += relative_patcher_->RelativeCallThunksSize();
2652 size_misc_thunks_ += relative_patcher_->MiscThunksSize();
2653
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002654 return relative_offset;
Brian Carlstrome24fa612011-09-29 00:53:55 -07002655}
2656
Vladimir Marko944da602016-02-19 12:27:55 +00002657bool OatWriter::RecordOatDataOffset(OutputStream* out) {
Vladimir Marko49b0f452015-12-10 13:49:19 +00002658 // Get the elf file offset of the oat file.
2659 const off_t raw_file_offset = out->Seek(0, kSeekCurrent);
2660 if (raw_file_offset == static_cast<off_t>(-1)) {
2661 LOG(ERROR) << "Failed to get file offset in " << out->GetLocation();
2662 return false;
2663 }
2664 oat_data_offset_ = static_cast<size_t>(raw_file_offset);
2665 return true;
2666}
2667
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002668bool OatWriter::ReadDexFileHeader(File* file, OatDexFile* oat_dex_file) {
2669 // Read the dex file header and perform minimal verification.
2670 uint8_t raw_header[sizeof(DexFile::Header)];
2671 if (!file->ReadFully(&raw_header, sizeof(DexFile::Header))) {
2672 PLOG(ERROR) << "Failed to read dex file header. Actual: "
2673 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2674 return false;
2675 }
2676 if (!ValidateDexFileHeader(raw_header, oat_dex_file->GetLocation())) {
2677 return false;
2678 }
2679
2680 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_header);
2681 oat_dex_file->dex_file_size_ = header->file_size_;
2682 oat_dex_file->dex_file_location_checksum_ = header->checksum_;
2683 oat_dex_file->class_offsets_.resize(header->class_defs_size_);
2684 return true;
2685}
2686
2687bool OatWriter::ValidateDexFileHeader(const uint8_t* raw_header, const char* location) {
2688 if (!DexFile::IsMagicValid(raw_header)) {
2689 LOG(ERROR) << "Invalid magic number in dex file header. " << " File: " << location;
2690 return false;
2691 }
2692 if (!DexFile::IsVersionValid(raw_header)) {
2693 LOG(ERROR) << "Invalid version number in dex file header. " << " File: " << location;
2694 return false;
2695 }
2696 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_header);
2697 if (header->file_size_ < sizeof(DexFile::Header)) {
2698 LOG(ERROR) << "Dex file header specifies file size insufficient to contain the header."
2699 << " File: " << location;
2700 return false;
2701 }
2702 return true;
2703}
2704
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002705bool OatWriter::WriteDexFiles(OutputStream* out, File* file, bool update_input_vdex) {
David Brazdil7b49e6c2016-09-01 11:06:18 +01002706 TimingLogger::ScopedTiming split("Write Dex files", timings_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002707
David Brazdil7b49e6c2016-09-01 11:06:18 +01002708 vdex_dex_files_offset_ = vdex_size_;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002709
2710 // Write dex files.
2711 for (OatDexFile& oat_dex_file : oat_dex_files_) {
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002712 if (!WriteDexFile(out, file, &oat_dex_file, update_input_vdex)) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002713 return false;
2714 }
2715 }
2716
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002717 CloseSources();
2718 return true;
2719}
2720
2721void OatWriter::CloseSources() {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002722 for (OatDexFile& oat_dex_file : oat_dex_files_) {
2723 oat_dex_file.source_.Clear(); // Get rid of the reference, it's about to be invalidated.
2724 }
2725 zipped_dex_files_.clear();
2726 zip_archives_.clear();
2727 raw_dex_files_.clear();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002728}
2729
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002730bool OatWriter::WriteDexFile(OutputStream* out,
2731 File* file,
2732 OatDexFile* oat_dex_file,
2733 bool update_input_vdex) {
David Brazdil7b49e6c2016-09-01 11:06:18 +01002734 if (!SeekToDexFile(out, file, oat_dex_file)) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002735 return false;
2736 }
Jeff Hao608f2ce2016-10-19 11:17:11 -07002737 if (profile_compilation_info_ != nullptr) {
Nicolas Geoffray1cfea7a2017-05-24 14:44:38 +01002738 CHECK(!update_input_vdex) << "We should never update the input vdex when doing dexlayout";
Jeff Hao608f2ce2016-10-19 11:17:11 -07002739 if (!LayoutAndWriteDexFile(out, oat_dex_file)) {
2740 return false;
2741 }
2742 } else if (oat_dex_file->source_.IsZipEntry()) {
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002743 DCHECK(!update_input_vdex);
David Brazdil7b49e6c2016-09-01 11:06:18 +01002744 if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetZipEntry())) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002745 return false;
2746 }
2747 } else if (oat_dex_file->source_.IsRawFile()) {
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002748 DCHECK(!update_input_vdex);
David Brazdil7b49e6c2016-09-01 11:06:18 +01002749 if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetRawFile())) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002750 return false;
2751 }
2752 } else {
2753 DCHECK(oat_dex_file->source_.IsRawData());
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002754 if (!WriteDexFile(out, oat_dex_file, oat_dex_file->source_.GetRawData(), update_input_vdex)) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002755 return false;
2756 }
2757 }
2758
2759 // Update current size and account for the written data.
David Brazdil7b49e6c2016-09-01 11:06:18 +01002760 if (kIsVdexEnabled) {
2761 DCHECK_EQ(vdex_size_, oat_dex_file->dex_file_offset_);
2762 vdex_size_ += oat_dex_file->dex_file_size_;
2763 } else {
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002764 DCHECK(!update_input_vdex);
David Brazdil7b49e6c2016-09-01 11:06:18 +01002765 DCHECK_EQ(oat_size_, oat_dex_file->dex_file_offset_);
2766 oat_size_ += oat_dex_file->dex_file_size_;
2767 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002768 size_dex_file_ += oat_dex_file->dex_file_size_;
2769 return true;
2770}
2771
2772bool OatWriter::SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file) {
2773 // Dex files are required to be 4 byte aligned.
David Brazdil7b49e6c2016-09-01 11:06:18 +01002774 size_t initial_offset = kIsVdexEnabled ? vdex_size_ : oat_size_;
2775 size_t start_offset = RoundUp(initial_offset, 4);
2776 size_t file_offset = kIsVdexEnabled ? start_offset : (oat_data_offset_ + start_offset);
2777 size_dex_file_alignment_ += start_offset - initial_offset;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002778
2779 // Seek to the start of the dex file and flush any pending operations in the stream.
2780 // Verify that, after flushing the stream, the file is at the same offset as the stream.
David Brazdil7b49e6c2016-09-01 11:06:18 +01002781 off_t actual_offset = out->Seek(file_offset, kSeekSet);
2782 if (actual_offset != static_cast<off_t>(file_offset)) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002783 PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
David Brazdil7b49e6c2016-09-01 11:06:18 +01002784 << " Expected: " << file_offset
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002785 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2786 return false;
2787 }
2788 if (!out->Flush()) {
2789 PLOG(ERROR) << "Failed to flush before writing dex file."
2790 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2791 return false;
2792 }
2793 actual_offset = lseek(file->Fd(), 0, SEEK_CUR);
David Brazdil7b49e6c2016-09-01 11:06:18 +01002794 if (actual_offset != static_cast<off_t>(file_offset)) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002795 PLOG(ERROR) << "Stream/file position mismatch! Actual: " << actual_offset
David Brazdil7b49e6c2016-09-01 11:06:18 +01002796 << " Expected: " << file_offset
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002797 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2798 return false;
2799 }
2800
David Brazdil7b49e6c2016-09-01 11:06:18 +01002801 if (kIsVdexEnabled) {
2802 vdex_size_ = start_offset;
2803 } else {
2804 oat_size_ = start_offset;
2805 }
2806 oat_dex_file->dex_file_offset_ = start_offset;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002807 return true;
2808}
2809
Jeff Hao608f2ce2016-10-19 11:17:11 -07002810bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_file) {
2811 TimingLogger::ScopedTiming split("Dex Layout", timings_);
2812 std::string error_msg;
2813 std::string location(oat_dex_file->GetLocation());
2814 std::unique_ptr<const DexFile> dex_file;
2815 if (oat_dex_file->source_.IsZipEntry()) {
2816 ZipEntry* zip_entry = oat_dex_file->source_.GetZipEntry();
2817 std::unique_ptr<MemMap> mem_map(
2818 zip_entry->ExtractToMemMap(location.c_str(), "classes.dex", &error_msg));
Jeff Hao41b2f532017-03-02 16:36:31 -08002819 if (mem_map == nullptr) {
2820 LOG(ERROR) << "Failed to extract dex file to mem map for layout: " << error_msg;
2821 return false;
2822 }
Jeff Hao608f2ce2016-10-19 11:17:11 -07002823 dex_file = DexFile::Open(location,
2824 zip_entry->GetCrc32(),
2825 std::move(mem_map),
2826 /* verify */ true,
2827 /* verify_checksum */ true,
2828 &error_msg);
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +01002829 } else if (oat_dex_file->source_.IsRawFile()) {
Jeff Hao608f2ce2016-10-19 11:17:11 -07002830 File* raw_file = oat_dex_file->source_.GetRawFile();
Jeff Hao68c48f02017-08-24 11:36:24 -07002831 int dup_fd = dup(raw_file->Fd());
2832 if (dup_fd < 0) {
2833 PLOG(ERROR) << "Failed to dup dex file descriptor (" << raw_file->Fd() << ") at " << location;
2834 return false;
2835 }
2836 dex_file = DexFile::OpenDex(dup_fd, location, /* verify_checksum */ true, &error_msg);
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +01002837 } else {
2838 // The source data is a vdex file.
2839 CHECK(oat_dex_file->source_.IsRawData())
2840 << static_cast<size_t>(oat_dex_file->source_.GetType());
2841 const uint8_t* raw_dex_file = oat_dex_file->source_.GetRawData();
2842 // Note: The raw data has already been checked to contain the header
2843 // and all the data that the header specifies as the file size.
2844 DCHECK(raw_dex_file != nullptr);
2845 DCHECK(ValidateDexFileHeader(raw_dex_file, oat_dex_file->GetLocation()));
2846 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
2847 // Since the source may have had its layout changed, or may be quickened, don't verify it.
2848 dex_file = DexFile::Open(raw_dex_file,
2849 header->file_size_,
2850 location,
2851 oat_dex_file->dex_file_location_checksum_,
2852 nullptr,
2853 /* verify */ false,
2854 /* verify_checksum */ false,
2855 &error_msg);
Jeff Hao608f2ce2016-10-19 11:17:11 -07002856 }
Jeff Haode197542017-02-03 10:48:13 -08002857 if (dex_file == nullptr) {
Jeff Haod9df7802017-02-06 16:41:16 -08002858 LOG(ERROR) << "Failed to open dex file for layout: " << error_msg;
Jeff Haode197542017-02-03 10:48:13 -08002859 return false;
2860 }
Jeff Hao608f2ce2016-10-19 11:17:11 -07002861 Options options;
2862 options.output_to_memmap_ = true;
2863 DexLayout dex_layout(options, profile_compilation_info_, nullptr);
2864 dex_layout.ProcessDexFile(location.c_str(), dex_file.get(), 0);
2865 std::unique_ptr<MemMap> mem_map(dex_layout.GetAndReleaseMemMap());
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002866 if (!WriteDexFile(out, oat_dex_file, mem_map->Begin(), /* update_input_vdex */ false)) {
Jeff Hao608f2ce2016-10-19 11:17:11 -07002867 return false;
2868 }
Mathieu Chartier120aa282017-08-05 16:03:03 -07002869 oat_dex_file->dex_sections_layout_ = dex_layout.GetSections();
Jeff Hao608f2ce2016-10-19 11:17:11 -07002870 // Set the checksum of the new oat dex file to be the original file's checksum.
2871 oat_dex_file->dex_file_location_checksum_ = dex_file->GetLocationChecksum();
2872 return true;
2873}
2874
David Brazdil7b49e6c2016-09-01 11:06:18 +01002875bool OatWriter::WriteDexFile(OutputStream* out,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002876 File* file,
2877 OatDexFile* oat_dex_file,
2878 ZipEntry* dex_file) {
David Brazdil7b49e6c2016-09-01 11:06:18 +01002879 size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_;
2880 DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002881
2882 // Extract the dex file and get the extracted size.
2883 std::string error_msg;
2884 if (!dex_file->ExtractToFile(*file, &error_msg)) {
2885 LOG(ERROR) << "Failed to extract dex file from ZIP entry: " << error_msg
2886 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2887 return false;
2888 }
2889 if (file->Flush() != 0) {
2890 PLOG(ERROR) << "Failed to flush dex file from ZIP entry."
2891 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2892 return false;
2893 }
2894 off_t extracted_end = lseek(file->Fd(), 0, SEEK_CUR);
2895 if (extracted_end == static_cast<off_t>(-1)) {
2896 PLOG(ERROR) << "Failed get end offset after writing dex file from ZIP entry."
2897 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2898 return false;
2899 }
2900 if (extracted_end < static_cast<off_t>(start_offset)) {
2901 LOG(ERROR) << "Dex file end position is before start position! End: " << extracted_end
2902 << " Start: " << start_offset
2903 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2904 return false;
2905 }
2906 uint64_t extracted_size = static_cast<uint64_t>(extracted_end - start_offset);
2907 if (extracted_size < sizeof(DexFile::Header)) {
2908 LOG(ERROR) << "Extracted dex file is shorter than dex file header. size: "
2909 << extracted_size << " File: " << oat_dex_file->GetLocation();
2910 return false;
2911 }
2912
2913 // Read the dex file header and extract required data to OatDexFile.
2914 off_t actual_offset = lseek(file->Fd(), start_offset, SEEK_SET);
2915 if (actual_offset != static_cast<off_t>(start_offset)) {
2916 PLOG(ERROR) << "Failed to seek back to dex file header. Actual: " << actual_offset
2917 << " Expected: " << start_offset
2918 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2919 return false;
2920 }
2921 if (!ReadDexFileHeader(file, oat_dex_file)) {
2922 return false;
2923 }
2924 if (extracted_size < oat_dex_file->dex_file_size_) {
2925 LOG(ERROR) << "Extracted truncated dex file. Extracted size: " << extracted_size
2926 << " file size from header: " << oat_dex_file->dex_file_size_
2927 << " File: " << oat_dex_file->GetLocation();
2928 return false;
2929 }
2930
2931 // Override the checksum from header with the CRC from ZIP entry.
2932 oat_dex_file->dex_file_location_checksum_ = dex_file->GetCrc32();
2933
2934 // Seek both file and stream to the end offset.
2935 size_t end_offset = start_offset + oat_dex_file->dex_file_size_;
2936 actual_offset = lseek(file->Fd(), end_offset, SEEK_SET);
2937 if (actual_offset != static_cast<off_t>(end_offset)) {
2938 PLOG(ERROR) << "Failed to seek to end of dex file. Actual: " << actual_offset
2939 << " Expected: " << end_offset
2940 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2941 return false;
2942 }
David Brazdil7b49e6c2016-09-01 11:06:18 +01002943 actual_offset = out->Seek(end_offset, kSeekSet);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002944 if (actual_offset != static_cast<off_t>(end_offset)) {
2945 PLOG(ERROR) << "Failed to seek stream to end of dex file. Actual: " << actual_offset
2946 << " Expected: " << end_offset << " File: " << oat_dex_file->GetLocation();
2947 return false;
2948 }
David Brazdil7b49e6c2016-09-01 11:06:18 +01002949 if (!out->Flush()) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002950 PLOG(ERROR) << "Failed to flush stream after seeking over dex file."
2951 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2952 return false;
2953 }
2954
2955 // If we extracted more than the size specified in the header, truncate the file.
2956 if (extracted_size > oat_dex_file->dex_file_size_) {
2957 if (file->SetLength(end_offset) != 0) {
2958 PLOG(ERROR) << "Failed to truncate excessive dex file length."
David Brazdil7b49e6c2016-09-01 11:06:18 +01002959 << " File: " << oat_dex_file->GetLocation()
2960 << " Output: " << file->GetPath();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002961 return false;
2962 }
2963 }
2964
2965 return true;
2966}
2967
David Brazdil7b49e6c2016-09-01 11:06:18 +01002968bool OatWriter::WriteDexFile(OutputStream* out,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002969 File* file,
2970 OatDexFile* oat_dex_file,
2971 File* dex_file) {
David Brazdil7b49e6c2016-09-01 11:06:18 +01002972 size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_;
2973 DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002974
2975 off_t input_offset = lseek(dex_file->Fd(), 0, SEEK_SET);
2976 if (input_offset != static_cast<off_t>(0)) {
2977 PLOG(ERROR) << "Failed to seek to dex file header. Actual: " << input_offset
2978 << " Expected: 0"
2979 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2980 return false;
2981 }
2982 if (!ReadDexFileHeader(dex_file, oat_dex_file)) {
2983 return false;
2984 }
2985
2986 // Copy the input dex file using sendfile().
2987 if (!file->Copy(dex_file, 0, oat_dex_file->dex_file_size_)) {
2988 PLOG(ERROR) << "Failed to copy dex file to oat file."
2989 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2990 return false;
2991 }
2992 if (file->Flush() != 0) {
2993 PLOG(ERROR) << "Failed to flush dex file."
2994 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2995 return false;
2996 }
2997
2998 // Check file position and seek the stream to the end offset.
2999 size_t end_offset = start_offset + oat_dex_file->dex_file_size_;
3000 off_t actual_offset = lseek(file->Fd(), 0, SEEK_CUR);
3001 if (actual_offset != static_cast<off_t>(end_offset)) {
3002 PLOG(ERROR) << "Unexpected file position after copying dex file. Actual: " << actual_offset
3003 << " Expected: " << end_offset
3004 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3005 return false;
3006 }
David Brazdil7b49e6c2016-09-01 11:06:18 +01003007 actual_offset = out->Seek(end_offset, kSeekSet);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003008 if (actual_offset != static_cast<off_t>(end_offset)) {
3009 PLOG(ERROR) << "Failed to seek stream to end of dex file. Actual: " << actual_offset
3010 << " Expected: " << end_offset << " File: " << oat_dex_file->GetLocation();
3011 return false;
3012 }
David Brazdil7b49e6c2016-09-01 11:06:18 +01003013 if (!out->Flush()) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003014 PLOG(ERROR) << "Failed to flush stream after seeking over dex file."
3015 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3016 return false;
3017 }
3018
3019 return true;
3020}
3021
David Brazdil7b49e6c2016-09-01 11:06:18 +01003022bool OatWriter::WriteDexFile(OutputStream* out,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003023 OatDexFile* oat_dex_file,
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00003024 const uint8_t* dex_file,
3025 bool update_input_vdex) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003026 // Note: The raw data has already been checked to contain the header
3027 // and all the data that the header specifies as the file size.
3028 DCHECK(dex_file != nullptr);
3029 DCHECK(ValidateDexFileHeader(dex_file, oat_dex_file->GetLocation()));
3030 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(dex_file);
3031
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00003032 if (update_input_vdex) {
3033 // The vdex already contains the dex code, no need to write it again.
3034 } else {
3035 if (!out->WriteFully(dex_file, header->file_size_)) {
3036 PLOG(ERROR) << "Failed to write dex file " << oat_dex_file->GetLocation()
3037 << " to " << out->GetLocation();
3038 return false;
3039 }
3040 if (!out->Flush()) {
3041 PLOG(ERROR) << "Failed to flush stream after writing dex file."
3042 << " File: " << oat_dex_file->GetLocation();
3043 return false;
3044 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003045 }
3046
3047 // Update dex file size and resize class offsets in the OatDexFile.
3048 // Note: For raw data, the checksum is passed directly to AddRawDexFileSource().
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +00003049 // Note: For vdex, the checksum is copied from the existing vdex file.
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003050 oat_dex_file->dex_file_size_ = header->file_size_;
3051 oat_dex_file->class_offsets_.resize(header->class_defs_size_);
3052 return true;
3053}
3054
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003055bool OatWriter::OpenDexFiles(
3056 File* file,
Andreas Gampe3a2bd292016-01-26 17:23:47 -08003057 bool verify,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003058 /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map,
3059 /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
3060 TimingLogger::ScopedTiming split("OpenDexFiles", timings_);
3061
3062 if (oat_dex_files_.empty()) {
3063 // Nothing to do.
3064 return true;
3065 }
3066
3067 size_t map_offset = oat_dex_files_[0].dex_file_offset_;
David Brazdil7b49e6c2016-09-01 11:06:18 +01003068 size_t length = kIsVdexEnabled ? (vdex_size_ - map_offset) : (oat_size_ - map_offset);
3069
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003070 std::string error_msg;
David Brazdil7b49e6c2016-09-01 11:06:18 +01003071 std::unique_ptr<MemMap> dex_files_map(MemMap::MapFile(
3072 length,
3073 PROT_READ | PROT_WRITE,
3074 MAP_SHARED,
3075 file->Fd(),
3076 kIsVdexEnabled ? map_offset : (oat_data_offset_ + map_offset),
3077 /* low_4gb */ false,
3078 file->GetPath().c_str(),
3079 &error_msg));
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003080 if (dex_files_map == nullptr) {
3081 LOG(ERROR) << "Failed to mmap() dex files from oat file. File: " << file->GetPath()
3082 << " error: " << error_msg;
3083 return false;
3084 }
3085 std::vector<std::unique_ptr<const DexFile>> dex_files;
3086 for (OatDexFile& oat_dex_file : oat_dex_files_) {
3087 // Make sure no one messed with input files while we were copying data.
3088 // At the very least we need consistent file size and number of class definitions.
3089 const uint8_t* raw_dex_file =
3090 dex_files_map->Begin() + oat_dex_file.dex_file_offset_ - map_offset;
3091 if (!ValidateDexFileHeader(raw_dex_file, oat_dex_file.GetLocation())) {
3092 // Note: ValidateDexFileHeader() already logged an error message.
3093 LOG(ERROR) << "Failed to verify written dex file header!"
3094 << " Output: " << file->GetPath() << " ~ " << std::hex << map_offset
3095 << " ~ " << static_cast<const void*>(raw_dex_file);
3096 return false;
3097 }
3098 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
3099 if (header->file_size_ != oat_dex_file.dex_file_size_) {
3100 LOG(ERROR) << "File size mismatch in written dex file header! Expected: "
3101 << oat_dex_file.dex_file_size_ << " Actual: " << header->file_size_
3102 << " Output: " << file->GetPath();
3103 return false;
3104 }
3105 if (header->class_defs_size_ != oat_dex_file.class_offsets_.size()) {
3106 LOG(ERROR) << "Class defs size mismatch in written dex file header! Expected: "
3107 << oat_dex_file.class_offsets_.size() << " Actual: " << header->class_defs_size_
3108 << " Output: " << file->GetPath();
3109 return false;
3110 }
3111
3112 // Now, open the dex file.
3113 dex_files.emplace_back(DexFile::Open(raw_dex_file,
3114 oat_dex_file.dex_file_size_,
3115 oat_dex_file.GetLocation(),
3116 oat_dex_file.dex_file_location_checksum_,
3117 /* oat_dex_file */ nullptr,
Andreas Gampe3a2bd292016-01-26 17:23:47 -08003118 verify,
Aart Bik37d6a3b2016-06-21 18:30:10 -07003119 verify,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003120 &error_msg));
3121 if (dex_files.back() == nullptr) {
Andreas Gampe3a2bd292016-01-26 17:23:47 -08003122 LOG(ERROR) << "Failed to open dex file from oat file. File: " << oat_dex_file.GetLocation()
3123 << " Error: " << error_msg;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003124 return false;
3125 }
3126 }
3127
3128 *opened_dex_files_map = std::move(dex_files_map);
3129 *opened_dex_files = std::move(dex_files);
3130 return true;
3131}
3132
3133bool OatWriter::WriteTypeLookupTables(
David Brazdil7b49e6c2016-09-01 11:06:18 +01003134 OutputStream* oat_rodata,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003135 const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files) {
3136 TimingLogger::ScopedTiming split("WriteTypeLookupTables", timings_);
3137
David Brazdil7b49e6c2016-09-01 11:06:18 +01003138 uint32_t expected_offset = oat_data_offset_ + oat_size_;
3139 off_t actual_offset = oat_rodata->Seek(expected_offset, kSeekSet);
3140 if (static_cast<uint32_t>(actual_offset) != expected_offset) {
3141 PLOG(ERROR) << "Failed to seek to TypeLookupTable section. Actual: " << actual_offset
3142 << " Expected: " << expected_offset << " File: " << oat_rodata->GetLocation();
3143 return false;
3144 }
3145
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003146 DCHECK_EQ(opened_dex_files.size(), oat_dex_files_.size());
3147 for (size_t i = 0, size = opened_dex_files.size(); i != size; ++i) {
3148 OatDexFile* oat_dex_file = &oat_dex_files_[i];
David Brazdil181e1cc2016-09-01 16:38:47 +00003149 DCHECK_EQ(oat_dex_file->lookup_table_offset_, 0u);
3150
3151 if (oat_dex_file->create_type_lookup_table_ != CreateTypeLookupTable::kCreate ||
3152 oat_dex_file->class_offsets_.empty()) {
3153 continue;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003154 }
David Brazdil181e1cc2016-09-01 16:38:47 +00003155
3156 size_t table_size = TypeLookupTable::RawDataLength(oat_dex_file->class_offsets_.size());
3157 if (table_size == 0u) {
3158 continue;
3159 }
3160
3161 // Create the lookup table. When `nullptr` is given as the storage buffer,
David Sehr9aa352e2016-09-15 18:13:52 -07003162 // TypeLookupTable allocates its own and OatDexFile takes ownership.
Mathieu Chartier1b868492016-11-16 16:22:37 -08003163 const DexFile& dex_file = *opened_dex_files[i];
3164 {
3165 std::unique_ptr<TypeLookupTable> type_lookup_table =
3166 TypeLookupTable::Create(dex_file, /* storage */ nullptr);
3167 type_lookup_table_oat_dex_files_.push_back(
3168 std::make_unique<art::OatDexFile>(std::move(type_lookup_table)));
3169 dex_file.SetOatDexFile(type_lookup_table_oat_dex_files_.back().get());
3170 }
3171 TypeLookupTable* const table = type_lookup_table_oat_dex_files_.back()->GetTypeLookupTable();
David Brazdil181e1cc2016-09-01 16:38:47 +00003172
3173 // Type tables are required to be 4 byte aligned.
David Brazdil7b49e6c2016-09-01 11:06:18 +01003174 size_t initial_offset = oat_size_;
3175 size_t rodata_offset = RoundUp(initial_offset, 4);
3176 size_t padding_size = rodata_offset - initial_offset;
David Brazdil181e1cc2016-09-01 16:38:47 +00003177
3178 if (padding_size != 0u) {
3179 std::vector<uint8_t> buffer(padding_size, 0u);
David Brazdil7b49e6c2016-09-01 11:06:18 +01003180 if (!oat_rodata->WriteFully(buffer.data(), padding_size)) {
David Brazdil181e1cc2016-09-01 16:38:47 +00003181 PLOG(ERROR) << "Failed to write lookup table alignment padding."
3182 << " File: " << oat_dex_file->GetLocation()
David Brazdil7b49e6c2016-09-01 11:06:18 +01003183 << " Output: " << oat_rodata->GetLocation();
David Brazdil181e1cc2016-09-01 16:38:47 +00003184 return false;
3185 }
3186 }
3187
3188 DCHECK_EQ(oat_data_offset_ + rodata_offset,
David Brazdil7b49e6c2016-09-01 11:06:18 +01003189 static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent)));
David Brazdil181e1cc2016-09-01 16:38:47 +00003190 DCHECK_EQ(table_size, table->RawDataLength());
3191
David Brazdil7b49e6c2016-09-01 11:06:18 +01003192 if (!oat_rodata->WriteFully(table->RawData(), table_size)) {
David Brazdil181e1cc2016-09-01 16:38:47 +00003193 PLOG(ERROR) << "Failed to write lookup table."
3194 << " File: " << oat_dex_file->GetLocation()
David Brazdil7b49e6c2016-09-01 11:06:18 +01003195 << " Output: " << oat_rodata->GetLocation();
David Brazdil181e1cc2016-09-01 16:38:47 +00003196 return false;
3197 }
3198
3199 oat_dex_file->lookup_table_offset_ = rodata_offset;
3200
David Brazdil7b49e6c2016-09-01 11:06:18 +01003201 oat_size_ += padding_size + table_size;
David Brazdil181e1cc2016-09-01 16:38:47 +00003202 size_oat_lookup_table_ += table_size;
3203 size_oat_lookup_table_alignment_ += padding_size;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003204 }
3205
David Brazdil7b49e6c2016-09-01 11:06:18 +01003206 if (!oat_rodata->Flush()) {
David Brazdil181e1cc2016-09-01 16:38:47 +00003207 PLOG(ERROR) << "Failed to flush stream after writing type lookup tables."
David Brazdil7b49e6c2016-09-01 11:06:18 +01003208 << " File: " << oat_rodata->GetLocation();
3209 return false;
3210 }
3211
3212 return true;
3213}
3214
Mathieu Chartier120aa282017-08-05 16:03:03 -07003215bool OatWriter::WriteDexLayoutSections(
3216 OutputStream* oat_rodata,
3217 const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files) {
3218 TimingLogger::ScopedTiming split(__FUNCTION__, timings_);
3219
3220 if (!kWriteDexLayoutInfo) {
3221 return true;;
3222 }
3223
3224 uint32_t expected_offset = oat_data_offset_ + oat_size_;
3225 off_t actual_offset = oat_rodata->Seek(expected_offset, kSeekSet);
3226 if (static_cast<uint32_t>(actual_offset) != expected_offset) {
3227 PLOG(ERROR) << "Failed to seek to dex layout section offset section. Actual: " << actual_offset
3228 << " Expected: " << expected_offset << " File: " << oat_rodata->GetLocation();
3229 return false;
3230 }
3231
3232 DCHECK_EQ(opened_dex_files.size(), oat_dex_files_.size());
3233 size_t rodata_offset = oat_size_;
3234 for (size_t i = 0, size = opened_dex_files.size(); i != size; ++i) {
3235 OatDexFile* oat_dex_file = &oat_dex_files_[i];
3236 DCHECK_EQ(oat_dex_file->dex_sections_layout_offset_, 0u);
3237
3238 // Write dex layout section alignment bytes.
3239 const size_t padding_size =
3240 RoundUp(rodata_offset, alignof(DexLayoutSections)) - rodata_offset;
3241 if (padding_size != 0u) {
3242 std::vector<uint8_t> buffer(padding_size, 0u);
3243 if (!oat_rodata->WriteFully(buffer.data(), padding_size)) {
3244 PLOG(ERROR) << "Failed to write lookup table alignment padding."
3245 << " File: " << oat_dex_file->GetLocation()
3246 << " Output: " << oat_rodata->GetLocation();
3247 return false;
3248 }
3249 size_oat_dex_file_dex_layout_sections_alignment_ += padding_size;
3250 rodata_offset += padding_size;
3251 }
3252
3253 DCHECK_ALIGNED(rodata_offset, alignof(DexLayoutSections));
3254 DCHECK_EQ(oat_data_offset_ + rodata_offset,
3255 static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent)));
3256 DCHECK(oat_dex_file != nullptr);
3257 if (!oat_rodata->WriteFully(&oat_dex_file->dex_sections_layout_,
3258 sizeof(oat_dex_file->dex_sections_layout_))) {
3259 PLOG(ERROR) << "Failed to write dex layout sections."
3260 << " File: " << oat_dex_file->GetLocation()
3261 << " Output: " << oat_rodata->GetLocation();
3262 return false;
3263 }
3264 oat_dex_file->dex_sections_layout_offset_ = rodata_offset;
3265 size_oat_dex_file_dex_layout_sections_ += sizeof(oat_dex_file->dex_sections_layout_);
3266 rodata_offset += sizeof(oat_dex_file->dex_sections_layout_);
3267 }
3268 oat_size_ = rodata_offset;
3269
3270 if (!oat_rodata->Flush()) {
3271 PLOG(ERROR) << "Failed to flush stream after writing type dex layout sections."
3272 << " File: " << oat_rodata->GetLocation();
3273 return false;
3274 }
3275
3276 return true;
3277}
3278
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +00003279bool OatWriter::WriteChecksumsAndVdexHeader(OutputStream* vdex_out) {
David Brazdil5d5a36b2016-09-14 15:34:10 +01003280 if (!kIsVdexEnabled) {
3281 return true;
3282 }
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +00003283 // Write checksums
3284 off_t actual_offset = vdex_out->Seek(sizeof(VdexFile::Header), kSeekSet);
3285 if (actual_offset != sizeof(VdexFile::Header)) {
3286 PLOG(ERROR) << "Failed to seek to the checksum location of vdex file. Actual: " << actual_offset
3287 << " File: " << vdex_out->GetLocation();
3288 return false;
3289 }
3290
3291 for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
3292 OatDexFile* oat_dex_file = &oat_dex_files_[i];
3293 if (!vdex_out->WriteFully(
3294 &oat_dex_file->dex_file_location_checksum_, sizeof(VdexFile::VdexChecksum))) {
3295 PLOG(ERROR) << "Failed to write dex file location checksum. File: "
3296 << vdex_out->GetLocation();
3297 return false;
3298 }
3299 size_vdex_checksums_ += sizeof(VdexFile::VdexChecksum);
3300 }
3301
3302 // Write header.
3303 actual_offset = vdex_out->Seek(0, kSeekSet);
David Brazdil7b49e6c2016-09-01 11:06:18 +01003304 if (actual_offset != 0) {
3305 PLOG(ERROR) << "Failed to seek to the beginning of vdex file. Actual: " << actual_offset
3306 << " File: " << vdex_out->GetLocation();
3307 return false;
3308 }
3309
David Brazdil5d5a36b2016-09-14 15:34:10 +01003310 DCHECK_NE(vdex_dex_files_offset_, 0u);
3311 DCHECK_NE(vdex_verifier_deps_offset_, 0u);
3312
3313 size_t dex_section_size = vdex_verifier_deps_offset_ - vdex_dex_files_offset_;
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01003314 size_t verifier_deps_section_size = vdex_quickening_info_offset_ - vdex_verifier_deps_offset_;
3315 size_t quickening_info_section_size = vdex_size_ - vdex_quickening_info_offset_;
David Brazdil5d5a36b2016-09-14 15:34:10 +01003316
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +00003317 VdexFile::Header vdex_header(oat_dex_files_.size(),
3318 dex_section_size,
3319 verifier_deps_section_size,
3320 quickening_info_section_size);
David Brazdil7b49e6c2016-09-01 11:06:18 +01003321 if (!vdex_out->WriteFully(&vdex_header, sizeof(VdexFile::Header))) {
3322 PLOG(ERROR) << "Failed to write vdex header. File: " << vdex_out->GetLocation();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003323 return false;
3324 }
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +00003325 size_vdex_header_ = sizeof(VdexFile::Header);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003326
David Brazdil5d5a36b2016-09-14 15:34:10 +01003327 if (!vdex_out->Flush()) {
3328 PLOG(ERROR) << "Failed to flush stream after writing to vdex file."
3329 << " File: " << vdex_out->GetLocation();
3330 return false;
3331 }
3332
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003333 return true;
3334}
3335
Vladimir Markof4da6752014-08-01 19:04:18 +01003336bool OatWriter::WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01003337 return WriteUpTo16BytesAlignment(out, aligned_code_delta, &size_code_alignment_);
3338}
3339
3340bool OatWriter::WriteUpTo16BytesAlignment(OutputStream* out, uint32_t size, uint32_t* stat) {
Vladimir Markof4da6752014-08-01 19:04:18 +01003341 static const uint8_t kPadding[] = {
3342 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u
3343 };
Vladimir Marko0eb882b2017-05-15 13:39:18 +01003344 DCHECK_LE(size, sizeof(kPadding));
3345 if (UNLIKELY(!out->WriteFully(kPadding, size))) {
Vladimir Markof4da6752014-08-01 19:04:18 +01003346 return false;
3347 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01003348 *stat += size;
Vladimir Markof4da6752014-08-01 19:04:18 +01003349 return true;
3350}
3351
Vladimir Marko944da602016-02-19 12:27:55 +00003352void OatWriter::SetMultiOatRelativePatcherAdjustment() {
3353 DCHECK(dex_files_ != nullptr);
3354 DCHECK(relative_patcher_ != nullptr);
3355 DCHECK_NE(oat_data_offset_, 0u);
3356 if (image_writer_ != nullptr && !dex_files_->empty()) {
3357 // The oat data begin may not be initialized yet but the oat file offset is ready.
3358 size_t oat_index = image_writer_->GetOatIndexForDexFile(dex_files_->front());
3359 size_t elf_file_offset = image_writer_->GetOatFileOffset(oat_index);
3360 relative_patcher_->StartOatFile(elf_file_offset + oat_data_offset_);
Vladimir Markob163bb72015-03-31 21:49:49 +01003361 }
3362}
3363
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003364OatWriter::OatDexFile::OatDexFile(const char* dex_file_location,
3365 DexFileSource source,
3366 CreateTypeLookupTable create_type_lookup_table)
3367 : source_(source),
3368 create_type_lookup_table_(create_type_lookup_table),
3369 dex_file_size_(0),
3370 offset_(0),
3371 dex_file_location_size_(strlen(dex_file_location)),
3372 dex_file_location_data_(dex_file_location),
3373 dex_file_location_checksum_(0u),
3374 dex_file_offset_(0u),
3375 class_offsets_offset_(0u),
3376 lookup_table_offset_(0u),
Vladimir Marko0eb882b2017-05-15 13:39:18 +01003377 method_bss_mapping_offset_(0u),
Mathieu Chartier120aa282017-08-05 16:03:03 -07003378 dex_sections_layout_offset_(0u),
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003379 class_offsets_() {
Brian Carlstrome24fa612011-09-29 00:53:55 -07003380}
3381
3382size_t OatWriter::OatDexFile::SizeOf() const {
3383 return sizeof(dex_file_location_size_)
3384 + dex_file_location_size_
Brian Carlstrom5b332c82012-02-01 15:02:31 -08003385 + sizeof(dex_file_location_checksum_)
Brian Carlstrom89521892011-12-07 22:05:07 -08003386 + sizeof(dex_file_offset_)
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003387 + sizeof(class_offsets_offset_)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01003388 + sizeof(lookup_table_offset_)
Mathieu Chartier120aa282017-08-05 16:03:03 -07003389 + sizeof(method_bss_mapping_offset_)
3390 + sizeof(dex_sections_layout_offset_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003391}
3392
3393bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream* out) const {
3394 const size_t file_offset = oat_writer->oat_data_offset_;
Brian Carlstrom265091e2013-01-30 14:08:26 -08003395 DCHECK_OFFSET_();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003396
Vladimir Markoe079e212016-05-25 12:49:49 +01003397 if (!out->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08003398 PLOG(ERROR) << "Failed to write dex file location length to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07003399 return false;
3400 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07003401 oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003402
Vladimir Markoe079e212016-05-25 12:49:49 +01003403 if (!out->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
Ian Rogers3d504072014-03-01 09:16:49 -08003404 PLOG(ERROR) << "Failed to write dex file location data to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07003405 return false;
3406 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07003407 oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003408
Vladimir Markoe079e212016-05-25 12:49:49 +01003409 if (!out->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08003410 PLOG(ERROR) << "Failed to write dex file location checksum to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07003411 return false;
3412 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07003413 oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003414
Vladimir Markoe079e212016-05-25 12:49:49 +01003415 if (!out->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08003416 PLOG(ERROR) << "Failed to write dex file offset to " << out->GetLocation();
Brian Carlstrom89521892011-12-07 22:05:07 -08003417 return false;
3418 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07003419 oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003420
Vladimir Markoe079e212016-05-25 12:49:49 +01003421 if (!out->WriteFully(&class_offsets_offset_, sizeof(class_offsets_offset_))) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003422 PLOG(ERROR) << "Failed to write class offsets offset to " << out->GetLocation();
3423 return false;
3424 }
3425 oat_writer->size_oat_dex_file_class_offsets_offset_ += sizeof(class_offsets_offset_);
3426
Vladimir Markoe079e212016-05-25 12:49:49 +01003427 if (!out->WriteFully(&lookup_table_offset_, sizeof(lookup_table_offset_))) {
Artem Udovichenkod9786b02015-10-14 16:36:55 +03003428 PLOG(ERROR) << "Failed to write lookup table offset to " << out->GetLocation();
3429 return false;
3430 }
Vladimir Marko49b0f452015-12-10 13:49:19 +00003431 oat_writer->size_oat_dex_file_lookup_table_offset_ += sizeof(lookup_table_offset_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003432
Mathieu Chartier120aa282017-08-05 16:03:03 -07003433 if (!out->WriteFully(&dex_sections_layout_offset_, sizeof(dex_sections_layout_offset_))) {
3434 PLOG(ERROR) << "Failed to write dex section layout info to " << out->GetLocation();
3435 return false;
3436 }
3437 oat_writer->size_oat_dex_file_dex_layout_sections_offset_ += sizeof(dex_sections_layout_offset_);
3438
Vladimir Marko0eb882b2017-05-15 13:39:18 +01003439 if (!out->WriteFully(&method_bss_mapping_offset_, sizeof(method_bss_mapping_offset_))) {
3440 PLOG(ERROR) << "Failed to write method bss mapping offset to " << out->GetLocation();
3441 return false;
3442 }
3443 oat_writer->size_oat_dex_file_method_bss_mapping_offset_ += sizeof(method_bss_mapping_offset_);
3444
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003445 return true;
3446}
3447
3448bool OatWriter::OatDexFile::WriteClassOffsets(OatWriter* oat_writer, OutputStream* out) {
Vladimir Markoe079e212016-05-25 12:49:49 +01003449 if (!out->WriteFully(class_offsets_.data(), GetClassOffsetsRawSize())) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003450 PLOG(ERROR) << "Failed to write oat class offsets for " << GetLocation()
3451 << " to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07003452 return false;
3453 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003454 oat_writer->size_oat_class_offsets_ += GetClassOffsetsRawSize();
Brian Carlstrome24fa612011-09-29 00:53:55 -07003455 return true;
3456}
3457
Mathieu Chartier3957bff2017-07-16 13:55:27 -07003458OatWriter::OatClass::OatClass(const dchecked_vector<CompiledMethod*>& compiled_methods,
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01003459 uint32_t compiled_methods_with_code,
Mathieu Chartier3957bff2017-07-16 13:55:27 -07003460 uint16_t oat_class_type)
Vladimir Marko96c6ab92014-04-08 14:00:50 +01003461 : compiled_methods_(compiled_methods) {
Mathieu Chartier3957bff2017-07-16 13:55:27 -07003462 const uint32_t num_methods = compiled_methods.size();
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01003463 CHECK_LE(compiled_methods_with_code, num_methods);
Brian Carlstromba150c32013-08-27 17:31:03 -07003464
Brian Carlstromba150c32013-08-27 17:31:03 -07003465 oat_method_offsets_offsets_from_oat_class_.resize(num_methods);
3466
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01003467 method_offsets_.resize(compiled_methods_with_code);
3468 method_headers_.resize(compiled_methods_with_code);
Brian Carlstromba150c32013-08-27 17:31:03 -07003469
Mathieu Chartier3957bff2017-07-16 13:55:27 -07003470 uint32_t oat_method_offsets_offset_from_oat_class = OatClassHeader::SizeOf();
3471 // We only create this instance if there are at least some compiled.
3472 if (oat_class_type == kOatClassSomeCompiled) {
Vladimir Marko49b0f452015-12-10 13:49:19 +00003473 method_bitmap_.reset(new BitVector(num_methods, false, Allocator::GetMallocAllocator()));
Brian Carlstromba150c32013-08-27 17:31:03 -07003474 method_bitmap_size_ = method_bitmap_->GetSizeOf();
3475 oat_method_offsets_offset_from_oat_class += sizeof(method_bitmap_size_);
3476 oat_method_offsets_offset_from_oat_class += method_bitmap_size_;
3477 } else {
Mathieu Chartier2cebb242015-04-21 16:50:40 -07003478 method_bitmap_ = nullptr;
Brian Carlstromba150c32013-08-27 17:31:03 -07003479 method_bitmap_size_ = 0;
3480 }
3481
3482 for (size_t i = 0; i < num_methods; i++) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01003483 CompiledMethod* compiled_method = compiled_methods_[i];
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01003484 if (HasCompiledCode(compiled_method)) {
Brian Carlstromba150c32013-08-27 17:31:03 -07003485 oat_method_offsets_offsets_from_oat_class_[i] = oat_method_offsets_offset_from_oat_class;
3486 oat_method_offsets_offset_from_oat_class += sizeof(OatMethodOffsets);
Mathieu Chartier3957bff2017-07-16 13:55:27 -07003487 if (oat_class_type == kOatClassSomeCompiled) {
Brian Carlstromba150c32013-08-27 17:31:03 -07003488 method_bitmap_->SetBit(i);
3489 }
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01003490 } else {
3491 oat_method_offsets_offsets_from_oat_class_[i] = 0;
Brian Carlstromba150c32013-08-27 17:31:03 -07003492 }
3493 }
Brian Carlstrome24fa612011-09-29 00:53:55 -07003494}
3495
Brian Carlstrom265091e2013-01-30 14:08:26 -08003496size_t OatWriter::OatClass::SizeOf() const {
Mathieu Chartier3957bff2017-07-16 13:55:27 -07003497 return ((method_bitmap_size_ == 0) ? 0 : sizeof(method_bitmap_size_))
Brian Carlstromba150c32013-08-27 17:31:03 -07003498 + method_bitmap_size_
3499 + (sizeof(method_offsets_[0]) * method_offsets_.size());
Brian Carlstrome24fa612011-09-29 00:53:55 -07003500}
3501
Mathieu Chartier3957bff2017-07-16 13:55:27 -07003502bool OatWriter::OatClassHeader::Write(OatWriter* oat_writer,
3503 OutputStream* out,
3504 const size_t file_offset) const {
Brian Carlstrom265091e2013-01-30 14:08:26 -08003505 DCHECK_OFFSET_();
Vladimir Markoe079e212016-05-25 12:49:49 +01003506 if (!out->WriteFully(&status_, sizeof(status_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08003507 PLOG(ERROR) << "Failed to write class status to " << out->GetLocation();
Brian Carlstrom0755ec52012-01-11 15:19:46 -08003508 return false;
3509 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07003510 oat_writer->size_oat_class_status_ += sizeof(status_);
Vladimir Marko49b0f452015-12-10 13:49:19 +00003511
Vladimir Markoe079e212016-05-25 12:49:49 +01003512 if (!out->WriteFully(&type_, sizeof(type_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08003513 PLOG(ERROR) << "Failed to write oat class type to " << out->GetLocation();
Brian Carlstromba150c32013-08-27 17:31:03 -07003514 return false;
3515 }
3516 oat_writer->size_oat_class_type_ += sizeof(type_);
Mathieu Chartier3957bff2017-07-16 13:55:27 -07003517 return true;
3518}
Vladimir Marko49b0f452015-12-10 13:49:19 +00003519
Mathieu Chartier3957bff2017-07-16 13:55:27 -07003520bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream* out) const {
Brian Carlstromba150c32013-08-27 17:31:03 -07003521 if (method_bitmap_size_ != 0) {
Vladimir Markoe079e212016-05-25 12:49:49 +01003522 if (!out->WriteFully(&method_bitmap_size_, sizeof(method_bitmap_size_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08003523 PLOG(ERROR) << "Failed to write method bitmap size to " << out->GetLocation();
Brian Carlstromba150c32013-08-27 17:31:03 -07003524 return false;
3525 }
3526 oat_writer->size_oat_class_method_bitmaps_ += sizeof(method_bitmap_size_);
Vladimir Marko49b0f452015-12-10 13:49:19 +00003527
Vladimir Markoe079e212016-05-25 12:49:49 +01003528 if (!out->WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_size_)) {
Ian Rogers3d504072014-03-01 09:16:49 -08003529 PLOG(ERROR) << "Failed to write method bitmap to " << out->GetLocation();
Brian Carlstromba150c32013-08-27 17:31:03 -07003530 return false;
3531 }
3532 oat_writer->size_oat_class_method_bitmaps_ += method_bitmap_size_;
3533 }
Vladimir Marko49b0f452015-12-10 13:49:19 +00003534
Vladimir Markoe079e212016-05-25 12:49:49 +01003535 if (!out->WriteFully(method_offsets_.data(), GetMethodOffsetsRawSize())) {
Ian Rogers3d504072014-03-01 09:16:49 -08003536 PLOG(ERROR) << "Failed to write method offsets to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07003537 return false;
3538 }
Vladimir Marko49b0f452015-12-10 13:49:19 +00003539 oat_writer->size_oat_class_method_offsets_ += GetMethodOffsetsRawSize();
Brian Carlstrome24fa612011-09-29 00:53:55 -07003540 return true;
3541}
3542
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01003543const uint8_t* OatWriter::LookupBootImageInternTableSlot(const DexFile& dex_file,
3544 dex::StringIndex string_idx)
3545 NO_THREAD_SAFETY_ANALYSIS {
3546 // Single-threaded OatWriter can avoid locking.
3547 uint32_t utf16_length;
3548 const char* utf8_data = dex_file.StringDataAndUtf16LengthByIdx(string_idx, &utf16_length);
3549 DCHECK_EQ(utf16_length, CountModifiedUtf8Chars(utf8_data));
3550 InternTable::Utf8String string(utf16_length,
3551 utf8_data,
3552 ComputeUtf16HashFromModifiedUtf8(utf8_data, utf16_length));
3553 const InternTable* intern_table = Runtime::Current()->GetClassLinker()->intern_table_;
3554 for (const InternTable::Table::UnorderedSet& table : intern_table->strong_interns_.tables_) {
3555 auto it = table.Find(string);
3556 if (it != table.end()) {
3557 return reinterpret_cast<const uint8_t*>(std::addressof(*it));
3558 }
3559 }
3560 LOG(FATAL) << "Did not find boot image string " << utf8_data;
3561 UNREACHABLE();
3562}
3563
Brian Carlstrome24fa612011-09-29 00:53:55 -07003564} // namespace art