blob: 4fcfdc058c3748b34e081515cf21de35c9347332 [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 Marko94ec2db2017-09-06 17:21:03 +010031#include "class_table-inl.h"
Vladimir Marko20f85592015-03-19 10:07:02 +000032#include "compiled_method.h"
David Srbecky4fda4eb2016-02-05 13:34:46 +000033#include "debug/method_debug_info.h"
Vladimir Markoc7f83202014-01-24 17:55:18 +000034#include "dex/verification_results.h"
David Srbecky4fda4eb2016-02-05 13:34:46 +000035#include "dex_file-inl.h"
Andreas Gampee2abbc62017-09-15 11:59:26 -070036#include "dex_file_types.h"
Jeff Hao608f2ce2016-10-19 11:17:11 -070037#include "dexlayout.h"
Andreas Gamped482e732017-04-24 17:59:09 -070038#include "driver/compiler_driver-inl.h"
Vladimir Marko20f85592015-03-19 10:07:02 +000039#include "driver/compiler_options.h"
Vladimir Marko09d09432015-09-08 13:47:48 +010040#include "gc/space/image_space.h"
Ian Rogers1d54e732013-05-02 21:10:01 -070041#include "gc/space/space.h"
Artem Udovichenkod9786b02015-10-14 16:36:55 +030042#include "handle_scope-inl.h"
Vladimir Markof4da6752014-08-01 19:04:18 +010043#include "image_writer.h"
David Brazdil7b49e6c2016-09-01 11:06:18 +010044#include "linker/buffered_output_stream.h"
45#include "linker/file_output_stream.h"
Vladimir Marko0eb882b2017-05-15 13:39:18 +010046#include "linker/method_bss_mapping_encoder.h"
Vladimir Marko944da602016-02-19 12:27:55 +000047#include "linker/multi_oat_relative_patcher.h"
Vladimir Marko131980f2015-12-03 18:29:23 +000048#include "linker/output_stream.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080049#include "mirror/array.h"
50#include "mirror/class_loader.h"
Vladimir Marko3481ba22015-04-13 12:22:36 +010051#include "mirror/dex_cache-inl.h"
Ian Rogers4f6ad8a2013-03-18 15:27:28 -070052#include "mirror/object-inl.h"
Nicolas Geoffray524e7ea2015-10-16 17:13:34 +010053#include "oat_quick_method_header.h"
Brian Carlstrome24fa612011-09-29 00:53:55 -070054#include "os.h"
Elliott Hughesa0e18062012-04-13 15:59:59 -070055#include "safe_map.h"
Mathieu Chartier0795f232016-09-27 18:43:30 -070056#include "scoped_thread_state_change-inl.h"
Artem Udovichenkod9786b02015-10-14 16:36:55 +030057#include "type_lookup_table.h"
Vladimir Marko09d09432015-09-08 13:47:48 +010058#include "utils/dex_cache_arrays_layout-inl.h"
David Brazdil7b49e6c2016-09-01 11:06:18 +010059#include "vdex_file.h"
David Brazdil5d5a36b2016-09-14 15:34:10 +010060#include "verifier/verifier_deps.h"
Vladimir Marko9bdf1082016-01-21 12:15:52 +000061#include "zip_archive.h"
Brian Carlstrome24fa612011-09-29 00:53:55 -070062
63namespace art {
64
Vladimir Marko9bdf1082016-01-21 12:15:52 +000065namespace { // anonymous namespace
66
Mathieu Chartier120aa282017-08-05 16:03:03 -070067// If we write dex layout info in the oat file.
68static constexpr bool kWriteDexLayoutInfo = true;
69
Vladimir Marko9bdf1082016-01-21 12:15:52 +000070typedef DexFile::Header __attribute__((aligned(1))) UnalignedDexFileHeader;
71
72const UnalignedDexFileHeader* AsUnalignedDexFileHeader(const uint8_t* raw_data) {
73 return reinterpret_cast<const UnalignedDexFileHeader*>(raw_data);
74}
75
Vladimir Markoe079e212016-05-25 12:49:49 +010076class ChecksumUpdatingOutputStream : public OutputStream {
77 public:
78 ChecksumUpdatingOutputStream(OutputStream* out, OatHeader* oat_header)
79 : OutputStream(out->GetLocation()), out_(out), oat_header_(oat_header) { }
80
81 bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE {
82 oat_header_->UpdateChecksum(buffer, byte_count);
83 return out_->WriteFully(buffer, byte_count);
84 }
85
86 off_t Seek(off_t offset, Whence whence) OVERRIDE {
87 return out_->Seek(offset, whence);
88 }
89
90 bool Flush() OVERRIDE {
91 return out_->Flush();
92 }
93
94 private:
95 OutputStream* const out_;
96 OatHeader* const oat_header_;
97};
98
Vladimir Marko0c737df2016-08-01 16:33:16 +010099inline uint32_t CodeAlignmentSize(uint32_t header_offset, const CompiledMethod& compiled_method) {
100 // We want to align the code rather than the preheader.
101 uint32_t unaligned_code_offset = header_offset + sizeof(OatQuickMethodHeader);
102 uint32_t aligned_code_offset = compiled_method.AlignCode(unaligned_code_offset);
103 return aligned_code_offset - unaligned_code_offset;
104}
105
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000106} // anonymous namespace
107
108// Defines the location of the raw dex file to write.
109class OatWriter::DexFileSource {
110 public:
Mathieu Chartier497d5262017-02-28 20:17:30 -0800111 enum Type {
112 kNone,
113 kZipEntry,
114 kRawFile,
115 kRawData,
116 };
117
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000118 explicit DexFileSource(ZipEntry* zip_entry)
119 : type_(kZipEntry), source_(zip_entry) {
120 DCHECK(source_ != nullptr);
121 }
122
123 explicit DexFileSource(File* raw_file)
124 : type_(kRawFile), source_(raw_file) {
125 DCHECK(source_ != nullptr);
126 }
127
128 explicit DexFileSource(const uint8_t* dex_file)
129 : type_(kRawData), source_(dex_file) {
130 DCHECK(source_ != nullptr);
131 }
132
Mathieu Chartier497d5262017-02-28 20:17:30 -0800133 Type GetType() const { return type_; }
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000134 bool IsZipEntry() const { return type_ == kZipEntry; }
135 bool IsRawFile() const { return type_ == kRawFile; }
136 bool IsRawData() const { return type_ == kRawData; }
137
138 ZipEntry* GetZipEntry() const {
139 DCHECK(IsZipEntry());
140 DCHECK(source_ != nullptr);
141 return static_cast<ZipEntry*>(const_cast<void*>(source_));
142 }
143
144 File* GetRawFile() const {
145 DCHECK(IsRawFile());
146 DCHECK(source_ != nullptr);
147 return static_cast<File*>(const_cast<void*>(source_));
148 }
149
150 const uint8_t* GetRawData() const {
151 DCHECK(IsRawData());
152 DCHECK(source_ != nullptr);
153 return static_cast<const uint8_t*>(source_);
154 }
155
156 void Clear() {
157 type_ = kNone;
158 source_ = nullptr;
159 }
160
161 private:
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000162 Type type_;
163 const void* source_;
164};
165
Mathieu Chartier3957bff2017-07-16 13:55:27 -0700166// OatClassHeader is the header only part of the oat class that is required even when compilation
167// is not enabled.
168class OatWriter::OatClassHeader {
169 public:
170 OatClassHeader(uint32_t offset,
171 uint32_t num_non_null_compiled_methods,
172 uint32_t num_methods,
173 mirror::Class::Status status)
174 : status_(status),
175 offset_(offset) {
176 // We just arbitrarily say that 0 methods means kOatClassNoneCompiled and that we won't use
177 // kOatClassAllCompiled unless there is at least one compiled method. This means in an
178 // interpreter only system, we can assert that all classes are kOatClassNoneCompiled.
179 if (num_non_null_compiled_methods == 0) {
180 type_ = kOatClassNoneCompiled;
181 } else if (num_non_null_compiled_methods == num_methods) {
182 type_ = kOatClassAllCompiled;
183 } else {
184 type_ = kOatClassSomeCompiled;
185 }
186 }
187
188 bool Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const;
189
190 static size_t SizeOf() {
191 return sizeof(status_) + sizeof(type_);
192 }
193
194 // Data to write.
195 static_assert(mirror::Class::Status::kStatusMax < (1 << 16), "class status won't fit in 16bits");
196 int16_t status_;
197
198 static_assert(OatClassType::kOatClassMax < (1 << 16), "oat_class type won't fit in 16bits");
199 uint16_t type_;
200
201 // Offset of start of OatClass from beginning of OatHeader. It is
202 // used to validate file position when writing.
203 uint32_t offset_;
204};
205
206// The actual oat class body contains the information about compiled methods. It is only required
207// for compiler filters that have any compilation.
Vladimir Marko49b0f452015-12-10 13:49:19 +0000208class OatWriter::OatClass {
209 public:
Mathieu Chartier3957bff2017-07-16 13:55:27 -0700210 OatClass(const dchecked_vector<CompiledMethod*>& compiled_methods,
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100211 uint32_t compiled_methods_with_code,
Mathieu Chartier3957bff2017-07-16 13:55:27 -0700212 uint16_t oat_class_type);
Vladimir Marko49b0f452015-12-10 13:49:19 +0000213 OatClass(OatClass&& src) = default;
Vladimir Marko49b0f452015-12-10 13:49:19 +0000214 size_t SizeOf() const;
Mathieu Chartier3957bff2017-07-16 13:55:27 -0700215 bool Write(OatWriter* oat_writer, OutputStream* out) const;
Vladimir Marko49b0f452015-12-10 13:49:19 +0000216
217 CompiledMethod* GetCompiledMethod(size_t class_def_method_index) const {
218 return compiled_methods_[class_def_method_index];
219 }
220
Vladimir Marko49b0f452015-12-10 13:49:19 +0000221 // CompiledMethods for each class_def_method_index, or null if no method is available.
222 dchecked_vector<CompiledMethod*> compiled_methods_;
223
224 // Offset from OatClass::offset_ to the OatMethodOffsets for the
225 // class_def_method_index. If 0, it means the corresponding
226 // CompiledMethod entry in OatClass::compiled_methods_ should be
227 // null and that the OatClass::type_ should be kOatClassBitmap.
228 dchecked_vector<uint32_t> oat_method_offsets_offsets_from_oat_class_;
229
230 // Data to write.
Vladimir Marko49b0f452015-12-10 13:49:19 +0000231 uint32_t method_bitmap_size_;
232
233 // bit vector indexed by ClassDef method index. When
234 // OatClassType::type_ is kOatClassBitmap, a set bit indicates the
235 // method has an OatMethodOffsets in methods_offsets_, otherwise
236 // the entry was ommited to save space. If OatClassType::type_ is
237 // not is kOatClassBitmap, the bitmap will be null.
238 std::unique_ptr<BitVector> method_bitmap_;
239
240 // OatMethodOffsets and OatMethodHeaders for each CompiledMethod
241 // present in the OatClass. Note that some may be missing if
242 // OatClass::compiled_methods_ contains null values (and
243 // oat_method_offsets_offsets_from_oat_class_ should contain 0
244 // values in this case).
245 dchecked_vector<OatMethodOffsets> method_offsets_;
246 dchecked_vector<OatQuickMethodHeader> method_headers_;
247
248 private:
249 size_t GetMethodOffsetsRawSize() const {
250 return method_offsets_.size() * sizeof(method_offsets_[0]);
251 }
252
253 DISALLOW_COPY_AND_ASSIGN(OatClass);
254};
255
256class OatWriter::OatDexFile {
257 public:
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000258 OatDexFile(const char* dex_file_location,
259 DexFileSource source,
260 CreateTypeLookupTable create_type_lookup_table);
Vladimir Marko49b0f452015-12-10 13:49:19 +0000261 OatDexFile(OatDexFile&& src) = default;
262
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000263 const char* GetLocation() const {
264 return dex_file_location_data_;
265 }
266
Vladimir Marko49b0f452015-12-10 13:49:19 +0000267 size_t SizeOf() const;
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000268 bool Write(OatWriter* oat_writer, OutputStream* out) const;
269 bool WriteClassOffsets(OatWriter* oat_writer, OutputStream* out);
270
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100271 size_t GetClassOffsetsRawSize() const {
272 return class_offsets_.size() * sizeof(class_offsets_[0]);
273 }
274
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000275 // The source of the dex file.
276 DexFileSource source_;
277
278 // Whether to create the type lookup table.
279 CreateTypeLookupTable create_type_lookup_table_;
280
281 // Dex file size. Initialized when writing the dex file.
282 size_t dex_file_size_;
Vladimir Marko49b0f452015-12-10 13:49:19 +0000283
284 // Offset of start of OatDexFile from beginning of OatHeader. It is
285 // used to validate file position when writing.
286 size_t offset_;
287
288 // Data to write.
289 uint32_t dex_file_location_size_;
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000290 const char* dex_file_location_data_;
Vladimir Marko49b0f452015-12-10 13:49:19 +0000291 uint32_t dex_file_location_checksum_;
292 uint32_t dex_file_offset_;
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000293 uint32_t class_offsets_offset_;
Vladimir Marko49b0f452015-12-10 13:49:19 +0000294 uint32_t lookup_table_offset_;
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100295 uint32_t method_bss_mapping_offset_;
Mathieu Chartier120aa282017-08-05 16:03:03 -0700296 uint32_t dex_sections_layout_offset_;
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000297
298 // Data to write to a separate section.
Vladimir Marko49b0f452015-12-10 13:49:19 +0000299 dchecked_vector<uint32_t> class_offsets_;
300
Mathieu Chartier120aa282017-08-05 16:03:03 -0700301 // Dex section layout info to serialize.
302 DexLayoutSections dex_sections_layout_;
303
Vladimir Marko49b0f452015-12-10 13:49:19 +0000304 private:
Vladimir Marko49b0f452015-12-10 13:49:19 +0000305 DISALLOW_COPY_AND_ASSIGN(OatDexFile);
306};
307
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100308#define DCHECK_OFFSET() \
309 DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out->Seek(0, kSeekCurrent)) \
310 << "file_offset=" << file_offset << " relative_offset=" << relative_offset
311
312#define DCHECK_OFFSET_() \
313 DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \
314 << "file_offset=" << file_offset << " offset_=" << offset_
315
Jeff Hao608f2ce2016-10-19 11:17:11 -0700316OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings, ProfileCompilationInfo* info)
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000317 : write_state_(WriteState::kAddingDexFileSources),
318 timings_(timings),
319 raw_dex_files_(),
320 zip_archives_(),
321 zipped_dex_files_(),
322 zipped_dex_file_locations_(),
323 compiler_driver_(nullptr),
324 image_writer_(nullptr),
Mathieu Chartierda5b28a2015-11-05 08:03:47 -0800325 compiling_boot_image_(compiling_boot_image),
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000326 dex_files_(nullptr),
David Brazdil7b49e6c2016-09-01 11:06:18 +0100327 vdex_size_(0u),
328 vdex_dex_files_offset_(0u),
David Brazdil5d5a36b2016-09-14 15:34:10 +0100329 vdex_verifier_deps_offset_(0u),
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100330 vdex_quickening_info_offset_(0u),
David Brazdil7b49e6c2016-09-01 11:06:18 +0100331 oat_size_(0u),
Vladimir Markoaad75c62016-10-03 08:46:48 +0000332 bss_start_(0u),
Vladimir Marko5c42c292015-02-25 12:02:49 +0000333 bss_size_(0u),
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100334 bss_methods_offset_(0u),
Vladimir Markoaad75c62016-10-03 08:46:48 +0000335 bss_roots_offset_(0u),
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100336 bss_method_entry_references_(),
337 bss_method_entries_(),
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000338 bss_type_entries_(),
Vladimir Markoaad75c62016-10-03 08:46:48 +0000339 bss_string_entries_(),
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +0100340 map_boot_image_tables_to_bss_(false),
Vladimir Markof4da6752014-08-01 19:04:18 +0100341 oat_data_offset_(0u),
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700342 oat_header_(nullptr),
David Brazdil7b49e6c2016-09-01 11:06:18 +0100343 size_vdex_header_(0),
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000344 size_vdex_checksums_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700345 size_dex_file_alignment_(0),
346 size_executable_offset_alignment_(0),
347 size_oat_header_(0),
Andreas Gampe22f8e5c2014-07-09 11:38:21 -0700348 size_oat_header_key_value_store_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700349 size_dex_file_(0),
David Brazdil5d5a36b2016-09-14 15:34:10 +0100350 size_verifier_deps_(0),
351 size_verifier_deps_alignment_(0),
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100352 size_quickening_info_(0),
353 size_quickening_info_alignment_(0),
Ian Rogers848871b2013-08-05 10:56:33 -0700354 size_interpreter_to_interpreter_bridge_(0),
355 size_interpreter_to_compiled_code_bridge_(0),
356 size_jni_dlsym_lookup_(0),
Andreas Gampe2da88232014-02-27 12:26:20 -0800357 size_quick_generic_jni_trampoline_(0),
Jeff Hao88474b42013-10-23 16:24:40 -0700358 size_quick_imt_conflict_trampoline_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700359 size_quick_resolution_trampoline_(0),
Ian Rogers848871b2013-08-05 10:56:33 -0700360 size_quick_to_interpreter_bridge_(0),
361 size_trampoline_alignment_(0),
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100362 size_method_header_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700363 size_code_(0),
364 size_code_alignment_(0),
Vladimir Markof4da6752014-08-01 19:04:18 +0100365 size_relative_call_thunks_(0),
Vladimir Markoc74658b2015-03-31 10:26:41 +0100366 size_misc_thunks_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700367 size_vmap_table_(0),
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700368 size_method_info_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700369 size_oat_dex_file_location_size_(0),
370 size_oat_dex_file_location_data_(0),
371 size_oat_dex_file_location_checksum_(0),
372 size_oat_dex_file_offset_(0),
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000373 size_oat_dex_file_class_offsets_offset_(0),
Vladimir Marko49b0f452015-12-10 13:49:19 +0000374 size_oat_dex_file_lookup_table_offset_(0),
Mathieu Chartier120aa282017-08-05 16:03:03 -0700375 size_oat_dex_file_dex_layout_sections_offset_(0),
376 size_oat_dex_file_dex_layout_sections_(0),
377 size_oat_dex_file_dex_layout_sections_alignment_(0),
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100378 size_oat_dex_file_method_bss_mapping_offset_(0),
Vladimir Marko49b0f452015-12-10 13:49:19 +0000379 size_oat_lookup_table_alignment_(0),
380 size_oat_lookup_table_(0),
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000381 size_oat_class_offsets_alignment_(0),
382 size_oat_class_offsets_(0),
Brian Carlstromba150c32013-08-27 17:31:03 -0700383 size_oat_class_type_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700384 size_oat_class_status_(0),
Brian Carlstromba150c32013-08-27 17:31:03 -0700385 size_oat_class_method_bitmaps_(0),
Vladimir Markof4da6752014-08-01 19:04:18 +0100386 size_oat_class_method_offsets_(0),
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100387 size_method_bss_mappings_(0u),
Vladimir Marko944da602016-02-19 12:27:55 +0000388 relative_patcher_(nullptr),
Jeff Hao608f2ce2016-10-19 11:17:11 -0700389 absolute_patch_locations_(),
390 profile_compilation_info_(info) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000391}
392
393bool OatWriter::AddDexFileSource(const char* filename,
394 const char* location,
395 CreateTypeLookupTable create_type_lookup_table) {
396 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
397 uint32_t magic;
398 std::string error_msg;
Andreas Gampe43e10b02016-07-15 17:17:34 -0700399 File fd = OpenAndReadMagic(filename, &magic, &error_msg);
400 if (fd.Fd() == -1) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000401 PLOG(ERROR) << "Failed to read magic number from dex file: '" << filename << "'";
402 return false;
403 } else if (IsDexMagic(magic)) {
404 // The file is open for reading, not writing, so it's OK to let the File destructor
405 // close it without checking for explicit Close(), so pass checkUsage = false.
Andreas Gampe43e10b02016-07-15 17:17:34 -0700406 raw_dex_files_.emplace_back(new File(fd.Release(), location, /* checkUsage */ false));
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000407 oat_dex_files_.emplace_back(location,
408 DexFileSource(raw_dex_files_.back().get()),
409 create_type_lookup_table);
410 } else if (IsZipMagic(magic)) {
411 if (!AddZippedDexFilesSource(std::move(fd), location, create_type_lookup_table)) {
412 return false;
413 }
414 } else {
415 LOG(ERROR) << "Expected valid zip or dex file: '" << filename << "'";
416 return false;
417 }
418 return true;
419}
420
421// Add dex file source(s) from a zip file specified by a file handle.
Andreas Gampe43e10b02016-07-15 17:17:34 -0700422bool OatWriter::AddZippedDexFilesSource(File&& zip_fd,
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000423 const char* location,
424 CreateTypeLookupTable create_type_lookup_table) {
425 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
426 std::string error_msg;
Andreas Gampe43e10b02016-07-15 17:17:34 -0700427 zip_archives_.emplace_back(ZipArchive::OpenFromFd(zip_fd.Release(), location, &error_msg));
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000428 ZipArchive* zip_archive = zip_archives_.back().get();
429 if (zip_archive == nullptr) {
430 LOG(ERROR) << "Failed to open zip from file descriptor for '" << location << "': "
431 << error_msg;
432 return false;
433 }
434 for (size_t i = 0; ; ++i) {
435 std::string entry_name = DexFile::GetMultiDexClassesDexName(i);
436 std::unique_ptr<ZipEntry> entry(zip_archive->Find(entry_name.c_str(), &error_msg));
437 if (entry == nullptr) {
438 break;
439 }
440 zipped_dex_files_.push_back(std::move(entry));
441 zipped_dex_file_locations_.push_back(DexFile::GetMultiDexLocation(i, location));
442 const char* full_location = zipped_dex_file_locations_.back().c_str();
443 oat_dex_files_.emplace_back(full_location,
444 DexFileSource(zipped_dex_files_.back().get()),
445 create_type_lookup_table);
446 }
447 if (zipped_dex_file_locations_.empty()) {
448 LOG(ERROR) << "No dex files in zip file '" << location << "': " << error_msg;
449 return false;
450 }
451 return true;
452}
453
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000454// Add dex file source(s) from a vdex file specified by a file handle.
455bool OatWriter::AddVdexDexFilesSource(const VdexFile& vdex_file,
456 const char* location,
457 CreateTypeLookupTable create_type_lookup_table) {
458 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
459 const uint8_t* current_dex_data = nullptr;
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000460 for (size_t i = 0; i < vdex_file.GetHeader().GetNumberOfDexFiles(); ++i) {
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000461 current_dex_data = vdex_file.GetNextDexFileData(current_dex_data);
462 if (current_dex_data == nullptr) {
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000463 LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
464 return false;
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000465 }
466 if (!DexFile::IsMagicValid(current_dex_data)) {
467 LOG(ERROR) << "Invalid magic in vdex file created from " << location;
468 return false;
469 }
470 // We used `zipped_dex_file_locations_` to keep the strings in memory.
471 zipped_dex_file_locations_.push_back(DexFile::GetMultiDexLocation(i, location));
472 const char* full_location = zipped_dex_file_locations_.back().c_str();
473 oat_dex_files_.emplace_back(full_location,
474 DexFileSource(current_dex_data),
475 create_type_lookup_table);
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000476 oat_dex_files_.back().dex_file_location_checksum_ = vdex_file.GetLocationChecksum(i);
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000477 }
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000478
479 if (vdex_file.GetNextDexFileData(current_dex_data) != nullptr) {
480 LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
481 return false;
482 }
483
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000484 if (oat_dex_files_.empty()) {
485 LOG(ERROR) << "No dex files in vdex file created from " << location;
486 return false;
487 }
488 return true;
489}
490
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000491// Add dex file source from raw memory.
492bool OatWriter::AddRawDexFileSource(const ArrayRef<const uint8_t>& data,
493 const char* location,
494 uint32_t location_checksum,
495 CreateTypeLookupTable create_type_lookup_table) {
496 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
497 if (data.size() < sizeof(DexFile::Header)) {
498 LOG(ERROR) << "Provided data is shorter than dex file header. size: "
499 << data.size() << " File: " << location;
500 return false;
501 }
502 if (!ValidateDexFileHeader(data.data(), location)) {
503 return false;
504 }
505 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(data.data());
506 if (data.size() < header->file_size_) {
507 LOG(ERROR) << "Truncated dex file data. Data size: " << data.size()
508 << " file size from header: " << header->file_size_ << " File: " << location;
509 return false;
510 }
511
512 oat_dex_files_.emplace_back(location, DexFileSource(data.data()), create_type_lookup_table);
513 oat_dex_files_.back().dex_file_location_checksum_ = location_checksum;
514 return true;
515}
516
Calin Juravle1ce70852017-06-28 10:59:03 -0700517dchecked_vector<std::string> OatWriter::GetSourceLocations() const {
518 dchecked_vector<std::string> locations;
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000519 locations.reserve(oat_dex_files_.size());
520 for (const OatDexFile& oat_dex_file : oat_dex_files_) {
521 locations.push_back(oat_dex_file.GetLocation());
522 }
523 return locations;
524}
525
Mathieu Chartier3957bff2017-07-16 13:55:27 -0700526bool OatWriter::MayHaveCompiledMethods() const {
527 return CompilerFilter::IsAnyCompilationEnabled(
528 GetCompilerDriver()->GetCompilerOptions().GetCompilerFilter());
529}
530
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000531bool OatWriter::WriteAndOpenDexFiles(
David Brazdil7b49e6c2016-09-01 11:06:18 +0100532 File* vdex_file,
533 OutputStream* oat_rodata,
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000534 InstructionSet instruction_set,
535 const InstructionSetFeatures* instruction_set_features,
536 SafeMap<std::string, std::string>* key_value_store,
Andreas Gampe3a2bd292016-01-26 17:23:47 -0800537 bool verify,
Nicolas Geoffray81f57d12016-12-20 13:17:09 +0000538 bool update_input_vdex,
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000539 /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map,
540 /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
541 CHECK(write_state_ == WriteState::kAddingDexFileSources);
542
David Brazdil7b49e6c2016-09-01 11:06:18 +0100543 // Record the ELF rodata section offset, i.e. the beginning of the OAT data.
544 if (!RecordOatDataOffset(oat_rodata)) {
545 return false;
546 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000547
548 std::unique_ptr<MemMap> dex_files_map;
549 std::vector<std::unique_ptr<const DexFile>> dex_files;
David Brazdil7b49e6c2016-09-01 11:06:18 +0100550
551 // Initialize VDEX and OAT headers.
552 if (kIsVdexEnabled) {
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000553 // Reserve space for Vdex header and checksums.
554 vdex_size_ = sizeof(VdexFile::Header) + oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum);
David Brazdil7b49e6c2016-09-01 11:06:18 +0100555 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100556 oat_size_ = InitOatHeader(instruction_set,
557 instruction_set_features,
558 dchecked_integral_cast<uint32_t>(oat_dex_files_.size()),
559 key_value_store);
David Brazdil7b49e6c2016-09-01 11:06:18 +0100560
561 ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, oat_header_.get());
562
563 if (kIsVdexEnabled) {
Andreas Gampe8bdda5a2017-06-08 15:30:36 -0700564 std::unique_ptr<BufferedOutputStream> vdex_out =
565 std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file));
David Brazdil7b49e6c2016-09-01 11:06:18 +0100566 // Write DEX files into VDEX, mmap and open them.
Nicolas Geoffray81f57d12016-12-20 13:17:09 +0000567 if (!WriteDexFiles(vdex_out.get(), vdex_file, update_input_vdex) ||
David Brazdil7b49e6c2016-09-01 11:06:18 +0100568 !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
569 return false;
570 }
David Brazdil7b49e6c2016-09-01 11:06:18 +0100571 } else {
Nicolas Geoffray81f57d12016-12-20 13:17:09 +0000572 DCHECK(!update_input_vdex);
David Brazdil7b49e6c2016-09-01 11:06:18 +0100573 // Write DEX files into OAT, mmap and open them.
Nicolas Geoffray81f57d12016-12-20 13:17:09 +0000574 if (!WriteDexFiles(oat_rodata, vdex_file, update_input_vdex) ||
David Brazdil7b49e6c2016-09-01 11:06:18 +0100575 !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
576 return false;
577 }
578
579 // Do a bulk checksum update for Dex[]. Doing it piece by piece would be
580 // difficult because we're not using the OutputStream directly.
581 if (!oat_dex_files_.empty()) {
582 size_t size = oat_size_ - oat_dex_files_[0].dex_file_offset_;
583 oat_header_->UpdateChecksum(dex_files_map->Begin(), size);
584 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000585 }
David Brazdil181e1cc2016-09-01 16:38:47 +0000586
Mathieu Chartier120aa282017-08-05 16:03:03 -0700587 // Write type lookup tables into the oat file.
David Brazdil181e1cc2016-09-01 16:38:47 +0000588 if (!WriteTypeLookupTables(&checksum_updating_rodata, dex_files)) {
589 return false;
590 }
591
Mathieu Chartier120aa282017-08-05 16:03:03 -0700592 // Write dex layout sections into the oat file.
593 if (!WriteDexLayoutSections(&checksum_updating_rodata, dex_files)) {
594 return false;
595 }
596
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000597 *opened_dex_files_map = std::move(dex_files_map);
598 *opened_dex_files = std::move(dex_files);
599 write_state_ = WriteState::kPrepareLayout;
600 return true;
601}
602
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100603void OatWriter::PrepareLayout(linker::MultiOatRelativePatcher* relative_patcher) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000604 CHECK(write_state_ == WriteState::kPrepareLayout);
605
Vladimir Marko944da602016-02-19 12:27:55 +0000606 relative_patcher_ = relative_patcher;
607 SetMultiOatRelativePatcherAdjustment();
608
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000609 if (compiling_boot_image_) {
610 CHECK(image_writer_ != nullptr);
Mathieu Chartierda5b28a2015-11-05 08:03:47 -0800611 }
Vladimir Markob163bb72015-03-31 21:49:49 +0100612 InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000613 CHECK_EQ(instruction_set, oat_header_->GetInstructionSet());
Vladimir Markof4da6752014-08-01 19:04:18 +0100614
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100615 {
616 TimingLogger::ScopedTiming split("InitBssLayout", timings_);
617 InitBssLayout(instruction_set);
618 }
619
David Brazdil7b49e6c2016-09-01 11:06:18 +0100620 uint32_t offset = oat_size_;
Ian Rogersca368cb2013-11-15 15:52:08 -0800621 {
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100622 TimingLogger::ScopedTiming split("InitClassOffsets", timings_);
623 offset = InitClassOffsets(offset);
624 }
625 {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000626 TimingLogger::ScopedTiming split("InitOatClasses", timings_);
Ian Rogersca368cb2013-11-15 15:52:08 -0800627 offset = InitOatClasses(offset);
628 }
629 {
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100630 TimingLogger::ScopedTiming split("InitMethodBssMappings", timings_);
631 offset = InitMethodBssMappings(offset);
632 }
633 {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000634 TimingLogger::ScopedTiming split("InitOatMaps", timings_);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100635 offset = InitOatMaps(offset);
636 }
637 {
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100638 TimingLogger::ScopedTiming split("InitOatDexFiles", timings_);
639 oat_header_->SetOatDexFilesOffset(offset);
640 offset = InitOatDexFiles(offset);
641 }
642 {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000643 TimingLogger::ScopedTiming split("InitOatCode", timings_);
Ian Rogersca368cb2013-11-15 15:52:08 -0800644 offset = InitOatCode(offset);
645 }
646 {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000647 TimingLogger::ScopedTiming split("InitOatCodeDexFiles", timings_);
Ian Rogersca368cb2013-11-15 15:52:08 -0800648 offset = InitOatCodeDexFiles(offset);
649 }
David Brazdil7b49e6c2016-09-01 11:06:18 +0100650 oat_size_ = offset;
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100651 bss_start_ = (bss_size_ != 0u) ? RoundUp(oat_size_, kPageSize) : 0u;
Vladimir Marko09d09432015-09-08 13:47:48 +0100652
Brian Carlstrome24fa612011-09-29 00:53:55 -0700653 CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
Mathieu Chartierda5b28a2015-11-05 08:03:47 -0800654 if (compiling_boot_image_) {
655 CHECK_EQ(image_writer_ != nullptr,
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000656 oat_header_->GetStoreValueByKey(OatHeader::kImageLocationKey) == nullptr);
Mathieu Chartierda5b28a2015-11-05 08:03:47 -0800657 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000658
659 write_state_ = WriteState::kWriteRoData;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700660}
661
Ian Rogers0571d352011-11-03 19:51:38 -0700662OatWriter::~OatWriter() {
Ian Rogers0571d352011-11-03 19:51:38 -0700663}
664
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100665class OatWriter::DexMethodVisitor {
666 public:
667 DexMethodVisitor(OatWriter* writer, size_t offset)
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100668 : writer_(writer),
669 offset_(offset),
670 dex_file_(nullptr),
Andreas Gampee2abbc62017-09-15 11:59:26 -0700671 class_def_index_(dex::kDexNoIndex) {}
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100672
673 virtual bool StartClass(const DexFile* dex_file, size_t class_def_index) {
674 DCHECK(dex_file_ == nullptr);
Andreas Gampee2abbc62017-09-15 11:59:26 -0700675 DCHECK_EQ(class_def_index_, dex::kDexNoIndex);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100676 dex_file_ = dex_file;
677 class_def_index_ = class_def_index;
678 return true;
679 }
680
681 virtual bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) = 0;
682
683 virtual bool EndClass() {
684 if (kIsDebugBuild) {
685 dex_file_ = nullptr;
Andreas Gampee2abbc62017-09-15 11:59:26 -0700686 class_def_index_ = dex::kDexNoIndex;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100687 }
688 return true;
689 }
690
691 size_t GetOffset() const {
692 return offset_;
693 }
694
695 protected:
696 virtual ~DexMethodVisitor() { }
697
698 OatWriter* const writer_;
699
700 // The offset is usually advanced for each visited method by the derived class.
701 size_t offset_;
702
703 // The dex file and class def index are set in StartClass().
704 const DexFile* dex_file_;
705 size_t class_def_index_;
706};
707
708class OatWriter::OatDexMethodVisitor : public DexMethodVisitor {
709 public:
710 OatDexMethodVisitor(OatWriter* writer, size_t offset)
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100711 : DexMethodVisitor(writer, offset),
712 oat_class_index_(0u),
713 method_offsets_index_(0u) {}
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100714
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100715 bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE {
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100716 DexMethodVisitor::StartClass(dex_file, class_def_index);
Mathieu Chartier3957bff2017-07-16 13:55:27 -0700717 if (kIsDebugBuild && writer_->MayHaveCompiledMethods()) {
718 // There are no oat classes if there aren't any compiled methods.
719 CHECK_LT(oat_class_index_, writer_->oat_classes_.size());
720 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100721 method_offsets_index_ = 0u;
722 return true;
723 }
724
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100725 bool EndClass() OVERRIDE {
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100726 ++oat_class_index_;
727 return DexMethodVisitor::EndClass();
728 }
729
730 protected:
731 size_t oat_class_index_;
732 size_t method_offsets_index_;
733};
734
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100735static bool HasCompiledCode(const CompiledMethod* method) {
736 // The dextodexcompiler puts the quickening info table into the CompiledMethod
737 // for simplicity. For such methods, we will emit an OatQuickMethodHeader
738 // only when vdex is disabled.
739 return method != nullptr && (!method->GetQuickCode().empty() || !kIsVdexEnabled);
740}
741
742static bool HasQuickeningInfo(const CompiledMethod* method) {
743 return method != nullptr && method->GetQuickCode().empty() && !method->GetVmapTable().empty();
744}
745
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100746class OatWriter::InitBssLayoutMethodVisitor : public DexMethodVisitor {
747 public:
748 explicit InitBssLayoutMethodVisitor(OatWriter* writer)
749 : DexMethodVisitor(writer, /* offset */ 0u) {}
750
751 bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,
752 const ClassDataItemIterator& it) OVERRIDE {
753 // Look for patches with .bss references and prepare maps with placeholders for their offsets.
754 CompiledMethod* compiled_method = writer_->compiler_driver_->GetCompiledMethod(
755 MethodReference(dex_file_, it.GetMemberIndex()));
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100756 if (HasCompiledCode(compiled_method)) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100757 for (const LinkerPatch& patch : compiled_method->GetPatches()) {
758 if (patch.GetType() == LinkerPatch::Type::kMethodBssEntry) {
759 MethodReference target_method = patch.TargetMethod();
760 auto refs_it = writer_->bss_method_entry_references_.find(target_method.dex_file);
761 if (refs_it == writer_->bss_method_entry_references_.end()) {
762 refs_it = writer_->bss_method_entry_references_.Put(
763 target_method.dex_file,
764 BitVector(target_method.dex_file->NumMethodIds(),
765 /* expandable */ false,
766 Allocator::GetMallocAllocator()));
767 refs_it->second.ClearAllBits();
768 }
769 refs_it->second.SetBit(target_method.dex_method_index);
770 writer_->bss_method_entries_.Overwrite(target_method, /* placeholder */ 0u);
771 } else if (patch.GetType() == LinkerPatch::Type::kTypeBssEntry) {
772 TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex());
773 writer_->bss_type_entries_.Overwrite(ref, /* placeholder */ 0u);
774 } else if (patch.GetType() == LinkerPatch::Type::kStringBssEntry) {
775 StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
776 writer_->bss_string_entries_.Overwrite(ref, /* placeholder */ 0u);
Vladimir Marko94ec2db2017-09-06 17:21:03 +0100777 } else if (patch.GetType() == LinkerPatch::Type::kStringInternTable ||
778 patch.GetType() == LinkerPatch::Type::kTypeClassTable) {
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +0100779 writer_->map_boot_image_tables_to_bss_ = true;
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100780 }
781 }
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100782 } else {
783 DCHECK(compiled_method == nullptr || compiled_method->GetPatches().empty());
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100784 }
785 return true;
786 }
787};
788
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100789class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor {
790 public:
791 InitOatClassesMethodVisitor(OatWriter* writer, size_t offset)
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100792 : DexMethodVisitor(writer, offset),
793 compiled_methods_(),
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100794 compiled_methods_with_code_(0u) {
Vladimir Marko49b0f452015-12-10 13:49:19 +0000795 size_t num_classes = 0u;
796 for (const OatDexFile& oat_dex_file : writer_->oat_dex_files_) {
797 num_classes += oat_dex_file.class_offsets_.size();
798 }
Mathieu Chartier3957bff2017-07-16 13:55:27 -0700799 // If we aren't compiling only reserve headers.
800 writer_->oat_class_headers_.reserve(num_classes);
801 if (writer->MayHaveCompiledMethods()) {
802 writer->oat_classes_.reserve(num_classes);
803 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100804 compiled_methods_.reserve(256u);
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100805 // If there are any classes, the class offsets allocation aligns the offset.
806 DCHECK(num_classes == 0u || IsAligned<4u>(offset));
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100807 }
808
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100809 bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE {
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100810 DexMethodVisitor::StartClass(dex_file, class_def_index);
811 compiled_methods_.clear();
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100812 compiled_methods_with_code_ = 0u;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100813 return true;
814 }
815
Artem Udovichenkod9786b02015-10-14 16:36:55 +0300816 bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100817 const ClassDataItemIterator& it) OVERRIDE {
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100818 // Fill in the compiled_methods_ array for methods that have a
819 // CompiledMethod. We track the number of non-null entries in
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100820 // compiled_methods_with_code_ since we only want to allocate
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100821 // OatMethodOffsets for the compiled methods.
822 uint32_t method_idx = it.GetMemberIndex();
823 CompiledMethod* compiled_method =
824 writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
825 compiled_methods_.push_back(compiled_method);
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100826 if (HasCompiledCode(compiled_method)) {
827 ++compiled_methods_with_code_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100828 }
829 return true;
830 }
831
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100832 bool EndClass() OVERRIDE {
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100833 ClassReference class_ref(dex_file_, class_def_index_);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100834 mirror::Class::Status status;
Andreas Gampebb846102017-05-11 21:03:35 -0700835 bool found = writer_->compiler_driver_->GetCompiledClass(class_ref, &status);
836 if (!found) {
Mathieu Chartier0733dc82017-07-17 14:05:28 -0700837 VerificationResults* results = writer_->compiler_driver_->GetVerificationResults();
838 if (results != nullptr && results->IsClassRejected(class_ref)) {
Andreas Gampebb846102017-05-11 21:03:35 -0700839 // The oat class status is used only for verification of resolved classes,
840 // so use kStatusErrorResolved whether the class was resolved or unresolved
841 // during compile-time verification.
842 status = mirror::Class::kStatusErrorResolved;
843 } else {
844 status = mirror::Class::kStatusNotReady;
845 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100846 }
847
Mathieu Chartier3957bff2017-07-16 13:55:27 -0700848 writer_->oat_class_headers_.emplace_back(offset_,
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100849 compiled_methods_with_code_,
Mathieu Chartier3957bff2017-07-16 13:55:27 -0700850 compiled_methods_.size(),
851 status);
852 OatClassHeader& header = writer_->oat_class_headers_.back();
853 offset_ += header.SizeOf();
854 if (writer_->MayHaveCompiledMethods()) {
855 writer_->oat_classes_.emplace_back(compiled_methods_,
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100856 compiled_methods_with_code_,
Mathieu Chartier3957bff2017-07-16 13:55:27 -0700857 header.type_);
858 offset_ += writer_->oat_classes_.back().SizeOf();
859 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100860 return DexMethodVisitor::EndClass();
861 }
862
863 private:
Vladimir Marko49b0f452015-12-10 13:49:19 +0000864 dchecked_vector<CompiledMethod*> compiled_methods_;
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100865 size_t compiled_methods_with_code_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100866};
867
868class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor {
869 public:
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100870 InitCodeMethodVisitor(OatWriter* writer, size_t offset)
Vladimir Marko1b404a82017-09-01 13:35:26 +0100871 : InitCodeMethodVisitor(writer, offset, writer->GetCompilerDriver()->GetCompilerOptions()) {}
Vladimir Markof4da6752014-08-01 19:04:18 +0100872
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100873 bool EndClass() OVERRIDE {
Vladimir Markof4da6752014-08-01 19:04:18 +0100874 OatDexMethodVisitor::EndClass();
875 if (oat_class_index_ == writer_->oat_classes_.size()) {
Vladimir Marko1b404a82017-09-01 13:35:26 +0100876 offset_ = relative_patcher_->ReserveSpaceEnd(offset_);
877 if (generate_debug_info_) {
878 std::vector<debug::MethodDebugInfo> thunk_infos =
879 relative_patcher_->GenerateThunkDebugInfo(executable_offset_);
880 writer_->method_info_.insert(writer_->method_info_.end(),
881 std::make_move_iterator(thunk_infos.begin()),
882 std::make_move_iterator(thunk_infos.end()));
883 }
Vladimir Markof4da6752014-08-01 19:04:18 +0100884 }
885 return true;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100886 }
887
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100888 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700889 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko49b0f452015-12-10 13:49:19 +0000890 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100891 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
892
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100893 if (HasCompiledCode(compiled_method)) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100894 // Derived from CompiledMethod.
895 uint32_t quick_code_offset = 0;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100896
Vladimir Marko35831e82015-09-11 11:59:18 +0100897 ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
898 uint32_t code_size = quick_code.size() * sizeof(uint8_t);
Elliott Hughes956af0f2014-12-11 14:34:28 -0800899 uint32_t thumb_offset = compiled_method->CodeDelta();
Elliott Hughes956af0f2014-12-11 14:34:28 -0800900
David Srbecky009e2a62015-04-15 02:46:30 +0100901 // Deduplicate code arrays if we are not producing debuggable code.
Vladimir Marko9d07e3d2016-03-31 12:02:28 +0100902 bool deduped = true;
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800903 MethodReference method_ref(dex_file_, it.GetMemberIndex());
Nicolas Geoffrayed6195a2015-07-13 17:02:30 +0000904 if (debuggable_) {
Vladimir Marko1b404a82017-09-01 13:35:26 +0100905 quick_code_offset = relative_patcher_->GetOffset(method_ref);
Vladimir Marko944da602016-02-19 12:27:55 +0000906 if (quick_code_offset != 0u) {
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800907 // Duplicate methods, we want the same code for both of them so that the oat writer puts
908 // the same code in both ArtMethods so that we do not get different oat code at runtime.
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800909 } else {
910 quick_code_offset = NewQuickCodeOffset(compiled_method, it, thumb_offset);
Vladimir Marko9d07e3d2016-03-31 12:02:28 +0100911 deduped = false;
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800912 }
Nicolas Geoffrayed6195a2015-07-13 17:02:30 +0000913 } else {
Vladimir Marko9d07e3d2016-03-31 12:02:28 +0100914 quick_code_offset = dedupe_map_.GetOrCreate(
915 compiled_method,
916 [this, &deduped, compiled_method, &it, thumb_offset]() {
917 deduped = false;
918 return NewQuickCodeOffset(compiled_method, it, thumb_offset);
919 });
Elliott Hughes956af0f2014-12-11 14:34:28 -0800920 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100921
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100922 if (code_size != 0) {
Vladimir Marko1b404a82017-09-01 13:35:26 +0100923 if (relative_patcher_->GetOffset(method_ref) != 0u) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100924 // TODO: Should this be a hard failure?
925 LOG(WARNING) << "Multiple definitions of "
David Sehr709b0702016-10-13 09:12:37 -0700926 << method_ref.dex_file->PrettyMethod(method_ref.dex_method_index)
Vladimir Marko1b404a82017-09-01 13:35:26 +0100927 << " offsets " << relative_patcher_->GetOffset(method_ref)
Vladimir Marko944da602016-02-19 12:27:55 +0000928 << " " << quick_code_offset;
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100929 } else {
Vladimir Marko1b404a82017-09-01 13:35:26 +0100930 relative_patcher_->SetOffset(method_ref, quick_code_offset);
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100931 }
Elliott Hughes956af0f2014-12-11 14:34:28 -0800932 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100933
Elliott Hughes956af0f2014-12-11 14:34:28 -0800934 // Update quick method header.
935 DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size());
936 OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
Mingyao Yang063fc772016-08-02 11:02:54 -0700937 uint32_t vmap_table_offset = method_header->GetVmapTableOffset();
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700938 uint32_t method_info_offset = method_header->GetMethodInfoOffset();
Elliott Hughes956af0f2014-12-11 14:34:28 -0800939 // The code offset was 0 when the mapping/vmap table offset was set, so it's set
940 // to 0-offset and we need to adjust it by code_offset.
941 uint32_t code_offset = quick_code_offset - thumb_offset;
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100942 if (!compiled_method->GetQuickCode().empty()) {
943 // If the code is compiled, we write the offset of the stack map relative
944 // to the code,
945 if (vmap_table_offset != 0u) {
946 vmap_table_offset += code_offset;
947 DCHECK_LT(vmap_table_offset, code_offset);
948 }
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700949 if (method_info_offset != 0u) {
950 method_info_offset += code_offset;
951 DCHECK_LT(method_info_offset, code_offset);
952 }
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100953 } else {
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100954 CHECK(!kIsVdexEnabled);
955 // We write the offset of the quickening info relative to the code.
956 vmap_table_offset += code_offset;
957 DCHECK_LT(vmap_table_offset, code_offset);
Elliott Hughes956af0f2014-12-11 14:34:28 -0800958 }
Elliott Hughes956af0f2014-12-11 14:34:28 -0800959 uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
960 uint32_t core_spill_mask = compiled_method->GetCoreSpillMask();
961 uint32_t fp_spill_mask = compiled_method->GetFpSpillMask();
Vladimir Marko9d07e3d2016-03-31 12:02:28 +0100962 *method_header = OatQuickMethodHeader(vmap_table_offset,
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700963 method_info_offset,
Vladimir Marko9d07e3d2016-03-31 12:02:28 +0100964 frame_size_in_bytes,
965 core_spill_mask,
966 fp_spill_mask,
967 code_size);
Vladimir Marko7624d252014-05-02 14:40:15 +0100968
Nicolas Geoffrayed6195a2015-07-13 17:02:30 +0000969 if (!deduped) {
Elliott Hughes956af0f2014-12-11 14:34:28 -0800970 // Update offsets. (Checksum is updated when writing.)
971 offset_ += sizeof(*method_header); // Method header is prepended before code.
972 offset_ += code_size;
973 // Record absolute patch locations.
974 if (!compiled_method->GetPatches().empty()) {
975 uintptr_t base_loc = offset_ - code_size - writer_->oat_header_->GetExecutableOffset();
976 for (const LinkerPatch& patch : compiled_method->GetPatches()) {
Vladimir Marko20f85592015-03-19 10:07:02 +0000977 if (!patch.IsPcRelative()) {
David Srbeckyf8980872015-05-22 17:04:47 +0100978 writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset());
Vladimir Markof4da6752014-08-01 19:04:18 +0100979 }
980 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100981 }
Elliott Hughes956af0f2014-12-11 14:34:28 -0800982 }
Alex Light78382fa2014-06-06 15:45:32 -0700983
David Srbecky197160d2016-03-07 17:33:57 +0000984 // Exclude quickened dex methods (code_size == 0) since they have no native code.
Vladimir Marko1b404a82017-09-01 13:35:26 +0100985 if (generate_debug_info_ && code_size != 0) {
David Srbecky197160d2016-03-07 17:33:57 +0000986 bool has_code_info = method_header->IsOptimized();
Elliott Hughes956af0f2014-12-11 14:34:28 -0800987 // Record debug information for this function if we are doing that.
Vladimir Marko1b404a82017-09-01 13:35:26 +0100988 debug::MethodDebugInfo info = {};
989 DCHECK(info.trampoline_name.empty());
David Srbecky197160d2016-03-07 17:33:57 +0000990 info.dex_file = dex_file_;
991 info.class_def_index = class_def_index_;
992 info.dex_method_index = it.GetMemberIndex();
993 info.access_flags = it.GetMethodAccessFlags();
994 info.code_item = it.GetMethodCodeItem();
995 info.isa = compiled_method->GetInstructionSet();
996 info.deduped = deduped;
Vladimir Marko1b404a82017-09-01 13:35:26 +0100997 info.is_native_debuggable = native_debuggable_;
David Srbecky197160d2016-03-07 17:33:57 +0000998 info.is_optimized = method_header->IsOptimized();
999 info.is_code_address_text_relative = true;
Vladimir Marko1b404a82017-09-01 13:35:26 +01001000 info.code_address = code_offset - executable_offset_;
David Srbecky197160d2016-03-07 17:33:57 +00001001 info.code_size = code_size;
1002 info.frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
1003 info.code_info = has_code_info ? compiled_method->GetVmapTable().data() : nullptr;
1004 info.cfi = compiled_method->GetCFIInfo();
1005 writer_->method_info_.push_back(info);
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001006 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001007
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001008 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1009 OatMethodOffsets* offsets = &oat_class->method_offsets_[method_offsets_index_];
1010 offsets->code_offset_ = quick_code_offset;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001011 ++method_offsets_index_;
1012 }
1013
1014 return true;
1015 }
1016
1017 private:
Vladimir Marko1b404a82017-09-01 13:35:26 +01001018 InitCodeMethodVisitor(OatWriter* writer, size_t offset, const CompilerOptions& compiler_options)
1019 : OatDexMethodVisitor(writer, offset),
1020 relative_patcher_(writer->relative_patcher_),
1021 executable_offset_(writer->oat_header_->GetExecutableOffset()),
1022 debuggable_(compiler_options.GetDebuggable()),
1023 native_debuggable_(compiler_options.GetNativeDebuggable()),
1024 generate_debug_info_(compiler_options.GenerateAnyDebugInfo()) {
1025 writer->absolute_patch_locations_.reserve(
1026 writer->GetCompilerDriver()->GetNonRelativeLinkerPatchCount());
1027 }
1028
Vladimir Marko20f85592015-03-19 10:07:02 +00001029 struct CodeOffsetsKeyComparator {
1030 bool operator()(const CompiledMethod* lhs, const CompiledMethod* rhs) const {
Vladimir Marko35831e82015-09-11 11:59:18 +01001031 // Code is deduplicated by CompilerDriver, compare only data pointers.
1032 if (lhs->GetQuickCode().data() != rhs->GetQuickCode().data()) {
1033 return lhs->GetQuickCode().data() < rhs->GetQuickCode().data();
Vladimir Marko20f85592015-03-19 10:07:02 +00001034 }
1035 // If the code is the same, all other fields are likely to be the same as well.
Vladimir Marko35831e82015-09-11 11:59:18 +01001036 if (UNLIKELY(lhs->GetVmapTable().data() != rhs->GetVmapTable().data())) {
1037 return lhs->GetVmapTable().data() < rhs->GetVmapTable().data();
Vladimir Marko20f85592015-03-19 10:07:02 +00001038 }
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001039 if (UNLIKELY(lhs->GetMethodInfo().data() != rhs->GetMethodInfo().data())) {
1040 return lhs->GetMethodInfo().data() < rhs->GetMethodInfo().data();
1041 }
Vladimir Marko35831e82015-09-11 11:59:18 +01001042 if (UNLIKELY(lhs->GetPatches().data() != rhs->GetPatches().data())) {
1043 return lhs->GetPatches().data() < rhs->GetPatches().data();
Vladimir Marko20f85592015-03-19 10:07:02 +00001044 }
1045 return false;
1046 }
1047 };
1048
David Srbecky009e2a62015-04-15 02:46:30 +01001049 uint32_t NewQuickCodeOffset(CompiledMethod* compiled_method,
1050 const ClassDataItemIterator& it,
1051 uint32_t thumb_offset) {
Vladimir Marko1b404a82017-09-01 13:35:26 +01001052 offset_ = relative_patcher_->ReserveSpace(
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001053 offset_, compiled_method, MethodReference(dex_file_, it.GetMemberIndex()));
Vladimir Marko0c737df2016-08-01 16:33:16 +01001054 offset_ += CodeAlignmentSize(offset_, *compiled_method);
1055 DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader),
David Srbecky009e2a62015-04-15 02:46:30 +01001056 GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
1057 return offset_ + sizeof(OatQuickMethodHeader) + thumb_offset;
1058 }
1059
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001060 // Deduplication is already done on a pointer basis by the compiler driver,
1061 // so we can simply compare the pointers to find out if things are duplicated.
Vladimir Marko8a630572014-04-09 18:45:35 +01001062 SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_;
David Srbecky2f6cdb02015-04-11 00:17:53 +01001063
Vladimir Marko1b404a82017-09-01 13:35:26 +01001064 // Cache writer_'s members and compiler options.
1065 linker::MultiOatRelativePatcher* relative_patcher_;
1066 uint32_t executable_offset_;
David Srbecky009e2a62015-04-15 02:46:30 +01001067 const bool debuggable_;
Vladimir Marko1b404a82017-09-01 13:35:26 +01001068 const bool native_debuggable_;
1069 const bool generate_debug_info_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001070};
1071
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001072class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor {
1073 public:
1074 InitMapMethodVisitor(OatWriter* writer, size_t offset)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001075 : OatDexMethodVisitor(writer, offset) {}
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001076
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001077 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001078 OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko49b0f452015-12-10 13:49:19 +00001079 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001080 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1081
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01001082 if (HasCompiledCode(compiled_method)) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001083 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01001084 DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].GetVmapTableOffset(), 0u);
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001085
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01001086 ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
1087 uint32_t map_size = map.size() * sizeof(map[0]);
1088 if (map_size != 0u) {
1089 size_t offset = dedupe_map_.GetOrCreate(
1090 map.data(),
1091 [this, map_size]() {
1092 uint32_t new_offset = offset_;
1093 offset_ += map_size;
1094 return new_offset;
1095 });
1096 // Code offset is not initialized yet, so set the map offset to 0u-offset.
1097 DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u);
1098 oat_class->method_headers_[method_offsets_index_].SetVmapTableOffset(0u - offset);
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001099 }
1100 ++method_offsets_index_;
1101 }
1102
1103 return true;
1104 }
1105
1106 private:
1107 // Deduplication is already done on a pointer basis by the compiler driver,
1108 // so we can simply compare the pointers to find out if things are duplicated.
Vladimir Marko35831e82015-09-11 11:59:18 +01001109 SafeMap<const uint8_t*, uint32_t> dedupe_map_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001110};
1111
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001112class OatWriter::InitMethodInfoVisitor : public OatDexMethodVisitor {
1113 public:
1114 InitMethodInfoVisitor(OatWriter* writer, size_t offset) : OatDexMethodVisitor(writer, offset) {}
1115
1116 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001117 OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001118 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1119 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1120
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01001121 if (HasCompiledCode(compiled_method)) {
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001122 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1123 DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].GetMethodInfoOffset(), 0u);
1124 ArrayRef<const uint8_t> map = compiled_method->GetMethodInfo();
1125 const uint32_t map_size = map.size() * sizeof(map[0]);
1126 if (map_size != 0u) {
1127 size_t offset = dedupe_map_.GetOrCreate(
1128 map.data(),
1129 [this, map_size]() {
1130 uint32_t new_offset = offset_;
1131 offset_ += map_size;
1132 return new_offset;
1133 });
1134 // Code offset is not initialized yet, so set the map offset to 0u-offset.
1135 DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u);
1136 oat_class->method_headers_[method_offsets_index_].SetMethodInfoOffset(0u - offset);
1137 }
1138 ++method_offsets_index_;
1139 }
1140
1141 return true;
1142 }
1143
1144 private:
1145 // Deduplication is already done on a pointer basis by the compiler driver,
1146 // so we can simply compare the pointers to find out if things are duplicated.
1147 SafeMap<const uint8_t*, uint32_t> dedupe_map_;
1148};
1149
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001150class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor {
1151 public:
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001152 InitImageMethodVisitor(OatWriter* writer,
1153 size_t offset,
1154 const std::vector<const DexFile*>* dex_files)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001155 : OatDexMethodVisitor(writer, offset),
1156 pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())),
Vladimir Marko07bfbac2017-07-06 14:55:02 +01001157 class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr),
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001158 dex_files_(dex_files),
1159 class_linker_(Runtime::Current()->GetClassLinker()) {}
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001160
1161 // Handle copied methods here. Copy pointer to quick code from
1162 // an origin method to a copied method only if they are
1163 // in the same oat file. If the origin and the copied methods are
1164 // in different oat files don't touch the copied method.
1165 // References to other oat files are not supported yet.
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001166 bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001167 REQUIRES_SHARED(Locks::mutator_lock_) {
1168 OatDexMethodVisitor::StartClass(dex_file, class_def_index);
1169 // Skip classes that are not in the image.
1170 if (!IsImageClass()) {
1171 return true;
1172 }
Vladimir Marko07bfbac2017-07-06 14:55:02 +01001173 ObjPtr<mirror::DexCache> dex_cache = class_linker_->FindDexCache(Thread::Current(), *dex_file);
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001174 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
1175 mirror::Class* klass = dex_cache->GetResolvedType(class_def.class_idx_);
1176 if (klass != nullptr) {
1177 for (ArtMethod& method : klass->GetCopiedMethods(pointer_size_)) {
1178 // Find origin method. Declaring class and dex_method_idx
1179 // in the copied method should be the same as in the origin
1180 // method.
1181 mirror::Class* declaring_class = method.GetDeclaringClass();
Vladimir Markoba118822017-06-12 15:41:56 +01001182 ArtMethod* origin = declaring_class->FindClassMethod(
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001183 declaring_class->GetDexCache(),
1184 method.GetDexMethodIndex(),
1185 pointer_size_);
1186 CHECK(origin != nullptr);
Vladimir Markoba118822017-06-12 15:41:56 +01001187 CHECK(!origin->IsDirect());
1188 CHECK(origin->GetDeclaringClass() == declaring_class);
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001189 if (IsInOatFile(&declaring_class->GetDexFile())) {
1190 const void* code_ptr =
1191 origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
1192 if (code_ptr == nullptr) {
1193 methods_to_process_.push_back(std::make_pair(&method, origin));
1194 } else {
1195 method.SetEntryPointFromQuickCompiledCodePtrSize(
1196 code_ptr, pointer_size_);
1197 }
1198 }
1199 }
1200 }
1201 return true;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001202 }
1203
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001204 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001205 REQUIRES_SHARED(Locks::mutator_lock_) {
Jeff Haodcdc85b2015-12-04 14:06:18 -08001206 // Skip methods that are not in the image.
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001207 if (!IsImageClass()) {
Jeff Haodcdc85b2015-12-04 14:06:18 -08001208 return true;
1209 }
1210
Vladimir Marko49b0f452015-12-10 13:49:19 +00001211 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001212 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1213
Mathieu Chartier957ca1c2014-11-21 16:51:29 -08001214 OatMethodOffsets offsets(0u);
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01001215 if (HasCompiledCode(compiled_method)) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001216 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1217 offsets = oat_class->method_offsets_[method_offsets_index_];
1218 ++method_offsets_index_;
1219 }
1220
Vladimir Marko07bfbac2017-07-06 14:55:02 +01001221 Thread* self = Thread::Current();
1222 ObjPtr<mirror::DexCache> dex_cache = class_linker_->FindDexCache(self, *dex_file_);
Mathieu Chartierfbc31082016-01-24 11:59:56 -08001223 ArtMethod* method;
1224 if (writer_->HasBootImage()) {
1225 const InvokeType invoke_type = it.GetMethodInvokeType(
1226 dex_file_->GetClassDef(class_def_index_));
Vladimir Marko07bfbac2017-07-06 14:55:02 +01001227 // Unchecked as we hold mutator_lock_ on entry.
1228 ScopedObjectAccessUnchecked soa(self);
1229 StackHandleScope<1> hs(self);
Vladimir Markoba118822017-06-12 15:41:56 +01001230 method = class_linker_->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
Mathieu Chartierfbc31082016-01-24 11:59:56 -08001231 *dex_file_,
1232 it.GetMemberIndex(),
Vladimir Marko07bfbac2017-07-06 14:55:02 +01001233 hs.NewHandle(dex_cache),
Mathieu Chartierfbc31082016-01-24 11:59:56 -08001234 ScopedNullHandle<mirror::ClassLoader>(),
1235 nullptr,
1236 invoke_type);
1237 if (method == nullptr) {
Andreas Gampe3fec9ac2016-09-13 10:47:28 -07001238 LOG(FATAL_WITHOUT_ABORT) << "Unexpected failure to resolve a method: "
David Sehr709b0702016-10-13 09:12:37 -07001239 << dex_file_->PrettyMethod(it.GetMemberIndex(), true);
Vladimir Marko07bfbac2017-07-06 14:55:02 +01001240 self->AssertPendingException();
1241 mirror::Throwable* exc = self->GetException();
Mathieu Chartierfbc31082016-01-24 11:59:56 -08001242 std::string dump = exc->Dump();
1243 LOG(FATAL) << dump;
1244 UNREACHABLE();
1245 }
1246 } else {
Vladimir Marko07bfbac2017-07-06 14:55:02 +01001247 // Should already have been resolved by the compiler.
Mathieu Chartierfbc31082016-01-24 11:59:56 -08001248 // 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 +01001249 // entrypoint. This is not fatal since we shall use a resolution method.
1250 method = class_linker_->LookupResolvedMethod(it.GetMemberIndex(), dex_cache, class_loader_);
Andreas Gamped9efea62014-07-21 22:56:08 -07001251 }
Mathieu Chartierfbc31082016-01-24 11:59:56 -08001252 if (method != nullptr &&
1253 compiled_method != nullptr &&
1254 compiled_method->GetQuickCode().size() != 0) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001255 method->SetEntryPointFromQuickCompiledCodePtrSize(
1256 reinterpret_cast<void*>(offsets.code_offset_), pointer_size_);
1257 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001258
1259 return true;
1260 }
Jeff Haoc7d11882015-02-03 15:08:39 -08001261
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001262 // Check whether current class is image class
1263 bool IsImageClass() {
1264 const DexFile::TypeId& type_id =
1265 dex_file_->GetTypeId(dex_file_->GetClassDef(class_def_index_).class_idx_);
1266 const char* class_descriptor = dex_file_->GetTypeDescriptor(type_id);
1267 return writer_->GetCompilerDriver()->IsImageClass(class_descriptor);
1268 }
1269
1270 // Check whether specified dex file is in the compiled oat file.
1271 bool IsInOatFile(const DexFile* dex_file) {
1272 return ContainsElement(*dex_files_, dex_file);
1273 }
1274
1275 // Assign a pointer to quick code for copied methods
1276 // not handled in the method StartClass
1277 void Postprocess() {
1278 for (std::pair<ArtMethod*, ArtMethod*>& p : methods_to_process_) {
1279 ArtMethod* method = p.first;
1280 ArtMethod* origin = p.second;
1281 const void* code_ptr =
1282 origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
1283 if (code_ptr != nullptr) {
1284 method->SetEntryPointFromQuickCompiledCodePtrSize(code_ptr, pointer_size_);
1285 }
1286 }
1287 }
1288
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001289 private:
Andreas Gampe542451c2016-07-26 09:02:02 -07001290 const PointerSize pointer_size_;
Vladimir Marko07bfbac2017-07-06 14:55:02 +01001291 ObjPtr<mirror::ClassLoader> class_loader_;
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001292 const std::vector<const DexFile*>* dex_files_;
1293 ClassLinker* const class_linker_;
1294 std::vector<std::pair<ArtMethod*, ArtMethod*>> methods_to_process_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001295};
1296
1297class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
1298 public:
1299 WriteCodeMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset,
Vladimir Markof4da6752014-08-01 19:04:18 +01001300 size_t relative_offset) SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001301 : OatDexMethodVisitor(writer, relative_offset),
1302 pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())),
1303 class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr),
1304 out_(out),
1305 file_offset_(file_offset),
1306 soa_(Thread::Current()),
1307 no_thread_suspension_("OatWriter patching"),
1308 class_linker_(Runtime::Current()->GetClassLinker()),
1309 dex_cache_(nullptr) {
Vladimir Marko09d09432015-09-08 13:47:48 +01001310 patched_code_.reserve(16 * KB);
Mathieu Chartierda5b28a2015-11-05 08:03:47 -08001311 if (writer_->HasBootImage()) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001312 // If we're creating the image, the address space must be ready so that we can apply patches.
1313 CHECK(writer_->image_writer_->IsImageAddressSpaceReady());
Vladimir Markof4da6752014-08-01 19:04:18 +01001314 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001315 }
1316
Vladimir Markof4da6752014-08-01 19:04:18 +01001317 ~WriteCodeMethodVisitor() UNLOCK_FUNCTION(Locks::mutator_lock_) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001318 }
1319
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001320 bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001321 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001322 OatDexMethodVisitor::StartClass(dex_file, class_def_index);
Mathieu Chartier72041a02017-07-14 18:23:25 -07001323 if (writer_->GetCompilerDriver()->GetCompilerOptions().IsAotCompilationEnabled()) {
1324 // Only need to set the dex cache if we have compilation. Other modes might have unloaded it.
1325 if (dex_cache_ == nullptr || dex_cache_->GetDexFile() != dex_file) {
1326 dex_cache_ = class_linker_->FindDexCache(Thread::Current(), *dex_file);
1327 DCHECK(dex_cache_ != nullptr);
1328 }
Vladimir Markof4da6752014-08-01 19:04:18 +01001329 }
1330 return true;
1331 }
1332
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001333 bool EndClass() OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001334 bool result = OatDexMethodVisitor::EndClass();
1335 if (oat_class_index_ == writer_->oat_classes_.size()) {
1336 DCHECK(result); // OatDexMethodVisitor::EndClass() never fails.
Vladimir Marko20f85592015-03-19 10:07:02 +00001337 offset_ = writer_->relative_patcher_->WriteThunks(out_, offset_);
Vladimir Markof4da6752014-08-01 19:04:18 +01001338 if (UNLIKELY(offset_ == 0u)) {
1339 PLOG(ERROR) << "Failed to write final relative call thunks";
1340 result = false;
1341 }
1342 }
1343 return result;
1344 }
1345
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001346 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001347 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko49b0f452015-12-10 13:49:19 +00001348 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001349 const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1350
Mathieu Chartier673ed3d2015-08-28 14:56:43 -07001351 // No thread suspension since dex_cache_ that may get invalidated if that occurs.
Mathieu Chartier268764d2016-09-13 12:09:38 -07001352 ScopedAssertNoThreadSuspension tsc(__FUNCTION__);
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01001353 if (HasCompiledCode(compiled_method)) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001354 size_t file_offset = file_offset_;
1355 OutputStream* out = out_;
1356
Vladimir Marko35831e82015-09-11 11:59:18 +01001357 ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
1358 uint32_t code_size = quick_code.size() * sizeof(uint8_t);
Nicolas Geoffrayf0758792015-07-13 11:56:00 +00001359
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001360 // Deduplicate code arrays.
1361 const OatMethodOffsets& method_offsets = oat_class->method_offsets_[method_offsets_index_];
1362 if (method_offsets.code_offset_ > offset_) {
1363 offset_ = writer_->relative_patcher_->WriteThunks(out, offset_);
1364 if (offset_ == 0u) {
1365 ReportWriteFailure("relative call thunk", it);
1366 return false;
Nicolas Geoffrayf0758792015-07-13 11:56:00 +00001367 }
Vladimir Marko0c737df2016-08-01 16:33:16 +01001368 uint32_t alignment_size = CodeAlignmentSize(offset_, *compiled_method);
1369 if (alignment_size != 0) {
1370 if (!writer_->WriteCodeAlignment(out, alignment_size)) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001371 ReportWriteFailure("code alignment padding", it);
1372 return false;
1373 }
Vladimir Marko0c737df2016-08-01 16:33:16 +01001374 offset_ += alignment_size;
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001375 DCHECK_OFFSET_();
1376 }
Vladimir Marko0c737df2016-08-01 16:33:16 +01001377 DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader),
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001378 GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
1379 DCHECK_EQ(method_offsets.code_offset_,
1380 offset_ + sizeof(OatQuickMethodHeader) + compiled_method->CodeDelta())
David Sehr709b0702016-10-13 09:12:37 -07001381 << dex_file_->PrettyMethod(it.GetMemberIndex());
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001382 const OatQuickMethodHeader& method_header =
1383 oat_class->method_headers_[method_offsets_index_];
Vladimir Markoe079e212016-05-25 12:49:49 +01001384 if (!out->WriteFully(&method_header, sizeof(method_header))) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001385 ReportWriteFailure("method header", it);
1386 return false;
1387 }
1388 writer_->size_method_header_ += sizeof(method_header);
1389 offset_ += sizeof(method_header);
Nicolas Geoffrayed6195a2015-07-13 17:02:30 +00001390 DCHECK_OFFSET_();
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001391
1392 if (!compiled_method->GetPatches().empty()) {
Vladimir Marko35831e82015-09-11 11:59:18 +01001393 patched_code_.assign(quick_code.begin(), quick_code.end());
1394 quick_code = ArrayRef<const uint8_t>(patched_code_);
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001395 for (const LinkerPatch& patch : compiled_method->GetPatches()) {
Vladimir Marko944da602016-02-19 12:27:55 +00001396 uint32_t literal_offset = patch.LiteralOffset();
Vladimir Markodb8e62d2016-03-30 16:30:21 +01001397 switch (patch.GetType()) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001398 case LinkerPatch::Type::kMethodBssEntry: {
1399 uint32_t target_offset =
1400 writer_->bss_start_ + writer_->bss_method_entries_.Get(patch.TargetMethod());
1401 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1402 patch,
1403 offset_ + literal_offset,
1404 target_offset);
1405 break;
1406 }
Vladimir Markodb8e62d2016-03-30 16:30:21 +01001407 case LinkerPatch::Type::kCallRelative: {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001408 // NOTE: Relative calls across oat files are not supported.
1409 uint32_t target_offset = GetTargetOffset(patch);
1410 writer_->relative_patcher_->PatchCall(&patched_code_,
1411 literal_offset,
1412 offset_ + literal_offset,
1413 target_offset);
1414 break;
1415 }
Vladimir Markodb8e62d2016-03-30 16:30:21 +01001416 case LinkerPatch::Type::kStringRelative: {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001417 uint32_t target_offset = GetTargetObjectOffset(GetTargetString(patch));
1418 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1419 patch,
1420 offset_ + literal_offset,
1421 target_offset);
1422 break;
1423 }
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001424 case LinkerPatch::Type::kStringInternTable: {
1425 uint32_t target_offset = GetInternTableEntryOffset(patch);
1426 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1427 patch,
1428 offset_ + literal_offset,
1429 target_offset);
1430 break;
1431 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00001432 case LinkerPatch::Type::kStringBssEntry: {
1433 StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001434 uint32_t target_offset =
1435 writer_->bss_start_ + writer_->bss_string_entries_.Get(ref);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001436 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1437 patch,
1438 offset_ + literal_offset,
1439 target_offset);
1440 break;
1441 }
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01001442 case LinkerPatch::Type::kTypeRelative: {
1443 uint32_t target_offset = GetTargetObjectOffset(GetTargetType(patch));
1444 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1445 patch,
1446 offset_ + literal_offset,
1447 target_offset);
1448 break;
1449 }
Vladimir Marko94ec2db2017-09-06 17:21:03 +01001450 case LinkerPatch::Type::kTypeClassTable: {
1451 uint32_t target_offset = GetClassTableEntryOffset(patch);
1452 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1453 patch,
1454 offset_ + literal_offset,
1455 target_offset);
1456 break;
1457 }
Vladimir Marko6bec91c2017-01-09 15:03:12 +00001458 case LinkerPatch::Type::kTypeBssEntry: {
1459 TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex());
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001460 uint32_t target_offset = writer_->bss_start_ + writer_->bss_type_entries_.Get(ref);
Vladimir Marko6bec91c2017-01-09 15:03:12 +00001461 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1462 patch,
1463 offset_ + literal_offset,
1464 target_offset);
1465 break;
1466 }
Vladimir Markodb8e62d2016-03-30 16:30:21 +01001467 case LinkerPatch::Type::kCall: {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001468 uint32_t target_offset = GetTargetOffset(patch);
1469 PatchCodeAddress(&patched_code_, literal_offset, target_offset);
1470 break;
1471 }
Vladimir Marko65979462017-05-19 17:25:12 +01001472 case LinkerPatch::Type::kMethodRelative: {
1473 uint32_t target_offset = GetTargetMethodOffset(GetTargetMethod(patch));
1474 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1475 patch,
1476 offset_ + literal_offset,
1477 target_offset);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001478 break;
1479 }
Vladimir Markof4f2daa2017-03-20 18:26:59 +00001480 case LinkerPatch::Type::kBakerReadBarrierBranch: {
1481 writer_->relative_patcher_->PatchBakerReadBarrierBranch(&patched_code_,
1482 patch,
1483 offset_ + literal_offset);
1484 break;
1485 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001486 default: {
Richard Uhlerc52f3032017-03-02 13:45:45 +00001487 DCHECK(false) << "Unexpected linker patch type: " << patch.GetType();
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001488 break;
1489 }
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001490 }
1491 }
1492 }
1493
Vladimir Markoe079e212016-05-25 12:49:49 +01001494 if (!out->WriteFully(quick_code.data(), code_size)) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001495 ReportWriteFailure("method code", it);
1496 return false;
1497 }
1498 writer_->size_code_ += code_size;
1499 offset_ += code_size;
Nicolas Geoffrayf0758792015-07-13 11:56:00 +00001500 }
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001501 DCHECK_OFFSET_();
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001502 ++method_offsets_index_;
1503 }
1504
1505 return true;
1506 }
1507
1508 private:
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001509 const PointerSize pointer_size_;
Vladimir Marko8d6768d2017-03-14 10:13:21 +00001510 ObjPtr<mirror::ClassLoader> class_loader_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001511 OutputStream* const out_;
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +01001512 const size_t file_offset_;
1513 const ScopedObjectAccess soa_;
1514 const ScopedAssertNoThreadSuspension no_thread_suspension_;
Vladimir Markof4da6752014-08-01 19:04:18 +01001515 ClassLinker* const class_linker_;
Vladimir Markocd556b02017-02-03 11:47:34 +00001516 ObjPtr<mirror::DexCache> dex_cache_;
Vladimir Markof4da6752014-08-01 19:04:18 +01001517 std::vector<uint8_t> patched_code_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001518
1519 void ReportWriteFailure(const char* what, const ClassDataItemIterator& it) {
1520 PLOG(ERROR) << "Failed to write " << what << " for "
David Sehr709b0702016-10-13 09:12:37 -07001521 << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001522 }
Vladimir Markof4da6752014-08-01 19:04:18 +01001523
Mathieu Chartiere401d142015-04-22 13:56:20 -07001524 ArtMethod* GetTargetMethod(const LinkerPatch& patch)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001525 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001526 MethodReference ref = patch.TargetMethod();
Vladimir Markocd556b02017-02-03 11:47:34 +00001527 ObjPtr<mirror::DexCache> dex_cache =
Mathieu Chartier673ed3d2015-08-28 14:56:43 -07001528 (dex_file_ == ref.dex_file) ? dex_cache_ : class_linker_->FindDexCache(
1529 Thread::Current(), *ref.dex_file);
Vladimir Marko07bfbac2017-07-06 14:55:02 +01001530 ArtMethod* method =
1531 class_linker_->LookupResolvedMethod(ref.dex_method_index, dex_cache, class_loader_);
Vladimir Markof4da6752014-08-01 19:04:18 +01001532 CHECK(method != nullptr);
1533 return method;
1534 }
1535
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001536 uint32_t GetTargetOffset(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko944da602016-02-19 12:27:55 +00001537 uint32_t target_offset = writer_->relative_patcher_->GetOffset(patch.TargetMethod());
1538 // If there's no new compiled code, either we're compiling an app and the target method
1539 // is in the boot image, or we need to point to the correct trampoline.
Vladimir Markof4da6752014-08-01 19:04:18 +01001540 if (UNLIKELY(target_offset == 0)) {
Mathieu Chartiere401d142015-04-22 13:56:20 -07001541 ArtMethod* target = GetTargetMethod(patch);
Vladimir Markof4da6752014-08-01 19:04:18 +01001542 DCHECK(target != nullptr);
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001543 const void* oat_code_offset =
1544 target->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
Jeff Haoa0acc2d2015-01-27 11:22:04 -08001545 if (oat_code_offset != 0) {
Vladimir Marko944da602016-02-19 12:27:55 +00001546 DCHECK(!writer_->HasBootImage());
Jeff Haoa0acc2d2015-01-27 11:22:04 -08001547 DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(oat_code_offset));
1548 DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(oat_code_offset));
1549 DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickGenericJniStub(oat_code_offset));
1550 target_offset = PointerToLowMemUInt32(oat_code_offset);
1551 } else {
1552 target_offset = target->IsNative()
1553 ? writer_->oat_header_->GetQuickGenericJniTrampolineOffset()
1554 : writer_->oat_header_->GetQuickToInterpreterBridgeOffset();
1555 }
Vladimir Markof4da6752014-08-01 19:04:18 +01001556 }
1557 return target_offset;
1558 }
1559
Vladimir Markocd556b02017-02-03 11:47:34 +00001560 ObjPtr<mirror::DexCache> GetDexCache(const DexFile* target_dex_file)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001561 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko052164a2016-04-27 13:54:18 +01001562 return (target_dex_file == dex_file_)
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001563 ? dex_cache_
Vladimir Marko052164a2016-04-27 13:54:18 +01001564 : class_linker_->FindDexCache(Thread::Current(), *target_dex_file);
1565 }
1566
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001567 mirror::Class* GetTargetType(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko8d6768d2017-03-14 10:13:21 +00001568 DCHECK(writer_->HasImage());
Vladimir Markocd556b02017-02-03 11:47:34 +00001569 ObjPtr<mirror::DexCache> dex_cache = GetDexCache(patch.TargetTypeDexFile());
Vladimir Marko8d6768d2017-03-14 10:13:21 +00001570 ObjPtr<mirror::Class> type =
1571 ClassLinker::LookupResolvedType(patch.TargetTypeIndex(), dex_cache, class_loader_);
Vladimir Markof4da6752014-08-01 19:04:18 +01001572 CHECK(type != nullptr);
Vladimir Marko8d6768d2017-03-14 10:13:21 +00001573 return type.Ptr();
Vladimir Markof4da6752014-08-01 19:04:18 +01001574 }
1575
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001576 mirror::String* GetTargetString(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07001577 ClassLinker* linker = Runtime::Current()->GetClassLinker();
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07001578 mirror::String* string = linker->LookupString(*patch.TargetStringDexFile(),
1579 patch.TargetStringIndex(),
Vladimir Markof25cc732017-03-16 16:18:15 +00001580 GetDexCache(patch.TargetStringDexFile()));
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001581 DCHECK(string != nullptr);
1582 DCHECK(writer_->HasBootImage() ||
1583 Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(string));
1584 return string;
1585 }
1586
Vladimir Marko65979462017-05-19 17:25:12 +01001587 uint32_t GetTargetMethodOffset(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
1588 DCHECK(writer_->HasBootImage());
1589 method = writer_->image_writer_->GetImageMethodAddress(method);
1590 size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
1591 uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
1592 // TODO: Clean up offset types. The target offset must be treated as signed.
1593 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(method) - oat_data_begin);
1594 }
1595
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001596 uint32_t GetTargetObjectOffset(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001597 DCHECK(writer_->HasBootImage());
1598 object = writer_->image_writer_->GetImageAddress(object);
1599 size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
1600 uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
1601 // TODO: Clean up offset types. The target offset must be treated as signed.
1602 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(object) - oat_data_begin);
1603 }
1604
Vladimir Markof4da6752014-08-01 19:04:18 +01001605 void PatchObjectAddress(std::vector<uint8_t>* code, uint32_t offset, mirror::Object* object)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001606 REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartierda5b28a2015-11-05 08:03:47 -08001607 if (writer_->HasBootImage()) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001608 object = writer_->image_writer_->GetImageAddress(object);
Vladimir Marko09d09432015-09-08 13:47:48 +01001609 } else {
1610 // NOTE: We're using linker patches for app->boot references when the image can
1611 // be relocated and therefore we need to emit .oat_patches. We're not using this
1612 // for app->app references, so check that the object is in the image space.
1613 DCHECK(Runtime::Current()->GetHeap()->FindSpaceFromObject(object, false)->IsImageSpace());
Vladimir Markof4da6752014-08-01 19:04:18 +01001614 }
Vladimir Marko09d09432015-09-08 13:47:48 +01001615 // Note: We only patch targeting Objects in image which is in the low 4gb.
Vladimir Markof4da6752014-08-01 19:04:18 +01001616 uint32_t address = PointerToLowMemUInt32(object);
1617 DCHECK_LE(offset + 4, code->size());
1618 uint8_t* data = &(*code)[offset];
1619 data[0] = address & 0xffu;
1620 data[1] = (address >> 8) & 0xffu;
1621 data[2] = (address >> 16) & 0xffu;
1622 data[3] = (address >> 24) & 0xffu;
1623 }
1624
1625 void PatchCodeAddress(std::vector<uint8_t>* code, uint32_t offset, uint32_t target_offset)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001626 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko09d09432015-09-08 13:47:48 +01001627 uint32_t address = target_offset;
Mathieu Chartierda5b28a2015-11-05 08:03:47 -08001628 if (writer_->HasBootImage()) {
Vladimir Marko944da602016-02-19 12:27:55 +00001629 size_t oat_index = writer_->image_writer_->GetOatIndexForDexCache(dex_cache_);
1630 // TODO: Clean up offset types.
1631 // The target_offset must be treated as signed for cross-oat patching.
1632 const void* target = reinterpret_cast<const void*>(
1633 writer_->image_writer_->GetOatDataBegin(oat_index) +
1634 static_cast<int32_t>(target_offset));
1635 address = PointerToLowMemUInt32(target);
Vladimir Marko09d09432015-09-08 13:47:48 +01001636 }
Vladimir Markof4da6752014-08-01 19:04:18 +01001637 DCHECK_LE(offset + 4, code->size());
1638 uint8_t* data = &(*code)[offset];
1639 data[0] = address & 0xffu;
1640 data[1] = (address >> 8) & 0xffu;
1641 data[2] = (address >> 16) & 0xffu;
1642 data[3] = (address >> 24) & 0xffu;
1643 }
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001644
1645 // Calculate the offset of the InternTable slot (GcRoot<String>) when mmapped to the .bss.
1646 uint32_t GetInternTableEntryOffset(const LinkerPatch& patch)
1647 REQUIRES_SHARED(Locks::mutator_lock_) {
1648 DCHECK(!writer_->HasBootImage());
1649 const uint8_t* string_root = writer_->LookupBootImageInternTableSlot(
1650 *patch.TargetStringDexFile(), patch.TargetStringIndex());
1651 DCHECK(string_root != nullptr);
Vladimir Marko94ec2db2017-09-06 17:21:03 +01001652 return GetBootImageTableEntryOffset(string_root);
1653 }
1654
1655 // Calculate the offset of the ClassTable::TableSlot when mmapped to the .bss.
1656 uint32_t GetClassTableEntryOffset(const LinkerPatch& patch)
1657 REQUIRES_SHARED(Locks::mutator_lock_) {
1658 DCHECK(!writer_->HasBootImage());
1659 const uint8_t* table_slot =
1660 writer_->LookupBootImageClassTableSlot(*patch.TargetTypeDexFile(), patch.TargetTypeIndex());
1661 DCHECK(table_slot != nullptr);
1662 return GetBootImageTableEntryOffset(table_slot);
1663 }
1664
1665 uint32_t GetBootImageTableEntryOffset(const uint8_t* raw_root) {
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001666 uint32_t base_offset = writer_->bss_start_;
1667 for (gc::space::ImageSpace* space : Runtime::Current()->GetHeap()->GetBootImageSpaces()) {
1668 const uint8_t* const_tables_begin =
1669 space->Begin() + space->GetImageHeader().GetBootImageConstantTablesOffset();
Vladimir Marko94ec2db2017-09-06 17:21:03 +01001670 size_t offset = static_cast<size_t>(raw_root - const_tables_begin);
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001671 if (offset < space->GetImageHeader().GetBootImageConstantTablesSize()) {
1672 DCHECK_LE(base_offset + offset, writer_->bss_start_ + writer_->bss_methods_offset_);
1673 return base_offset + offset;
1674 }
1675 base_offset += space->GetImageHeader().GetBootImageConstantTablesSize();
1676 }
1677 LOG(FATAL) << "Didn't find boot image string in boot image intern tables!";
1678 UNREACHABLE();
1679 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001680};
1681
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001682class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor {
1683 public:
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001684 WriteMapMethodVisitor(OatWriter* writer,
1685 OutputStream* out,
1686 const size_t file_offset,
Mathieu Chartier957ca1c2014-11-21 16:51:29 -08001687 size_t relative_offset)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001688 : OatDexMethodVisitor(writer, relative_offset),
1689 out_(out),
1690 file_offset_(file_offset) {}
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001691
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001692 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE {
Vladimir Marko49b0f452015-12-10 13:49:19 +00001693 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001694 const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1695
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01001696 if (HasCompiledCode(compiled_method)) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001697 size_t file_offset = file_offset_;
1698 OutputStream* out = out_;
1699
Mingyao Yang063fc772016-08-02 11:02:54 -07001700 uint32_t map_offset = oat_class->method_headers_[method_offsets_index_].GetVmapTableOffset();
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001701 uint32_t code_offset = oat_class->method_offsets_[method_offsets_index_].code_offset_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001702 ++method_offsets_index_;
1703
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001704 DCHECK((compiled_method->GetVmapTable().size() == 0u && map_offset == 0u) ||
1705 (compiled_method->GetVmapTable().size() != 0u && map_offset != 0u))
1706 << compiled_method->GetVmapTable().size() << " " << map_offset << " "
David Sehr709b0702016-10-13 09:12:37 -07001707 << dex_file_->PrettyMethod(it.GetMemberIndex());
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001708
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01001709 // If vdex is enabled, only emit the map for compiled code. The quickening info
1710 // is emitted in the vdex already.
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01001711 if (map_offset != 0u) {
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001712 // Transform map_offset to actual oat data offset.
1713 map_offset = (code_offset - compiled_method->CodeDelta()) - map_offset;
1714 DCHECK_NE(map_offset, 0u);
David Sehr709b0702016-10-13 09:12:37 -07001715 DCHECK_LE(map_offset, offset_) << dex_file_->PrettyMethod(it.GetMemberIndex());
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001716
1717 ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
1718 size_t map_size = map.size() * sizeof(map[0]);
1719 if (map_offset == offset_) {
1720 // Write deduplicated map (code info for Optimizing or transformation info for dex2dex).
Vladimir Markoe079e212016-05-25 12:49:49 +01001721 if (UNLIKELY(!out->WriteFully(map.data(), map_size))) {
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001722 ReportWriteFailure(it);
1723 return false;
1724 }
1725 offset_ += map_size;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001726 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001727 }
1728 DCHECK_OFFSET_();
1729 }
1730
1731 return true;
1732 }
1733
1734 private:
1735 OutputStream* const out_;
1736 size_t const file_offset_;
1737
1738 void ReportWriteFailure(const ClassDataItemIterator& it) {
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001739 PLOG(ERROR) << "Failed to write map for "
David Sehr709b0702016-10-13 09:12:37 -07001740 << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001741 }
1742};
1743
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001744class OatWriter::WriteMethodInfoVisitor : public OatDexMethodVisitor {
1745 public:
1746 WriteMethodInfoVisitor(OatWriter* writer,
1747 OutputStream* out,
1748 const size_t file_offset,
1749 size_t relative_offset)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001750 : OatDexMethodVisitor(writer, relative_offset),
1751 out_(out),
1752 file_offset_(file_offset) {}
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001753
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001754 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE {
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001755 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1756 const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1757
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01001758 if (HasCompiledCode(compiled_method)) {
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001759 size_t file_offset = file_offset_;
1760 OutputStream* out = out_;
1761 uint32_t map_offset = oat_class->method_headers_[method_offsets_index_].GetMethodInfoOffset();
1762 uint32_t code_offset = oat_class->method_offsets_[method_offsets_index_].code_offset_;
1763 ++method_offsets_index_;
1764 DCHECK((compiled_method->GetMethodInfo().size() == 0u && map_offset == 0u) ||
1765 (compiled_method->GetMethodInfo().size() != 0u && map_offset != 0u))
1766 << compiled_method->GetMethodInfo().size() << " " << map_offset << " "
1767 << dex_file_->PrettyMethod(it.GetMemberIndex());
1768 if (map_offset != 0u) {
1769 // Transform map_offset to actual oat data offset.
1770 map_offset = (code_offset - compiled_method->CodeDelta()) - map_offset;
1771 DCHECK_NE(map_offset, 0u);
1772 DCHECK_LE(map_offset, offset_) << dex_file_->PrettyMethod(it.GetMemberIndex());
1773
1774 ArrayRef<const uint8_t> map = compiled_method->GetMethodInfo();
1775 size_t map_size = map.size() * sizeof(map[0]);
1776 if (map_offset == offset_) {
1777 // Write deduplicated map (code info for Optimizing or transformation info for dex2dex).
1778 if (UNLIKELY(!out->WriteFully(map.data(), map_size))) {
1779 ReportWriteFailure(it);
1780 return false;
1781 }
1782 offset_ += map_size;
1783 }
1784 }
1785 DCHECK_OFFSET_();
1786 }
1787
1788 return true;
1789 }
1790
1791 private:
1792 OutputStream* const out_;
1793 size_t const file_offset_;
1794
1795 void ReportWriteFailure(const ClassDataItemIterator& it) {
1796 PLOG(ERROR) << "Failed to write map for "
1797 << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
1798 }
1799};
1800
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001801// Visit all methods from all classes in all dex files with the specified visitor.
1802bool OatWriter::VisitDexMethods(DexMethodVisitor* visitor) {
1803 for (const DexFile* dex_file : *dex_files_) {
1804 const size_t class_def_count = dex_file->NumClassDefs();
1805 for (size_t class_def_index = 0; class_def_index != class_def_count; ++class_def_index) {
1806 if (UNLIKELY(!visitor->StartClass(dex_file, class_def_index))) {
1807 return false;
1808 }
Mathieu Chartier3957bff2017-07-16 13:55:27 -07001809 if (MayHaveCompiledMethods()) {
Nicolas Geoffray60ca9492016-12-20 21:15:00 +00001810 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
1811 const uint8_t* class_data = dex_file->GetClassData(class_def);
1812 if (class_data != nullptr) { // ie not an empty class, such as a marker interface
1813 ClassDataItemIterator it(*dex_file, class_data);
Mathieu Chartiere17cf242017-06-19 11:05:51 -07001814 it.SkipAllFields();
Nicolas Geoffray60ca9492016-12-20 21:15:00 +00001815 size_t class_def_method_index = 0u;
1816 while (it.HasNextDirectMethod()) {
1817 if (!visitor->VisitMethod(class_def_method_index, it)) {
1818 return false;
1819 }
1820 ++class_def_method_index;
1821 it.Next();
1822 }
1823 while (it.HasNextVirtualMethod()) {
1824 if (UNLIKELY(!visitor->VisitMethod(class_def_method_index, it))) {
1825 return false;
1826 }
1827 ++class_def_method_index;
1828 it.Next();
1829 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001830 }
1831 }
1832 if (UNLIKELY(!visitor->EndClass())) {
1833 return false;
1834 }
1835 }
1836 }
1837 return true;
1838}
1839
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001840size_t OatWriter::InitOatHeader(InstructionSet instruction_set,
1841 const InstructionSetFeatures* instruction_set_features,
1842 uint32_t num_dex_files,
1843 SafeMap<std::string, std::string>* key_value_store) {
1844 TimingLogger::ScopedTiming split("InitOatHeader", timings_);
1845 oat_header_.reset(OatHeader::Create(instruction_set,
1846 instruction_set_features,
1847 num_dex_files,
1848 key_value_store));
1849 size_oat_header_ += sizeof(OatHeader);
1850 size_oat_header_key_value_store_ += oat_header_->GetHeaderSize() - sizeof(OatHeader);
Andreas Gampe22f8e5c2014-07-09 11:38:21 -07001851 return oat_header_->GetHeaderSize();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001852}
1853
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001854size_t OatWriter::InitClassOffsets(size_t offset) {
1855 // Reserve space for class offsets in OAT and update class_offsets_offset_.
Vladimir Marko49b0f452015-12-10 13:49:19 +00001856 for (OatDexFile& oat_dex_file : oat_dex_files_) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001857 DCHECK_EQ(oat_dex_file.class_offsets_offset_, 0u);
1858 if (!oat_dex_file.class_offsets_.empty()) {
1859 // Class offsets are required to be 4 byte aligned.
1860 offset = RoundUp(offset, 4u);
1861 oat_dex_file.class_offsets_offset_ = offset;
1862 offset += oat_dex_file.GetClassOffsetsRawSize();
1863 DCHECK_ALIGNED(offset, 4u);
1864 }
Artem Udovichenkod9786b02015-10-14 16:36:55 +03001865 }
1866 return offset;
1867}
1868
Brian Carlstrom389efb02012-01-11 12:06:26 -08001869size_t OatWriter::InitOatClasses(size_t offset) {
Brian Carlstrom389efb02012-01-11 12:06:26 -08001870 // calculate the offsets within OatDexFiles to OatClasses
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001871 InitOatClassesMethodVisitor visitor(this, offset);
1872 bool success = VisitDexMethods(&visitor);
1873 CHECK(success);
1874 offset = visitor.GetOffset();
Brian Carlstromba150c32013-08-27 17:31:03 -07001875
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001876 // Update oat_dex_files_.
Mathieu Chartier3957bff2017-07-16 13:55:27 -07001877 auto oat_class_it = oat_class_headers_.begin();
Vladimir Marko49b0f452015-12-10 13:49:19 +00001878 for (OatDexFile& oat_dex_file : oat_dex_files_) {
1879 for (uint32_t& class_offset : oat_dex_file.class_offsets_) {
Mathieu Chartier3957bff2017-07-16 13:55:27 -07001880 DCHECK(oat_class_it != oat_class_headers_.end());
Vladimir Marko49b0f452015-12-10 13:49:19 +00001881 class_offset = oat_class_it->offset_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001882 ++oat_class_it;
Brian Carlstrome24fa612011-09-29 00:53:55 -07001883 }
Brian Carlstrome24fa612011-09-29 00:53:55 -07001884 }
Mathieu Chartier3957bff2017-07-16 13:55:27 -07001885 CHECK(oat_class_it == oat_class_headers_.end());
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001886
1887 return offset;
1888}
1889
1890size_t OatWriter::InitOatMaps(size_t offset) {
Mathieu Chartier3957bff2017-07-16 13:55:27 -07001891 if (!MayHaveCompiledMethods()) {
Nicolas Geoffray60ca9492016-12-20 21:15:00 +00001892 return offset;
1893 }
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001894 {
1895 InitMapMethodVisitor visitor(this, offset);
1896 bool success = VisitDexMethods(&visitor);
1897 DCHECK(success);
1898 offset = visitor.GetOffset();
1899 }
1900 {
1901 InitMethodInfoVisitor visitor(this, offset);
1902 bool success = VisitDexMethods(&visitor);
1903 DCHECK(success);
1904 offset = visitor.GetOffset();
1905 }
Brian Carlstrome24fa612011-09-29 00:53:55 -07001906 return offset;
1907}
1908
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001909size_t OatWriter::InitMethodBssMappings(size_t offset) {
1910 size_t number_of_dex_files = 0u;
1911 for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
1912 const DexFile* dex_file = (*dex_files_)[i];
1913 auto it = bss_method_entry_references_.find(dex_file);
1914 if (it != bss_method_entry_references_.end()) {
1915 const BitVector& method_indexes = it->second;
1916 ++number_of_dex_files;
1917 // If there are any classes, the class offsets allocation aligns the offset
1918 // and we cannot have method bss mappings without class offsets.
1919 static_assert(alignof(MethodBssMapping) == 4u, "MethodBssMapping alignment check.");
1920 DCHECK_ALIGNED(offset, 4u);
1921 oat_dex_files_[i].method_bss_mapping_offset_ = offset;
1922
1923 linker::MethodBssMappingEncoder encoder(
1924 GetInstructionSetPointerSize(oat_header_->GetInstructionSet()));
1925 size_t number_of_entries = 0u;
1926 bool first_index = true;
1927 for (uint32_t method_index : method_indexes.Indexes()) {
1928 uint32_t bss_offset = bss_method_entries_.Get(MethodReference(dex_file, method_index));
1929 if (first_index || !encoder.TryMerge(method_index, bss_offset)) {
1930 encoder.Reset(method_index, bss_offset);
1931 ++number_of_entries;
1932 first_index = false;
1933 }
1934 }
1935 DCHECK_NE(number_of_entries, 0u);
1936 offset += MethodBssMapping::ComputeSize(number_of_entries);
1937 }
1938 }
1939 // Check that all dex files targeted by method bss entries are in `*dex_files_`.
1940 CHECK_EQ(number_of_dex_files, bss_method_entry_references_.size());
1941 return offset;
1942}
1943
1944size_t OatWriter::InitOatDexFiles(size_t offset) {
1945 // Initialize offsets of oat dex files.
1946 for (OatDexFile& oat_dex_file : oat_dex_files_) {
1947 oat_dex_file.offset_ = offset;
1948 offset += oat_dex_file.SizeOf();
1949 }
1950 return offset;
1951}
1952
Brian Carlstrome24fa612011-09-29 00:53:55 -07001953size_t OatWriter::InitOatCode(size_t offset) {
1954 // calculate the offsets within OatHeader to executable code
1955 size_t old_offset = offset;
1956 // required to be on a new page boundary
1957 offset = RoundUp(offset, kPageSize);
1958 oat_header_->SetExecutableOffset(offset);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001959 size_executable_offset_alignment_ = offset - old_offset;
Vladimir Marko1b404a82017-09-01 13:35:26 +01001960 // TODO: Remove unused trampoline offsets from the OatHeader (requires oat version change).
1961 oat_header_->SetInterpreterToInterpreterBridgeOffset(0);
1962 oat_header_->SetInterpreterToCompiledCodeBridgeOffset(0);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001963 if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001964 InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
Vladimir Marko1b404a82017-09-01 13:35:26 +01001965 const bool generate_debug_info = compiler_driver_->GetCompilerOptions().GenerateAnyDebugInfo();
1966 size_t adjusted_offset = offset;
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001967
Vladimir Marko1b404a82017-09-01 13:35:26 +01001968 #define DO_TRAMPOLINE(field, fn_name) \
1969 offset = CompiledCode::AlignCode(offset, instruction_set); \
1970 adjusted_offset = offset + CompiledCode::CodeDelta(instruction_set); \
1971 oat_header_->Set ## fn_name ## Offset(adjusted_offset); \
1972 (field) = compiler_driver_->Create ## fn_name(); \
1973 if (generate_debug_info) { \
1974 debug::MethodDebugInfo info = {}; \
1975 info.trampoline_name = #fn_name; \
1976 info.isa = instruction_set; \
1977 info.is_code_address_text_relative = true; \
1978 /* Use the code offset rather than the `adjusted_offset`. */ \
1979 info.code_address = offset - oat_header_->GetExecutableOffset(); \
1980 info.code_size = (field)->size(); \
1981 method_info_.push_back(std::move(info)); \
1982 } \
Chih-Hung Hsiehfba39972016-05-11 11:26:48 -07001983 offset += (field)->size();
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001984
Ian Rogers848871b2013-08-05 10:56:33 -07001985 DO_TRAMPOLINE(jni_dlsym_lookup_, JniDlsymLookup);
Andreas Gampe2da88232014-02-27 12:26:20 -08001986 DO_TRAMPOLINE(quick_generic_jni_trampoline_, QuickGenericJniTrampoline);
Jeff Hao88474b42013-10-23 16:24:40 -07001987 DO_TRAMPOLINE(quick_imt_conflict_trampoline_, QuickImtConflictTrampoline);
Ian Rogers848871b2013-08-05 10:56:33 -07001988 DO_TRAMPOLINE(quick_resolution_trampoline_, QuickResolutionTrampoline);
1989 DO_TRAMPOLINE(quick_to_interpreter_bridge_, QuickToInterpreterBridge);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001990
Ian Rogers848871b2013-08-05 10:56:33 -07001991 #undef DO_TRAMPOLINE
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001992 } else {
Ian Rogers848871b2013-08-05 10:56:33 -07001993 oat_header_->SetJniDlsymLookupOffset(0);
Andreas Gampe2da88232014-02-27 12:26:20 -08001994 oat_header_->SetQuickGenericJniTrampolineOffset(0);
Jeff Hao88474b42013-10-23 16:24:40 -07001995 oat_header_->SetQuickImtConflictTrampolineOffset(0);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001996 oat_header_->SetQuickResolutionTrampolineOffset(0);
Ian Rogers848871b2013-08-05 10:56:33 -07001997 oat_header_->SetQuickToInterpreterBridgeOffset(0);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001998 }
Brian Carlstrome24fa612011-09-29 00:53:55 -07001999 return offset;
2000}
2001
2002size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
Nicolas Geoffray49cda062017-04-21 13:08:25 +01002003 if (!compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
Nicolas Geoffray60ca9492016-12-20 21:15:00 +00002004 return offset;
2005 }
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01002006 InitCodeMethodVisitor code_visitor(this, offset);
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002007 bool success = VisitDexMethods(&code_visitor);
2008 DCHECK(success);
2009 offset = code_visitor.GetOffset();
Brian Carlstrome24fa612011-09-29 00:53:55 -07002010
Mathieu Chartierfbc31082016-01-24 11:59:56 -08002011 if (HasImage()) {
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03002012 InitImageMethodVisitor image_visitor(this, offset, dex_files_);
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002013 success = VisitDexMethods(&image_visitor);
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03002014 image_visitor.Postprocess();
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002015 DCHECK(success);
2016 offset = image_visitor.GetOffset();
Ian Rogers0571d352011-11-03 19:51:38 -07002017 }
Logan Chien8b977d32012-02-21 19:14:55 +08002018
Brian Carlstrome24fa612011-09-29 00:53:55 -07002019 return offset;
2020}
2021
Vladimir Markoaad75c62016-10-03 08:46:48 +00002022void OatWriter::InitBssLayout(InstructionSet instruction_set) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002023 {
2024 InitBssLayoutMethodVisitor visitor(this);
2025 bool success = VisitDexMethods(&visitor);
2026 DCHECK(success);
2027 }
2028
2029 DCHECK_EQ(bss_size_, 0u);
Vladimir Marko1998cd02017-01-13 13:02:58 +00002030 if (HasBootImage()) {
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01002031 DCHECK(!map_boot_image_tables_to_bss_);
Vladimir Marko1998cd02017-01-13 13:02:58 +00002032 DCHECK(bss_string_entries_.empty());
Vladimir Marko0f3c7002017-09-07 14:15:56 +01002033 }
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01002034 if (!map_boot_image_tables_to_bss_ &&
2035 bss_method_entries_.empty() &&
Vladimir Marko0f3c7002017-09-07 14:15:56 +01002036 bss_type_entries_.empty() &&
2037 bss_string_entries_.empty()) {
2038 // Nothing to put to the .bss section.
2039 return;
Vladimir Marko1998cd02017-01-13 13:02:58 +00002040 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00002041
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01002042 // Allocate space for boot image tables in the .bss section.
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002043 PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set);
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01002044 if (map_boot_image_tables_to_bss_) {
2045 for (gc::space::ImageSpace* space : Runtime::Current()->GetHeap()->GetBootImageSpaces()) {
2046 bss_size_ += space->GetImageHeader().GetBootImageConstantTablesSize();
2047 }
2048 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00002049
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002050 bss_methods_offset_ = bss_size_;
2051
2052 // Prepare offsets for .bss ArtMethod entries.
2053 for (auto& entry : bss_method_entries_) {
2054 DCHECK_EQ(entry.second, 0u);
2055 entry.second = bss_size_;
2056 bss_size_ += static_cast<size_t>(pointer_size);
2057 }
2058
Vladimir Markoaad75c62016-10-03 08:46:48 +00002059 bss_roots_offset_ = bss_size_;
2060
Vladimir Marko6bec91c2017-01-09 15:03:12 +00002061 // Prepare offsets for .bss Class entries.
2062 for (auto& entry : bss_type_entries_) {
2063 DCHECK_EQ(entry.second, 0u);
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002064 entry.second = bss_size_;
Vladimir Marko6bec91c2017-01-09 15:03:12 +00002065 bss_size_ += sizeof(GcRoot<mirror::Class>);
2066 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00002067 // Prepare offsets for .bss String entries.
2068 for (auto& entry : bss_string_entries_) {
2069 DCHECK_EQ(entry.second, 0u);
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002070 entry.second = bss_size_;
Vladimir Markoaad75c62016-10-03 08:46:48 +00002071 bss_size_ += sizeof(GcRoot<mirror::String>);
2072 }
2073}
2074
David Srbeckybc90fd02015-04-22 19:40:27 +01002075bool OatWriter::WriteRodata(OutputStream* out) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002076 CHECK(write_state_ == WriteState::kWriteRoData);
2077
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002078 size_t file_offset = oat_data_offset_;
2079 off_t current_offset = out->Seek(0, kSeekCurrent);
2080 if (current_offset == static_cast<off_t>(-1)) {
2081 PLOG(ERROR) << "Failed to retrieve current position in " << out->GetLocation();
2082 }
2083 DCHECK_GE(static_cast<size_t>(current_offset), file_offset + oat_header_->GetHeaderSize());
2084 size_t relative_offset = current_offset - file_offset;
2085
Vladimir Markoe079e212016-05-25 12:49:49 +01002086 // Wrap out to update checksum with each write.
2087 ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get());
2088 out = &checksum_updating_out;
2089
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002090 relative_offset = WriteClassOffsets(out, file_offset, relative_offset);
2091 if (relative_offset == 0) {
2092 PLOG(ERROR) << "Failed to write class offsets to " << out->GetLocation();
Vladimir Markof4da6752014-08-01 19:04:18 +01002093 return false;
2094 }
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002095
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002096 relative_offset = WriteClasses(out, file_offset, relative_offset);
2097 if (relative_offset == 0) {
2098 PLOG(ERROR) << "Failed to write classes to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07002099 return false;
2100 }
2101
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002102 relative_offset = WriteMethodBssMappings(out, file_offset, relative_offset);
2103 if (relative_offset == 0) {
2104 PLOG(ERROR) << "Failed to write method bss mappings to " << out->GetLocation();
Vladimir Markof4da6752014-08-01 19:04:18 +01002105 return false;
2106 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002107
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002108 relative_offset = WriteMaps(out, file_offset, relative_offset);
2109 if (relative_offset == 0) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002110 PLOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
2111 return false;
2112 }
2113
2114 relative_offset = WriteOatDexFiles(out, file_offset, relative_offset);
2115 if (relative_offset == 0) {
2116 PLOG(ERROR) << "Failed to write oat dex information to " << out->GetLocation();
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002117 return false;
2118 }
2119
David Srbeckybc90fd02015-04-22 19:40:27 +01002120 // Write padding.
2121 off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent);
2122 relative_offset += size_executable_offset_alignment_;
2123 DCHECK_EQ(relative_offset, oat_header_->GetExecutableOffset());
2124 size_t expected_file_offset = file_offset + relative_offset;
2125 if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
2126 PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
2127 << " Expected: " << expected_file_offset << " File: " << out->GetLocation();
2128 return 0;
2129 }
2130 DCHECK_OFFSET();
2131
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002132 write_state_ = WriteState::kWriteText;
David Srbeckybc90fd02015-04-22 19:40:27 +01002133 return true;
2134}
2135
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002136class OatWriter::WriteQuickeningInfoMethodVisitor : public DexMethodVisitor {
2137 public:
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01002138 WriteQuickeningInfoMethodVisitor(OatWriter* writer,
2139 OutputStream* out,
2140 uint32_t offset,
2141 SafeMap<const uint8_t*, uint32_t>* offset_map)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002142 : DexMethodVisitor(writer, offset),
2143 out_(out),
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01002144 written_bytes_(0u),
2145 offset_map_(offset_map) {}
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002146
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01002147 bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED, const ClassDataItemIterator& it)
2148 OVERRIDE {
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002149 uint32_t method_idx = it.GetMemberIndex();
2150 CompiledMethod* compiled_method =
2151 writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
2152
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01002153 if (HasQuickeningInfo(compiled_method)) {
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002154 ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01002155 // Deduplication is already done on a pointer basis by the compiler driver,
2156 // so we can simply compare the pointers to find out if things are duplicated.
2157 if (offset_map_->find(map.data()) == offset_map_->end()) {
2158 uint32_t length = map.size() * sizeof(map.front());
2159 offset_map_->Put(map.data(), written_bytes_);
2160 if (!out_->WriteFully(&length, sizeof(length)) ||
2161 !out_->WriteFully(map.data(), length)) {
2162 PLOG(ERROR) << "Failed to write quickening info for "
2163 << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to "
2164 << out_->GetLocation();
2165 return false;
2166 }
2167 written_bytes_ += sizeof(length) + length;
2168 offset_ += sizeof(length) + length;
2169 }
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002170 }
2171
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002172 return true;
2173 }
2174
2175 size_t GetNumberOfWrittenBytes() const {
2176 return written_bytes_;
2177 }
2178
2179 private:
2180 OutputStream* const out_;
2181 size_t written_bytes_;
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01002182 // Maps quickening map to its offset in the file.
2183 SafeMap<const uint8_t*, uint32_t>* offset_map_;
2184};
2185
2186class OatWriter::WriteQuickeningIndicesMethodVisitor {
2187 public:
2188 WriteQuickeningIndicesMethodVisitor(OutputStream* out,
2189 uint32_t indices_offset,
2190 const SafeMap<const uint8_t*, uint32_t>& offset_map,
2191 std::vector<uint32_t>* dex_files_offset)
2192 : out_(out),
2193 indices_offset_(indices_offset),
2194 written_bytes_(0u),
2195 dex_files_offset_(dex_files_offset),
2196 offset_map_(offset_map) {}
2197
2198 bool VisitDexMethods(const std::vector<const DexFile*>& dex_files, const CompilerDriver& driver) {
2199 for (const DexFile* dex_file : dex_files) {
2200 // Record the offset for this current dex file. It will be written in the vdex file
2201 // later.
2202 dex_files_offset_->push_back(indices_offset_ + GetNumberOfWrittenBytes());
2203 const size_t class_def_count = dex_file->NumClassDefs();
2204 for (size_t class_def_index = 0; class_def_index != class_def_count; ++class_def_index) {
2205 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
2206 const uint8_t* class_data = dex_file->GetClassData(class_def);
2207 if (class_data == nullptr) {
2208 continue;
2209 }
2210 for (ClassDataItemIterator class_it(*dex_file, class_data);
2211 class_it.HasNext();
2212 class_it.Next()) {
2213 if (!class_it.IsAtMethod()) {
2214 continue;
2215 }
2216 uint32_t method_idx = class_it.GetMemberIndex();
2217 CompiledMethod* compiled_method =
2218 driver.GetCompiledMethod(MethodReference(dex_file, method_idx));
2219 if (HasQuickeningInfo(compiled_method)) {
2220 uint32_t code_item_offset = class_it.GetMethodCodeItemOffset();
2221 uint32_t offset = offset_map_.Get(compiled_method->GetVmapTable().data());
2222 if (!out_->WriteFully(&code_item_offset, sizeof(code_item_offset)) ||
2223 !out_->WriteFully(&offset, sizeof(offset))) {
2224 PLOG(ERROR) << "Failed to write quickening info for "
2225 << dex_file->PrettyMethod(method_idx) << " to "
2226 << out_->GetLocation();
2227 return false;
2228 }
2229 written_bytes_ += sizeof(code_item_offset) + sizeof(offset);
2230 }
2231 }
2232 }
2233 }
2234 return true;
2235 }
2236
2237 size_t GetNumberOfWrittenBytes() const {
2238 return written_bytes_;
2239 }
2240
2241 private:
2242 OutputStream* const out_;
2243 const uint32_t indices_offset_;
2244 size_t written_bytes_;
2245 std::vector<uint32_t>* dex_files_offset_;
2246 // Maps quickening map to its offset in the file.
2247 const SafeMap<const uint8_t*, uint32_t>& offset_map_;
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002248};
2249
2250bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) {
2251 if (!kIsVdexEnabled) {
2252 return true;
2253 }
2254
2255 size_t initial_offset = vdex_size_;
2256 size_t start_offset = RoundUp(initial_offset, 4u);
2257
2258 vdex_size_ = start_offset;
2259 vdex_quickening_info_offset_ = vdex_size_;
2260 size_quickening_info_alignment_ = start_offset - initial_offset;
2261
2262 off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet);
2263 if (actual_offset != static_cast<off_t>(start_offset)) {
2264 PLOG(ERROR) << "Failed to seek to quickening info section. Actual: " << actual_offset
2265 << " Expected: " << start_offset
2266 << " Output: " << vdex_out->GetLocation();
2267 return false;
2268 }
2269
Nicolas Geoffray49cda062017-04-21 13:08:25 +01002270 if (compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01002271 std::vector<uint32_t> dex_files_indices;
2272 SafeMap<const uint8_t*, uint32_t> offset_map;
2273 WriteQuickeningInfoMethodVisitor visitor1(this, vdex_out, start_offset, &offset_map);
2274 if (!VisitDexMethods(&visitor1)) {
2275 PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation();
2276 return false;
2277 }
2278
2279 WriteQuickeningIndicesMethodVisitor visitor2(vdex_out,
2280 visitor1.GetNumberOfWrittenBytes(),
2281 offset_map,
2282 &dex_files_indices);
2283 if (!visitor2.VisitDexMethods(*dex_files_, *compiler_driver_)) {
2284 PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation();
2285 return false;
2286 }
2287
2288 DCHECK_EQ(dex_files_->size(), dex_files_indices.size());
2289 if (!vdex_out->WriteFully(
2290 dex_files_indices.data(), sizeof(dex_files_indices[0]) * dex_files_indices.size())) {
Nicolas Geoffray60ca9492016-12-20 21:15:00 +00002291 PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation();
2292 return false;
2293 }
2294
2295 if (!vdex_out->Flush()) {
2296 PLOG(ERROR) << "Failed to flush stream after writing quickening info."
2297 << " File: " << vdex_out->GetLocation();
2298 return false;
2299 }
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01002300 size_quickening_info_ = visitor1.GetNumberOfWrittenBytes() +
2301 visitor2.GetNumberOfWrittenBytes() +
2302 dex_files_->size() * sizeof(uint32_t);
Nicolas Geoffray60ca9492016-12-20 21:15:00 +00002303 } else {
2304 // We know we did not quicken.
2305 size_quickening_info_ = 0;
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002306 }
2307
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002308 vdex_size_ += size_quickening_info_;
2309 return true;
2310}
2311
David Brazdil5d5a36b2016-09-14 15:34:10 +01002312bool OatWriter::WriteVerifierDeps(OutputStream* vdex_out, verifier::VerifierDeps* verifier_deps) {
2313 if (!kIsVdexEnabled) {
2314 return true;
2315 }
2316
2317 if (verifier_deps == nullptr) {
2318 // Nothing to write. Record the offset, but no need
2319 // for alignment.
2320 vdex_verifier_deps_offset_ = vdex_size_;
2321 return true;
2322 }
2323
2324 size_t initial_offset = vdex_size_;
2325 size_t start_offset = RoundUp(initial_offset, 4u);
2326
2327 vdex_size_ = start_offset;
2328 vdex_verifier_deps_offset_ = vdex_size_;
2329 size_verifier_deps_alignment_ = start_offset - initial_offset;
2330
2331 off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet);
2332 if (actual_offset != static_cast<off_t>(start_offset)) {
2333 PLOG(ERROR) << "Failed to seek to verifier deps section. Actual: " << actual_offset
2334 << " Expected: " << start_offset
2335 << " Output: " << vdex_out->GetLocation();
2336 return false;
2337 }
2338
2339 std::vector<uint8_t> buffer;
Nicolas Geoffrayd01f60c2016-10-28 14:45:48 +01002340 verifier_deps->Encode(*dex_files_, &buffer);
David Brazdil5d5a36b2016-09-14 15:34:10 +01002341
2342 if (!vdex_out->WriteFully(buffer.data(), buffer.size())) {
2343 PLOG(ERROR) << "Failed to write verifier deps."
2344 << " File: " << vdex_out->GetLocation();
2345 return false;
2346 }
2347 if (!vdex_out->Flush()) {
2348 PLOG(ERROR) << "Failed to flush stream after writing verifier deps."
2349 << " File: " << vdex_out->GetLocation();
2350 return false;
2351 }
2352
2353 size_verifier_deps_ = buffer.size();
2354 vdex_size_ += size_verifier_deps_;
2355 return true;
2356}
2357
David Srbeckybc90fd02015-04-22 19:40:27 +01002358bool OatWriter::WriteCode(OutputStream* out) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002359 CHECK(write_state_ == WriteState::kWriteText);
2360
Vladimir Markoe079e212016-05-25 12:49:49 +01002361 // Wrap out to update checksum with each write.
2362 ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get());
2363 out = &checksum_updating_out;
2364
Vladimir Marko944da602016-02-19 12:27:55 +00002365 SetMultiOatRelativePatcherAdjustment();
2366
David Srbeckybc90fd02015-04-22 19:40:27 +01002367 const size_t file_offset = oat_data_offset_;
2368 size_t relative_offset = oat_header_->GetExecutableOffset();
2369 DCHECK_OFFSET();
2370
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002371 relative_offset = WriteCode(out, file_offset, relative_offset);
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002372 if (relative_offset == 0) {
Ian Rogers3d504072014-03-01 09:16:49 -08002373 LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07002374 return false;
2375 }
2376
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002377 relative_offset = WriteCodeDexFiles(out, file_offset, relative_offset);
2378 if (relative_offset == 0) {
Ian Rogers3d504072014-03-01 09:16:49 -08002379 LOG(ERROR) << "Failed to write oat code for dex files to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07002380 return false;
2381 }
2382
Vladimir Markof4da6752014-08-01 19:04:18 +01002383 const off_t oat_end_file_offset = out->Seek(0, kSeekCurrent);
Vladimir Marko49b0f452015-12-10 13:49:19 +00002384 if (oat_end_file_offset == static_cast<off_t>(-1)) {
Vladimir Markof4da6752014-08-01 19:04:18 +01002385 LOG(ERROR) << "Failed to get oat end file offset in " << out->GetLocation();
2386 return false;
2387 }
2388
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002389 if (kIsDebugBuild) {
2390 uint32_t size_total = 0;
2391 #define DO_STAT(x) \
Chih-Hung Hsiehfba39972016-05-11 11:26:48 -07002392 VLOG(compiler) << #x "=" << PrettySize(x) << " (" << (x) << "B)"; \
2393 size_total += (x);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002394
David Brazdil7b49e6c2016-09-01 11:06:18 +01002395 DO_STAT(size_vdex_header_);
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +00002396 DO_STAT(size_vdex_checksums_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002397 DO_STAT(size_dex_file_alignment_);
2398 DO_STAT(size_executable_offset_alignment_);
2399 DO_STAT(size_oat_header_);
Andreas Gampe22f8e5c2014-07-09 11:38:21 -07002400 DO_STAT(size_oat_header_key_value_store_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002401 DO_STAT(size_dex_file_);
David Brazdil5d5a36b2016-09-14 15:34:10 +01002402 DO_STAT(size_verifier_deps_);
2403 DO_STAT(size_verifier_deps_alignment_);
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002404 DO_STAT(size_quickening_info_);
2405 DO_STAT(size_quickening_info_alignment_);
Ian Rogers848871b2013-08-05 10:56:33 -07002406 DO_STAT(size_interpreter_to_interpreter_bridge_);
2407 DO_STAT(size_interpreter_to_compiled_code_bridge_);
2408 DO_STAT(size_jni_dlsym_lookup_);
Andreas Gampe2da88232014-02-27 12:26:20 -08002409 DO_STAT(size_quick_generic_jni_trampoline_);
Jeff Hao88474b42013-10-23 16:24:40 -07002410 DO_STAT(size_quick_imt_conflict_trampoline_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002411 DO_STAT(size_quick_resolution_trampoline_);
Ian Rogers848871b2013-08-05 10:56:33 -07002412 DO_STAT(size_quick_to_interpreter_bridge_);
2413 DO_STAT(size_trampoline_alignment_);
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002414 DO_STAT(size_method_header_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002415 DO_STAT(size_code_);
2416 DO_STAT(size_code_alignment_);
Vladimir Markof4da6752014-08-01 19:04:18 +01002417 DO_STAT(size_relative_call_thunks_);
Vladimir Markoc74658b2015-03-31 10:26:41 +01002418 DO_STAT(size_misc_thunks_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002419 DO_STAT(size_vmap_table_);
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07002420 DO_STAT(size_method_info_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002421 DO_STAT(size_oat_dex_file_location_size_);
2422 DO_STAT(size_oat_dex_file_location_data_);
2423 DO_STAT(size_oat_dex_file_location_checksum_);
2424 DO_STAT(size_oat_dex_file_offset_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002425 DO_STAT(size_oat_dex_file_class_offsets_offset_);
Vladimir Marko49b0f452015-12-10 13:49:19 +00002426 DO_STAT(size_oat_dex_file_lookup_table_offset_);
Mathieu Chartier120aa282017-08-05 16:03:03 -07002427 DO_STAT(size_oat_dex_file_dex_layout_sections_offset_);
2428 DO_STAT(size_oat_dex_file_dex_layout_sections_);
2429 DO_STAT(size_oat_dex_file_dex_layout_sections_alignment_);
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002430 DO_STAT(size_oat_dex_file_method_bss_mapping_offset_);
Vladimir Marko49b0f452015-12-10 13:49:19 +00002431 DO_STAT(size_oat_lookup_table_alignment_);
2432 DO_STAT(size_oat_lookup_table_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002433 DO_STAT(size_oat_class_offsets_alignment_);
2434 DO_STAT(size_oat_class_offsets_);
Brian Carlstromba150c32013-08-27 17:31:03 -07002435 DO_STAT(size_oat_class_type_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002436 DO_STAT(size_oat_class_status_);
Brian Carlstromba150c32013-08-27 17:31:03 -07002437 DO_STAT(size_oat_class_method_bitmaps_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002438 DO_STAT(size_oat_class_method_offsets_);
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002439 DO_STAT(size_method_bss_mappings_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002440 #undef DO_STAT
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002441
David Brazdil7b49e6c2016-09-01 11:06:18 +01002442 VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)";
2443
2444 CHECK_EQ(vdex_size_ + oat_size_, size_total);
2445 CHECK_EQ(file_offset + size_total - vdex_size_, static_cast<size_t>(oat_end_file_offset));
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002446 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002447
David Brazdil7b49e6c2016-09-01 11:06:18 +01002448 CHECK_EQ(file_offset + oat_size_, static_cast<size_t>(oat_end_file_offset));
2449 CHECK_EQ(oat_size_, relative_offset);
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002450
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002451 write_state_ = WriteState::kWriteHeader;
2452 return true;
2453}
2454
2455bool OatWriter::WriteHeader(OutputStream* out,
2456 uint32_t image_file_location_oat_checksum,
2457 uintptr_t image_file_location_oat_begin,
2458 int32_t image_patch_delta) {
2459 CHECK(write_state_ == WriteState::kWriteHeader);
2460
2461 oat_header_->SetImageFileLocationOatChecksum(image_file_location_oat_checksum);
2462 oat_header_->SetImageFileLocationOatDataBegin(image_file_location_oat_begin);
Vladimir Markoaad75c62016-10-03 08:46:48 +00002463 if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002464 CHECK_EQ(image_patch_delta, 0);
2465 CHECK_EQ(oat_header_->GetImagePatchDelta(), 0);
2466 } else {
2467 CHECK_ALIGNED(image_patch_delta, kPageSize);
2468 oat_header_->SetImagePatchDelta(image_patch_delta);
2469 }
Vladimir Marko49b0f452015-12-10 13:49:19 +00002470 oat_header_->UpdateChecksumWithHeaderData();
2471
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002472 const size_t file_offset = oat_data_offset_;
2473
2474 off_t current_offset = out->Seek(0, kSeekCurrent);
2475 if (current_offset == static_cast<off_t>(-1)) {
2476 PLOG(ERROR) << "Failed to get current offset from " << out->GetLocation();
2477 return false;
2478 }
Vladimir Marko49b0f452015-12-10 13:49:19 +00002479 if (out->Seek(file_offset, kSeekSet) == static_cast<off_t>(-1)) {
Vladimir Markof4da6752014-08-01 19:04:18 +01002480 PLOG(ERROR) << "Failed to seek to oat header position in " << out->GetLocation();
2481 return false;
2482 }
David Srbeckybc90fd02015-04-22 19:40:27 +01002483 DCHECK_EQ(file_offset, static_cast<size_t>(out->Seek(0, kSeekCurrent)));
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002484
2485 // Flush all other data before writing the header.
2486 if (!out->Flush()) {
2487 PLOG(ERROR) << "Failed to flush before writing oat header to " << out->GetLocation();
2488 return false;
2489 }
2490 // Write the header.
2491 size_t header_size = oat_header_->GetHeaderSize();
Vladimir Marko49b0f452015-12-10 13:49:19 +00002492 if (!out->WriteFully(oat_header_.get(), header_size)) {
Vladimir Markof4da6752014-08-01 19:04:18 +01002493 PLOG(ERROR) << "Failed to write oat header to " << out->GetLocation();
2494 return false;
2495 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002496 // Flush the header data.
2497 if (!out->Flush()) {
2498 PLOG(ERROR) << "Failed to flush after writing oat header to " << out->GetLocation();
Vladimir Markof4da6752014-08-01 19:04:18 +01002499 return false;
2500 }
Vladimir Markof4da6752014-08-01 19:04:18 +01002501
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002502 if (out->Seek(current_offset, kSeekSet) == static_cast<off_t>(-1)) {
2503 PLOG(ERROR) << "Failed to seek back after writing oat header to " << out->GetLocation();
2504 return false;
2505 }
2506 DCHECK_EQ(current_offset, out->Seek(0, kSeekCurrent));
2507
2508 write_state_ = WriteState::kDone;
Brian Carlstrome24fa612011-09-29 00:53:55 -07002509 return true;
2510}
2511
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002512size_t OatWriter::WriteClassOffsets(OutputStream* out, size_t file_offset, size_t relative_offset) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002513 for (OatDexFile& oat_dex_file : oat_dex_files_) {
2514 if (oat_dex_file.class_offsets_offset_ != 0u) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002515 // Class offsets are required to be 4 byte aligned.
2516 if (UNLIKELY(!IsAligned<4u>(relative_offset))) {
2517 size_t padding_size = RoundUp(relative_offset, 4u) - relative_offset;
2518 if (!WriteUpTo16BytesAlignment(out, padding_size, &size_oat_class_offsets_alignment_)) {
2519 return 0u;
2520 }
2521 relative_offset += padding_size;
Vladimir Marko919f5532016-01-20 19:13:01 +00002522 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002523 DCHECK_OFFSET();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002524 if (!oat_dex_file.WriteClassOffsets(this, out)) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002525 return 0u;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002526 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002527 relative_offset += oat_dex_file.GetClassOffsetsRawSize();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002528 }
2529 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002530 return relative_offset;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002531}
2532
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002533size_t OatWriter::WriteClasses(OutputStream* out, size_t file_offset, size_t relative_offset) {
Mathieu Chartier3957bff2017-07-16 13:55:27 -07002534 const bool may_have_compiled = MayHaveCompiledMethods();
2535 if (may_have_compiled) {
2536 CHECK_EQ(oat_class_headers_.size(), oat_classes_.size());
2537 }
2538 for (size_t i = 0; i < oat_class_headers_.size(); ++i) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002539 // If there are any classes, the class offsets allocation aligns the offset.
2540 DCHECK_ALIGNED(relative_offset, 4u);
2541 DCHECK_OFFSET();
Mathieu Chartier3957bff2017-07-16 13:55:27 -07002542 if (!oat_class_headers_[i].Write(this, out, oat_data_offset_)) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002543 return 0u;
Vladimir Marko919f5532016-01-20 19:13:01 +00002544 }
Mathieu Chartier3957bff2017-07-16 13:55:27 -07002545 relative_offset += oat_class_headers_[i].SizeOf();
2546 if (may_have_compiled) {
2547 if (!oat_classes_[i].Write(this, out)) {
2548 return 0u;
2549 }
2550 relative_offset += oat_classes_[i].SizeOf();
2551 }
Artem Udovichenkod9786b02015-10-14 16:36:55 +03002552 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002553 return relative_offset;
Artem Udovichenkod9786b02015-10-14 16:36:55 +03002554}
2555
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002556size_t OatWriter::WriteMaps(OutputStream* out, size_t file_offset, size_t relative_offset) {
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07002557 {
2558 size_t vmap_tables_offset = relative_offset;
2559 WriteMapMethodVisitor visitor(this, out, file_offset, relative_offset);
2560 if (UNLIKELY(!VisitDexMethods(&visitor))) {
2561 return 0;
2562 }
2563 relative_offset = visitor.GetOffset();
2564 size_vmap_table_ = relative_offset - vmap_tables_offset;
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01002565 }
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07002566 {
2567 size_t method_infos_offset = relative_offset;
2568 WriteMethodInfoVisitor visitor(this, out, file_offset, relative_offset);
2569 if (UNLIKELY(!VisitDexMethods(&visitor))) {
2570 return 0;
2571 }
2572 relative_offset = visitor.GetOffset();
2573 size_method_info_ = relative_offset - method_infos_offset;
2574 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002575
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002576 return relative_offset;
2577}
2578
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002579size_t OatWriter::WriteMethodBssMappings(OutputStream* out,
2580 size_t file_offset,
2581 size_t relative_offset) {
2582 TimingLogger::ScopedTiming split("WriteMethodBssMappings", timings_);
2583
2584 for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
2585 const DexFile* dex_file = (*dex_files_)[i];
2586 OatDexFile* oat_dex_file = &oat_dex_files_[i];
2587 auto it = bss_method_entry_references_.find(dex_file);
2588 if (it != bss_method_entry_references_.end()) {
2589 const BitVector& method_indexes = it->second;
2590 // If there are any classes, the class offsets allocation aligns the offset
2591 // and we cannot have method bss mappings without class offsets.
2592 static_assert(alignof(MethodBssMapping) == sizeof(uint32_t),
2593 "MethodBssMapping alignment check.");
2594 DCHECK_ALIGNED(relative_offset, sizeof(uint32_t));
2595
2596 linker::MethodBssMappingEncoder encoder(
2597 GetInstructionSetPointerSize(oat_header_->GetInstructionSet()));
2598 // Allocate a sufficiently large MethodBssMapping.
2599 size_t number_of_method_indexes = method_indexes.NumSetBits();
2600 DCHECK_NE(number_of_method_indexes, 0u);
2601 size_t max_mappings_size = MethodBssMapping::ComputeSize(number_of_method_indexes);
2602 DCHECK_ALIGNED(max_mappings_size, sizeof(uint32_t));
2603 std::unique_ptr<uint32_t[]> storage(new uint32_t[max_mappings_size / sizeof(uint32_t)]);
2604 MethodBssMapping* mappings = new(storage.get()) MethodBssMapping(number_of_method_indexes);
2605 mappings->ClearPadding();
2606 // Encode the MethodBssMapping.
2607 auto init_it = mappings->begin();
2608 bool first_index = true;
2609 for (uint32_t method_index : method_indexes.Indexes()) {
2610 size_t bss_offset = bss_method_entries_.Get(MethodReference(dex_file, method_index));
2611 if (first_index) {
2612 first_index = false;
2613 encoder.Reset(method_index, bss_offset);
2614 } else if (!encoder.TryMerge(method_index, bss_offset)) {
2615 *init_it = encoder.GetEntry();
2616 ++init_it;
2617 encoder.Reset(method_index, bss_offset);
2618 }
2619 }
2620 // Store the last entry and shrink the mapping to the actual size.
2621 *init_it = encoder.GetEntry();
2622 ++init_it;
2623 DCHECK(init_it <= mappings->end());
2624 mappings->SetSize(std::distance(mappings->begin(), init_it));
2625 size_t mappings_size = MethodBssMapping::ComputeSize(mappings->size());
2626
2627 DCHECK_EQ(relative_offset, oat_dex_file->method_bss_mapping_offset_);
2628 DCHECK_OFFSET();
2629 if (!out->WriteFully(storage.get(), mappings_size)) {
2630 return 0u;
2631 }
2632 size_method_bss_mappings_ += mappings_size;
2633 relative_offset += mappings_size;
2634 } else {
2635 DCHECK_EQ(0u, oat_dex_file->method_bss_mapping_offset_);
2636 }
2637 }
2638 return relative_offset;
2639}
2640
2641size_t OatWriter::WriteOatDexFiles(OutputStream* out, size_t file_offset, size_t relative_offset) {
2642 TimingLogger::ScopedTiming split("WriteOatDexFiles", timings_);
2643
2644 for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
2645 OatDexFile* oat_dex_file = &oat_dex_files_[i];
2646 DCHECK_EQ(relative_offset, oat_dex_file->offset_);
2647 DCHECK_OFFSET();
2648
2649 // Write OatDexFile.
2650 if (!oat_dex_file->Write(this, out)) {
2651 return 0u;
2652 }
2653 relative_offset += oat_dex_file->SizeOf();
2654 }
2655
2656 return relative_offset;
2657}
2658
2659size_t OatWriter::WriteCode(OutputStream* out, size_t file_offset, size_t relative_offset) {
Vladimir Markoaad75c62016-10-03 08:46:48 +00002660 if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002661 InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002662
Ian Rogers848871b2013-08-05 10:56:33 -07002663 #define DO_TRAMPOLINE(field) \
2664 do { \
2665 uint32_t aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set); \
2666 uint32_t alignment_padding = aligned_offset - relative_offset; \
Ian Rogers3d504072014-03-01 09:16:49 -08002667 out->Seek(alignment_padding, kSeekCurrent); \
Ian Rogers848871b2013-08-05 10:56:33 -07002668 size_trampoline_alignment_ += alignment_padding; \
Vladimir Markoe079e212016-05-25 12:49:49 +01002669 if (!out->WriteFully((field)->data(), (field)->size())) { \
Ian Rogers3d504072014-03-01 09:16:49 -08002670 PLOG(ERROR) << "Failed to write " # field " to " << out->GetLocation(); \
Ian Rogers848871b2013-08-05 10:56:33 -07002671 return false; \
2672 } \
Chih-Hung Hsiehfba39972016-05-11 11:26:48 -07002673 size_ ## field += (field)->size(); \
2674 relative_offset += alignment_padding + (field)->size(); \
Ian Rogers848871b2013-08-05 10:56:33 -07002675 DCHECK_OFFSET(); \
2676 } while (false)
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002677
Ian Rogers848871b2013-08-05 10:56:33 -07002678 DO_TRAMPOLINE(jni_dlsym_lookup_);
Andreas Gampe2da88232014-02-27 12:26:20 -08002679 DO_TRAMPOLINE(quick_generic_jni_trampoline_);
Jeff Hao88474b42013-10-23 16:24:40 -07002680 DO_TRAMPOLINE(quick_imt_conflict_trampoline_);
Ian Rogers848871b2013-08-05 10:56:33 -07002681 DO_TRAMPOLINE(quick_resolution_trampoline_);
2682 DO_TRAMPOLINE(quick_to_interpreter_bridge_);
2683 #undef DO_TRAMPOLINE
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002684 }
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002685 return relative_offset;
Brian Carlstrome24fa612011-09-29 00:53:55 -07002686}
2687
Ian Rogers3d504072014-03-01 09:16:49 -08002688size_t OatWriter::WriteCodeDexFiles(OutputStream* out,
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002689 size_t file_offset,
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002690 size_t relative_offset) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002691 #define VISIT(VisitorType) \
2692 do { \
2693 VisitorType visitor(this, out, file_offset, relative_offset); \
2694 if (UNLIKELY(!VisitDexMethods(&visitor))) { \
2695 return 0; \
2696 } \
2697 relative_offset = visitor.GetOffset(); \
2698 } while (false)
Brian Carlstrome24fa612011-09-29 00:53:55 -07002699
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002700 VISIT(WriteCodeMethodVisitor);
Brian Carlstrome24fa612011-09-29 00:53:55 -07002701
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002702 #undef VISIT
Brian Carlstrom265091e2013-01-30 14:08:26 -08002703
Vladimir Markob163bb72015-03-31 21:49:49 +01002704 size_code_alignment_ += relative_patcher_->CodeAlignmentSize();
2705 size_relative_call_thunks_ += relative_patcher_->RelativeCallThunksSize();
2706 size_misc_thunks_ += relative_patcher_->MiscThunksSize();
2707
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002708 return relative_offset;
Brian Carlstrome24fa612011-09-29 00:53:55 -07002709}
2710
Vladimir Marko944da602016-02-19 12:27:55 +00002711bool OatWriter::RecordOatDataOffset(OutputStream* out) {
Vladimir Marko49b0f452015-12-10 13:49:19 +00002712 // Get the elf file offset of the oat file.
2713 const off_t raw_file_offset = out->Seek(0, kSeekCurrent);
2714 if (raw_file_offset == static_cast<off_t>(-1)) {
2715 LOG(ERROR) << "Failed to get file offset in " << out->GetLocation();
2716 return false;
2717 }
2718 oat_data_offset_ = static_cast<size_t>(raw_file_offset);
2719 return true;
2720}
2721
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002722bool OatWriter::ReadDexFileHeader(File* file, OatDexFile* oat_dex_file) {
2723 // Read the dex file header and perform minimal verification.
2724 uint8_t raw_header[sizeof(DexFile::Header)];
2725 if (!file->ReadFully(&raw_header, sizeof(DexFile::Header))) {
2726 PLOG(ERROR) << "Failed to read dex file header. Actual: "
2727 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2728 return false;
2729 }
2730 if (!ValidateDexFileHeader(raw_header, oat_dex_file->GetLocation())) {
2731 return false;
2732 }
2733
2734 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_header);
2735 oat_dex_file->dex_file_size_ = header->file_size_;
2736 oat_dex_file->dex_file_location_checksum_ = header->checksum_;
2737 oat_dex_file->class_offsets_.resize(header->class_defs_size_);
2738 return true;
2739}
2740
2741bool OatWriter::ValidateDexFileHeader(const uint8_t* raw_header, const char* location) {
2742 if (!DexFile::IsMagicValid(raw_header)) {
2743 LOG(ERROR) << "Invalid magic number in dex file header. " << " File: " << location;
2744 return false;
2745 }
2746 if (!DexFile::IsVersionValid(raw_header)) {
2747 LOG(ERROR) << "Invalid version number in dex file header. " << " File: " << location;
2748 return false;
2749 }
2750 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_header);
2751 if (header->file_size_ < sizeof(DexFile::Header)) {
2752 LOG(ERROR) << "Dex file header specifies file size insufficient to contain the header."
2753 << " File: " << location;
2754 return false;
2755 }
2756 return true;
2757}
2758
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002759bool OatWriter::WriteDexFiles(OutputStream* out, File* file, bool update_input_vdex) {
David Brazdil7b49e6c2016-09-01 11:06:18 +01002760 TimingLogger::ScopedTiming split("Write Dex files", timings_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002761
David Brazdil7b49e6c2016-09-01 11:06:18 +01002762 vdex_dex_files_offset_ = vdex_size_;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002763
2764 // Write dex files.
2765 for (OatDexFile& oat_dex_file : oat_dex_files_) {
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002766 if (!WriteDexFile(out, file, &oat_dex_file, update_input_vdex)) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002767 return false;
2768 }
2769 }
2770
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002771 CloseSources();
2772 return true;
2773}
2774
2775void OatWriter::CloseSources() {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002776 for (OatDexFile& oat_dex_file : oat_dex_files_) {
2777 oat_dex_file.source_.Clear(); // Get rid of the reference, it's about to be invalidated.
2778 }
2779 zipped_dex_files_.clear();
2780 zip_archives_.clear();
2781 raw_dex_files_.clear();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002782}
2783
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002784bool OatWriter::WriteDexFile(OutputStream* out,
2785 File* file,
2786 OatDexFile* oat_dex_file,
2787 bool update_input_vdex) {
David Brazdil7b49e6c2016-09-01 11:06:18 +01002788 if (!SeekToDexFile(out, file, oat_dex_file)) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002789 return false;
2790 }
Jeff Hao608f2ce2016-10-19 11:17:11 -07002791 if (profile_compilation_info_ != nullptr) {
Nicolas Geoffray1cfea7a2017-05-24 14:44:38 +01002792 CHECK(!update_input_vdex) << "We should never update the input vdex when doing dexlayout";
Jeff Hao608f2ce2016-10-19 11:17:11 -07002793 if (!LayoutAndWriteDexFile(out, oat_dex_file)) {
2794 return false;
2795 }
2796 } else if (oat_dex_file->source_.IsZipEntry()) {
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002797 DCHECK(!update_input_vdex);
David Brazdil7b49e6c2016-09-01 11:06:18 +01002798 if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetZipEntry())) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002799 return false;
2800 }
2801 } else if (oat_dex_file->source_.IsRawFile()) {
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002802 DCHECK(!update_input_vdex);
David Brazdil7b49e6c2016-09-01 11:06:18 +01002803 if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetRawFile())) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002804 return false;
2805 }
2806 } else {
2807 DCHECK(oat_dex_file->source_.IsRawData());
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002808 if (!WriteDexFile(out, oat_dex_file, oat_dex_file->source_.GetRawData(), update_input_vdex)) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002809 return false;
2810 }
2811 }
2812
2813 // Update current size and account for the written data.
David Brazdil7b49e6c2016-09-01 11:06:18 +01002814 if (kIsVdexEnabled) {
2815 DCHECK_EQ(vdex_size_, oat_dex_file->dex_file_offset_);
2816 vdex_size_ += oat_dex_file->dex_file_size_;
2817 } else {
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002818 DCHECK(!update_input_vdex);
David Brazdil7b49e6c2016-09-01 11:06:18 +01002819 DCHECK_EQ(oat_size_, oat_dex_file->dex_file_offset_);
2820 oat_size_ += oat_dex_file->dex_file_size_;
2821 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002822 size_dex_file_ += oat_dex_file->dex_file_size_;
2823 return true;
2824}
2825
2826bool OatWriter::SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file) {
2827 // Dex files are required to be 4 byte aligned.
David Brazdil7b49e6c2016-09-01 11:06:18 +01002828 size_t initial_offset = kIsVdexEnabled ? vdex_size_ : oat_size_;
2829 size_t start_offset = RoundUp(initial_offset, 4);
2830 size_t file_offset = kIsVdexEnabled ? start_offset : (oat_data_offset_ + start_offset);
2831 size_dex_file_alignment_ += start_offset - initial_offset;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002832
2833 // Seek to the start of the dex file and flush any pending operations in the stream.
2834 // Verify that, after flushing the stream, the file is at the same offset as the stream.
David Brazdil7b49e6c2016-09-01 11:06:18 +01002835 off_t actual_offset = out->Seek(file_offset, kSeekSet);
2836 if (actual_offset != static_cast<off_t>(file_offset)) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002837 PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
David Brazdil7b49e6c2016-09-01 11:06:18 +01002838 << " Expected: " << file_offset
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002839 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2840 return false;
2841 }
2842 if (!out->Flush()) {
2843 PLOG(ERROR) << "Failed to flush before writing dex file."
2844 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2845 return false;
2846 }
2847 actual_offset = lseek(file->Fd(), 0, SEEK_CUR);
David Brazdil7b49e6c2016-09-01 11:06:18 +01002848 if (actual_offset != static_cast<off_t>(file_offset)) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002849 PLOG(ERROR) << "Stream/file position mismatch! Actual: " << actual_offset
David Brazdil7b49e6c2016-09-01 11:06:18 +01002850 << " Expected: " << file_offset
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002851 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2852 return false;
2853 }
2854
David Brazdil7b49e6c2016-09-01 11:06:18 +01002855 if (kIsVdexEnabled) {
2856 vdex_size_ = start_offset;
2857 } else {
2858 oat_size_ = start_offset;
2859 }
2860 oat_dex_file->dex_file_offset_ = start_offset;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002861 return true;
2862}
2863
Jeff Hao608f2ce2016-10-19 11:17:11 -07002864bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_file) {
2865 TimingLogger::ScopedTiming split("Dex Layout", timings_);
2866 std::string error_msg;
2867 std::string location(oat_dex_file->GetLocation());
2868 std::unique_ptr<const DexFile> dex_file;
2869 if (oat_dex_file->source_.IsZipEntry()) {
2870 ZipEntry* zip_entry = oat_dex_file->source_.GetZipEntry();
2871 std::unique_ptr<MemMap> mem_map(
2872 zip_entry->ExtractToMemMap(location.c_str(), "classes.dex", &error_msg));
Jeff Hao41b2f532017-03-02 16:36:31 -08002873 if (mem_map == nullptr) {
2874 LOG(ERROR) << "Failed to extract dex file to mem map for layout: " << error_msg;
2875 return false;
2876 }
Jeff Hao608f2ce2016-10-19 11:17:11 -07002877 dex_file = DexFile::Open(location,
2878 zip_entry->GetCrc32(),
2879 std::move(mem_map),
2880 /* verify */ true,
2881 /* verify_checksum */ true,
2882 &error_msg);
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +01002883 } else if (oat_dex_file->source_.IsRawFile()) {
Jeff Hao608f2ce2016-10-19 11:17:11 -07002884 File* raw_file = oat_dex_file->source_.GetRawFile();
Jeff Hao68c48f02017-08-24 11:36:24 -07002885 int dup_fd = dup(raw_file->Fd());
2886 if (dup_fd < 0) {
2887 PLOG(ERROR) << "Failed to dup dex file descriptor (" << raw_file->Fd() << ") at " << location;
2888 return false;
2889 }
2890 dex_file = DexFile::OpenDex(dup_fd, location, /* verify_checksum */ true, &error_msg);
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +01002891 } else {
2892 // The source data is a vdex file.
2893 CHECK(oat_dex_file->source_.IsRawData())
2894 << static_cast<size_t>(oat_dex_file->source_.GetType());
2895 const uint8_t* raw_dex_file = oat_dex_file->source_.GetRawData();
2896 // Note: The raw data has already been checked to contain the header
2897 // and all the data that the header specifies as the file size.
2898 DCHECK(raw_dex_file != nullptr);
2899 DCHECK(ValidateDexFileHeader(raw_dex_file, oat_dex_file->GetLocation()));
2900 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
2901 // Since the source may have had its layout changed, or may be quickened, don't verify it.
2902 dex_file = DexFile::Open(raw_dex_file,
2903 header->file_size_,
2904 location,
2905 oat_dex_file->dex_file_location_checksum_,
2906 nullptr,
2907 /* verify */ false,
2908 /* verify_checksum */ false,
2909 &error_msg);
Jeff Hao608f2ce2016-10-19 11:17:11 -07002910 }
Jeff Haode197542017-02-03 10:48:13 -08002911 if (dex_file == nullptr) {
Jeff Haod9df7802017-02-06 16:41:16 -08002912 LOG(ERROR) << "Failed to open dex file for layout: " << error_msg;
Jeff Haode197542017-02-03 10:48:13 -08002913 return false;
2914 }
Jeff Hao608f2ce2016-10-19 11:17:11 -07002915 Options options;
2916 options.output_to_memmap_ = true;
2917 DexLayout dex_layout(options, profile_compilation_info_, nullptr);
2918 dex_layout.ProcessDexFile(location.c_str(), dex_file.get(), 0);
2919 std::unique_ptr<MemMap> mem_map(dex_layout.GetAndReleaseMemMap());
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002920 if (!WriteDexFile(out, oat_dex_file, mem_map->Begin(), /* update_input_vdex */ false)) {
Jeff Hao608f2ce2016-10-19 11:17:11 -07002921 return false;
2922 }
Mathieu Chartier120aa282017-08-05 16:03:03 -07002923 oat_dex_file->dex_sections_layout_ = dex_layout.GetSections();
Jeff Hao608f2ce2016-10-19 11:17:11 -07002924 // Set the checksum of the new oat dex file to be the original file's checksum.
2925 oat_dex_file->dex_file_location_checksum_ = dex_file->GetLocationChecksum();
2926 return true;
2927}
2928
David Brazdil7b49e6c2016-09-01 11:06:18 +01002929bool OatWriter::WriteDexFile(OutputStream* out,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002930 File* file,
2931 OatDexFile* oat_dex_file,
2932 ZipEntry* dex_file) {
David Brazdil7b49e6c2016-09-01 11:06:18 +01002933 size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_;
2934 DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002935
2936 // Extract the dex file and get the extracted size.
2937 std::string error_msg;
2938 if (!dex_file->ExtractToFile(*file, &error_msg)) {
2939 LOG(ERROR) << "Failed to extract dex file from ZIP entry: " << error_msg
2940 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2941 return false;
2942 }
2943 if (file->Flush() != 0) {
2944 PLOG(ERROR) << "Failed to flush dex file from ZIP entry."
2945 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2946 return false;
2947 }
2948 off_t extracted_end = lseek(file->Fd(), 0, SEEK_CUR);
2949 if (extracted_end == static_cast<off_t>(-1)) {
2950 PLOG(ERROR) << "Failed get end offset after writing dex file from ZIP entry."
2951 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2952 return false;
2953 }
2954 if (extracted_end < static_cast<off_t>(start_offset)) {
2955 LOG(ERROR) << "Dex file end position is before start position! End: " << extracted_end
2956 << " Start: " << start_offset
2957 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2958 return false;
2959 }
2960 uint64_t extracted_size = static_cast<uint64_t>(extracted_end - start_offset);
2961 if (extracted_size < sizeof(DexFile::Header)) {
2962 LOG(ERROR) << "Extracted dex file is shorter than dex file header. size: "
2963 << extracted_size << " File: " << oat_dex_file->GetLocation();
2964 return false;
2965 }
2966
2967 // Read the dex file header and extract required data to OatDexFile.
2968 off_t actual_offset = lseek(file->Fd(), start_offset, SEEK_SET);
2969 if (actual_offset != static_cast<off_t>(start_offset)) {
2970 PLOG(ERROR) << "Failed to seek back to dex file header. Actual: " << actual_offset
2971 << " Expected: " << start_offset
2972 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2973 return false;
2974 }
2975 if (!ReadDexFileHeader(file, oat_dex_file)) {
2976 return false;
2977 }
2978 if (extracted_size < oat_dex_file->dex_file_size_) {
2979 LOG(ERROR) << "Extracted truncated dex file. Extracted size: " << extracted_size
2980 << " file size from header: " << oat_dex_file->dex_file_size_
2981 << " File: " << oat_dex_file->GetLocation();
2982 return false;
2983 }
2984
2985 // Override the checksum from header with the CRC from ZIP entry.
2986 oat_dex_file->dex_file_location_checksum_ = dex_file->GetCrc32();
2987
2988 // Seek both file and stream to the end offset.
2989 size_t end_offset = start_offset + oat_dex_file->dex_file_size_;
2990 actual_offset = lseek(file->Fd(), end_offset, SEEK_SET);
2991 if (actual_offset != static_cast<off_t>(end_offset)) {
2992 PLOG(ERROR) << "Failed to seek to end of dex file. Actual: " << actual_offset
2993 << " Expected: " << end_offset
2994 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2995 return false;
2996 }
David Brazdil7b49e6c2016-09-01 11:06:18 +01002997 actual_offset = out->Seek(end_offset, kSeekSet);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002998 if (actual_offset != static_cast<off_t>(end_offset)) {
2999 PLOG(ERROR) << "Failed to seek stream to end of dex file. Actual: " << actual_offset
3000 << " Expected: " << end_offset << " File: " << oat_dex_file->GetLocation();
3001 return false;
3002 }
David Brazdil7b49e6c2016-09-01 11:06:18 +01003003 if (!out->Flush()) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003004 PLOG(ERROR) << "Failed to flush stream after seeking over dex file."
3005 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3006 return false;
3007 }
3008
3009 // If we extracted more than the size specified in the header, truncate the file.
3010 if (extracted_size > oat_dex_file->dex_file_size_) {
3011 if (file->SetLength(end_offset) != 0) {
3012 PLOG(ERROR) << "Failed to truncate excessive dex file length."
David Brazdil7b49e6c2016-09-01 11:06:18 +01003013 << " File: " << oat_dex_file->GetLocation()
3014 << " Output: " << file->GetPath();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003015 return false;
3016 }
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 File* file,
3024 OatDexFile* oat_dex_file,
3025 File* dex_file) {
David Brazdil7b49e6c2016-09-01 11:06:18 +01003026 size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_;
3027 DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003028
3029 off_t input_offset = lseek(dex_file->Fd(), 0, SEEK_SET);
3030 if (input_offset != static_cast<off_t>(0)) {
3031 PLOG(ERROR) << "Failed to seek to dex file header. Actual: " << input_offset
3032 << " Expected: 0"
3033 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3034 return false;
3035 }
3036 if (!ReadDexFileHeader(dex_file, oat_dex_file)) {
3037 return false;
3038 }
3039
3040 // Copy the input dex file using sendfile().
3041 if (!file->Copy(dex_file, 0, oat_dex_file->dex_file_size_)) {
3042 PLOG(ERROR) << "Failed to copy dex file to oat file."
3043 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3044 return false;
3045 }
3046 if (file->Flush() != 0) {
3047 PLOG(ERROR) << "Failed to flush dex file."
3048 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3049 return false;
3050 }
3051
3052 // Check file position and seek the stream to the end offset.
3053 size_t end_offset = start_offset + oat_dex_file->dex_file_size_;
3054 off_t actual_offset = lseek(file->Fd(), 0, SEEK_CUR);
3055 if (actual_offset != static_cast<off_t>(end_offset)) {
3056 PLOG(ERROR) << "Unexpected file position after copying dex file. Actual: " << actual_offset
3057 << " Expected: " << end_offset
3058 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3059 return false;
3060 }
David Brazdil7b49e6c2016-09-01 11:06:18 +01003061 actual_offset = out->Seek(end_offset, kSeekSet);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003062 if (actual_offset != static_cast<off_t>(end_offset)) {
3063 PLOG(ERROR) << "Failed to seek stream to end of dex file. Actual: " << actual_offset
3064 << " Expected: " << end_offset << " File: " << oat_dex_file->GetLocation();
3065 return false;
3066 }
David Brazdil7b49e6c2016-09-01 11:06:18 +01003067 if (!out->Flush()) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003068 PLOG(ERROR) << "Failed to flush stream after seeking over dex file."
3069 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3070 return false;
3071 }
3072
3073 return true;
3074}
3075
David Brazdil7b49e6c2016-09-01 11:06:18 +01003076bool OatWriter::WriteDexFile(OutputStream* out,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003077 OatDexFile* oat_dex_file,
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00003078 const uint8_t* dex_file,
3079 bool update_input_vdex) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003080 // Note: The raw data has already been checked to contain the header
3081 // and all the data that the header specifies as the file size.
3082 DCHECK(dex_file != nullptr);
3083 DCHECK(ValidateDexFileHeader(dex_file, oat_dex_file->GetLocation()));
3084 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(dex_file);
3085
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00003086 if (update_input_vdex) {
3087 // The vdex already contains the dex code, no need to write it again.
3088 } else {
3089 if (!out->WriteFully(dex_file, header->file_size_)) {
3090 PLOG(ERROR) << "Failed to write dex file " << oat_dex_file->GetLocation()
3091 << " to " << out->GetLocation();
3092 return false;
3093 }
3094 if (!out->Flush()) {
3095 PLOG(ERROR) << "Failed to flush stream after writing dex file."
3096 << " File: " << oat_dex_file->GetLocation();
3097 return false;
3098 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003099 }
3100
3101 // Update dex file size and resize class offsets in the OatDexFile.
3102 // Note: For raw data, the checksum is passed directly to AddRawDexFileSource().
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +00003103 // Note: For vdex, the checksum is copied from the existing vdex file.
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003104 oat_dex_file->dex_file_size_ = header->file_size_;
3105 oat_dex_file->class_offsets_.resize(header->class_defs_size_);
3106 return true;
3107}
3108
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003109bool OatWriter::OpenDexFiles(
3110 File* file,
Andreas Gampe3a2bd292016-01-26 17:23:47 -08003111 bool verify,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003112 /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map,
3113 /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
3114 TimingLogger::ScopedTiming split("OpenDexFiles", timings_);
3115
3116 if (oat_dex_files_.empty()) {
3117 // Nothing to do.
3118 return true;
3119 }
3120
3121 size_t map_offset = oat_dex_files_[0].dex_file_offset_;
David Brazdil7b49e6c2016-09-01 11:06:18 +01003122 size_t length = kIsVdexEnabled ? (vdex_size_ - map_offset) : (oat_size_ - map_offset);
3123
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003124 std::string error_msg;
David Brazdil7b49e6c2016-09-01 11:06:18 +01003125 std::unique_ptr<MemMap> dex_files_map(MemMap::MapFile(
3126 length,
3127 PROT_READ | PROT_WRITE,
3128 MAP_SHARED,
3129 file->Fd(),
3130 kIsVdexEnabled ? map_offset : (oat_data_offset_ + map_offset),
3131 /* low_4gb */ false,
3132 file->GetPath().c_str(),
3133 &error_msg));
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003134 if (dex_files_map == nullptr) {
3135 LOG(ERROR) << "Failed to mmap() dex files from oat file. File: " << file->GetPath()
3136 << " error: " << error_msg;
3137 return false;
3138 }
3139 std::vector<std::unique_ptr<const DexFile>> dex_files;
3140 for (OatDexFile& oat_dex_file : oat_dex_files_) {
3141 // Make sure no one messed with input files while we were copying data.
3142 // At the very least we need consistent file size and number of class definitions.
3143 const uint8_t* raw_dex_file =
3144 dex_files_map->Begin() + oat_dex_file.dex_file_offset_ - map_offset;
3145 if (!ValidateDexFileHeader(raw_dex_file, oat_dex_file.GetLocation())) {
3146 // Note: ValidateDexFileHeader() already logged an error message.
3147 LOG(ERROR) << "Failed to verify written dex file header!"
3148 << " Output: " << file->GetPath() << " ~ " << std::hex << map_offset
3149 << " ~ " << static_cast<const void*>(raw_dex_file);
3150 return false;
3151 }
3152 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
3153 if (header->file_size_ != oat_dex_file.dex_file_size_) {
3154 LOG(ERROR) << "File size mismatch in written dex file header! Expected: "
3155 << oat_dex_file.dex_file_size_ << " Actual: " << header->file_size_
3156 << " Output: " << file->GetPath();
3157 return false;
3158 }
3159 if (header->class_defs_size_ != oat_dex_file.class_offsets_.size()) {
3160 LOG(ERROR) << "Class defs size mismatch in written dex file header! Expected: "
3161 << oat_dex_file.class_offsets_.size() << " Actual: " << header->class_defs_size_
3162 << " Output: " << file->GetPath();
3163 return false;
3164 }
3165
3166 // Now, open the dex file.
3167 dex_files.emplace_back(DexFile::Open(raw_dex_file,
3168 oat_dex_file.dex_file_size_,
3169 oat_dex_file.GetLocation(),
3170 oat_dex_file.dex_file_location_checksum_,
3171 /* oat_dex_file */ nullptr,
Andreas Gampe3a2bd292016-01-26 17:23:47 -08003172 verify,
Aart Bik37d6a3b2016-06-21 18:30:10 -07003173 verify,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003174 &error_msg));
3175 if (dex_files.back() == nullptr) {
Andreas Gampe3a2bd292016-01-26 17:23:47 -08003176 LOG(ERROR) << "Failed to open dex file from oat file. File: " << oat_dex_file.GetLocation()
3177 << " Error: " << error_msg;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003178 return false;
3179 }
3180 }
3181
3182 *opened_dex_files_map = std::move(dex_files_map);
3183 *opened_dex_files = std::move(dex_files);
3184 return true;
3185}
3186
3187bool OatWriter::WriteTypeLookupTables(
David Brazdil7b49e6c2016-09-01 11:06:18 +01003188 OutputStream* oat_rodata,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003189 const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files) {
3190 TimingLogger::ScopedTiming split("WriteTypeLookupTables", timings_);
3191
David Brazdil7b49e6c2016-09-01 11:06:18 +01003192 uint32_t expected_offset = oat_data_offset_ + oat_size_;
3193 off_t actual_offset = oat_rodata->Seek(expected_offset, kSeekSet);
3194 if (static_cast<uint32_t>(actual_offset) != expected_offset) {
3195 PLOG(ERROR) << "Failed to seek to TypeLookupTable section. Actual: " << actual_offset
3196 << " Expected: " << expected_offset << " File: " << oat_rodata->GetLocation();
3197 return false;
3198 }
3199
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003200 DCHECK_EQ(opened_dex_files.size(), oat_dex_files_.size());
3201 for (size_t i = 0, size = opened_dex_files.size(); i != size; ++i) {
3202 OatDexFile* oat_dex_file = &oat_dex_files_[i];
David Brazdil181e1cc2016-09-01 16:38:47 +00003203 DCHECK_EQ(oat_dex_file->lookup_table_offset_, 0u);
3204
3205 if (oat_dex_file->create_type_lookup_table_ != CreateTypeLookupTable::kCreate ||
3206 oat_dex_file->class_offsets_.empty()) {
3207 continue;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003208 }
David Brazdil181e1cc2016-09-01 16:38:47 +00003209
3210 size_t table_size = TypeLookupTable::RawDataLength(oat_dex_file->class_offsets_.size());
3211 if (table_size == 0u) {
3212 continue;
3213 }
3214
3215 // Create the lookup table. When `nullptr` is given as the storage buffer,
David Sehr9aa352e2016-09-15 18:13:52 -07003216 // TypeLookupTable allocates its own and OatDexFile takes ownership.
Mathieu Chartier1b868492016-11-16 16:22:37 -08003217 const DexFile& dex_file = *opened_dex_files[i];
3218 {
3219 std::unique_ptr<TypeLookupTable> type_lookup_table =
3220 TypeLookupTable::Create(dex_file, /* storage */ nullptr);
3221 type_lookup_table_oat_dex_files_.push_back(
3222 std::make_unique<art::OatDexFile>(std::move(type_lookup_table)));
3223 dex_file.SetOatDexFile(type_lookup_table_oat_dex_files_.back().get());
3224 }
3225 TypeLookupTable* const table = type_lookup_table_oat_dex_files_.back()->GetTypeLookupTable();
David Brazdil181e1cc2016-09-01 16:38:47 +00003226
3227 // Type tables are required to be 4 byte aligned.
David Brazdil7b49e6c2016-09-01 11:06:18 +01003228 size_t initial_offset = oat_size_;
3229 size_t rodata_offset = RoundUp(initial_offset, 4);
3230 size_t padding_size = rodata_offset - initial_offset;
David Brazdil181e1cc2016-09-01 16:38:47 +00003231
3232 if (padding_size != 0u) {
3233 std::vector<uint8_t> buffer(padding_size, 0u);
David Brazdil7b49e6c2016-09-01 11:06:18 +01003234 if (!oat_rodata->WriteFully(buffer.data(), padding_size)) {
David Brazdil181e1cc2016-09-01 16:38:47 +00003235 PLOG(ERROR) << "Failed to write lookup table alignment padding."
3236 << " File: " << oat_dex_file->GetLocation()
David Brazdil7b49e6c2016-09-01 11:06:18 +01003237 << " Output: " << oat_rodata->GetLocation();
David Brazdil181e1cc2016-09-01 16:38:47 +00003238 return false;
3239 }
3240 }
3241
3242 DCHECK_EQ(oat_data_offset_ + rodata_offset,
David Brazdil7b49e6c2016-09-01 11:06:18 +01003243 static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent)));
David Brazdil181e1cc2016-09-01 16:38:47 +00003244 DCHECK_EQ(table_size, table->RawDataLength());
3245
David Brazdil7b49e6c2016-09-01 11:06:18 +01003246 if (!oat_rodata->WriteFully(table->RawData(), table_size)) {
David Brazdil181e1cc2016-09-01 16:38:47 +00003247 PLOG(ERROR) << "Failed to write lookup table."
3248 << " File: " << oat_dex_file->GetLocation()
David Brazdil7b49e6c2016-09-01 11:06:18 +01003249 << " Output: " << oat_rodata->GetLocation();
David Brazdil181e1cc2016-09-01 16:38:47 +00003250 return false;
3251 }
3252
3253 oat_dex_file->lookup_table_offset_ = rodata_offset;
3254
David Brazdil7b49e6c2016-09-01 11:06:18 +01003255 oat_size_ += padding_size + table_size;
David Brazdil181e1cc2016-09-01 16:38:47 +00003256 size_oat_lookup_table_ += table_size;
3257 size_oat_lookup_table_alignment_ += padding_size;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003258 }
3259
David Brazdil7b49e6c2016-09-01 11:06:18 +01003260 if (!oat_rodata->Flush()) {
David Brazdil181e1cc2016-09-01 16:38:47 +00003261 PLOG(ERROR) << "Failed to flush stream after writing type lookup tables."
David Brazdil7b49e6c2016-09-01 11:06:18 +01003262 << " File: " << oat_rodata->GetLocation();
3263 return false;
3264 }
3265
3266 return true;
3267}
3268
Mathieu Chartier120aa282017-08-05 16:03:03 -07003269bool OatWriter::WriteDexLayoutSections(
3270 OutputStream* oat_rodata,
3271 const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files) {
3272 TimingLogger::ScopedTiming split(__FUNCTION__, timings_);
3273
3274 if (!kWriteDexLayoutInfo) {
3275 return true;;
3276 }
3277
3278 uint32_t expected_offset = oat_data_offset_ + oat_size_;
3279 off_t actual_offset = oat_rodata->Seek(expected_offset, kSeekSet);
3280 if (static_cast<uint32_t>(actual_offset) != expected_offset) {
3281 PLOG(ERROR) << "Failed to seek to dex layout section offset section. Actual: " << actual_offset
3282 << " Expected: " << expected_offset << " File: " << oat_rodata->GetLocation();
3283 return false;
3284 }
3285
3286 DCHECK_EQ(opened_dex_files.size(), oat_dex_files_.size());
3287 size_t rodata_offset = oat_size_;
3288 for (size_t i = 0, size = opened_dex_files.size(); i != size; ++i) {
3289 OatDexFile* oat_dex_file = &oat_dex_files_[i];
3290 DCHECK_EQ(oat_dex_file->dex_sections_layout_offset_, 0u);
3291
3292 // Write dex layout section alignment bytes.
3293 const size_t padding_size =
3294 RoundUp(rodata_offset, alignof(DexLayoutSections)) - rodata_offset;
3295 if (padding_size != 0u) {
3296 std::vector<uint8_t> buffer(padding_size, 0u);
3297 if (!oat_rodata->WriteFully(buffer.data(), padding_size)) {
3298 PLOG(ERROR) << "Failed to write lookup table alignment padding."
3299 << " File: " << oat_dex_file->GetLocation()
3300 << " Output: " << oat_rodata->GetLocation();
3301 return false;
3302 }
3303 size_oat_dex_file_dex_layout_sections_alignment_ += padding_size;
3304 rodata_offset += padding_size;
3305 }
3306
3307 DCHECK_ALIGNED(rodata_offset, alignof(DexLayoutSections));
3308 DCHECK_EQ(oat_data_offset_ + rodata_offset,
3309 static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent)));
3310 DCHECK(oat_dex_file != nullptr);
3311 if (!oat_rodata->WriteFully(&oat_dex_file->dex_sections_layout_,
3312 sizeof(oat_dex_file->dex_sections_layout_))) {
3313 PLOG(ERROR) << "Failed to write dex layout sections."
3314 << " File: " << oat_dex_file->GetLocation()
3315 << " Output: " << oat_rodata->GetLocation();
3316 return false;
3317 }
3318 oat_dex_file->dex_sections_layout_offset_ = rodata_offset;
3319 size_oat_dex_file_dex_layout_sections_ += sizeof(oat_dex_file->dex_sections_layout_);
3320 rodata_offset += sizeof(oat_dex_file->dex_sections_layout_);
3321 }
3322 oat_size_ = rodata_offset;
3323
3324 if (!oat_rodata->Flush()) {
3325 PLOG(ERROR) << "Failed to flush stream after writing type dex layout sections."
3326 << " File: " << oat_rodata->GetLocation();
3327 return false;
3328 }
3329
3330 return true;
3331}
3332
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +00003333bool OatWriter::WriteChecksumsAndVdexHeader(OutputStream* vdex_out) {
David Brazdil5d5a36b2016-09-14 15:34:10 +01003334 if (!kIsVdexEnabled) {
3335 return true;
3336 }
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +00003337 // Write checksums
3338 off_t actual_offset = vdex_out->Seek(sizeof(VdexFile::Header), kSeekSet);
3339 if (actual_offset != sizeof(VdexFile::Header)) {
3340 PLOG(ERROR) << "Failed to seek to the checksum location of vdex file. Actual: " << actual_offset
3341 << " File: " << vdex_out->GetLocation();
3342 return false;
3343 }
3344
3345 for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
3346 OatDexFile* oat_dex_file = &oat_dex_files_[i];
3347 if (!vdex_out->WriteFully(
3348 &oat_dex_file->dex_file_location_checksum_, sizeof(VdexFile::VdexChecksum))) {
3349 PLOG(ERROR) << "Failed to write dex file location checksum. File: "
3350 << vdex_out->GetLocation();
3351 return false;
3352 }
3353 size_vdex_checksums_ += sizeof(VdexFile::VdexChecksum);
3354 }
3355
3356 // Write header.
3357 actual_offset = vdex_out->Seek(0, kSeekSet);
David Brazdil7b49e6c2016-09-01 11:06:18 +01003358 if (actual_offset != 0) {
3359 PLOG(ERROR) << "Failed to seek to the beginning of vdex file. Actual: " << actual_offset
3360 << " File: " << vdex_out->GetLocation();
3361 return false;
3362 }
3363
David Brazdil5d5a36b2016-09-14 15:34:10 +01003364 DCHECK_NE(vdex_dex_files_offset_, 0u);
3365 DCHECK_NE(vdex_verifier_deps_offset_, 0u);
3366
3367 size_t dex_section_size = vdex_verifier_deps_offset_ - vdex_dex_files_offset_;
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01003368 size_t verifier_deps_section_size = vdex_quickening_info_offset_ - vdex_verifier_deps_offset_;
3369 size_t quickening_info_section_size = vdex_size_ - vdex_quickening_info_offset_;
David Brazdil5d5a36b2016-09-14 15:34:10 +01003370
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +00003371 VdexFile::Header vdex_header(oat_dex_files_.size(),
3372 dex_section_size,
3373 verifier_deps_section_size,
3374 quickening_info_section_size);
David Brazdil7b49e6c2016-09-01 11:06:18 +01003375 if (!vdex_out->WriteFully(&vdex_header, sizeof(VdexFile::Header))) {
3376 PLOG(ERROR) << "Failed to write vdex header. File: " << vdex_out->GetLocation();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003377 return false;
3378 }
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +00003379 size_vdex_header_ = sizeof(VdexFile::Header);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003380
David Brazdil5d5a36b2016-09-14 15:34:10 +01003381 if (!vdex_out->Flush()) {
3382 PLOG(ERROR) << "Failed to flush stream after writing to vdex file."
3383 << " File: " << vdex_out->GetLocation();
3384 return false;
3385 }
3386
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003387 return true;
3388}
3389
Vladimir Markof4da6752014-08-01 19:04:18 +01003390bool OatWriter::WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01003391 return WriteUpTo16BytesAlignment(out, aligned_code_delta, &size_code_alignment_);
3392}
3393
3394bool OatWriter::WriteUpTo16BytesAlignment(OutputStream* out, uint32_t size, uint32_t* stat) {
Vladimir Markof4da6752014-08-01 19:04:18 +01003395 static const uint8_t kPadding[] = {
3396 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u
3397 };
Vladimir Marko0eb882b2017-05-15 13:39:18 +01003398 DCHECK_LE(size, sizeof(kPadding));
3399 if (UNLIKELY(!out->WriteFully(kPadding, size))) {
Vladimir Markof4da6752014-08-01 19:04:18 +01003400 return false;
3401 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01003402 *stat += size;
Vladimir Markof4da6752014-08-01 19:04:18 +01003403 return true;
3404}
3405
Vladimir Marko944da602016-02-19 12:27:55 +00003406void OatWriter::SetMultiOatRelativePatcherAdjustment() {
3407 DCHECK(dex_files_ != nullptr);
3408 DCHECK(relative_patcher_ != nullptr);
3409 DCHECK_NE(oat_data_offset_, 0u);
3410 if (image_writer_ != nullptr && !dex_files_->empty()) {
3411 // The oat data begin may not be initialized yet but the oat file offset is ready.
3412 size_t oat_index = image_writer_->GetOatIndexForDexFile(dex_files_->front());
3413 size_t elf_file_offset = image_writer_->GetOatFileOffset(oat_index);
3414 relative_patcher_->StartOatFile(elf_file_offset + oat_data_offset_);
Vladimir Markob163bb72015-03-31 21:49:49 +01003415 }
3416}
3417
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003418OatWriter::OatDexFile::OatDexFile(const char* dex_file_location,
3419 DexFileSource source,
3420 CreateTypeLookupTable create_type_lookup_table)
3421 : source_(source),
3422 create_type_lookup_table_(create_type_lookup_table),
3423 dex_file_size_(0),
3424 offset_(0),
3425 dex_file_location_size_(strlen(dex_file_location)),
3426 dex_file_location_data_(dex_file_location),
3427 dex_file_location_checksum_(0u),
3428 dex_file_offset_(0u),
3429 class_offsets_offset_(0u),
3430 lookup_table_offset_(0u),
Vladimir Marko0eb882b2017-05-15 13:39:18 +01003431 method_bss_mapping_offset_(0u),
Mathieu Chartier120aa282017-08-05 16:03:03 -07003432 dex_sections_layout_offset_(0u),
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003433 class_offsets_() {
Brian Carlstrome24fa612011-09-29 00:53:55 -07003434}
3435
3436size_t OatWriter::OatDexFile::SizeOf() const {
3437 return sizeof(dex_file_location_size_)
3438 + dex_file_location_size_
Brian Carlstrom5b332c82012-02-01 15:02:31 -08003439 + sizeof(dex_file_location_checksum_)
Brian Carlstrom89521892011-12-07 22:05:07 -08003440 + sizeof(dex_file_offset_)
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003441 + sizeof(class_offsets_offset_)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01003442 + sizeof(lookup_table_offset_)
Mathieu Chartier120aa282017-08-05 16:03:03 -07003443 + sizeof(method_bss_mapping_offset_)
3444 + sizeof(dex_sections_layout_offset_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003445}
3446
3447bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream* out) const {
3448 const size_t file_offset = oat_writer->oat_data_offset_;
Brian Carlstrom265091e2013-01-30 14:08:26 -08003449 DCHECK_OFFSET_();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003450
Vladimir Markoe079e212016-05-25 12:49:49 +01003451 if (!out->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08003452 PLOG(ERROR) << "Failed to write dex file location length to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07003453 return false;
3454 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07003455 oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003456
Vladimir Markoe079e212016-05-25 12:49:49 +01003457 if (!out->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
Ian Rogers3d504072014-03-01 09:16:49 -08003458 PLOG(ERROR) << "Failed to write dex file location data to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07003459 return false;
3460 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07003461 oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003462
Vladimir Markoe079e212016-05-25 12:49:49 +01003463 if (!out->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08003464 PLOG(ERROR) << "Failed to write dex file location checksum to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07003465 return false;
3466 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07003467 oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003468
Vladimir Markoe079e212016-05-25 12:49:49 +01003469 if (!out->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08003470 PLOG(ERROR) << "Failed to write dex file offset to " << out->GetLocation();
Brian Carlstrom89521892011-12-07 22:05:07 -08003471 return false;
3472 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07003473 oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003474
Vladimir Markoe079e212016-05-25 12:49:49 +01003475 if (!out->WriteFully(&class_offsets_offset_, sizeof(class_offsets_offset_))) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003476 PLOG(ERROR) << "Failed to write class offsets offset to " << out->GetLocation();
3477 return false;
3478 }
3479 oat_writer->size_oat_dex_file_class_offsets_offset_ += sizeof(class_offsets_offset_);
3480
Vladimir Markoe079e212016-05-25 12:49:49 +01003481 if (!out->WriteFully(&lookup_table_offset_, sizeof(lookup_table_offset_))) {
Artem Udovichenkod9786b02015-10-14 16:36:55 +03003482 PLOG(ERROR) << "Failed to write lookup table offset to " << out->GetLocation();
3483 return false;
3484 }
Vladimir Marko49b0f452015-12-10 13:49:19 +00003485 oat_writer->size_oat_dex_file_lookup_table_offset_ += sizeof(lookup_table_offset_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003486
Mathieu Chartier120aa282017-08-05 16:03:03 -07003487 if (!out->WriteFully(&dex_sections_layout_offset_, sizeof(dex_sections_layout_offset_))) {
3488 PLOG(ERROR) << "Failed to write dex section layout info to " << out->GetLocation();
3489 return false;
3490 }
3491 oat_writer->size_oat_dex_file_dex_layout_sections_offset_ += sizeof(dex_sections_layout_offset_);
3492
Vladimir Marko0eb882b2017-05-15 13:39:18 +01003493 if (!out->WriteFully(&method_bss_mapping_offset_, sizeof(method_bss_mapping_offset_))) {
3494 PLOG(ERROR) << "Failed to write method bss mapping offset to " << out->GetLocation();
3495 return false;
3496 }
3497 oat_writer->size_oat_dex_file_method_bss_mapping_offset_ += sizeof(method_bss_mapping_offset_);
3498
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003499 return true;
3500}
3501
3502bool OatWriter::OatDexFile::WriteClassOffsets(OatWriter* oat_writer, OutputStream* out) {
Vladimir Markoe079e212016-05-25 12:49:49 +01003503 if (!out->WriteFully(class_offsets_.data(), GetClassOffsetsRawSize())) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003504 PLOG(ERROR) << "Failed to write oat class offsets for " << GetLocation()
3505 << " to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07003506 return false;
3507 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003508 oat_writer->size_oat_class_offsets_ += GetClassOffsetsRawSize();
Brian Carlstrome24fa612011-09-29 00:53:55 -07003509 return true;
3510}
3511
Mathieu Chartier3957bff2017-07-16 13:55:27 -07003512OatWriter::OatClass::OatClass(const dchecked_vector<CompiledMethod*>& compiled_methods,
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01003513 uint32_t compiled_methods_with_code,
Mathieu Chartier3957bff2017-07-16 13:55:27 -07003514 uint16_t oat_class_type)
Vladimir Marko96c6ab92014-04-08 14:00:50 +01003515 : compiled_methods_(compiled_methods) {
Mathieu Chartier3957bff2017-07-16 13:55:27 -07003516 const uint32_t num_methods = compiled_methods.size();
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01003517 CHECK_LE(compiled_methods_with_code, num_methods);
Brian Carlstromba150c32013-08-27 17:31:03 -07003518
Brian Carlstromba150c32013-08-27 17:31:03 -07003519 oat_method_offsets_offsets_from_oat_class_.resize(num_methods);
3520
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01003521 method_offsets_.resize(compiled_methods_with_code);
3522 method_headers_.resize(compiled_methods_with_code);
Brian Carlstromba150c32013-08-27 17:31:03 -07003523
Mathieu Chartier3957bff2017-07-16 13:55:27 -07003524 uint32_t oat_method_offsets_offset_from_oat_class = OatClassHeader::SizeOf();
3525 // We only create this instance if there are at least some compiled.
3526 if (oat_class_type == kOatClassSomeCompiled) {
Vladimir Marko49b0f452015-12-10 13:49:19 +00003527 method_bitmap_.reset(new BitVector(num_methods, false, Allocator::GetMallocAllocator()));
Brian Carlstromba150c32013-08-27 17:31:03 -07003528 method_bitmap_size_ = method_bitmap_->GetSizeOf();
3529 oat_method_offsets_offset_from_oat_class += sizeof(method_bitmap_size_);
3530 oat_method_offsets_offset_from_oat_class += method_bitmap_size_;
3531 } else {
Mathieu Chartier2cebb242015-04-21 16:50:40 -07003532 method_bitmap_ = nullptr;
Brian Carlstromba150c32013-08-27 17:31:03 -07003533 method_bitmap_size_ = 0;
3534 }
3535
3536 for (size_t i = 0; i < num_methods; i++) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01003537 CompiledMethod* compiled_method = compiled_methods_[i];
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01003538 if (HasCompiledCode(compiled_method)) {
Brian Carlstromba150c32013-08-27 17:31:03 -07003539 oat_method_offsets_offsets_from_oat_class_[i] = oat_method_offsets_offset_from_oat_class;
3540 oat_method_offsets_offset_from_oat_class += sizeof(OatMethodOffsets);
Mathieu Chartier3957bff2017-07-16 13:55:27 -07003541 if (oat_class_type == kOatClassSomeCompiled) {
Brian Carlstromba150c32013-08-27 17:31:03 -07003542 method_bitmap_->SetBit(i);
3543 }
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +01003544 } else {
3545 oat_method_offsets_offsets_from_oat_class_[i] = 0;
Brian Carlstromba150c32013-08-27 17:31:03 -07003546 }
3547 }
Brian Carlstrome24fa612011-09-29 00:53:55 -07003548}
3549
Brian Carlstrom265091e2013-01-30 14:08:26 -08003550size_t OatWriter::OatClass::SizeOf() const {
Mathieu Chartier3957bff2017-07-16 13:55:27 -07003551 return ((method_bitmap_size_ == 0) ? 0 : sizeof(method_bitmap_size_))
Brian Carlstromba150c32013-08-27 17:31:03 -07003552 + method_bitmap_size_
3553 + (sizeof(method_offsets_[0]) * method_offsets_.size());
Brian Carlstrome24fa612011-09-29 00:53:55 -07003554}
3555
Mathieu Chartier3957bff2017-07-16 13:55:27 -07003556bool OatWriter::OatClassHeader::Write(OatWriter* oat_writer,
3557 OutputStream* out,
3558 const size_t file_offset) const {
Brian Carlstrom265091e2013-01-30 14:08:26 -08003559 DCHECK_OFFSET_();
Vladimir Markoe079e212016-05-25 12:49:49 +01003560 if (!out->WriteFully(&status_, sizeof(status_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08003561 PLOG(ERROR) << "Failed to write class status to " << out->GetLocation();
Brian Carlstrom0755ec52012-01-11 15:19:46 -08003562 return false;
3563 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07003564 oat_writer->size_oat_class_status_ += sizeof(status_);
Vladimir Marko49b0f452015-12-10 13:49:19 +00003565
Vladimir Markoe079e212016-05-25 12:49:49 +01003566 if (!out->WriteFully(&type_, sizeof(type_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08003567 PLOG(ERROR) << "Failed to write oat class type to " << out->GetLocation();
Brian Carlstromba150c32013-08-27 17:31:03 -07003568 return false;
3569 }
3570 oat_writer->size_oat_class_type_ += sizeof(type_);
Mathieu Chartier3957bff2017-07-16 13:55:27 -07003571 return true;
3572}
Vladimir Marko49b0f452015-12-10 13:49:19 +00003573
Mathieu Chartier3957bff2017-07-16 13:55:27 -07003574bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream* out) const {
Brian Carlstromba150c32013-08-27 17:31:03 -07003575 if (method_bitmap_size_ != 0) {
Vladimir Markoe079e212016-05-25 12:49:49 +01003576 if (!out->WriteFully(&method_bitmap_size_, sizeof(method_bitmap_size_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08003577 PLOG(ERROR) << "Failed to write method bitmap size to " << out->GetLocation();
Brian Carlstromba150c32013-08-27 17:31:03 -07003578 return false;
3579 }
3580 oat_writer->size_oat_class_method_bitmaps_ += sizeof(method_bitmap_size_);
Vladimir Marko49b0f452015-12-10 13:49:19 +00003581
Vladimir Markoe079e212016-05-25 12:49:49 +01003582 if (!out->WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_size_)) {
Ian Rogers3d504072014-03-01 09:16:49 -08003583 PLOG(ERROR) << "Failed to write method bitmap to " << out->GetLocation();
Brian Carlstromba150c32013-08-27 17:31:03 -07003584 return false;
3585 }
3586 oat_writer->size_oat_class_method_bitmaps_ += method_bitmap_size_;
3587 }
Vladimir Marko49b0f452015-12-10 13:49:19 +00003588
Vladimir Markoe079e212016-05-25 12:49:49 +01003589 if (!out->WriteFully(method_offsets_.data(), GetMethodOffsetsRawSize())) {
Ian Rogers3d504072014-03-01 09:16:49 -08003590 PLOG(ERROR) << "Failed to write method offsets to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07003591 return false;
3592 }
Vladimir Marko49b0f452015-12-10 13:49:19 +00003593 oat_writer->size_oat_class_method_offsets_ += GetMethodOffsetsRawSize();
Brian Carlstrome24fa612011-09-29 00:53:55 -07003594 return true;
3595}
3596
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01003597const uint8_t* OatWriter::LookupBootImageInternTableSlot(const DexFile& dex_file,
3598 dex::StringIndex string_idx)
Vladimir Marko94ec2db2017-09-06 17:21:03 +01003599 NO_THREAD_SAFETY_ANALYSIS { // Single-threaded OatWriter can avoid locking.
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01003600 uint32_t utf16_length;
3601 const char* utf8_data = dex_file.StringDataAndUtf16LengthByIdx(string_idx, &utf16_length);
3602 DCHECK_EQ(utf16_length, CountModifiedUtf8Chars(utf8_data));
3603 InternTable::Utf8String string(utf16_length,
3604 utf8_data,
3605 ComputeUtf16HashFromModifiedUtf8(utf8_data, utf16_length));
3606 const InternTable* intern_table = Runtime::Current()->GetClassLinker()->intern_table_;
3607 for (const InternTable::Table::UnorderedSet& table : intern_table->strong_interns_.tables_) {
3608 auto it = table.Find(string);
3609 if (it != table.end()) {
3610 return reinterpret_cast<const uint8_t*>(std::addressof(*it));
3611 }
3612 }
3613 LOG(FATAL) << "Did not find boot image string " << utf8_data;
3614 UNREACHABLE();
3615}
3616
Vladimir Marko94ec2db2017-09-06 17:21:03 +01003617const uint8_t* OatWriter::LookupBootImageClassTableSlot(const DexFile& dex_file,
3618 dex::TypeIndex type_idx)
3619 NO_THREAD_SAFETY_ANALYSIS { // Single-threaded OatWriter can avoid locking.
3620 const char* descriptor = dex_file.StringByTypeIdx(type_idx);
3621 ClassTable::DescriptorHashPair pair(descriptor, ComputeModifiedUtf8Hash(descriptor));
3622 ClassTable* table = Runtime::Current()->GetClassLinker()->boot_class_table_.get();
3623 for (const ClassTable::ClassSet& class_set : table->classes_) {
3624 auto it = class_set.Find(pair);
3625 if (it != class_set.end()) {
3626 return reinterpret_cast<const uint8_t*>(std::addressof(*it));
3627 }
3628 }
3629 LOG(FATAL) << "Did not find boot image class " << descriptor;
3630 UNREACHABLE();
3631}
3632
Brian Carlstrome24fa612011-09-29 00:53:55 -07003633} // namespace art