blob: 59daf5a09ecf108de1a29f9bae9f32d8bd39ae56 [file] [log] [blame]
Elliott Hughes2faa5f12012-01-30 14:42:07 -08001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Brian Carlstrome24fa612011-09-29 00:53:55 -070016
17#include "oat_writer.h"
18
Vladimir Marko9bdf1082016-01-21 12:15:52 +000019#include <unistd.h>
Elliott Hughesa0e18062012-04-13 15:59:59 -070020#include <zlib.h>
21
Vladimir Markoc74658b2015-03-31 10:26:41 +010022#include "arch/arm64/instruction_set_features_arm64.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070023#include "art_method-inl.h"
Ian Rogerse77493c2014-08-20 15:08:45 -070024#include "base/allocator.h"
Vladimir Marko0eb882b2017-05-15 13:39:18 +010025#include "base/bit_vector-inl.h"
Andreas Gampe542451c2016-07-26 09:02:02 -070026#include "base/enums.h"
Vladimir Marko9bdf1082016-01-21 12:15:52 +000027#include "base/file_magic.h"
Elliott Hughes1aa246d2012-12-13 09:29:36 -080028#include "base/stl_util.h"
Elliott Hughes76160052012-12-12 16:31:20 -080029#include "base/unix_file/fd_file.h"
Brian Carlstrome24fa612011-09-29 00:53:55 -070030#include "class_linker.h"
Vladimir Marko20f85592015-03-19 10:07:02 +000031#include "compiled_method.h"
David Srbecky4fda4eb2016-02-05 13:34:46 +000032#include "debug/method_debug_info.h"
Vladimir Markoc7f83202014-01-24 17:55:18 +000033#include "dex/verification_results.h"
David Srbecky4fda4eb2016-02-05 13:34:46 +000034#include "dex_file-inl.h"
Jeff Hao608f2ce2016-10-19 11:17:11 -070035#include "dexlayout.h"
Andreas Gamped482e732017-04-24 17:59:09 -070036#include "driver/compiler_driver-inl.h"
Vladimir Marko20f85592015-03-19 10:07:02 +000037#include "driver/compiler_options.h"
Vladimir Marko09d09432015-09-08 13:47:48 +010038#include "gc/space/image_space.h"
Ian Rogers1d54e732013-05-02 21:10:01 -070039#include "gc/space/space.h"
Artem Udovichenkod9786b02015-10-14 16:36:55 +030040#include "handle_scope-inl.h"
Vladimir Markof4da6752014-08-01 19:04:18 +010041#include "image_writer.h"
David Brazdil7b49e6c2016-09-01 11:06:18 +010042#include "linker/buffered_output_stream.h"
43#include "linker/file_output_stream.h"
Vladimir Marko0eb882b2017-05-15 13:39:18 +010044#include "linker/method_bss_mapping_encoder.h"
Vladimir Marko944da602016-02-19 12:27:55 +000045#include "linker/multi_oat_relative_patcher.h"
Vladimir Marko131980f2015-12-03 18:29:23 +000046#include "linker/output_stream.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080047#include "mirror/array.h"
48#include "mirror/class_loader.h"
Vladimir Marko3481ba22015-04-13 12:22:36 +010049#include "mirror/dex_cache-inl.h"
Ian Rogers4f6ad8a2013-03-18 15:27:28 -070050#include "mirror/object-inl.h"
Nicolas Geoffray524e7ea2015-10-16 17:13:34 +010051#include "oat_quick_method_header.h"
Brian Carlstrome24fa612011-09-29 00:53:55 -070052#include "os.h"
Elliott Hughesa0e18062012-04-13 15:59:59 -070053#include "safe_map.h"
Mathieu Chartier0795f232016-09-27 18:43:30 -070054#include "scoped_thread_state_change-inl.h"
Artem Udovichenkod9786b02015-10-14 16:36:55 +030055#include "type_lookup_table.h"
Vladimir Marko09d09432015-09-08 13:47:48 +010056#include "utils/dex_cache_arrays_layout-inl.h"
David Brazdil7b49e6c2016-09-01 11:06:18 +010057#include "vdex_file.h"
David Brazdil5d5a36b2016-09-14 15:34:10 +010058#include "verifier/verifier_deps.h"
Vladimir Marko9bdf1082016-01-21 12:15:52 +000059#include "zip_archive.h"
Brian Carlstrome24fa612011-09-29 00:53:55 -070060
61namespace art {
62
Vladimir Marko9bdf1082016-01-21 12:15:52 +000063namespace { // anonymous namespace
64
65typedef DexFile::Header __attribute__((aligned(1))) UnalignedDexFileHeader;
66
67const UnalignedDexFileHeader* AsUnalignedDexFileHeader(const uint8_t* raw_data) {
68 return reinterpret_cast<const UnalignedDexFileHeader*>(raw_data);
69}
70
Vladimir Markoe079e212016-05-25 12:49:49 +010071class ChecksumUpdatingOutputStream : public OutputStream {
72 public:
73 ChecksumUpdatingOutputStream(OutputStream* out, OatHeader* oat_header)
74 : OutputStream(out->GetLocation()), out_(out), oat_header_(oat_header) { }
75
76 bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE {
77 oat_header_->UpdateChecksum(buffer, byte_count);
78 return out_->WriteFully(buffer, byte_count);
79 }
80
81 off_t Seek(off_t offset, Whence whence) OVERRIDE {
82 return out_->Seek(offset, whence);
83 }
84
85 bool Flush() OVERRIDE {
86 return out_->Flush();
87 }
88
89 private:
90 OutputStream* const out_;
91 OatHeader* const oat_header_;
92};
93
Vladimir Marko0c737df2016-08-01 16:33:16 +010094inline uint32_t CodeAlignmentSize(uint32_t header_offset, const CompiledMethod& compiled_method) {
95 // We want to align the code rather than the preheader.
96 uint32_t unaligned_code_offset = header_offset + sizeof(OatQuickMethodHeader);
97 uint32_t aligned_code_offset = compiled_method.AlignCode(unaligned_code_offset);
98 return aligned_code_offset - unaligned_code_offset;
99}
100
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000101} // anonymous namespace
102
103// Defines the location of the raw dex file to write.
104class OatWriter::DexFileSource {
105 public:
Mathieu Chartier497d5262017-02-28 20:17:30 -0800106 enum Type {
107 kNone,
108 kZipEntry,
109 kRawFile,
110 kRawData,
111 };
112
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000113 explicit DexFileSource(ZipEntry* zip_entry)
114 : type_(kZipEntry), source_(zip_entry) {
115 DCHECK(source_ != nullptr);
116 }
117
118 explicit DexFileSource(File* raw_file)
119 : type_(kRawFile), source_(raw_file) {
120 DCHECK(source_ != nullptr);
121 }
122
123 explicit DexFileSource(const uint8_t* dex_file)
124 : type_(kRawData), source_(dex_file) {
125 DCHECK(source_ != nullptr);
126 }
127
Mathieu Chartier497d5262017-02-28 20:17:30 -0800128 Type GetType() const { return type_; }
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000129 bool IsZipEntry() const { return type_ == kZipEntry; }
130 bool IsRawFile() const { return type_ == kRawFile; }
131 bool IsRawData() const { return type_ == kRawData; }
132
133 ZipEntry* GetZipEntry() const {
134 DCHECK(IsZipEntry());
135 DCHECK(source_ != nullptr);
136 return static_cast<ZipEntry*>(const_cast<void*>(source_));
137 }
138
139 File* GetRawFile() const {
140 DCHECK(IsRawFile());
141 DCHECK(source_ != nullptr);
142 return static_cast<File*>(const_cast<void*>(source_));
143 }
144
145 const uint8_t* GetRawData() const {
146 DCHECK(IsRawData());
147 DCHECK(source_ != nullptr);
148 return static_cast<const uint8_t*>(source_);
149 }
150
151 void Clear() {
152 type_ = kNone;
153 source_ = nullptr;
154 }
155
156 private:
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000157 Type type_;
158 const void* source_;
159};
160
Vladimir Marko49b0f452015-12-10 13:49:19 +0000161class OatWriter::OatClass {
162 public:
163 OatClass(size_t offset,
164 const dchecked_vector<CompiledMethod*>& compiled_methods,
165 uint32_t num_non_null_compiled_methods,
166 mirror::Class::Status status);
167 OatClass(OatClass&& src) = default;
168 size_t GetOatMethodOffsetsOffsetFromOatHeader(size_t class_def_method_index_) const;
169 size_t GetOatMethodOffsetsOffsetFromOatClass(size_t class_def_method_index_) const;
170 size_t SizeOf() const;
171 bool Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const;
172
173 CompiledMethod* GetCompiledMethod(size_t class_def_method_index) const {
174 return compiled_methods_[class_def_method_index];
175 }
176
177 // Offset of start of OatClass from beginning of OatHeader. It is
178 // used to validate file position when writing.
179 size_t offset_;
180
181 // CompiledMethods for each class_def_method_index, or null if no method is available.
182 dchecked_vector<CompiledMethod*> compiled_methods_;
183
184 // Offset from OatClass::offset_ to the OatMethodOffsets for the
185 // class_def_method_index. If 0, it means the corresponding
186 // CompiledMethod entry in OatClass::compiled_methods_ should be
187 // null and that the OatClass::type_ should be kOatClassBitmap.
188 dchecked_vector<uint32_t> oat_method_offsets_offsets_from_oat_class_;
189
190 // Data to write.
191
192 static_assert(mirror::Class::Status::kStatusMax < (1 << 16), "class status won't fit in 16bits");
193 int16_t status_;
194
195 static_assert(OatClassType::kOatClassMax < (1 << 16), "oat_class type won't fit in 16bits");
196 uint16_t type_;
197
198 uint32_t method_bitmap_size_;
199
200 // bit vector indexed by ClassDef method index. When
201 // OatClassType::type_ is kOatClassBitmap, a set bit indicates the
202 // method has an OatMethodOffsets in methods_offsets_, otherwise
203 // the entry was ommited to save space. If OatClassType::type_ is
204 // not is kOatClassBitmap, the bitmap will be null.
205 std::unique_ptr<BitVector> method_bitmap_;
206
207 // OatMethodOffsets and OatMethodHeaders for each CompiledMethod
208 // present in the OatClass. Note that some may be missing if
209 // OatClass::compiled_methods_ contains null values (and
210 // oat_method_offsets_offsets_from_oat_class_ should contain 0
211 // values in this case).
212 dchecked_vector<OatMethodOffsets> method_offsets_;
213 dchecked_vector<OatQuickMethodHeader> method_headers_;
214
215 private:
216 size_t GetMethodOffsetsRawSize() const {
217 return method_offsets_.size() * sizeof(method_offsets_[0]);
218 }
219
220 DISALLOW_COPY_AND_ASSIGN(OatClass);
221};
222
223class OatWriter::OatDexFile {
224 public:
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000225 OatDexFile(const char* dex_file_location,
226 DexFileSource source,
227 CreateTypeLookupTable create_type_lookup_table);
Vladimir Marko49b0f452015-12-10 13:49:19 +0000228 OatDexFile(OatDexFile&& src) = default;
229
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000230 const char* GetLocation() const {
231 return dex_file_location_data_;
232 }
233
Vladimir Marko49b0f452015-12-10 13:49:19 +0000234 size_t SizeOf() const;
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000235 bool Write(OatWriter* oat_writer, OutputStream* out) const;
236 bool WriteClassOffsets(OatWriter* oat_writer, OutputStream* out);
237
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100238 size_t GetClassOffsetsRawSize() const {
239 return class_offsets_.size() * sizeof(class_offsets_[0]);
240 }
241
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000242 // The source of the dex file.
243 DexFileSource source_;
244
245 // Whether to create the type lookup table.
246 CreateTypeLookupTable create_type_lookup_table_;
247
248 // Dex file size. Initialized when writing the dex file.
249 size_t dex_file_size_;
Vladimir Marko49b0f452015-12-10 13:49:19 +0000250
251 // Offset of start of OatDexFile from beginning of OatHeader. It is
252 // used to validate file position when writing.
253 size_t offset_;
254
255 // Data to write.
256 uint32_t dex_file_location_size_;
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000257 const char* dex_file_location_data_;
Vladimir Marko49b0f452015-12-10 13:49:19 +0000258 uint32_t dex_file_location_checksum_;
259 uint32_t dex_file_offset_;
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000260 uint32_t class_offsets_offset_;
Vladimir Marko49b0f452015-12-10 13:49:19 +0000261 uint32_t lookup_table_offset_;
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100262 uint32_t method_bss_mapping_offset_;
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000263
264 // Data to write to a separate section.
Vladimir Marko49b0f452015-12-10 13:49:19 +0000265 dchecked_vector<uint32_t> class_offsets_;
266
267 private:
Vladimir Marko49b0f452015-12-10 13:49:19 +0000268 DISALLOW_COPY_AND_ASSIGN(OatDexFile);
269};
270
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100271#define DCHECK_OFFSET() \
272 DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out->Seek(0, kSeekCurrent)) \
273 << "file_offset=" << file_offset << " relative_offset=" << relative_offset
274
275#define DCHECK_OFFSET_() \
276 DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \
277 << "file_offset=" << file_offset << " offset_=" << offset_
278
Jeff Hao608f2ce2016-10-19 11:17:11 -0700279OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings, ProfileCompilationInfo* info)
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000280 : write_state_(WriteState::kAddingDexFileSources),
281 timings_(timings),
282 raw_dex_files_(),
283 zip_archives_(),
284 zipped_dex_files_(),
285 zipped_dex_file_locations_(),
286 compiler_driver_(nullptr),
287 image_writer_(nullptr),
Mathieu Chartierda5b28a2015-11-05 08:03:47 -0800288 compiling_boot_image_(compiling_boot_image),
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000289 dex_files_(nullptr),
David Brazdil7b49e6c2016-09-01 11:06:18 +0100290 vdex_size_(0u),
291 vdex_dex_files_offset_(0u),
David Brazdil5d5a36b2016-09-14 15:34:10 +0100292 vdex_verifier_deps_offset_(0u),
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100293 vdex_quickening_info_offset_(0u),
David Brazdil7b49e6c2016-09-01 11:06:18 +0100294 oat_size_(0u),
Vladimir Markoaad75c62016-10-03 08:46:48 +0000295 bss_start_(0u),
Vladimir Marko5c42c292015-02-25 12:02:49 +0000296 bss_size_(0u),
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100297 bss_methods_offset_(0u),
Vladimir Markoaad75c62016-10-03 08:46:48 +0000298 bss_roots_offset_(0u),
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100299 bss_method_entry_references_(),
300 bss_method_entries_(),
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000301 bss_type_entries_(),
Vladimir Markoaad75c62016-10-03 08:46:48 +0000302 bss_string_entries_(),
Vladimir Markof4da6752014-08-01 19:04:18 +0100303 oat_data_offset_(0u),
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700304 oat_header_(nullptr),
David Brazdil7b49e6c2016-09-01 11:06:18 +0100305 size_vdex_header_(0),
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000306 size_vdex_checksums_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700307 size_dex_file_alignment_(0),
308 size_executable_offset_alignment_(0),
309 size_oat_header_(0),
Andreas Gampe22f8e5c2014-07-09 11:38:21 -0700310 size_oat_header_key_value_store_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700311 size_dex_file_(0),
David Brazdil5d5a36b2016-09-14 15:34:10 +0100312 size_verifier_deps_(0),
313 size_verifier_deps_alignment_(0),
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100314 size_quickening_info_(0),
315 size_quickening_info_alignment_(0),
Ian Rogers848871b2013-08-05 10:56:33 -0700316 size_interpreter_to_interpreter_bridge_(0),
317 size_interpreter_to_compiled_code_bridge_(0),
318 size_jni_dlsym_lookup_(0),
Andreas Gampe2da88232014-02-27 12:26:20 -0800319 size_quick_generic_jni_trampoline_(0),
Jeff Hao88474b42013-10-23 16:24:40 -0700320 size_quick_imt_conflict_trampoline_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700321 size_quick_resolution_trampoline_(0),
Ian Rogers848871b2013-08-05 10:56:33 -0700322 size_quick_to_interpreter_bridge_(0),
323 size_trampoline_alignment_(0),
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100324 size_method_header_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700325 size_code_(0),
326 size_code_alignment_(0),
Vladimir Markof4da6752014-08-01 19:04:18 +0100327 size_relative_call_thunks_(0),
Vladimir Markoc74658b2015-03-31 10:26:41 +0100328 size_misc_thunks_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700329 size_vmap_table_(0),
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700330 size_method_info_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700331 size_oat_dex_file_location_size_(0),
332 size_oat_dex_file_location_data_(0),
333 size_oat_dex_file_location_checksum_(0),
334 size_oat_dex_file_offset_(0),
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000335 size_oat_dex_file_class_offsets_offset_(0),
Vladimir Marko49b0f452015-12-10 13:49:19 +0000336 size_oat_dex_file_lookup_table_offset_(0),
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100337 size_oat_dex_file_method_bss_mapping_offset_(0),
Vladimir Marko49b0f452015-12-10 13:49:19 +0000338 size_oat_lookup_table_alignment_(0),
339 size_oat_lookup_table_(0),
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000340 size_oat_class_offsets_alignment_(0),
341 size_oat_class_offsets_(0),
Brian Carlstromba150c32013-08-27 17:31:03 -0700342 size_oat_class_type_(0),
Jeff Hao0aba0ba2013-06-03 14:49:28 -0700343 size_oat_class_status_(0),
Brian Carlstromba150c32013-08-27 17:31:03 -0700344 size_oat_class_method_bitmaps_(0),
Vladimir Markof4da6752014-08-01 19:04:18 +0100345 size_oat_class_method_offsets_(0),
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100346 size_method_bss_mappings_(0u),
Vladimir Marko944da602016-02-19 12:27:55 +0000347 relative_patcher_(nullptr),
Jeff Hao608f2ce2016-10-19 11:17:11 -0700348 absolute_patch_locations_(),
349 profile_compilation_info_(info) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000350}
351
352bool OatWriter::AddDexFileSource(const char* filename,
353 const char* location,
354 CreateTypeLookupTable create_type_lookup_table) {
355 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
356 uint32_t magic;
357 std::string error_msg;
Andreas Gampe43e10b02016-07-15 17:17:34 -0700358 File fd = OpenAndReadMagic(filename, &magic, &error_msg);
359 if (fd.Fd() == -1) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000360 PLOG(ERROR) << "Failed to read magic number from dex file: '" << filename << "'";
361 return false;
362 } else if (IsDexMagic(magic)) {
363 // The file is open for reading, not writing, so it's OK to let the File destructor
364 // close it without checking for explicit Close(), so pass checkUsage = false.
Andreas Gampe43e10b02016-07-15 17:17:34 -0700365 raw_dex_files_.emplace_back(new File(fd.Release(), location, /* checkUsage */ false));
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000366 oat_dex_files_.emplace_back(location,
367 DexFileSource(raw_dex_files_.back().get()),
368 create_type_lookup_table);
369 } else if (IsZipMagic(magic)) {
370 if (!AddZippedDexFilesSource(std::move(fd), location, create_type_lookup_table)) {
371 return false;
372 }
373 } else {
374 LOG(ERROR) << "Expected valid zip or dex file: '" << filename << "'";
375 return false;
376 }
377 return true;
378}
379
380// Add dex file source(s) from a zip file specified by a file handle.
Andreas Gampe43e10b02016-07-15 17:17:34 -0700381bool OatWriter::AddZippedDexFilesSource(File&& zip_fd,
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000382 const char* location,
383 CreateTypeLookupTable create_type_lookup_table) {
384 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
385 std::string error_msg;
Andreas Gampe43e10b02016-07-15 17:17:34 -0700386 zip_archives_.emplace_back(ZipArchive::OpenFromFd(zip_fd.Release(), location, &error_msg));
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000387 ZipArchive* zip_archive = zip_archives_.back().get();
388 if (zip_archive == nullptr) {
389 LOG(ERROR) << "Failed to open zip from file descriptor for '" << location << "': "
390 << error_msg;
391 return false;
392 }
393 for (size_t i = 0; ; ++i) {
394 std::string entry_name = DexFile::GetMultiDexClassesDexName(i);
395 std::unique_ptr<ZipEntry> entry(zip_archive->Find(entry_name.c_str(), &error_msg));
396 if (entry == nullptr) {
397 break;
398 }
399 zipped_dex_files_.push_back(std::move(entry));
400 zipped_dex_file_locations_.push_back(DexFile::GetMultiDexLocation(i, location));
401 const char* full_location = zipped_dex_file_locations_.back().c_str();
402 oat_dex_files_.emplace_back(full_location,
403 DexFileSource(zipped_dex_files_.back().get()),
404 create_type_lookup_table);
405 }
406 if (zipped_dex_file_locations_.empty()) {
407 LOG(ERROR) << "No dex files in zip file '" << location << "': " << error_msg;
408 return false;
409 }
410 return true;
411}
412
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000413// Add dex file source(s) from a vdex file specified by a file handle.
414bool OatWriter::AddVdexDexFilesSource(const VdexFile& vdex_file,
415 const char* location,
416 CreateTypeLookupTable create_type_lookup_table) {
417 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
418 const uint8_t* current_dex_data = nullptr;
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000419 for (size_t i = 0; i < vdex_file.GetHeader().GetNumberOfDexFiles(); ++i) {
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000420 current_dex_data = vdex_file.GetNextDexFileData(current_dex_data);
421 if (current_dex_data == nullptr) {
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000422 LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
423 return false;
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000424 }
425 if (!DexFile::IsMagicValid(current_dex_data)) {
426 LOG(ERROR) << "Invalid magic in vdex file created from " << location;
427 return false;
428 }
429 // We used `zipped_dex_file_locations_` to keep the strings in memory.
430 zipped_dex_file_locations_.push_back(DexFile::GetMultiDexLocation(i, location));
431 const char* full_location = zipped_dex_file_locations_.back().c_str();
432 oat_dex_files_.emplace_back(full_location,
433 DexFileSource(current_dex_data),
434 create_type_lookup_table);
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000435 oat_dex_files_.back().dex_file_location_checksum_ = vdex_file.GetLocationChecksum(i);
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000436 }
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000437
438 if (vdex_file.GetNextDexFileData(current_dex_data) != nullptr) {
439 LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
440 return false;
441 }
442
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000443 if (oat_dex_files_.empty()) {
444 LOG(ERROR) << "No dex files in vdex file created from " << location;
445 return false;
446 }
447 return true;
448}
449
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000450// Add dex file source from raw memory.
451bool OatWriter::AddRawDexFileSource(const ArrayRef<const uint8_t>& data,
452 const char* location,
453 uint32_t location_checksum,
454 CreateTypeLookupTable create_type_lookup_table) {
455 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
456 if (data.size() < sizeof(DexFile::Header)) {
457 LOG(ERROR) << "Provided data is shorter than dex file header. size: "
458 << data.size() << " File: " << location;
459 return false;
460 }
461 if (!ValidateDexFileHeader(data.data(), location)) {
462 return false;
463 }
464 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(data.data());
465 if (data.size() < header->file_size_) {
466 LOG(ERROR) << "Truncated dex file data. Data size: " << data.size()
467 << " file size from header: " << header->file_size_ << " File: " << location;
468 return false;
469 }
470
471 oat_dex_files_.emplace_back(location, DexFileSource(data.data()), create_type_lookup_table);
472 oat_dex_files_.back().dex_file_location_checksum_ = location_checksum;
473 return true;
474}
475
476dchecked_vector<const char*> OatWriter::GetSourceLocations() const {
477 dchecked_vector<const char*> locations;
478 locations.reserve(oat_dex_files_.size());
479 for (const OatDexFile& oat_dex_file : oat_dex_files_) {
480 locations.push_back(oat_dex_file.GetLocation());
481 }
482 return locations;
483}
484
485bool OatWriter::WriteAndOpenDexFiles(
David Brazdil7b49e6c2016-09-01 11:06:18 +0100486 File* vdex_file,
487 OutputStream* oat_rodata,
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000488 InstructionSet instruction_set,
489 const InstructionSetFeatures* instruction_set_features,
490 SafeMap<std::string, std::string>* key_value_store,
Andreas Gampe3a2bd292016-01-26 17:23:47 -0800491 bool verify,
Nicolas Geoffray81f57d12016-12-20 13:17:09 +0000492 bool update_input_vdex,
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000493 /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map,
494 /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
495 CHECK(write_state_ == WriteState::kAddingDexFileSources);
496
David Brazdil7b49e6c2016-09-01 11:06:18 +0100497 // Record the ELF rodata section offset, i.e. the beginning of the OAT data.
498 if (!RecordOatDataOffset(oat_rodata)) {
499 return false;
500 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000501
502 std::unique_ptr<MemMap> dex_files_map;
503 std::vector<std::unique_ptr<const DexFile>> dex_files;
David Brazdil7b49e6c2016-09-01 11:06:18 +0100504
505 // Initialize VDEX and OAT headers.
506 if (kIsVdexEnabled) {
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000507 // Reserve space for Vdex header and checksums.
508 vdex_size_ = sizeof(VdexFile::Header) + oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum);
David Brazdil7b49e6c2016-09-01 11:06:18 +0100509 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100510 oat_size_ = InitOatHeader(instruction_set,
511 instruction_set_features,
512 dchecked_integral_cast<uint32_t>(oat_dex_files_.size()),
513 key_value_store);
David Brazdil7b49e6c2016-09-01 11:06:18 +0100514
515 ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, oat_header_.get());
516
517 if (kIsVdexEnabled) {
Andreas Gampe8bdda5a2017-06-08 15:30:36 -0700518 std::unique_ptr<BufferedOutputStream> vdex_out =
519 std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file));
David Brazdil7b49e6c2016-09-01 11:06:18 +0100520 // Write DEX files into VDEX, mmap and open them.
Nicolas Geoffray81f57d12016-12-20 13:17:09 +0000521 if (!WriteDexFiles(vdex_out.get(), vdex_file, update_input_vdex) ||
David Brazdil7b49e6c2016-09-01 11:06:18 +0100522 !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
523 return false;
524 }
David Brazdil7b49e6c2016-09-01 11:06:18 +0100525 } else {
Nicolas Geoffray81f57d12016-12-20 13:17:09 +0000526 DCHECK(!update_input_vdex);
David Brazdil7b49e6c2016-09-01 11:06:18 +0100527 // Write DEX files into OAT, mmap and open them.
Nicolas Geoffray81f57d12016-12-20 13:17:09 +0000528 if (!WriteDexFiles(oat_rodata, vdex_file, update_input_vdex) ||
David Brazdil7b49e6c2016-09-01 11:06:18 +0100529 !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
530 return false;
531 }
532
533 // Do a bulk checksum update for Dex[]. Doing it piece by piece would be
534 // difficult because we're not using the OutputStream directly.
535 if (!oat_dex_files_.empty()) {
536 size_t size = oat_size_ - oat_dex_files_[0].dex_file_offset_;
537 oat_header_->UpdateChecksum(dex_files_map->Begin(), size);
538 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000539 }
David Brazdil181e1cc2016-09-01 16:38:47 +0000540
David Brazdil7b49e6c2016-09-01 11:06:18 +0100541 // Write TypeLookupTables into OAT.
David Brazdil181e1cc2016-09-01 16:38:47 +0000542 if (!WriteTypeLookupTables(&checksum_updating_rodata, dex_files)) {
543 return false;
544 }
545
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000546 *opened_dex_files_map = std::move(dex_files_map);
547 *opened_dex_files = std::move(dex_files);
548 write_state_ = WriteState::kPrepareLayout;
549 return true;
550}
551
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100552void OatWriter::PrepareLayout(linker::MultiOatRelativePatcher* relative_patcher) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000553 CHECK(write_state_ == WriteState::kPrepareLayout);
554
Vladimir Marko944da602016-02-19 12:27:55 +0000555 relative_patcher_ = relative_patcher;
556 SetMultiOatRelativePatcherAdjustment();
557
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000558 if (compiling_boot_image_) {
559 CHECK(image_writer_ != nullptr);
Mathieu Chartierda5b28a2015-11-05 08:03:47 -0800560 }
Vladimir Markob163bb72015-03-31 21:49:49 +0100561 InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000562 CHECK_EQ(instruction_set, oat_header_->GetInstructionSet());
Vladimir Markof4da6752014-08-01 19:04:18 +0100563
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100564 {
565 TimingLogger::ScopedTiming split("InitBssLayout", timings_);
566 InitBssLayout(instruction_set);
567 }
568
David Brazdil7b49e6c2016-09-01 11:06:18 +0100569 uint32_t offset = oat_size_;
Ian Rogersca368cb2013-11-15 15:52:08 -0800570 {
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100571 TimingLogger::ScopedTiming split("InitClassOffsets", timings_);
572 offset = InitClassOffsets(offset);
573 }
574 {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000575 TimingLogger::ScopedTiming split("InitOatClasses", timings_);
Ian Rogersca368cb2013-11-15 15:52:08 -0800576 offset = InitOatClasses(offset);
577 }
578 {
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100579 TimingLogger::ScopedTiming split("InitMethodBssMappings", timings_);
580 offset = InitMethodBssMappings(offset);
581 }
582 {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000583 TimingLogger::ScopedTiming split("InitOatMaps", timings_);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100584 offset = InitOatMaps(offset);
585 }
586 {
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100587 TimingLogger::ScopedTiming split("InitOatDexFiles", timings_);
588 oat_header_->SetOatDexFilesOffset(offset);
589 offset = InitOatDexFiles(offset);
590 }
591 {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000592 TimingLogger::ScopedTiming split("InitOatCode", timings_);
Ian Rogersca368cb2013-11-15 15:52:08 -0800593 offset = InitOatCode(offset);
594 }
595 {
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000596 TimingLogger::ScopedTiming split("InitOatCodeDexFiles", timings_);
Ian Rogersca368cb2013-11-15 15:52:08 -0800597 offset = InitOatCodeDexFiles(offset);
598 }
David Brazdil7b49e6c2016-09-01 11:06:18 +0100599 oat_size_ = offset;
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100600 bss_start_ = (bss_size_ != 0u) ? RoundUp(oat_size_, kPageSize) : 0u;
Vladimir Marko09d09432015-09-08 13:47:48 +0100601
Brian Carlstrome24fa612011-09-29 00:53:55 -0700602 CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
Mathieu Chartierda5b28a2015-11-05 08:03:47 -0800603 if (compiling_boot_image_) {
604 CHECK_EQ(image_writer_ != nullptr,
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000605 oat_header_->GetStoreValueByKey(OatHeader::kImageLocationKey) == nullptr);
Mathieu Chartierda5b28a2015-11-05 08:03:47 -0800606 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000607
608 write_state_ = WriteState::kWriteRoData;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700609}
610
Ian Rogers0571d352011-11-03 19:51:38 -0700611OatWriter::~OatWriter() {
Ian Rogers0571d352011-11-03 19:51:38 -0700612}
613
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100614class OatWriter::DexMethodVisitor {
615 public:
616 DexMethodVisitor(OatWriter* writer, size_t offset)
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100617 : writer_(writer),
618 offset_(offset),
619 dex_file_(nullptr),
620 class_def_index_(DexFile::kDexNoIndex) {}
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100621
622 virtual bool StartClass(const DexFile* dex_file, size_t class_def_index) {
623 DCHECK(dex_file_ == nullptr);
624 DCHECK_EQ(class_def_index_, DexFile::kDexNoIndex);
625 dex_file_ = dex_file;
626 class_def_index_ = class_def_index;
627 return true;
628 }
629
630 virtual bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) = 0;
631
632 virtual bool EndClass() {
633 if (kIsDebugBuild) {
634 dex_file_ = nullptr;
635 class_def_index_ = DexFile::kDexNoIndex;
636 }
637 return true;
638 }
639
640 size_t GetOffset() const {
641 return offset_;
642 }
643
644 protected:
645 virtual ~DexMethodVisitor() { }
646
647 OatWriter* const writer_;
648
649 // The offset is usually advanced for each visited method by the derived class.
650 size_t offset_;
651
652 // The dex file and class def index are set in StartClass().
653 const DexFile* dex_file_;
654 size_t class_def_index_;
655};
656
657class OatWriter::OatDexMethodVisitor : public DexMethodVisitor {
658 public:
659 OatDexMethodVisitor(OatWriter* writer, size_t offset)
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100660 : DexMethodVisitor(writer, offset),
661 oat_class_index_(0u),
662 method_offsets_index_(0u) {}
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100663
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100664 bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE {
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100665 DexMethodVisitor::StartClass(dex_file, class_def_index);
666 DCHECK_LT(oat_class_index_, writer_->oat_classes_.size());
667 method_offsets_index_ = 0u;
668 return true;
669 }
670
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100671 bool EndClass() OVERRIDE {
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100672 ++oat_class_index_;
673 return DexMethodVisitor::EndClass();
674 }
675
676 protected:
677 size_t oat_class_index_;
678 size_t method_offsets_index_;
679};
680
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100681class OatWriter::InitBssLayoutMethodVisitor : public DexMethodVisitor {
682 public:
683 explicit InitBssLayoutMethodVisitor(OatWriter* writer)
684 : DexMethodVisitor(writer, /* offset */ 0u) {}
685
686 bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,
687 const ClassDataItemIterator& it) OVERRIDE {
688 // Look for patches with .bss references and prepare maps with placeholders for their offsets.
689 CompiledMethod* compiled_method = writer_->compiler_driver_->GetCompiledMethod(
690 MethodReference(dex_file_, it.GetMemberIndex()));
691 if (compiled_method != nullptr) {
692 for (const LinkerPatch& patch : compiled_method->GetPatches()) {
693 if (patch.GetType() == LinkerPatch::Type::kMethodBssEntry) {
694 MethodReference target_method = patch.TargetMethod();
695 auto refs_it = writer_->bss_method_entry_references_.find(target_method.dex_file);
696 if (refs_it == writer_->bss_method_entry_references_.end()) {
697 refs_it = writer_->bss_method_entry_references_.Put(
698 target_method.dex_file,
699 BitVector(target_method.dex_file->NumMethodIds(),
700 /* expandable */ false,
701 Allocator::GetMallocAllocator()));
702 refs_it->second.ClearAllBits();
703 }
704 refs_it->second.SetBit(target_method.dex_method_index);
705 writer_->bss_method_entries_.Overwrite(target_method, /* placeholder */ 0u);
706 } else if (patch.GetType() == LinkerPatch::Type::kTypeBssEntry) {
707 TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex());
708 writer_->bss_type_entries_.Overwrite(ref, /* placeholder */ 0u);
709 } else if (patch.GetType() == LinkerPatch::Type::kStringBssEntry) {
710 StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
711 writer_->bss_string_entries_.Overwrite(ref, /* placeholder */ 0u);
712 }
713 }
714 }
715 return true;
716 }
717};
718
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100719class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor {
720 public:
721 InitOatClassesMethodVisitor(OatWriter* writer, size_t offset)
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100722 : DexMethodVisitor(writer, offset),
723 compiled_methods_(),
724 num_non_null_compiled_methods_(0u) {
Vladimir Marko49b0f452015-12-10 13:49:19 +0000725 size_t num_classes = 0u;
726 for (const OatDexFile& oat_dex_file : writer_->oat_dex_files_) {
727 num_classes += oat_dex_file.class_offsets_.size();
728 }
729 writer_->oat_classes_.reserve(num_classes);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100730 compiled_methods_.reserve(256u);
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100731 // If there are any classes, the class offsets allocation aligns the offset.
732 DCHECK(num_classes == 0u || IsAligned<4u>(offset));
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100733 }
734
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100735 bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE {
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100736 DexMethodVisitor::StartClass(dex_file, class_def_index);
737 compiled_methods_.clear();
738 num_non_null_compiled_methods_ = 0u;
739 return true;
740 }
741
Artem Udovichenkod9786b02015-10-14 16:36:55 +0300742 bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100743 const ClassDataItemIterator& it) OVERRIDE {
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100744 // Fill in the compiled_methods_ array for methods that have a
745 // CompiledMethod. We track the number of non-null entries in
746 // num_non_null_compiled_methods_ since we only want to allocate
747 // OatMethodOffsets for the compiled methods.
748 uint32_t method_idx = it.GetMemberIndex();
749 CompiledMethod* compiled_method =
750 writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
751 compiled_methods_.push_back(compiled_method);
752 if (compiled_method != nullptr) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100753 ++num_non_null_compiled_methods_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100754 }
755 return true;
756 }
757
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100758 bool EndClass() OVERRIDE {
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100759 ClassReference class_ref(dex_file_, class_def_index_);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100760 mirror::Class::Status status;
Andreas Gampebb846102017-05-11 21:03:35 -0700761 bool found = writer_->compiler_driver_->GetCompiledClass(class_ref, &status);
762 if (!found) {
763 if (writer_->compiler_driver_->GetVerificationResults()->IsClassRejected(class_ref)) {
764 // The oat class status is used only for verification of resolved classes,
765 // so use kStatusErrorResolved whether the class was resolved or unresolved
766 // during compile-time verification.
767 status = mirror::Class::kStatusErrorResolved;
768 } else {
769 status = mirror::Class::kStatusNotReady;
770 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100771 }
772
Vladimir Marko49b0f452015-12-10 13:49:19 +0000773 writer_->oat_classes_.emplace_back(offset_,
774 compiled_methods_,
775 num_non_null_compiled_methods_,
776 status);
777 offset_ += writer_->oat_classes_.back().SizeOf();
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100778 return DexMethodVisitor::EndClass();
779 }
780
781 private:
Vladimir Marko49b0f452015-12-10 13:49:19 +0000782 dchecked_vector<CompiledMethod*> compiled_methods_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100783 size_t num_non_null_compiled_methods_;
784};
785
786class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor {
787 public:
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100788 InitCodeMethodVisitor(OatWriter* writer, size_t offset, size_t quickening_info_offset)
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100789 : OatDexMethodVisitor(writer, offset),
790 debuggable_(writer->GetCompilerDriver()->GetCompilerOptions().GetDebuggable()),
791 current_quickening_info_offset_(quickening_info_offset) {
David Srbeckyf8980872015-05-22 17:04:47 +0100792 writer_->absolute_patch_locations_.reserve(
Vladimir Markof4da6752014-08-01 19:04:18 +0100793 writer_->compiler_driver_->GetNonRelativeLinkerPatchCount());
794 }
795
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100796 bool EndClass() OVERRIDE {
Vladimir Markof4da6752014-08-01 19:04:18 +0100797 OatDexMethodVisitor::EndClass();
798 if (oat_class_index_ == writer_->oat_classes_.size()) {
Vladimir Marko71b0ddf2015-04-02 19:45:06 +0100799 offset_ = writer_->relative_patcher_->ReserveSpaceEnd(offset_);
Vladimir Markof4da6752014-08-01 19:04:18 +0100800 }
801 return true;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100802 }
803
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100804 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700805 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko49b0f452015-12-10 13:49:19 +0000806 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100807 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
808
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100809 if (it.GetMethodCodeItem() != nullptr) {
810 current_quickening_info_offset_ += sizeof(uint32_t);
811 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100812 if (compiled_method != nullptr) {
813 // Derived from CompiledMethod.
814 uint32_t quick_code_offset = 0;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100815
Vladimir Marko35831e82015-09-11 11:59:18 +0100816 ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
817 uint32_t code_size = quick_code.size() * sizeof(uint8_t);
Elliott Hughes956af0f2014-12-11 14:34:28 -0800818 uint32_t thumb_offset = compiled_method->CodeDelta();
Elliott Hughes956af0f2014-12-11 14:34:28 -0800819
David Srbecky009e2a62015-04-15 02:46:30 +0100820 // Deduplicate code arrays if we are not producing debuggable code.
Vladimir Marko9d07e3d2016-03-31 12:02:28 +0100821 bool deduped = true;
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800822 MethodReference method_ref(dex_file_, it.GetMemberIndex());
Nicolas Geoffrayed6195a2015-07-13 17:02:30 +0000823 if (debuggable_) {
Vladimir Marko944da602016-02-19 12:27:55 +0000824 quick_code_offset = writer_->relative_patcher_->GetOffset(method_ref);
825 if (quick_code_offset != 0u) {
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800826 // Duplicate methods, we want the same code for both of them so that the oat writer puts
827 // the same code in both ArtMethods so that we do not get different oat code at runtime.
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800828 } else {
829 quick_code_offset = NewQuickCodeOffset(compiled_method, it, thumb_offset);
Vladimir Marko9d07e3d2016-03-31 12:02:28 +0100830 deduped = false;
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800831 }
Nicolas Geoffrayed6195a2015-07-13 17:02:30 +0000832 } else {
Vladimir Marko9d07e3d2016-03-31 12:02:28 +0100833 quick_code_offset = dedupe_map_.GetOrCreate(
834 compiled_method,
835 [this, &deduped, compiled_method, &it, thumb_offset]() {
836 deduped = false;
837 return NewQuickCodeOffset(compiled_method, it, thumb_offset);
838 });
Elliott Hughes956af0f2014-12-11 14:34:28 -0800839 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100840
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100841 if (code_size != 0) {
Vladimir Marko944da602016-02-19 12:27:55 +0000842 if (writer_->relative_patcher_->GetOffset(method_ref) != 0u) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100843 // TODO: Should this be a hard failure?
844 LOG(WARNING) << "Multiple definitions of "
David Sehr709b0702016-10-13 09:12:37 -0700845 << method_ref.dex_file->PrettyMethod(method_ref.dex_method_index)
Vladimir Marko944da602016-02-19 12:27:55 +0000846 << " offsets " << writer_->relative_patcher_->GetOffset(method_ref)
847 << " " << quick_code_offset;
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100848 } else {
Vladimir Marko944da602016-02-19 12:27:55 +0000849 writer_->relative_patcher_->SetOffset(method_ref, quick_code_offset);
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100850 }
Elliott Hughes956af0f2014-12-11 14:34:28 -0800851 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100852
Elliott Hughes956af0f2014-12-11 14:34:28 -0800853 // Update quick method header.
854 DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size());
855 OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
Mingyao Yang063fc772016-08-02 11:02:54 -0700856 uint32_t vmap_table_offset = method_header->GetVmapTableOffset();
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700857 uint32_t method_info_offset = method_header->GetMethodInfoOffset();
Elliott Hughes956af0f2014-12-11 14:34:28 -0800858 // The code offset was 0 when the mapping/vmap table offset was set, so it's set
859 // to 0-offset and we need to adjust it by code_offset.
860 uint32_t code_offset = quick_code_offset - thumb_offset;
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100861 if (!compiled_method->GetQuickCode().empty()) {
862 // If the code is compiled, we write the offset of the stack map relative
863 // to the code,
864 if (vmap_table_offset != 0u) {
865 vmap_table_offset += code_offset;
866 DCHECK_LT(vmap_table_offset, code_offset);
867 }
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700868 if (method_info_offset != 0u) {
869 method_info_offset += code_offset;
870 DCHECK_LT(method_info_offset, code_offset);
871 }
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100872 } else {
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700873 CHECK(compiled_method->GetMethodInfo().empty());
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100874 if (kIsVdexEnabled) {
875 // We write the offset in the .vdex file.
876 DCHECK_EQ(vmap_table_offset, 0u);
877 vmap_table_offset = current_quickening_info_offset_;
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700878 ArrayRef<const uint8_t> vmap_table = compiled_method->GetVmapTable();
879 current_quickening_info_offset_ += vmap_table.size() * sizeof(vmap_table.front());
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100880 } else {
881 // We write the offset of the quickening info relative to the code.
882 vmap_table_offset += code_offset;
883 DCHECK_LT(vmap_table_offset, code_offset);
884 }
Elliott Hughes956af0f2014-12-11 14:34:28 -0800885 }
Elliott Hughes956af0f2014-12-11 14:34:28 -0800886 uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
887 uint32_t core_spill_mask = compiled_method->GetCoreSpillMask();
888 uint32_t fp_spill_mask = compiled_method->GetFpSpillMask();
Vladimir Marko9d07e3d2016-03-31 12:02:28 +0100889 *method_header = OatQuickMethodHeader(vmap_table_offset,
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700890 method_info_offset,
Vladimir Marko9d07e3d2016-03-31 12:02:28 +0100891 frame_size_in_bytes,
892 core_spill_mask,
893 fp_spill_mask,
894 code_size);
Vladimir Marko7624d252014-05-02 14:40:15 +0100895
Nicolas Geoffrayed6195a2015-07-13 17:02:30 +0000896 if (!deduped) {
Elliott Hughes956af0f2014-12-11 14:34:28 -0800897 // Update offsets. (Checksum is updated when writing.)
898 offset_ += sizeof(*method_header); // Method header is prepended before code.
899 offset_ += code_size;
900 // Record absolute patch locations.
901 if (!compiled_method->GetPatches().empty()) {
902 uintptr_t base_loc = offset_ - code_size - writer_->oat_header_->GetExecutableOffset();
903 for (const LinkerPatch& patch : compiled_method->GetPatches()) {
Vladimir Marko20f85592015-03-19 10:07:02 +0000904 if (!patch.IsPcRelative()) {
David Srbeckyf8980872015-05-22 17:04:47 +0100905 writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset());
Vladimir Markof4da6752014-08-01 19:04:18 +0100906 }
907 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100908 }
Elliott Hughes956af0f2014-12-11 14:34:28 -0800909 }
Alex Light78382fa2014-06-06 15:45:32 -0700910
David Srbecky91cc06c2016-03-07 16:13:58 +0000911 const CompilerOptions& compiler_options = writer_->compiler_driver_->GetCompilerOptions();
David Srbecky197160d2016-03-07 17:33:57 +0000912 // Exclude quickened dex methods (code_size == 0) since they have no native code.
913 if (compiler_options.GenerateAnyDebugInfo() && code_size != 0) {
914 bool has_code_info = method_header->IsOptimized();
Elliott Hughes956af0f2014-12-11 14:34:28 -0800915 // Record debug information for this function if we are doing that.
David Srbecky09c2a6b2016-03-11 17:11:44 +0000916 debug::MethodDebugInfo info = debug::MethodDebugInfo();
917 info.trampoline_name = nullptr;
David Srbecky197160d2016-03-07 17:33:57 +0000918 info.dex_file = dex_file_;
919 info.class_def_index = class_def_index_;
920 info.dex_method_index = it.GetMemberIndex();
921 info.access_flags = it.GetMethodAccessFlags();
922 info.code_item = it.GetMethodCodeItem();
923 info.isa = compiled_method->GetInstructionSet();
924 info.deduped = deduped;
925 info.is_native_debuggable = compiler_options.GetNativeDebuggable();
926 info.is_optimized = method_header->IsOptimized();
927 info.is_code_address_text_relative = true;
928 info.code_address = code_offset - writer_->oat_header_->GetExecutableOffset();
929 info.code_size = code_size;
930 info.frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
931 info.code_info = has_code_info ? compiled_method->GetVmapTable().data() : nullptr;
932 info.cfi = compiled_method->GetCFIInfo();
933 writer_->method_info_.push_back(info);
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100934 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100935
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100936 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
937 OatMethodOffsets* offsets = &oat_class->method_offsets_[method_offsets_index_];
938 offsets->code_offset_ = quick_code_offset;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100939 ++method_offsets_index_;
940 }
941
942 return true;
943 }
944
945 private:
Vladimir Marko20f85592015-03-19 10:07:02 +0000946 struct CodeOffsetsKeyComparator {
947 bool operator()(const CompiledMethod* lhs, const CompiledMethod* rhs) const {
Vladimir Marko35831e82015-09-11 11:59:18 +0100948 // Code is deduplicated by CompilerDriver, compare only data pointers.
949 if (lhs->GetQuickCode().data() != rhs->GetQuickCode().data()) {
950 return lhs->GetQuickCode().data() < rhs->GetQuickCode().data();
Vladimir Marko20f85592015-03-19 10:07:02 +0000951 }
952 // If the code is the same, all other fields are likely to be the same as well.
Vladimir Marko35831e82015-09-11 11:59:18 +0100953 if (UNLIKELY(lhs->GetVmapTable().data() != rhs->GetVmapTable().data())) {
954 return lhs->GetVmapTable().data() < rhs->GetVmapTable().data();
Vladimir Marko20f85592015-03-19 10:07:02 +0000955 }
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700956 if (UNLIKELY(lhs->GetMethodInfo().data() != rhs->GetMethodInfo().data())) {
957 return lhs->GetMethodInfo().data() < rhs->GetMethodInfo().data();
958 }
Vladimir Marko35831e82015-09-11 11:59:18 +0100959 if (UNLIKELY(lhs->GetPatches().data() != rhs->GetPatches().data())) {
960 return lhs->GetPatches().data() < rhs->GetPatches().data();
Vladimir Marko20f85592015-03-19 10:07:02 +0000961 }
962 return false;
963 }
964 };
965
David Srbecky009e2a62015-04-15 02:46:30 +0100966 uint32_t NewQuickCodeOffset(CompiledMethod* compiled_method,
967 const ClassDataItemIterator& it,
968 uint32_t thumb_offset) {
969 offset_ = writer_->relative_patcher_->ReserveSpace(
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +0100970 offset_, compiled_method, MethodReference(dex_file_, it.GetMemberIndex()));
Vladimir Marko0c737df2016-08-01 16:33:16 +0100971 offset_ += CodeAlignmentSize(offset_, *compiled_method);
972 DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader),
David Srbecky009e2a62015-04-15 02:46:30 +0100973 GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
974 return offset_ + sizeof(OatQuickMethodHeader) + thumb_offset;
975 }
976
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100977 // Deduplication is already done on a pointer basis by the compiler driver,
978 // so we can simply compare the pointers to find out if things are duplicated.
Vladimir Marko8a630572014-04-09 18:45:35 +0100979 SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_;
David Srbecky2f6cdb02015-04-11 00:17:53 +0100980
David Srbecky009e2a62015-04-15 02:46:30 +0100981 // Cache of compiler's --debuggable option.
982 const bool debuggable_;
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100983
984 // Offset in the vdex file for the quickening info.
985 uint32_t current_quickening_info_offset_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100986};
987
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100988class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor {
989 public:
990 InitMapMethodVisitor(OatWriter* writer, size_t offset)
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100991 : OatDexMethodVisitor(writer, offset) {}
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100992
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700993 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED)
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100994 OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko49b0f452015-12-10 13:49:19 +0000995 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
Vladimir Marko96c6ab92014-04-08 14:00:50 +0100996 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
997
998 if (compiled_method != nullptr) {
999 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01001000 // If vdex is enabled, we only emit the stack map of compiled code. The quickening info will
1001 // be in the vdex file.
1002 if (!compiled_method->GetQuickCode().empty() || !kIsVdexEnabled) {
Mingyao Yang063fc772016-08-02 11:02:54 -07001003 DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].GetVmapTableOffset(), 0u);
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001004
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01001005 ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
1006 uint32_t map_size = map.size() * sizeof(map[0]);
1007 if (map_size != 0u) {
1008 size_t offset = dedupe_map_.GetOrCreate(
1009 map.data(),
1010 [this, map_size]() {
1011 uint32_t new_offset = offset_;
1012 offset_ += map_size;
1013 return new_offset;
1014 });
1015 // Code offset is not initialized yet, so set the map offset to 0u-offset.
1016 DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u);
Mingyao Yang063fc772016-08-02 11:02:54 -07001017 oat_class->method_headers_[method_offsets_index_].SetVmapTableOffset(0u - offset);
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01001018 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001019 }
1020 ++method_offsets_index_;
1021 }
1022
1023 return true;
1024 }
1025
1026 private:
1027 // Deduplication is already done on a pointer basis by the compiler driver,
1028 // so we can simply compare the pointers to find out if things are duplicated.
Vladimir Marko35831e82015-09-11 11:59:18 +01001029 SafeMap<const uint8_t*, uint32_t> dedupe_map_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001030};
1031
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001032class OatWriter::InitMethodInfoVisitor : public OatDexMethodVisitor {
1033 public:
1034 InitMethodInfoVisitor(OatWriter* writer, size_t offset) : OatDexMethodVisitor(writer, offset) {}
1035
1036 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001037 OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001038 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1039 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1040
1041 if (compiled_method != nullptr) {
1042 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1043 DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].GetMethodInfoOffset(), 0u);
1044 ArrayRef<const uint8_t> map = compiled_method->GetMethodInfo();
1045 const uint32_t map_size = map.size() * sizeof(map[0]);
1046 if (map_size != 0u) {
1047 size_t offset = dedupe_map_.GetOrCreate(
1048 map.data(),
1049 [this, map_size]() {
1050 uint32_t new_offset = offset_;
1051 offset_ += map_size;
1052 return new_offset;
1053 });
1054 // Code offset is not initialized yet, so set the map offset to 0u-offset.
1055 DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u);
1056 oat_class->method_headers_[method_offsets_index_].SetMethodInfoOffset(0u - offset);
1057 }
1058 ++method_offsets_index_;
1059 }
1060
1061 return true;
1062 }
1063
1064 private:
1065 // Deduplication is already done on a pointer basis by the compiler driver,
1066 // so we can simply compare the pointers to find out if things are duplicated.
1067 SafeMap<const uint8_t*, uint32_t> dedupe_map_;
1068};
1069
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001070class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor {
1071 public:
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001072 InitImageMethodVisitor(OatWriter* writer,
1073 size_t offset,
1074 const std::vector<const DexFile*>* dex_files)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001075 : OatDexMethodVisitor(writer, offset),
1076 pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())),
1077 dex_files_(dex_files),
1078 class_linker_(Runtime::Current()->GetClassLinker()) {}
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001079
1080 // Handle copied methods here. Copy pointer to quick code from
1081 // an origin method to a copied method only if they are
1082 // in the same oat file. If the origin and the copied methods are
1083 // in different oat files don't touch the copied method.
1084 // References to other oat files are not supported yet.
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001085 bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001086 REQUIRES_SHARED(Locks::mutator_lock_) {
1087 OatDexMethodVisitor::StartClass(dex_file, class_def_index);
1088 // Skip classes that are not in the image.
1089 if (!IsImageClass()) {
1090 return true;
1091 }
1092 ScopedObjectAccessUnchecked soa(Thread::Current());
1093 StackHandleScope<1> hs(soa.Self());
1094 Handle<mirror::DexCache> dex_cache = hs.NewHandle(
1095 class_linker_->FindDexCache(Thread::Current(), *dex_file));
1096 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
1097 mirror::Class* klass = dex_cache->GetResolvedType(class_def.class_idx_);
1098 if (klass != nullptr) {
1099 for (ArtMethod& method : klass->GetCopiedMethods(pointer_size_)) {
1100 // Find origin method. Declaring class and dex_method_idx
1101 // in the copied method should be the same as in the origin
1102 // method.
1103 mirror::Class* declaring_class = method.GetDeclaringClass();
1104 ArtMethod* origin = declaring_class->FindDeclaredVirtualMethod(
1105 declaring_class->GetDexCache(),
1106 method.GetDexMethodIndex(),
1107 pointer_size_);
1108 CHECK(origin != nullptr);
1109 if (IsInOatFile(&declaring_class->GetDexFile())) {
1110 const void* code_ptr =
1111 origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
1112 if (code_ptr == nullptr) {
1113 methods_to_process_.push_back(std::make_pair(&method, origin));
1114 } else {
1115 method.SetEntryPointFromQuickCompiledCodePtrSize(
1116 code_ptr, pointer_size_);
1117 }
1118 }
1119 }
1120 }
1121 return true;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001122 }
1123
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001124 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001125 REQUIRES_SHARED(Locks::mutator_lock_) {
Jeff Haodcdc85b2015-12-04 14:06:18 -08001126 // Skip methods that are not in the image.
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001127 if (!IsImageClass()) {
Jeff Haodcdc85b2015-12-04 14:06:18 -08001128 return true;
1129 }
1130
Vladimir Marko49b0f452015-12-10 13:49:19 +00001131 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001132 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1133
Mathieu Chartier957ca1c2014-11-21 16:51:29 -08001134 OatMethodOffsets offsets(0u);
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001135 if (compiled_method != nullptr) {
1136 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1137 offsets = oat_class->method_offsets_[method_offsets_index_];
1138 ++method_offsets_index_;
1139 }
1140
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001141 // Unchecked as we hold mutator_lock_ on entry.
1142 ScopedObjectAccessUnchecked soa(Thread::Current());
Mathieu Chartier957ca1c2014-11-21 16:51:29 -08001143 StackHandleScope<1> hs(soa.Self());
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001144 Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker_->FindDexCache(
Mathieu Chartier673ed3d2015-08-28 14:56:43 -07001145 Thread::Current(), *dex_file_)));
Mathieu Chartierfbc31082016-01-24 11:59:56 -08001146 ArtMethod* method;
1147 if (writer_->HasBootImage()) {
1148 const InvokeType invoke_type = it.GetMethodInvokeType(
1149 dex_file_->GetClassDef(class_def_index_));
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001150 method = class_linker_->ResolveMethod<ClassLinker::kNoICCECheckForCache>(
Mathieu Chartierfbc31082016-01-24 11:59:56 -08001151 *dex_file_,
1152 it.GetMemberIndex(),
1153 dex_cache,
1154 ScopedNullHandle<mirror::ClassLoader>(),
1155 nullptr,
1156 invoke_type);
1157 if (method == nullptr) {
Andreas Gampe3fec9ac2016-09-13 10:47:28 -07001158 LOG(FATAL_WITHOUT_ABORT) << "Unexpected failure to resolve a method: "
David Sehr709b0702016-10-13 09:12:37 -07001159 << dex_file_->PrettyMethod(it.GetMemberIndex(), true);
Mathieu Chartierfbc31082016-01-24 11:59:56 -08001160 soa.Self()->AssertPendingException();
1161 mirror::Throwable* exc = soa.Self()->GetException();
1162 std::string dump = exc->Dump();
1163 LOG(FATAL) << dump;
1164 UNREACHABLE();
1165 }
1166 } else {
1167 // Should already have been resolved by the compiler, just peek into the dex cache.
1168 // It may not be resolved if the class failed to verify, in this case, don't set the
1169 // entrypoint. This is not fatal since the dex cache will contain a resolution method.
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001170 method = dex_cache->GetResolvedMethod(it.GetMemberIndex(), pointer_size_);
Andreas Gamped9efea62014-07-21 22:56:08 -07001171 }
Mathieu Chartierfbc31082016-01-24 11:59:56 -08001172 if (method != nullptr &&
1173 compiled_method != nullptr &&
1174 compiled_method->GetQuickCode().size() != 0) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001175 method->SetEntryPointFromQuickCompiledCodePtrSize(
1176 reinterpret_cast<void*>(offsets.code_offset_), pointer_size_);
1177 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001178
1179 return true;
1180 }
Jeff Haoc7d11882015-02-03 15:08:39 -08001181
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001182 // Check whether current class is image class
1183 bool IsImageClass() {
1184 const DexFile::TypeId& type_id =
1185 dex_file_->GetTypeId(dex_file_->GetClassDef(class_def_index_).class_idx_);
1186 const char* class_descriptor = dex_file_->GetTypeDescriptor(type_id);
1187 return writer_->GetCompilerDriver()->IsImageClass(class_descriptor);
1188 }
1189
1190 // Check whether specified dex file is in the compiled oat file.
1191 bool IsInOatFile(const DexFile* dex_file) {
1192 return ContainsElement(*dex_files_, dex_file);
1193 }
1194
1195 // Assign a pointer to quick code for copied methods
1196 // not handled in the method StartClass
1197 void Postprocess() {
1198 for (std::pair<ArtMethod*, ArtMethod*>& p : methods_to_process_) {
1199 ArtMethod* method = p.first;
1200 ArtMethod* origin = p.second;
1201 const void* code_ptr =
1202 origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
1203 if (code_ptr != nullptr) {
1204 method->SetEntryPointFromQuickCompiledCodePtrSize(code_ptr, pointer_size_);
1205 }
1206 }
1207 }
1208
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001209 private:
Andreas Gampe542451c2016-07-26 09:02:02 -07001210 const PointerSize pointer_size_;
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001211 const std::vector<const DexFile*>* dex_files_;
1212 ClassLinker* const class_linker_;
1213 std::vector<std::pair<ArtMethod*, ArtMethod*>> methods_to_process_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001214};
1215
1216class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
1217 public:
1218 WriteCodeMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset,
Vladimir Markof4da6752014-08-01 19:04:18 +01001219 size_t relative_offset) SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001220 : OatDexMethodVisitor(writer, relative_offset),
1221 pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())),
1222 class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr),
1223 out_(out),
1224 file_offset_(file_offset),
1225 soa_(Thread::Current()),
1226 no_thread_suspension_("OatWriter patching"),
1227 class_linker_(Runtime::Current()->GetClassLinker()),
1228 dex_cache_(nullptr) {
Vladimir Marko09d09432015-09-08 13:47:48 +01001229 patched_code_.reserve(16 * KB);
Mathieu Chartierda5b28a2015-11-05 08:03:47 -08001230 if (writer_->HasBootImage()) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001231 // If we're creating the image, the address space must be ready so that we can apply patches.
1232 CHECK(writer_->image_writer_->IsImageAddressSpaceReady());
Vladimir Markof4da6752014-08-01 19:04:18 +01001233 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001234 }
1235
Vladimir Markof4da6752014-08-01 19:04:18 +01001236 ~WriteCodeMethodVisitor() UNLOCK_FUNCTION(Locks::mutator_lock_) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001237 }
1238
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001239 bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001240 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001241 OatDexMethodVisitor::StartClass(dex_file, class_def_index);
1242 if (dex_cache_ == nullptr || dex_cache_->GetDexFile() != dex_file) {
Mathieu Chartier673ed3d2015-08-28 14:56:43 -07001243 dex_cache_ = class_linker_->FindDexCache(Thread::Current(), *dex_file);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001244 DCHECK(dex_cache_ != nullptr);
Vladimir Markof4da6752014-08-01 19:04:18 +01001245 }
1246 return true;
1247 }
1248
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001249 bool EndClass() OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001250 bool result = OatDexMethodVisitor::EndClass();
1251 if (oat_class_index_ == writer_->oat_classes_.size()) {
1252 DCHECK(result); // OatDexMethodVisitor::EndClass() never fails.
Vladimir Marko20f85592015-03-19 10:07:02 +00001253 offset_ = writer_->relative_patcher_->WriteThunks(out_, offset_);
Vladimir Markof4da6752014-08-01 19:04:18 +01001254 if (UNLIKELY(offset_ == 0u)) {
1255 PLOG(ERROR) << "Failed to write final relative call thunks";
1256 result = false;
1257 }
1258 }
1259 return result;
1260 }
1261
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001262 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001263 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko49b0f452015-12-10 13:49:19 +00001264 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001265 const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1266
Mathieu Chartier673ed3d2015-08-28 14:56:43 -07001267 // No thread suspension since dex_cache_ that may get invalidated if that occurs.
Mathieu Chartier268764d2016-09-13 12:09:38 -07001268 ScopedAssertNoThreadSuspension tsc(__FUNCTION__);
Mathieu Chartier2cebb242015-04-21 16:50:40 -07001269 if (compiled_method != nullptr) { // ie. not an abstract method
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001270 size_t file_offset = file_offset_;
1271 OutputStream* out = out_;
1272
Vladimir Marko35831e82015-09-11 11:59:18 +01001273 ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
1274 uint32_t code_size = quick_code.size() * sizeof(uint8_t);
Nicolas Geoffrayf0758792015-07-13 11:56:00 +00001275
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001276 // Deduplicate code arrays.
1277 const OatMethodOffsets& method_offsets = oat_class->method_offsets_[method_offsets_index_];
1278 if (method_offsets.code_offset_ > offset_) {
1279 offset_ = writer_->relative_patcher_->WriteThunks(out, offset_);
1280 if (offset_ == 0u) {
1281 ReportWriteFailure("relative call thunk", it);
1282 return false;
Nicolas Geoffrayf0758792015-07-13 11:56:00 +00001283 }
Vladimir Marko0c737df2016-08-01 16:33:16 +01001284 uint32_t alignment_size = CodeAlignmentSize(offset_, *compiled_method);
1285 if (alignment_size != 0) {
1286 if (!writer_->WriteCodeAlignment(out, alignment_size)) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001287 ReportWriteFailure("code alignment padding", it);
1288 return false;
1289 }
Vladimir Marko0c737df2016-08-01 16:33:16 +01001290 offset_ += alignment_size;
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001291 DCHECK_OFFSET_();
1292 }
Vladimir Marko0c737df2016-08-01 16:33:16 +01001293 DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader),
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001294 GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
1295 DCHECK_EQ(method_offsets.code_offset_,
1296 offset_ + sizeof(OatQuickMethodHeader) + compiled_method->CodeDelta())
David Sehr709b0702016-10-13 09:12:37 -07001297 << dex_file_->PrettyMethod(it.GetMemberIndex());
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001298 const OatQuickMethodHeader& method_header =
1299 oat_class->method_headers_[method_offsets_index_];
Vladimir Markoe079e212016-05-25 12:49:49 +01001300 if (!out->WriteFully(&method_header, sizeof(method_header))) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001301 ReportWriteFailure("method header", it);
1302 return false;
1303 }
1304 writer_->size_method_header_ += sizeof(method_header);
1305 offset_ += sizeof(method_header);
Nicolas Geoffrayed6195a2015-07-13 17:02:30 +00001306 DCHECK_OFFSET_();
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001307
1308 if (!compiled_method->GetPatches().empty()) {
Vladimir Marko35831e82015-09-11 11:59:18 +01001309 patched_code_.assign(quick_code.begin(), quick_code.end());
1310 quick_code = ArrayRef<const uint8_t>(patched_code_);
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001311 for (const LinkerPatch& patch : compiled_method->GetPatches()) {
Vladimir Marko944da602016-02-19 12:27:55 +00001312 uint32_t literal_offset = patch.LiteralOffset();
Vladimir Markodb8e62d2016-03-30 16:30:21 +01001313 switch (patch.GetType()) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001314 case LinkerPatch::Type::kMethodBssEntry: {
1315 uint32_t target_offset =
1316 writer_->bss_start_ + writer_->bss_method_entries_.Get(patch.TargetMethod());
1317 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1318 patch,
1319 offset_ + literal_offset,
1320 target_offset);
1321 break;
1322 }
Vladimir Markodb8e62d2016-03-30 16:30:21 +01001323 case LinkerPatch::Type::kCallRelative: {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001324 // NOTE: Relative calls across oat files are not supported.
1325 uint32_t target_offset = GetTargetOffset(patch);
1326 writer_->relative_patcher_->PatchCall(&patched_code_,
1327 literal_offset,
1328 offset_ + literal_offset,
1329 target_offset);
1330 break;
1331 }
Vladimir Markodb8e62d2016-03-30 16:30:21 +01001332 case LinkerPatch::Type::kStringRelative: {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001333 uint32_t target_offset = GetTargetObjectOffset(GetTargetString(patch));
1334 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1335 patch,
1336 offset_ + literal_offset,
1337 target_offset);
1338 break;
1339 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00001340 case LinkerPatch::Type::kStringBssEntry: {
1341 StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001342 uint32_t target_offset =
1343 writer_->bss_start_ + writer_->bss_string_entries_.Get(ref);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001344 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1345 patch,
1346 offset_ + literal_offset,
1347 target_offset);
1348 break;
1349 }
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01001350 case LinkerPatch::Type::kTypeRelative: {
1351 uint32_t target_offset = GetTargetObjectOffset(GetTargetType(patch));
1352 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1353 patch,
1354 offset_ + literal_offset,
1355 target_offset);
1356 break;
1357 }
Vladimir Marko6bec91c2017-01-09 15:03:12 +00001358 case LinkerPatch::Type::kTypeBssEntry: {
1359 TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex());
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001360 uint32_t target_offset = writer_->bss_start_ + writer_->bss_type_entries_.Get(ref);
Vladimir Marko6bec91c2017-01-09 15:03:12 +00001361 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1362 patch,
1363 offset_ + literal_offset,
1364 target_offset);
1365 break;
1366 }
Vladimir Markodb8e62d2016-03-30 16:30:21 +01001367 case LinkerPatch::Type::kCall: {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001368 uint32_t target_offset = GetTargetOffset(patch);
1369 PatchCodeAddress(&patched_code_, literal_offset, target_offset);
1370 break;
1371 }
Vladimir Marko65979462017-05-19 17:25:12 +01001372 case LinkerPatch::Type::kMethodRelative: {
1373 uint32_t target_offset = GetTargetMethodOffset(GetTargetMethod(patch));
1374 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1375 patch,
1376 offset_ + literal_offset,
1377 target_offset);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001378 break;
1379 }
Vladimir Markof4f2daa2017-03-20 18:26:59 +00001380 case LinkerPatch::Type::kBakerReadBarrierBranch: {
1381 writer_->relative_patcher_->PatchBakerReadBarrierBranch(&patched_code_,
1382 patch,
1383 offset_ + literal_offset);
1384 break;
1385 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001386 default: {
Richard Uhlerc52f3032017-03-02 13:45:45 +00001387 DCHECK(false) << "Unexpected linker patch type: " << patch.GetType();
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001388 break;
1389 }
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001390 }
1391 }
1392 }
1393
Vladimir Markoe079e212016-05-25 12:49:49 +01001394 if (!out->WriteFully(quick_code.data(), code_size)) {
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001395 ReportWriteFailure("method code", it);
1396 return false;
1397 }
1398 writer_->size_code_ += code_size;
1399 offset_ += code_size;
Nicolas Geoffrayf0758792015-07-13 11:56:00 +00001400 }
Nicolas Geoffrayc04c8002015-07-14 11:37:54 +01001401 DCHECK_OFFSET_();
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001402 ++method_offsets_index_;
1403 }
1404
1405 return true;
1406 }
1407
1408 private:
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001409 const PointerSize pointer_size_;
Vladimir Marko8d6768d2017-03-14 10:13:21 +00001410 ObjPtr<mirror::ClassLoader> class_loader_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001411 OutputStream* const out_;
Vladimir Marko7c2ad5a2014-09-24 12:42:55 +01001412 const size_t file_offset_;
1413 const ScopedObjectAccess soa_;
1414 const ScopedAssertNoThreadSuspension no_thread_suspension_;
Vladimir Markof4da6752014-08-01 19:04:18 +01001415 ClassLinker* const class_linker_;
Vladimir Markocd556b02017-02-03 11:47:34 +00001416 ObjPtr<mirror::DexCache> dex_cache_;
Vladimir Markof4da6752014-08-01 19:04:18 +01001417 std::vector<uint8_t> patched_code_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001418
1419 void ReportWriteFailure(const char* what, const ClassDataItemIterator& it) {
1420 PLOG(ERROR) << "Failed to write " << what << " for "
David Sehr709b0702016-10-13 09:12:37 -07001421 << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001422 }
Vladimir Markof4da6752014-08-01 19:04:18 +01001423
Mathieu Chartiere401d142015-04-22 13:56:20 -07001424 ArtMethod* GetTargetMethod(const LinkerPatch& patch)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001425 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001426 MethodReference ref = patch.TargetMethod();
Vladimir Markocd556b02017-02-03 11:47:34 +00001427 ObjPtr<mirror::DexCache> dex_cache =
Mathieu Chartier673ed3d2015-08-28 14:56:43 -07001428 (dex_file_ == ref.dex_file) ? dex_cache_ : class_linker_->FindDexCache(
1429 Thread::Current(), *ref.dex_file);
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001430 ArtMethod* method = dex_cache->GetResolvedMethod(ref.dex_method_index, pointer_size_);
Vladimir Markof4da6752014-08-01 19:04:18 +01001431 CHECK(method != nullptr);
1432 return method;
1433 }
1434
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001435 uint32_t GetTargetOffset(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko944da602016-02-19 12:27:55 +00001436 uint32_t target_offset = writer_->relative_patcher_->GetOffset(patch.TargetMethod());
1437 // If there's no new compiled code, either we're compiling an app and the target method
1438 // is in the boot image, or we need to point to the correct trampoline.
Vladimir Markof4da6752014-08-01 19:04:18 +01001439 if (UNLIKELY(target_offset == 0)) {
Mathieu Chartiere401d142015-04-22 13:56:20 -07001440 ArtMethod* target = GetTargetMethod(patch);
Vladimir Markof4da6752014-08-01 19:04:18 +01001441 DCHECK(target != nullptr);
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001442 const void* oat_code_offset =
1443 target->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
Jeff Haoa0acc2d2015-01-27 11:22:04 -08001444 if (oat_code_offset != 0) {
Vladimir Marko944da602016-02-19 12:27:55 +00001445 DCHECK(!writer_->HasBootImage());
Jeff Haoa0acc2d2015-01-27 11:22:04 -08001446 DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(oat_code_offset));
1447 DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(oat_code_offset));
1448 DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickGenericJniStub(oat_code_offset));
1449 target_offset = PointerToLowMemUInt32(oat_code_offset);
1450 } else {
1451 target_offset = target->IsNative()
1452 ? writer_->oat_header_->GetQuickGenericJniTrampolineOffset()
1453 : writer_->oat_header_->GetQuickToInterpreterBridgeOffset();
1454 }
Vladimir Markof4da6752014-08-01 19:04:18 +01001455 }
1456 return target_offset;
1457 }
1458
Vladimir Markocd556b02017-02-03 11:47:34 +00001459 ObjPtr<mirror::DexCache> GetDexCache(const DexFile* target_dex_file)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001460 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko052164a2016-04-27 13:54:18 +01001461 return (target_dex_file == dex_file_)
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001462 ? dex_cache_
Vladimir Marko052164a2016-04-27 13:54:18 +01001463 : class_linker_->FindDexCache(Thread::Current(), *target_dex_file);
1464 }
1465
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001466 mirror::Class* GetTargetType(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko8d6768d2017-03-14 10:13:21 +00001467 DCHECK(writer_->HasImage());
Vladimir Markocd556b02017-02-03 11:47:34 +00001468 ObjPtr<mirror::DexCache> dex_cache = GetDexCache(patch.TargetTypeDexFile());
Vladimir Marko8d6768d2017-03-14 10:13:21 +00001469 ObjPtr<mirror::Class> type =
1470 ClassLinker::LookupResolvedType(patch.TargetTypeIndex(), dex_cache, class_loader_);
Vladimir Markof4da6752014-08-01 19:04:18 +01001471 CHECK(type != nullptr);
Vladimir Marko8d6768d2017-03-14 10:13:21 +00001472 return type.Ptr();
Vladimir Markof4da6752014-08-01 19:04:18 +01001473 }
1474
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001475 mirror::String* GetTargetString(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07001476 ScopedObjectAccessUnchecked soa(Thread::Current());
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07001477 ClassLinker* linker = Runtime::Current()->GetClassLinker();
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07001478 mirror::String* string = linker->LookupString(*patch.TargetStringDexFile(),
1479 patch.TargetStringIndex(),
Vladimir Markof25cc732017-03-16 16:18:15 +00001480 GetDexCache(patch.TargetStringDexFile()));
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001481 DCHECK(string != nullptr);
1482 DCHECK(writer_->HasBootImage() ||
1483 Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(string));
1484 return string;
1485 }
1486
Vladimir Marko65979462017-05-19 17:25:12 +01001487 uint32_t GetTargetMethodOffset(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
1488 DCHECK(writer_->HasBootImage());
1489 method = writer_->image_writer_->GetImageMethodAddress(method);
1490 size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
1491 uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
1492 // TODO: Clean up offset types. The target offset must be treated as signed.
1493 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(method) - oat_data_begin);
1494 }
1495
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001496 uint32_t GetTargetObjectOffset(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001497 DCHECK(writer_->HasBootImage());
1498 object = writer_->image_writer_->GetImageAddress(object);
1499 size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
1500 uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
1501 // TODO: Clean up offset types. The target offset must be treated as signed.
1502 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(object) - oat_data_begin);
1503 }
1504
Vladimir Markof4da6752014-08-01 19:04:18 +01001505 void PatchObjectAddress(std::vector<uint8_t>* code, uint32_t offset, mirror::Object* object)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001506 REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartierda5b28a2015-11-05 08:03:47 -08001507 if (writer_->HasBootImage()) {
Vladimir Markof4da6752014-08-01 19:04:18 +01001508 object = writer_->image_writer_->GetImageAddress(object);
Vladimir Marko09d09432015-09-08 13:47:48 +01001509 } else {
1510 // NOTE: We're using linker patches for app->boot references when the image can
1511 // be relocated and therefore we need to emit .oat_patches. We're not using this
1512 // for app->app references, so check that the object is in the image space.
1513 DCHECK(Runtime::Current()->GetHeap()->FindSpaceFromObject(object, false)->IsImageSpace());
Vladimir Markof4da6752014-08-01 19:04:18 +01001514 }
Vladimir Marko09d09432015-09-08 13:47:48 +01001515 // Note: We only patch targeting Objects in image which is in the low 4gb.
Vladimir Markof4da6752014-08-01 19:04:18 +01001516 uint32_t address = PointerToLowMemUInt32(object);
1517 DCHECK_LE(offset + 4, code->size());
1518 uint8_t* data = &(*code)[offset];
1519 data[0] = address & 0xffu;
1520 data[1] = (address >> 8) & 0xffu;
1521 data[2] = (address >> 16) & 0xffu;
1522 data[3] = (address >> 24) & 0xffu;
1523 }
1524
1525 void PatchCodeAddress(std::vector<uint8_t>* code, uint32_t offset, uint32_t target_offset)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001526 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko09d09432015-09-08 13:47:48 +01001527 uint32_t address = target_offset;
Mathieu Chartierda5b28a2015-11-05 08:03:47 -08001528 if (writer_->HasBootImage()) {
Vladimir Marko944da602016-02-19 12:27:55 +00001529 size_t oat_index = writer_->image_writer_->GetOatIndexForDexCache(dex_cache_);
1530 // TODO: Clean up offset types.
1531 // The target_offset must be treated as signed for cross-oat patching.
1532 const void* target = reinterpret_cast<const void*>(
1533 writer_->image_writer_->GetOatDataBegin(oat_index) +
1534 static_cast<int32_t>(target_offset));
1535 address = PointerToLowMemUInt32(target);
Vladimir Marko09d09432015-09-08 13:47:48 +01001536 }
Vladimir Markof4da6752014-08-01 19:04:18 +01001537 DCHECK_LE(offset + 4, code->size());
1538 uint8_t* data = &(*code)[offset];
1539 data[0] = address & 0xffu;
1540 data[1] = (address >> 8) & 0xffu;
1541 data[2] = (address >> 16) & 0xffu;
1542 data[3] = (address >> 24) & 0xffu;
1543 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001544};
1545
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001546class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor {
1547 public:
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001548 WriteMapMethodVisitor(OatWriter* writer,
1549 OutputStream* out,
1550 const size_t file_offset,
Mathieu Chartier957ca1c2014-11-21 16:51:29 -08001551 size_t relative_offset)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001552 : OatDexMethodVisitor(writer, relative_offset),
1553 out_(out),
1554 file_offset_(file_offset) {}
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001555
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001556 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE {
Vladimir Marko49b0f452015-12-10 13:49:19 +00001557 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001558 const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1559
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001560 if (compiled_method != nullptr) { // i.e. not an abstract method
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001561 size_t file_offset = file_offset_;
1562 OutputStream* out = out_;
1563
Mingyao Yang063fc772016-08-02 11:02:54 -07001564 uint32_t map_offset = oat_class->method_headers_[method_offsets_index_].GetVmapTableOffset();
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001565 uint32_t code_offset = oat_class->method_offsets_[method_offsets_index_].code_offset_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001566 ++method_offsets_index_;
1567
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001568 DCHECK((compiled_method->GetVmapTable().size() == 0u && map_offset == 0u) ||
1569 (compiled_method->GetVmapTable().size() != 0u && map_offset != 0u))
1570 << compiled_method->GetVmapTable().size() << " " << map_offset << " "
David Sehr709b0702016-10-13 09:12:37 -07001571 << dex_file_->PrettyMethod(it.GetMemberIndex());
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001572
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01001573 // If vdex is enabled, only emit the map for compiled code. The quickening info
1574 // is emitted in the vdex already.
1575 if (map_offset != 0u &&
1576 !(kIsVdexEnabled && compiled_method->GetQuickCode().empty())) {
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001577 // Transform map_offset to actual oat data offset.
1578 map_offset = (code_offset - compiled_method->CodeDelta()) - map_offset;
1579 DCHECK_NE(map_offset, 0u);
David Sehr709b0702016-10-13 09:12:37 -07001580 DCHECK_LE(map_offset, offset_) << dex_file_->PrettyMethod(it.GetMemberIndex());
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001581
1582 ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
1583 size_t map_size = map.size() * sizeof(map[0]);
1584 if (map_offset == offset_) {
1585 // Write deduplicated map (code info for Optimizing or transformation info for dex2dex).
Vladimir Markoe079e212016-05-25 12:49:49 +01001586 if (UNLIKELY(!out->WriteFully(map.data(), map_size))) {
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001587 ReportWriteFailure(it);
1588 return false;
1589 }
1590 offset_ += map_size;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001591 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001592 }
1593 DCHECK_OFFSET_();
1594 }
1595
1596 return true;
1597 }
1598
1599 private:
1600 OutputStream* const out_;
1601 size_t const file_offset_;
1602
1603 void ReportWriteFailure(const ClassDataItemIterator& it) {
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001604 PLOG(ERROR) << "Failed to write map for "
David Sehr709b0702016-10-13 09:12:37 -07001605 << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001606 }
1607};
1608
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001609class OatWriter::WriteMethodInfoVisitor : public OatDexMethodVisitor {
1610 public:
1611 WriteMethodInfoVisitor(OatWriter* writer,
1612 OutputStream* out,
1613 const size_t file_offset,
1614 size_t relative_offset)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001615 : OatDexMethodVisitor(writer, relative_offset),
1616 out_(out),
1617 file_offset_(file_offset) {}
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001618
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001619 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE {
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001620 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1621 const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1622
1623 if (compiled_method != nullptr) { // i.e. not an abstract method
1624 size_t file_offset = file_offset_;
1625 OutputStream* out = out_;
1626 uint32_t map_offset = oat_class->method_headers_[method_offsets_index_].GetMethodInfoOffset();
1627 uint32_t code_offset = oat_class->method_offsets_[method_offsets_index_].code_offset_;
1628 ++method_offsets_index_;
1629 DCHECK((compiled_method->GetMethodInfo().size() == 0u && map_offset == 0u) ||
1630 (compiled_method->GetMethodInfo().size() != 0u && map_offset != 0u))
1631 << compiled_method->GetMethodInfo().size() << " " << map_offset << " "
1632 << dex_file_->PrettyMethod(it.GetMemberIndex());
1633 if (map_offset != 0u) {
1634 // Transform map_offset to actual oat data offset.
1635 map_offset = (code_offset - compiled_method->CodeDelta()) - map_offset;
1636 DCHECK_NE(map_offset, 0u);
1637 DCHECK_LE(map_offset, offset_) << dex_file_->PrettyMethod(it.GetMemberIndex());
1638
1639 ArrayRef<const uint8_t> map = compiled_method->GetMethodInfo();
1640 size_t map_size = map.size() * sizeof(map[0]);
1641 if (map_offset == offset_) {
1642 // Write deduplicated map (code info for Optimizing or transformation info for dex2dex).
1643 if (UNLIKELY(!out->WriteFully(map.data(), map_size))) {
1644 ReportWriteFailure(it);
1645 return false;
1646 }
1647 offset_ += map_size;
1648 }
1649 }
1650 DCHECK_OFFSET_();
1651 }
1652
1653 return true;
1654 }
1655
1656 private:
1657 OutputStream* const out_;
1658 size_t const file_offset_;
1659
1660 void ReportWriteFailure(const ClassDataItemIterator& it) {
1661 PLOG(ERROR) << "Failed to write map for "
1662 << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
1663 }
1664};
1665
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001666// Visit all methods from all classes in all dex files with the specified visitor.
1667bool OatWriter::VisitDexMethods(DexMethodVisitor* visitor) {
1668 for (const DexFile* dex_file : *dex_files_) {
1669 const size_t class_def_count = dex_file->NumClassDefs();
1670 for (size_t class_def_index = 0; class_def_index != class_def_count; ++class_def_index) {
1671 if (UNLIKELY(!visitor->StartClass(dex_file, class_def_index))) {
1672 return false;
1673 }
Nicolas Geoffray49cda062017-04-21 13:08:25 +01001674 if (compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
Nicolas Geoffray60ca9492016-12-20 21:15:00 +00001675 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
1676 const uint8_t* class_data = dex_file->GetClassData(class_def);
1677 if (class_data != nullptr) { // ie not an empty class, such as a marker interface
1678 ClassDataItemIterator it(*dex_file, class_data);
1679 while (it.HasNextStaticField()) {
1680 it.Next();
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001681 }
Nicolas Geoffray60ca9492016-12-20 21:15:00 +00001682 while (it.HasNextInstanceField()) {
1683 it.Next();
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001684 }
Nicolas Geoffray60ca9492016-12-20 21:15:00 +00001685 size_t class_def_method_index = 0u;
1686 while (it.HasNextDirectMethod()) {
1687 if (!visitor->VisitMethod(class_def_method_index, it)) {
1688 return false;
1689 }
1690 ++class_def_method_index;
1691 it.Next();
1692 }
1693 while (it.HasNextVirtualMethod()) {
1694 if (UNLIKELY(!visitor->VisitMethod(class_def_method_index, it))) {
1695 return false;
1696 }
1697 ++class_def_method_index;
1698 it.Next();
1699 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001700 }
1701 }
1702 if (UNLIKELY(!visitor->EndClass())) {
1703 return false;
1704 }
1705 }
1706 }
1707 return true;
1708}
1709
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001710size_t OatWriter::InitOatHeader(InstructionSet instruction_set,
1711 const InstructionSetFeatures* instruction_set_features,
1712 uint32_t num_dex_files,
1713 SafeMap<std::string, std::string>* key_value_store) {
1714 TimingLogger::ScopedTiming split("InitOatHeader", timings_);
1715 oat_header_.reset(OatHeader::Create(instruction_set,
1716 instruction_set_features,
1717 num_dex_files,
1718 key_value_store));
1719 size_oat_header_ += sizeof(OatHeader);
1720 size_oat_header_key_value_store_ += oat_header_->GetHeaderSize() - sizeof(OatHeader);
Andreas Gampe22f8e5c2014-07-09 11:38:21 -07001721 return oat_header_->GetHeaderSize();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001722}
1723
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001724size_t OatWriter::InitClassOffsets(size_t offset) {
1725 // Reserve space for class offsets in OAT and update class_offsets_offset_.
Vladimir Marko49b0f452015-12-10 13:49:19 +00001726 for (OatDexFile& oat_dex_file : oat_dex_files_) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001727 DCHECK_EQ(oat_dex_file.class_offsets_offset_, 0u);
1728 if (!oat_dex_file.class_offsets_.empty()) {
1729 // Class offsets are required to be 4 byte aligned.
1730 offset = RoundUp(offset, 4u);
1731 oat_dex_file.class_offsets_offset_ = offset;
1732 offset += oat_dex_file.GetClassOffsetsRawSize();
1733 DCHECK_ALIGNED(offset, 4u);
1734 }
Artem Udovichenkod9786b02015-10-14 16:36:55 +03001735 }
1736 return offset;
1737}
1738
Brian Carlstrom389efb02012-01-11 12:06:26 -08001739size_t OatWriter::InitOatClasses(size_t offset) {
Brian Carlstrom389efb02012-01-11 12:06:26 -08001740 // calculate the offsets within OatDexFiles to OatClasses
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001741 InitOatClassesMethodVisitor visitor(this, offset);
1742 bool success = VisitDexMethods(&visitor);
1743 CHECK(success);
1744 offset = visitor.GetOffset();
Brian Carlstromba150c32013-08-27 17:31:03 -07001745
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001746 // Update oat_dex_files_.
1747 auto oat_class_it = oat_classes_.begin();
Vladimir Marko49b0f452015-12-10 13:49:19 +00001748 for (OatDexFile& oat_dex_file : oat_dex_files_) {
1749 for (uint32_t& class_offset : oat_dex_file.class_offsets_) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001750 DCHECK(oat_class_it != oat_classes_.end());
Vladimir Marko49b0f452015-12-10 13:49:19 +00001751 class_offset = oat_class_it->offset_;
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001752 ++oat_class_it;
Brian Carlstrome24fa612011-09-29 00:53:55 -07001753 }
Brian Carlstrome24fa612011-09-29 00:53:55 -07001754 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001755 CHECK(oat_class_it == oat_classes_.end());
1756
1757 return offset;
1758}
1759
1760size_t OatWriter::InitOatMaps(size_t offset) {
Nicolas Geoffray49cda062017-04-21 13:08:25 +01001761 if (!compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
Nicolas Geoffray60ca9492016-12-20 21:15:00 +00001762 return offset;
1763 }
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07001764 {
1765 InitMapMethodVisitor visitor(this, offset);
1766 bool success = VisitDexMethods(&visitor);
1767 DCHECK(success);
1768 offset = visitor.GetOffset();
1769 }
1770 {
1771 InitMethodInfoVisitor visitor(this, offset);
1772 bool success = VisitDexMethods(&visitor);
1773 DCHECK(success);
1774 offset = visitor.GetOffset();
1775 }
Brian Carlstrome24fa612011-09-29 00:53:55 -07001776 return offset;
1777}
1778
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001779size_t OatWriter::InitMethodBssMappings(size_t offset) {
1780 size_t number_of_dex_files = 0u;
1781 for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
1782 const DexFile* dex_file = (*dex_files_)[i];
1783 auto it = bss_method_entry_references_.find(dex_file);
1784 if (it != bss_method_entry_references_.end()) {
1785 const BitVector& method_indexes = it->second;
1786 ++number_of_dex_files;
1787 // If there are any classes, the class offsets allocation aligns the offset
1788 // and we cannot have method bss mappings without class offsets.
1789 static_assert(alignof(MethodBssMapping) == 4u, "MethodBssMapping alignment check.");
1790 DCHECK_ALIGNED(offset, 4u);
1791 oat_dex_files_[i].method_bss_mapping_offset_ = offset;
1792
1793 linker::MethodBssMappingEncoder encoder(
1794 GetInstructionSetPointerSize(oat_header_->GetInstructionSet()));
1795 size_t number_of_entries = 0u;
1796 bool first_index = true;
1797 for (uint32_t method_index : method_indexes.Indexes()) {
1798 uint32_t bss_offset = bss_method_entries_.Get(MethodReference(dex_file, method_index));
1799 if (first_index || !encoder.TryMerge(method_index, bss_offset)) {
1800 encoder.Reset(method_index, bss_offset);
1801 ++number_of_entries;
1802 first_index = false;
1803 }
1804 }
1805 DCHECK_NE(number_of_entries, 0u);
1806 offset += MethodBssMapping::ComputeSize(number_of_entries);
1807 }
1808 }
1809 // Check that all dex files targeted by method bss entries are in `*dex_files_`.
1810 CHECK_EQ(number_of_dex_files, bss_method_entry_references_.size());
1811 return offset;
1812}
1813
1814size_t OatWriter::InitOatDexFiles(size_t offset) {
1815 // Initialize offsets of oat dex files.
1816 for (OatDexFile& oat_dex_file : oat_dex_files_) {
1817 oat_dex_file.offset_ = offset;
1818 offset += oat_dex_file.SizeOf();
1819 }
1820 return offset;
1821}
1822
Brian Carlstrome24fa612011-09-29 00:53:55 -07001823size_t OatWriter::InitOatCode(size_t offset) {
1824 // calculate the offsets within OatHeader to executable code
1825 size_t old_offset = offset;
Dave Allison50abf0a2014-06-23 13:19:59 -07001826 size_t adjusted_offset = offset;
Brian Carlstrome24fa612011-09-29 00:53:55 -07001827 // required to be on a new page boundary
1828 offset = RoundUp(offset, kPageSize);
1829 oat_header_->SetExecutableOffset(offset);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001830 size_executable_offset_alignment_ = offset - old_offset;
Vladimir Markoaad75c62016-10-03 08:46:48 +00001831 if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001832 InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001833
Ian Rogers848871b2013-08-05 10:56:33 -07001834 #define DO_TRAMPOLINE(field, fn_name) \
1835 offset = CompiledCode::AlignCode(offset, instruction_set); \
Dave Allison50abf0a2014-06-23 13:19:59 -07001836 adjusted_offset = offset + CompiledCode::CodeDelta(instruction_set); \
1837 oat_header_->Set ## fn_name ## Offset(adjusted_offset); \
Chih-Hung Hsiehfba39972016-05-11 11:26:48 -07001838 (field) = compiler_driver_->Create ## fn_name(); \
1839 offset += (field)->size();
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001840
Ian Rogers848871b2013-08-05 10:56:33 -07001841 DO_TRAMPOLINE(jni_dlsym_lookup_, JniDlsymLookup);
Andreas Gampe2da88232014-02-27 12:26:20 -08001842 DO_TRAMPOLINE(quick_generic_jni_trampoline_, QuickGenericJniTrampoline);
Jeff Hao88474b42013-10-23 16:24:40 -07001843 DO_TRAMPOLINE(quick_imt_conflict_trampoline_, QuickImtConflictTrampoline);
Ian Rogers848871b2013-08-05 10:56:33 -07001844 DO_TRAMPOLINE(quick_resolution_trampoline_, QuickResolutionTrampoline);
1845 DO_TRAMPOLINE(quick_to_interpreter_bridge_, QuickToInterpreterBridge);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001846
Ian Rogers848871b2013-08-05 10:56:33 -07001847 #undef DO_TRAMPOLINE
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001848 } else {
Ian Rogers848871b2013-08-05 10:56:33 -07001849 oat_header_->SetInterpreterToInterpreterBridgeOffset(0);
1850 oat_header_->SetInterpreterToCompiledCodeBridgeOffset(0);
1851 oat_header_->SetJniDlsymLookupOffset(0);
Andreas Gampe2da88232014-02-27 12:26:20 -08001852 oat_header_->SetQuickGenericJniTrampolineOffset(0);
Jeff Hao88474b42013-10-23 16:24:40 -07001853 oat_header_->SetQuickImtConflictTrampolineOffset(0);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001854 oat_header_->SetQuickResolutionTrampolineOffset(0);
Ian Rogers848871b2013-08-05 10:56:33 -07001855 oat_header_->SetQuickToInterpreterBridgeOffset(0);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07001856 }
Brian Carlstrome24fa612011-09-29 00:53:55 -07001857 return offset;
1858}
1859
1860size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
Nicolas Geoffray49cda062017-04-21 13:08:25 +01001861 if (!compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
Nicolas Geoffray60ca9492016-12-20 21:15:00 +00001862 return offset;
1863 }
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01001864 InitCodeMethodVisitor code_visitor(this, offset, vdex_quickening_info_offset_);
1865 bool success = VisitDexMethods(&code_visitor);
1866 DCHECK(success);
1867 offset = code_visitor.GetOffset();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001868
Mathieu Chartierfbc31082016-01-24 11:59:56 -08001869 if (HasImage()) {
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001870 InitImageMethodVisitor image_visitor(this, offset, dex_files_);
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01001871 success = VisitDexMethods(&image_visitor);
Artem Udovichenkob3f2b5c2017-01-31 11:49:33 +03001872 image_visitor.Postprocess();
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01001873 DCHECK(success);
1874 offset = image_visitor.GetOffset();
Ian Rogers0571d352011-11-03 19:51:38 -07001875 }
Logan Chien8b977d32012-02-21 19:14:55 +08001876
Brian Carlstrome24fa612011-09-29 00:53:55 -07001877 return offset;
1878}
1879
Vladimir Markoaad75c62016-10-03 08:46:48 +00001880void OatWriter::InitBssLayout(InstructionSet instruction_set) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001881 {
1882 InitBssLayoutMethodVisitor visitor(this);
1883 bool success = VisitDexMethods(&visitor);
1884 DCHECK(success);
1885 }
1886
1887 DCHECK_EQ(bss_size_, 0u);
Vladimir Marko1998cd02017-01-13 13:02:58 +00001888 if (HasBootImage()) {
1889 DCHECK(bss_string_entries_.empty());
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001890 if (bss_method_entries_.empty() && bss_type_entries_.empty()) {
Vladimir Marko1998cd02017-01-13 13:02:58 +00001891 // Nothing to put to the .bss section.
1892 return;
1893 }
1894 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00001895
1896 // Allocate space for app dex cache arrays in the .bss section.
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001897 PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set);
Vladimir Marko1998cd02017-01-13 13:02:58 +00001898 if (!HasBootImage()) {
Vladimir Marko1998cd02017-01-13 13:02:58 +00001899 for (const DexFile* dex_file : *dex_files_) {
Vladimir Marko1998cd02017-01-13 13:02:58 +00001900 DexCacheArraysLayout layout(pointer_size, dex_file);
1901 bss_size_ += layout.Size();
1902 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00001903 }
1904
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001905 bss_methods_offset_ = bss_size_;
1906
1907 // Prepare offsets for .bss ArtMethod entries.
1908 for (auto& entry : bss_method_entries_) {
1909 DCHECK_EQ(entry.second, 0u);
1910 entry.second = bss_size_;
1911 bss_size_ += static_cast<size_t>(pointer_size);
1912 }
1913
Vladimir Markoaad75c62016-10-03 08:46:48 +00001914 bss_roots_offset_ = bss_size_;
1915
Vladimir Marko6bec91c2017-01-09 15:03:12 +00001916 // Prepare offsets for .bss Class entries.
1917 for (auto& entry : bss_type_entries_) {
1918 DCHECK_EQ(entry.second, 0u);
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001919 entry.second = bss_size_;
Vladimir Marko6bec91c2017-01-09 15:03:12 +00001920 bss_size_ += sizeof(GcRoot<mirror::Class>);
1921 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00001922 // Prepare offsets for .bss String entries.
1923 for (auto& entry : bss_string_entries_) {
1924 DCHECK_EQ(entry.second, 0u);
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001925 entry.second = bss_size_;
Vladimir Markoaad75c62016-10-03 08:46:48 +00001926 bss_size_ += sizeof(GcRoot<mirror::String>);
1927 }
1928}
1929
David Srbeckybc90fd02015-04-22 19:40:27 +01001930bool OatWriter::WriteRodata(OutputStream* out) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001931 CHECK(write_state_ == WriteState::kWriteRoData);
1932
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001933 size_t file_offset = oat_data_offset_;
1934 off_t current_offset = out->Seek(0, kSeekCurrent);
1935 if (current_offset == static_cast<off_t>(-1)) {
1936 PLOG(ERROR) << "Failed to retrieve current position in " << out->GetLocation();
1937 }
1938 DCHECK_GE(static_cast<size_t>(current_offset), file_offset + oat_header_->GetHeaderSize());
1939 size_t relative_offset = current_offset - file_offset;
1940
Vladimir Markoe079e212016-05-25 12:49:49 +01001941 // Wrap out to update checksum with each write.
1942 ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get());
1943 out = &checksum_updating_out;
1944
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001945 relative_offset = WriteClassOffsets(out, file_offset, relative_offset);
1946 if (relative_offset == 0) {
1947 PLOG(ERROR) << "Failed to write class offsets to " << out->GetLocation();
Vladimir Markof4da6752014-08-01 19:04:18 +01001948 return false;
1949 }
Brian Carlstromc50d8e12013-07-23 22:35:16 -07001950
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001951 relative_offset = WriteClasses(out, file_offset, relative_offset);
1952 if (relative_offset == 0) {
1953 PLOG(ERROR) << "Failed to write classes to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07001954 return false;
1955 }
1956
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001957 relative_offset = WriteMethodBssMappings(out, file_offset, relative_offset);
1958 if (relative_offset == 0) {
1959 PLOG(ERROR) << "Failed to write method bss mappings to " << out->GetLocation();
Vladimir Markof4da6752014-08-01 19:04:18 +01001960 return false;
1961 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001962
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001963 relative_offset = WriteMaps(out, file_offset, relative_offset);
1964 if (relative_offset == 0) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001965 PLOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
1966 return false;
1967 }
1968
1969 relative_offset = WriteOatDexFiles(out, file_offset, relative_offset);
1970 if (relative_offset == 0) {
1971 PLOG(ERROR) << "Failed to write oat dex information to " << out->GetLocation();
Vladimir Marko96c6ab92014-04-08 14:00:50 +01001972 return false;
1973 }
1974
David Srbeckybc90fd02015-04-22 19:40:27 +01001975 // Write padding.
1976 off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent);
1977 relative_offset += size_executable_offset_alignment_;
1978 DCHECK_EQ(relative_offset, oat_header_->GetExecutableOffset());
1979 size_t expected_file_offset = file_offset + relative_offset;
1980 if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
1981 PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
1982 << " Expected: " << expected_file_offset << " File: " << out->GetLocation();
1983 return 0;
1984 }
1985 DCHECK_OFFSET();
1986
Vladimir Marko9bdf1082016-01-21 12:15:52 +00001987 write_state_ = WriteState::kWriteText;
David Srbeckybc90fd02015-04-22 19:40:27 +01001988 return true;
1989}
1990
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01001991class OatWriter::WriteQuickeningInfoMethodVisitor : public DexMethodVisitor {
1992 public:
1993 WriteQuickeningInfoMethodVisitor(OatWriter* writer, OutputStream* out, uint32_t offset)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001994 : DexMethodVisitor(writer, offset),
1995 out_(out),
1996 written_bytes_(0u) {}
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01001997
1998 bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001999 const ClassDataItemIterator& it) OVERRIDE {
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002000 if (it.GetMethodCodeItem() == nullptr) {
2001 // No CodeItem. Native or abstract method.
2002 return true;
2003 }
2004
2005 uint32_t method_idx = it.GetMemberIndex();
2006 CompiledMethod* compiled_method =
2007 writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
2008
2009 uint32_t length = 0;
2010 const uint8_t* data = nullptr;
2011 // VMap only contains quickening info if this method is not compiled.
2012 if (compiled_method != nullptr && compiled_method->GetQuickCode().empty()) {
2013 ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
2014 data = map.data();
2015 length = map.size() * sizeof(map.front());
2016 }
2017
2018 if (!out_->WriteFully(&length, sizeof(length)) ||
2019 !out_->WriteFully(data, length)) {
2020 PLOG(ERROR) << "Failed to write quickening info for "
2021 << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
2022 return false;
2023 }
2024 offset_ += sizeof(length) + length;
2025 written_bytes_ += sizeof(length) + length;
2026 return true;
2027 }
2028
2029 size_t GetNumberOfWrittenBytes() const {
2030 return written_bytes_;
2031 }
2032
2033 private:
2034 OutputStream* const out_;
2035 size_t written_bytes_;
2036};
2037
2038bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) {
2039 if (!kIsVdexEnabled) {
2040 return true;
2041 }
2042
2043 size_t initial_offset = vdex_size_;
2044 size_t start_offset = RoundUp(initial_offset, 4u);
2045
2046 vdex_size_ = start_offset;
2047 vdex_quickening_info_offset_ = vdex_size_;
2048 size_quickening_info_alignment_ = start_offset - initial_offset;
2049
2050 off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet);
2051 if (actual_offset != static_cast<off_t>(start_offset)) {
2052 PLOG(ERROR) << "Failed to seek to quickening info section. Actual: " << actual_offset
2053 << " Expected: " << start_offset
2054 << " Output: " << vdex_out->GetLocation();
2055 return false;
2056 }
2057
Nicolas Geoffray49cda062017-04-21 13:08:25 +01002058 if (compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
Nicolas Geoffray60ca9492016-12-20 21:15:00 +00002059 WriteQuickeningInfoMethodVisitor visitor(this, vdex_out, start_offset);
2060 if (!VisitDexMethods(&visitor)) {
2061 PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation();
2062 return false;
2063 }
2064
2065 if (!vdex_out->Flush()) {
2066 PLOG(ERROR) << "Failed to flush stream after writing quickening info."
2067 << " File: " << vdex_out->GetLocation();
2068 return false;
2069 }
2070 size_quickening_info_ = visitor.GetNumberOfWrittenBytes();
2071 } else {
2072 // We know we did not quicken.
2073 size_quickening_info_ = 0;
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002074 }
2075
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002076 vdex_size_ += size_quickening_info_;
2077 return true;
2078}
2079
David Brazdil5d5a36b2016-09-14 15:34:10 +01002080bool OatWriter::WriteVerifierDeps(OutputStream* vdex_out, verifier::VerifierDeps* verifier_deps) {
2081 if (!kIsVdexEnabled) {
2082 return true;
2083 }
2084
2085 if (verifier_deps == nullptr) {
2086 // Nothing to write. Record the offset, but no need
2087 // for alignment.
2088 vdex_verifier_deps_offset_ = vdex_size_;
2089 return true;
2090 }
2091
2092 size_t initial_offset = vdex_size_;
2093 size_t start_offset = RoundUp(initial_offset, 4u);
2094
2095 vdex_size_ = start_offset;
2096 vdex_verifier_deps_offset_ = vdex_size_;
2097 size_verifier_deps_alignment_ = start_offset - initial_offset;
2098
2099 off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet);
2100 if (actual_offset != static_cast<off_t>(start_offset)) {
2101 PLOG(ERROR) << "Failed to seek to verifier deps section. Actual: " << actual_offset
2102 << " Expected: " << start_offset
2103 << " Output: " << vdex_out->GetLocation();
2104 return false;
2105 }
2106
2107 std::vector<uint8_t> buffer;
Nicolas Geoffrayd01f60c2016-10-28 14:45:48 +01002108 verifier_deps->Encode(*dex_files_, &buffer);
David Brazdil5d5a36b2016-09-14 15:34:10 +01002109
2110 if (!vdex_out->WriteFully(buffer.data(), buffer.size())) {
2111 PLOG(ERROR) << "Failed to write verifier deps."
2112 << " File: " << vdex_out->GetLocation();
2113 return false;
2114 }
2115 if (!vdex_out->Flush()) {
2116 PLOG(ERROR) << "Failed to flush stream after writing verifier deps."
2117 << " File: " << vdex_out->GetLocation();
2118 return false;
2119 }
2120
2121 size_verifier_deps_ = buffer.size();
2122 vdex_size_ += size_verifier_deps_;
2123 return true;
2124}
2125
David Srbeckybc90fd02015-04-22 19:40:27 +01002126bool OatWriter::WriteCode(OutputStream* out) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002127 CHECK(write_state_ == WriteState::kWriteText);
2128
Vladimir Markoe079e212016-05-25 12:49:49 +01002129 // Wrap out to update checksum with each write.
2130 ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get());
2131 out = &checksum_updating_out;
2132
Vladimir Marko944da602016-02-19 12:27:55 +00002133 SetMultiOatRelativePatcherAdjustment();
2134
David Srbeckybc90fd02015-04-22 19:40:27 +01002135 const size_t file_offset = oat_data_offset_;
2136 size_t relative_offset = oat_header_->GetExecutableOffset();
2137 DCHECK_OFFSET();
2138
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002139 relative_offset = WriteCode(out, file_offset, relative_offset);
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002140 if (relative_offset == 0) {
Ian Rogers3d504072014-03-01 09:16:49 -08002141 LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07002142 return false;
2143 }
2144
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002145 relative_offset = WriteCodeDexFiles(out, file_offset, relative_offset);
2146 if (relative_offset == 0) {
Ian Rogers3d504072014-03-01 09:16:49 -08002147 LOG(ERROR) << "Failed to write oat code for dex files to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07002148 return false;
2149 }
2150
Vladimir Markof4da6752014-08-01 19:04:18 +01002151 const off_t oat_end_file_offset = out->Seek(0, kSeekCurrent);
Vladimir Marko49b0f452015-12-10 13:49:19 +00002152 if (oat_end_file_offset == static_cast<off_t>(-1)) {
Vladimir Markof4da6752014-08-01 19:04:18 +01002153 LOG(ERROR) << "Failed to get oat end file offset in " << out->GetLocation();
2154 return false;
2155 }
2156
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002157 if (kIsDebugBuild) {
2158 uint32_t size_total = 0;
2159 #define DO_STAT(x) \
Chih-Hung Hsiehfba39972016-05-11 11:26:48 -07002160 VLOG(compiler) << #x "=" << PrettySize(x) << " (" << (x) << "B)"; \
2161 size_total += (x);
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002162
David Brazdil7b49e6c2016-09-01 11:06:18 +01002163 DO_STAT(size_vdex_header_);
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +00002164 DO_STAT(size_vdex_checksums_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002165 DO_STAT(size_dex_file_alignment_);
2166 DO_STAT(size_executable_offset_alignment_);
2167 DO_STAT(size_oat_header_);
Andreas Gampe22f8e5c2014-07-09 11:38:21 -07002168 DO_STAT(size_oat_header_key_value_store_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002169 DO_STAT(size_dex_file_);
David Brazdil5d5a36b2016-09-14 15:34:10 +01002170 DO_STAT(size_verifier_deps_);
2171 DO_STAT(size_verifier_deps_alignment_);
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01002172 DO_STAT(size_quickening_info_);
2173 DO_STAT(size_quickening_info_alignment_);
Ian Rogers848871b2013-08-05 10:56:33 -07002174 DO_STAT(size_interpreter_to_interpreter_bridge_);
2175 DO_STAT(size_interpreter_to_compiled_code_bridge_);
2176 DO_STAT(size_jni_dlsym_lookup_);
Andreas Gampe2da88232014-02-27 12:26:20 -08002177 DO_STAT(size_quick_generic_jni_trampoline_);
Jeff Hao88474b42013-10-23 16:24:40 -07002178 DO_STAT(size_quick_imt_conflict_trampoline_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002179 DO_STAT(size_quick_resolution_trampoline_);
Ian Rogers848871b2013-08-05 10:56:33 -07002180 DO_STAT(size_quick_to_interpreter_bridge_);
2181 DO_STAT(size_trampoline_alignment_);
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002182 DO_STAT(size_method_header_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002183 DO_STAT(size_code_);
2184 DO_STAT(size_code_alignment_);
Vladimir Markof4da6752014-08-01 19:04:18 +01002185 DO_STAT(size_relative_call_thunks_);
Vladimir Markoc74658b2015-03-31 10:26:41 +01002186 DO_STAT(size_misc_thunks_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002187 DO_STAT(size_vmap_table_);
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07002188 DO_STAT(size_method_info_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002189 DO_STAT(size_oat_dex_file_location_size_);
2190 DO_STAT(size_oat_dex_file_location_data_);
2191 DO_STAT(size_oat_dex_file_location_checksum_);
2192 DO_STAT(size_oat_dex_file_offset_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002193 DO_STAT(size_oat_dex_file_class_offsets_offset_);
Vladimir Marko49b0f452015-12-10 13:49:19 +00002194 DO_STAT(size_oat_dex_file_lookup_table_offset_);
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002195 DO_STAT(size_oat_dex_file_method_bss_mapping_offset_);
Vladimir Marko49b0f452015-12-10 13:49:19 +00002196 DO_STAT(size_oat_lookup_table_alignment_);
2197 DO_STAT(size_oat_lookup_table_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002198 DO_STAT(size_oat_class_offsets_alignment_);
2199 DO_STAT(size_oat_class_offsets_);
Brian Carlstromba150c32013-08-27 17:31:03 -07002200 DO_STAT(size_oat_class_type_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002201 DO_STAT(size_oat_class_status_);
Brian Carlstromba150c32013-08-27 17:31:03 -07002202 DO_STAT(size_oat_class_method_bitmaps_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002203 DO_STAT(size_oat_class_method_offsets_);
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002204 DO_STAT(size_method_bss_mappings_);
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002205 #undef DO_STAT
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002206
David Brazdil7b49e6c2016-09-01 11:06:18 +01002207 VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)";
2208
2209 CHECK_EQ(vdex_size_ + oat_size_, size_total);
2210 CHECK_EQ(file_offset + size_total - vdex_size_, static_cast<size_t>(oat_end_file_offset));
Ian Rogers4bdbbc82013-06-10 16:02:31 -07002211 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002212
David Brazdil7b49e6c2016-09-01 11:06:18 +01002213 CHECK_EQ(file_offset + oat_size_, static_cast<size_t>(oat_end_file_offset));
2214 CHECK_EQ(oat_size_, relative_offset);
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002215
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002216 write_state_ = WriteState::kWriteHeader;
2217 return true;
2218}
2219
2220bool OatWriter::WriteHeader(OutputStream* out,
2221 uint32_t image_file_location_oat_checksum,
2222 uintptr_t image_file_location_oat_begin,
2223 int32_t image_patch_delta) {
2224 CHECK(write_state_ == WriteState::kWriteHeader);
2225
2226 oat_header_->SetImageFileLocationOatChecksum(image_file_location_oat_checksum);
2227 oat_header_->SetImageFileLocationOatDataBegin(image_file_location_oat_begin);
Vladimir Markoaad75c62016-10-03 08:46:48 +00002228 if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002229 CHECK_EQ(image_patch_delta, 0);
2230 CHECK_EQ(oat_header_->GetImagePatchDelta(), 0);
2231 } else {
2232 CHECK_ALIGNED(image_patch_delta, kPageSize);
2233 oat_header_->SetImagePatchDelta(image_patch_delta);
2234 }
Vladimir Marko49b0f452015-12-10 13:49:19 +00002235 oat_header_->UpdateChecksumWithHeaderData();
2236
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002237 const size_t file_offset = oat_data_offset_;
2238
2239 off_t current_offset = out->Seek(0, kSeekCurrent);
2240 if (current_offset == static_cast<off_t>(-1)) {
2241 PLOG(ERROR) << "Failed to get current offset from " << out->GetLocation();
2242 return false;
2243 }
Vladimir Marko49b0f452015-12-10 13:49:19 +00002244 if (out->Seek(file_offset, kSeekSet) == static_cast<off_t>(-1)) {
Vladimir Markof4da6752014-08-01 19:04:18 +01002245 PLOG(ERROR) << "Failed to seek to oat header position in " << out->GetLocation();
2246 return false;
2247 }
David Srbeckybc90fd02015-04-22 19:40:27 +01002248 DCHECK_EQ(file_offset, static_cast<size_t>(out->Seek(0, kSeekCurrent)));
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002249
2250 // Flush all other data before writing the header.
2251 if (!out->Flush()) {
2252 PLOG(ERROR) << "Failed to flush before writing oat header to " << out->GetLocation();
2253 return false;
2254 }
2255 // Write the header.
2256 size_t header_size = oat_header_->GetHeaderSize();
Vladimir Marko49b0f452015-12-10 13:49:19 +00002257 if (!out->WriteFully(oat_header_.get(), header_size)) {
Vladimir Markof4da6752014-08-01 19:04:18 +01002258 PLOG(ERROR) << "Failed to write oat header to " << out->GetLocation();
2259 return false;
2260 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002261 // Flush the header data.
2262 if (!out->Flush()) {
2263 PLOG(ERROR) << "Failed to flush after writing oat header to " << out->GetLocation();
Vladimir Markof4da6752014-08-01 19:04:18 +01002264 return false;
2265 }
Vladimir Markof4da6752014-08-01 19:04:18 +01002266
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002267 if (out->Seek(current_offset, kSeekSet) == static_cast<off_t>(-1)) {
2268 PLOG(ERROR) << "Failed to seek back after writing oat header to " << out->GetLocation();
2269 return false;
2270 }
2271 DCHECK_EQ(current_offset, out->Seek(0, kSeekCurrent));
2272
2273 write_state_ = WriteState::kDone;
Brian Carlstrome24fa612011-09-29 00:53:55 -07002274 return true;
2275}
2276
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002277size_t OatWriter::WriteClassOffsets(OutputStream* out, size_t file_offset, size_t relative_offset) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002278 for (OatDexFile& oat_dex_file : oat_dex_files_) {
2279 if (oat_dex_file.class_offsets_offset_ != 0u) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002280 // Class offsets are required to be 4 byte aligned.
2281 if (UNLIKELY(!IsAligned<4u>(relative_offset))) {
2282 size_t padding_size = RoundUp(relative_offset, 4u) - relative_offset;
2283 if (!WriteUpTo16BytesAlignment(out, padding_size, &size_oat_class_offsets_alignment_)) {
2284 return 0u;
2285 }
2286 relative_offset += padding_size;
Vladimir Marko919f5532016-01-20 19:13:01 +00002287 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002288 DCHECK_OFFSET();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002289 if (!oat_dex_file.WriteClassOffsets(this, out)) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002290 return 0u;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002291 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002292 relative_offset += oat_dex_file.GetClassOffsetsRawSize();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002293 }
2294 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002295 return relative_offset;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002296}
2297
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002298size_t OatWriter::WriteClasses(OutputStream* out, size_t file_offset, size_t relative_offset) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002299 for (OatClass& oat_class : oat_classes_) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002300 // If there are any classes, the class offsets allocation aligns the offset.
2301 DCHECK_ALIGNED(relative_offset, 4u);
2302 DCHECK_OFFSET();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002303 if (!oat_class.Write(this, out, oat_data_offset_)) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002304 return 0u;
Vladimir Marko919f5532016-01-20 19:13:01 +00002305 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002306 relative_offset += oat_class.SizeOf();
Artem Udovichenkod9786b02015-10-14 16:36:55 +03002307 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002308 return relative_offset;
Artem Udovichenkod9786b02015-10-14 16:36:55 +03002309}
2310
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002311size_t OatWriter::WriteMaps(OutputStream* out, size_t file_offset, size_t relative_offset) {
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07002312 {
2313 size_t vmap_tables_offset = relative_offset;
2314 WriteMapMethodVisitor visitor(this, out, file_offset, relative_offset);
2315 if (UNLIKELY(!VisitDexMethods(&visitor))) {
2316 return 0;
2317 }
2318 relative_offset = visitor.GetOffset();
2319 size_vmap_table_ = relative_offset - vmap_tables_offset;
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01002320 }
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -07002321 {
2322 size_t method_infos_offset = relative_offset;
2323 WriteMethodInfoVisitor visitor(this, out, file_offset, relative_offset);
2324 if (UNLIKELY(!VisitDexMethods(&visitor))) {
2325 return 0;
2326 }
2327 relative_offset = visitor.GetOffset();
2328 size_method_info_ = relative_offset - method_infos_offset;
2329 }
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002330
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002331 return relative_offset;
2332}
2333
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002334size_t OatWriter::WriteMethodBssMappings(OutputStream* out,
2335 size_t file_offset,
2336 size_t relative_offset) {
2337 TimingLogger::ScopedTiming split("WriteMethodBssMappings", timings_);
2338
2339 for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
2340 const DexFile* dex_file = (*dex_files_)[i];
2341 OatDexFile* oat_dex_file = &oat_dex_files_[i];
2342 auto it = bss_method_entry_references_.find(dex_file);
2343 if (it != bss_method_entry_references_.end()) {
2344 const BitVector& method_indexes = it->second;
2345 // If there are any classes, the class offsets allocation aligns the offset
2346 // and we cannot have method bss mappings without class offsets.
2347 static_assert(alignof(MethodBssMapping) == sizeof(uint32_t),
2348 "MethodBssMapping alignment check.");
2349 DCHECK_ALIGNED(relative_offset, sizeof(uint32_t));
2350
2351 linker::MethodBssMappingEncoder encoder(
2352 GetInstructionSetPointerSize(oat_header_->GetInstructionSet()));
2353 // Allocate a sufficiently large MethodBssMapping.
2354 size_t number_of_method_indexes = method_indexes.NumSetBits();
2355 DCHECK_NE(number_of_method_indexes, 0u);
2356 size_t max_mappings_size = MethodBssMapping::ComputeSize(number_of_method_indexes);
2357 DCHECK_ALIGNED(max_mappings_size, sizeof(uint32_t));
2358 std::unique_ptr<uint32_t[]> storage(new uint32_t[max_mappings_size / sizeof(uint32_t)]);
2359 MethodBssMapping* mappings = new(storage.get()) MethodBssMapping(number_of_method_indexes);
2360 mappings->ClearPadding();
2361 // Encode the MethodBssMapping.
2362 auto init_it = mappings->begin();
2363 bool first_index = true;
2364 for (uint32_t method_index : method_indexes.Indexes()) {
2365 size_t bss_offset = bss_method_entries_.Get(MethodReference(dex_file, method_index));
2366 if (first_index) {
2367 first_index = false;
2368 encoder.Reset(method_index, bss_offset);
2369 } else if (!encoder.TryMerge(method_index, bss_offset)) {
2370 *init_it = encoder.GetEntry();
2371 ++init_it;
2372 encoder.Reset(method_index, bss_offset);
2373 }
2374 }
2375 // Store the last entry and shrink the mapping to the actual size.
2376 *init_it = encoder.GetEntry();
2377 ++init_it;
2378 DCHECK(init_it <= mappings->end());
2379 mappings->SetSize(std::distance(mappings->begin(), init_it));
2380 size_t mappings_size = MethodBssMapping::ComputeSize(mappings->size());
2381
2382 DCHECK_EQ(relative_offset, oat_dex_file->method_bss_mapping_offset_);
2383 DCHECK_OFFSET();
2384 if (!out->WriteFully(storage.get(), mappings_size)) {
2385 return 0u;
2386 }
2387 size_method_bss_mappings_ += mappings_size;
2388 relative_offset += mappings_size;
2389 } else {
2390 DCHECK_EQ(0u, oat_dex_file->method_bss_mapping_offset_);
2391 }
2392 }
2393 return relative_offset;
2394}
2395
2396size_t OatWriter::WriteOatDexFiles(OutputStream* out, size_t file_offset, size_t relative_offset) {
2397 TimingLogger::ScopedTiming split("WriteOatDexFiles", timings_);
2398
2399 for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
2400 OatDexFile* oat_dex_file = &oat_dex_files_[i];
2401 DCHECK_EQ(relative_offset, oat_dex_file->offset_);
2402 DCHECK_OFFSET();
2403
2404 // Write OatDexFile.
2405 if (!oat_dex_file->Write(this, out)) {
2406 return 0u;
2407 }
2408 relative_offset += oat_dex_file->SizeOf();
2409 }
2410
2411 return relative_offset;
2412}
2413
2414size_t OatWriter::WriteCode(OutputStream* out, size_t file_offset, size_t relative_offset) {
Vladimir Markoaad75c62016-10-03 08:46:48 +00002415 if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002416 InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002417
Ian Rogers848871b2013-08-05 10:56:33 -07002418 #define DO_TRAMPOLINE(field) \
2419 do { \
2420 uint32_t aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set); \
2421 uint32_t alignment_padding = aligned_offset - relative_offset; \
Ian Rogers3d504072014-03-01 09:16:49 -08002422 out->Seek(alignment_padding, kSeekCurrent); \
Ian Rogers848871b2013-08-05 10:56:33 -07002423 size_trampoline_alignment_ += alignment_padding; \
Vladimir Markoe079e212016-05-25 12:49:49 +01002424 if (!out->WriteFully((field)->data(), (field)->size())) { \
Ian Rogers3d504072014-03-01 09:16:49 -08002425 PLOG(ERROR) << "Failed to write " # field " to " << out->GetLocation(); \
Ian Rogers848871b2013-08-05 10:56:33 -07002426 return false; \
2427 } \
Chih-Hung Hsiehfba39972016-05-11 11:26:48 -07002428 size_ ## field += (field)->size(); \
2429 relative_offset += alignment_padding + (field)->size(); \
Ian Rogers848871b2013-08-05 10:56:33 -07002430 DCHECK_OFFSET(); \
2431 } while (false)
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002432
Ian Rogers848871b2013-08-05 10:56:33 -07002433 DO_TRAMPOLINE(jni_dlsym_lookup_);
Andreas Gampe2da88232014-02-27 12:26:20 -08002434 DO_TRAMPOLINE(quick_generic_jni_trampoline_);
Jeff Hao88474b42013-10-23 16:24:40 -07002435 DO_TRAMPOLINE(quick_imt_conflict_trampoline_);
Ian Rogers848871b2013-08-05 10:56:33 -07002436 DO_TRAMPOLINE(quick_resolution_trampoline_);
2437 DO_TRAMPOLINE(quick_to_interpreter_bridge_);
2438 #undef DO_TRAMPOLINE
Jeff Hao0aba0ba2013-06-03 14:49:28 -07002439 }
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002440 return relative_offset;
Brian Carlstrome24fa612011-09-29 00:53:55 -07002441}
2442
Ian Rogers3d504072014-03-01 09:16:49 -08002443size_t OatWriter::WriteCodeDexFiles(OutputStream* out,
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002444 size_t file_offset,
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002445 size_t relative_offset) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002446 #define VISIT(VisitorType) \
2447 do { \
2448 VisitorType visitor(this, out, file_offset, relative_offset); \
2449 if (UNLIKELY(!VisitDexMethods(&visitor))) { \
2450 return 0; \
2451 } \
2452 relative_offset = visitor.GetOffset(); \
2453 } while (false)
Brian Carlstrome24fa612011-09-29 00:53:55 -07002454
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002455 VISIT(WriteCodeMethodVisitor);
Brian Carlstrome24fa612011-09-29 00:53:55 -07002456
Vladimir Marko96c6ab92014-04-08 14:00:50 +01002457 #undef VISIT
Brian Carlstrom265091e2013-01-30 14:08:26 -08002458
Vladimir Markob163bb72015-03-31 21:49:49 +01002459 size_code_alignment_ += relative_patcher_->CodeAlignmentSize();
2460 size_relative_call_thunks_ += relative_patcher_->RelativeCallThunksSize();
2461 size_misc_thunks_ += relative_patcher_->MiscThunksSize();
2462
Brian Carlstromc50d8e12013-07-23 22:35:16 -07002463 return relative_offset;
Brian Carlstrome24fa612011-09-29 00:53:55 -07002464}
2465
Vladimir Marko944da602016-02-19 12:27:55 +00002466bool OatWriter::RecordOatDataOffset(OutputStream* out) {
Vladimir Marko49b0f452015-12-10 13:49:19 +00002467 // Get the elf file offset of the oat file.
2468 const off_t raw_file_offset = out->Seek(0, kSeekCurrent);
2469 if (raw_file_offset == static_cast<off_t>(-1)) {
2470 LOG(ERROR) << "Failed to get file offset in " << out->GetLocation();
2471 return false;
2472 }
2473 oat_data_offset_ = static_cast<size_t>(raw_file_offset);
2474 return true;
2475}
2476
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002477bool OatWriter::ReadDexFileHeader(File* file, OatDexFile* oat_dex_file) {
2478 // Read the dex file header and perform minimal verification.
2479 uint8_t raw_header[sizeof(DexFile::Header)];
2480 if (!file->ReadFully(&raw_header, sizeof(DexFile::Header))) {
2481 PLOG(ERROR) << "Failed to read dex file header. Actual: "
2482 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2483 return false;
2484 }
2485 if (!ValidateDexFileHeader(raw_header, oat_dex_file->GetLocation())) {
2486 return false;
2487 }
2488
2489 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_header);
2490 oat_dex_file->dex_file_size_ = header->file_size_;
2491 oat_dex_file->dex_file_location_checksum_ = header->checksum_;
2492 oat_dex_file->class_offsets_.resize(header->class_defs_size_);
2493 return true;
2494}
2495
2496bool OatWriter::ValidateDexFileHeader(const uint8_t* raw_header, const char* location) {
2497 if (!DexFile::IsMagicValid(raw_header)) {
2498 LOG(ERROR) << "Invalid magic number in dex file header. " << " File: " << location;
2499 return false;
2500 }
2501 if (!DexFile::IsVersionValid(raw_header)) {
2502 LOG(ERROR) << "Invalid version number in dex file header. " << " File: " << location;
2503 return false;
2504 }
2505 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_header);
2506 if (header->file_size_ < sizeof(DexFile::Header)) {
2507 LOG(ERROR) << "Dex file header specifies file size insufficient to contain the header."
2508 << " File: " << location;
2509 return false;
2510 }
2511 return true;
2512}
2513
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002514bool OatWriter::WriteDexFiles(OutputStream* out, File* file, bool update_input_vdex) {
David Brazdil7b49e6c2016-09-01 11:06:18 +01002515 TimingLogger::ScopedTiming split("Write Dex files", timings_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002516
David Brazdil7b49e6c2016-09-01 11:06:18 +01002517 vdex_dex_files_offset_ = vdex_size_;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002518
2519 // Write dex files.
2520 for (OatDexFile& oat_dex_file : oat_dex_files_) {
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002521 if (!WriteDexFile(out, file, &oat_dex_file, update_input_vdex)) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002522 return false;
2523 }
2524 }
2525
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002526 CloseSources();
2527 return true;
2528}
2529
2530void OatWriter::CloseSources() {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002531 for (OatDexFile& oat_dex_file : oat_dex_files_) {
2532 oat_dex_file.source_.Clear(); // Get rid of the reference, it's about to be invalidated.
2533 }
2534 zipped_dex_files_.clear();
2535 zip_archives_.clear();
2536 raw_dex_files_.clear();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002537}
2538
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002539bool OatWriter::WriteDexFile(OutputStream* out,
2540 File* file,
2541 OatDexFile* oat_dex_file,
2542 bool update_input_vdex) {
David Brazdil7b49e6c2016-09-01 11:06:18 +01002543 if (!SeekToDexFile(out, file, oat_dex_file)) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002544 return false;
2545 }
Jeff Hao608f2ce2016-10-19 11:17:11 -07002546 if (profile_compilation_info_ != nullptr) {
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002547 DCHECK(!update_input_vdex);
Jeff Hao608f2ce2016-10-19 11:17:11 -07002548 if (!LayoutAndWriteDexFile(out, oat_dex_file)) {
2549 return false;
2550 }
2551 } else if (oat_dex_file->source_.IsZipEntry()) {
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002552 DCHECK(!update_input_vdex);
David Brazdil7b49e6c2016-09-01 11:06:18 +01002553 if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetZipEntry())) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002554 return false;
2555 }
2556 } else if (oat_dex_file->source_.IsRawFile()) {
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002557 DCHECK(!update_input_vdex);
David Brazdil7b49e6c2016-09-01 11:06:18 +01002558 if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetRawFile())) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002559 return false;
2560 }
2561 } else {
2562 DCHECK(oat_dex_file->source_.IsRawData());
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002563 if (!WriteDexFile(out, oat_dex_file, oat_dex_file->source_.GetRawData(), update_input_vdex)) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002564 return false;
2565 }
2566 }
2567
2568 // Update current size and account for the written data.
David Brazdil7b49e6c2016-09-01 11:06:18 +01002569 if (kIsVdexEnabled) {
2570 DCHECK_EQ(vdex_size_, oat_dex_file->dex_file_offset_);
2571 vdex_size_ += oat_dex_file->dex_file_size_;
2572 } else {
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002573 DCHECK(!update_input_vdex);
David Brazdil7b49e6c2016-09-01 11:06:18 +01002574 DCHECK_EQ(oat_size_, oat_dex_file->dex_file_offset_);
2575 oat_size_ += oat_dex_file->dex_file_size_;
2576 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002577 size_dex_file_ += oat_dex_file->dex_file_size_;
2578 return true;
2579}
2580
2581bool OatWriter::SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file) {
2582 // Dex files are required to be 4 byte aligned.
David Brazdil7b49e6c2016-09-01 11:06:18 +01002583 size_t initial_offset = kIsVdexEnabled ? vdex_size_ : oat_size_;
2584 size_t start_offset = RoundUp(initial_offset, 4);
2585 size_t file_offset = kIsVdexEnabled ? start_offset : (oat_data_offset_ + start_offset);
2586 size_dex_file_alignment_ += start_offset - initial_offset;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002587
2588 // Seek to the start of the dex file and flush any pending operations in the stream.
2589 // Verify that, after flushing the stream, the file is at the same offset as the stream.
David Brazdil7b49e6c2016-09-01 11:06:18 +01002590 off_t actual_offset = out->Seek(file_offset, kSeekSet);
2591 if (actual_offset != static_cast<off_t>(file_offset)) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002592 PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
David Brazdil7b49e6c2016-09-01 11:06:18 +01002593 << " Expected: " << file_offset
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002594 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2595 return false;
2596 }
2597 if (!out->Flush()) {
2598 PLOG(ERROR) << "Failed to flush before writing dex file."
2599 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2600 return false;
2601 }
2602 actual_offset = lseek(file->Fd(), 0, SEEK_CUR);
David Brazdil7b49e6c2016-09-01 11:06:18 +01002603 if (actual_offset != static_cast<off_t>(file_offset)) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002604 PLOG(ERROR) << "Stream/file position mismatch! Actual: " << actual_offset
David Brazdil7b49e6c2016-09-01 11:06:18 +01002605 << " Expected: " << file_offset
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002606 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2607 return false;
2608 }
2609
David Brazdil7b49e6c2016-09-01 11:06:18 +01002610 if (kIsVdexEnabled) {
2611 vdex_size_ = start_offset;
2612 } else {
2613 oat_size_ = start_offset;
2614 }
2615 oat_dex_file->dex_file_offset_ = start_offset;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002616 return true;
2617}
2618
Jeff Hao608f2ce2016-10-19 11:17:11 -07002619bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_file) {
2620 TimingLogger::ScopedTiming split("Dex Layout", timings_);
2621 std::string error_msg;
2622 std::string location(oat_dex_file->GetLocation());
2623 std::unique_ptr<const DexFile> dex_file;
2624 if (oat_dex_file->source_.IsZipEntry()) {
2625 ZipEntry* zip_entry = oat_dex_file->source_.GetZipEntry();
2626 std::unique_ptr<MemMap> mem_map(
2627 zip_entry->ExtractToMemMap(location.c_str(), "classes.dex", &error_msg));
Jeff Hao41b2f532017-03-02 16:36:31 -08002628 if (mem_map == nullptr) {
2629 LOG(ERROR) << "Failed to extract dex file to mem map for layout: " << error_msg;
2630 return false;
2631 }
Jeff Hao608f2ce2016-10-19 11:17:11 -07002632 dex_file = DexFile::Open(location,
2633 zip_entry->GetCrc32(),
2634 std::move(mem_map),
2635 /* verify */ true,
2636 /* verify_checksum */ true,
2637 &error_msg);
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +01002638 } else if (oat_dex_file->source_.IsRawFile()) {
Jeff Hao608f2ce2016-10-19 11:17:11 -07002639 File* raw_file = oat_dex_file->source_.GetRawFile();
2640 dex_file = DexFile::OpenDex(raw_file->Fd(), location, /* verify_checksum */ true, &error_msg);
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +01002641 } else {
2642 // The source data is a vdex file.
2643 CHECK(oat_dex_file->source_.IsRawData())
2644 << static_cast<size_t>(oat_dex_file->source_.GetType());
2645 const uint8_t* raw_dex_file = oat_dex_file->source_.GetRawData();
2646 // Note: The raw data has already been checked to contain the header
2647 // and all the data that the header specifies as the file size.
2648 DCHECK(raw_dex_file != nullptr);
2649 DCHECK(ValidateDexFileHeader(raw_dex_file, oat_dex_file->GetLocation()));
2650 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
2651 // Since the source may have had its layout changed, or may be quickened, don't verify it.
2652 dex_file = DexFile::Open(raw_dex_file,
2653 header->file_size_,
2654 location,
2655 oat_dex_file->dex_file_location_checksum_,
2656 nullptr,
2657 /* verify */ false,
2658 /* verify_checksum */ false,
2659 &error_msg);
Jeff Hao608f2ce2016-10-19 11:17:11 -07002660 }
Jeff Haode197542017-02-03 10:48:13 -08002661 if (dex_file == nullptr) {
Jeff Haod9df7802017-02-06 16:41:16 -08002662 LOG(ERROR) << "Failed to open dex file for layout: " << error_msg;
Jeff Haode197542017-02-03 10:48:13 -08002663 return false;
2664 }
Jeff Hao608f2ce2016-10-19 11:17:11 -07002665 Options options;
2666 options.output_to_memmap_ = true;
2667 DexLayout dex_layout(options, profile_compilation_info_, nullptr);
2668 dex_layout.ProcessDexFile(location.c_str(), dex_file.get(), 0);
2669 std::unique_ptr<MemMap> mem_map(dex_layout.GetAndReleaseMemMap());
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002670 if (!WriteDexFile(out, oat_dex_file, mem_map->Begin(), /* update_input_vdex */ false)) {
Jeff Hao608f2ce2016-10-19 11:17:11 -07002671 return false;
2672 }
2673 // Set the checksum of the new oat dex file to be the original file's checksum.
2674 oat_dex_file->dex_file_location_checksum_ = dex_file->GetLocationChecksum();
2675 return true;
2676}
2677
David Brazdil7b49e6c2016-09-01 11:06:18 +01002678bool OatWriter::WriteDexFile(OutputStream* out,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002679 File* file,
2680 OatDexFile* oat_dex_file,
2681 ZipEntry* dex_file) {
David Brazdil7b49e6c2016-09-01 11:06:18 +01002682 size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_;
2683 DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002684
2685 // Extract the dex file and get the extracted size.
2686 std::string error_msg;
2687 if (!dex_file->ExtractToFile(*file, &error_msg)) {
2688 LOG(ERROR) << "Failed to extract dex file from ZIP entry: " << error_msg
2689 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2690 return false;
2691 }
2692 if (file->Flush() != 0) {
2693 PLOG(ERROR) << "Failed to flush dex file from ZIP entry."
2694 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2695 return false;
2696 }
2697 off_t extracted_end = lseek(file->Fd(), 0, SEEK_CUR);
2698 if (extracted_end == static_cast<off_t>(-1)) {
2699 PLOG(ERROR) << "Failed get end offset after writing dex file from ZIP entry."
2700 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2701 return false;
2702 }
2703 if (extracted_end < static_cast<off_t>(start_offset)) {
2704 LOG(ERROR) << "Dex file end position is before start position! End: " << extracted_end
2705 << " Start: " << start_offset
2706 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2707 return false;
2708 }
2709 uint64_t extracted_size = static_cast<uint64_t>(extracted_end - start_offset);
2710 if (extracted_size < sizeof(DexFile::Header)) {
2711 LOG(ERROR) << "Extracted dex file is shorter than dex file header. size: "
2712 << extracted_size << " File: " << oat_dex_file->GetLocation();
2713 return false;
2714 }
2715
2716 // Read the dex file header and extract required data to OatDexFile.
2717 off_t actual_offset = lseek(file->Fd(), start_offset, SEEK_SET);
2718 if (actual_offset != static_cast<off_t>(start_offset)) {
2719 PLOG(ERROR) << "Failed to seek back to dex file header. Actual: " << actual_offset
2720 << " Expected: " << start_offset
2721 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2722 return false;
2723 }
2724 if (!ReadDexFileHeader(file, oat_dex_file)) {
2725 return false;
2726 }
2727 if (extracted_size < oat_dex_file->dex_file_size_) {
2728 LOG(ERROR) << "Extracted truncated dex file. Extracted size: " << extracted_size
2729 << " file size from header: " << oat_dex_file->dex_file_size_
2730 << " File: " << oat_dex_file->GetLocation();
2731 return false;
2732 }
2733
2734 // Override the checksum from header with the CRC from ZIP entry.
2735 oat_dex_file->dex_file_location_checksum_ = dex_file->GetCrc32();
2736
2737 // Seek both file and stream to the end offset.
2738 size_t end_offset = start_offset + oat_dex_file->dex_file_size_;
2739 actual_offset = lseek(file->Fd(), end_offset, SEEK_SET);
2740 if (actual_offset != static_cast<off_t>(end_offset)) {
2741 PLOG(ERROR) << "Failed to seek to end of dex file. Actual: " << actual_offset
2742 << " Expected: " << end_offset
2743 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2744 return false;
2745 }
David Brazdil7b49e6c2016-09-01 11:06:18 +01002746 actual_offset = out->Seek(end_offset, kSeekSet);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002747 if (actual_offset != static_cast<off_t>(end_offset)) {
2748 PLOG(ERROR) << "Failed to seek stream to end of dex file. Actual: " << actual_offset
2749 << " Expected: " << end_offset << " File: " << oat_dex_file->GetLocation();
2750 return false;
2751 }
David Brazdil7b49e6c2016-09-01 11:06:18 +01002752 if (!out->Flush()) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002753 PLOG(ERROR) << "Failed to flush stream after seeking over dex file."
2754 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2755 return false;
2756 }
2757
2758 // If we extracted more than the size specified in the header, truncate the file.
2759 if (extracted_size > oat_dex_file->dex_file_size_) {
2760 if (file->SetLength(end_offset) != 0) {
2761 PLOG(ERROR) << "Failed to truncate excessive dex file length."
David Brazdil7b49e6c2016-09-01 11:06:18 +01002762 << " File: " << oat_dex_file->GetLocation()
2763 << " Output: " << file->GetPath();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002764 return false;
2765 }
2766 }
2767
2768 return true;
2769}
2770
David Brazdil7b49e6c2016-09-01 11:06:18 +01002771bool OatWriter::WriteDexFile(OutputStream* out,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002772 File* file,
2773 OatDexFile* oat_dex_file,
2774 File* dex_file) {
David Brazdil7b49e6c2016-09-01 11:06:18 +01002775 size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_;
2776 DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002777
2778 off_t input_offset = lseek(dex_file->Fd(), 0, SEEK_SET);
2779 if (input_offset != static_cast<off_t>(0)) {
2780 PLOG(ERROR) << "Failed to seek to dex file header. Actual: " << input_offset
2781 << " Expected: 0"
2782 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2783 return false;
2784 }
2785 if (!ReadDexFileHeader(dex_file, oat_dex_file)) {
2786 return false;
2787 }
2788
2789 // Copy the input dex file using sendfile().
2790 if (!file->Copy(dex_file, 0, oat_dex_file->dex_file_size_)) {
2791 PLOG(ERROR) << "Failed to copy dex file to oat file."
2792 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2793 return false;
2794 }
2795 if (file->Flush() != 0) {
2796 PLOG(ERROR) << "Failed to flush dex file."
2797 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2798 return false;
2799 }
2800
2801 // Check file position and seek the stream to the end offset.
2802 size_t end_offset = start_offset + oat_dex_file->dex_file_size_;
2803 off_t actual_offset = lseek(file->Fd(), 0, SEEK_CUR);
2804 if (actual_offset != static_cast<off_t>(end_offset)) {
2805 PLOG(ERROR) << "Unexpected file position after copying dex file. Actual: " << actual_offset
2806 << " Expected: " << end_offset
2807 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2808 return false;
2809 }
David Brazdil7b49e6c2016-09-01 11:06:18 +01002810 actual_offset = out->Seek(end_offset, kSeekSet);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002811 if (actual_offset != static_cast<off_t>(end_offset)) {
2812 PLOG(ERROR) << "Failed to seek stream to end of dex file. Actual: " << actual_offset
2813 << " Expected: " << end_offset << " File: " << oat_dex_file->GetLocation();
2814 return false;
2815 }
David Brazdil7b49e6c2016-09-01 11:06:18 +01002816 if (!out->Flush()) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002817 PLOG(ERROR) << "Failed to flush stream after seeking over dex file."
2818 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2819 return false;
2820 }
2821
2822 return true;
2823}
2824
David Brazdil7b49e6c2016-09-01 11:06:18 +01002825bool OatWriter::WriteDexFile(OutputStream* out,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002826 OatDexFile* oat_dex_file,
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002827 const uint8_t* dex_file,
2828 bool update_input_vdex) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002829 // Note: The raw data has already been checked to contain the header
2830 // and all the data that the header specifies as the file size.
2831 DCHECK(dex_file != nullptr);
2832 DCHECK(ValidateDexFileHeader(dex_file, oat_dex_file->GetLocation()));
2833 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(dex_file);
2834
Nicolas Geoffray81f57d12016-12-20 13:17:09 +00002835 if (update_input_vdex) {
2836 // The vdex already contains the dex code, no need to write it again.
2837 } else {
2838 if (!out->WriteFully(dex_file, header->file_size_)) {
2839 PLOG(ERROR) << "Failed to write dex file " << oat_dex_file->GetLocation()
2840 << " to " << out->GetLocation();
2841 return false;
2842 }
2843 if (!out->Flush()) {
2844 PLOG(ERROR) << "Failed to flush stream after writing dex file."
2845 << " File: " << oat_dex_file->GetLocation();
2846 return false;
2847 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002848 }
2849
2850 // Update dex file size and resize class offsets in the OatDexFile.
2851 // Note: For raw data, the checksum is passed directly to AddRawDexFileSource().
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +00002852 // Note: For vdex, the checksum is copied from the existing vdex file.
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002853 oat_dex_file->dex_file_size_ = header->file_size_;
2854 oat_dex_file->class_offsets_.resize(header->class_defs_size_);
2855 return true;
2856}
2857
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002858bool OatWriter::OpenDexFiles(
2859 File* file,
Andreas Gampe3a2bd292016-01-26 17:23:47 -08002860 bool verify,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002861 /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map,
2862 /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
2863 TimingLogger::ScopedTiming split("OpenDexFiles", timings_);
2864
2865 if (oat_dex_files_.empty()) {
2866 // Nothing to do.
2867 return true;
2868 }
2869
2870 size_t map_offset = oat_dex_files_[0].dex_file_offset_;
David Brazdil7b49e6c2016-09-01 11:06:18 +01002871 size_t length = kIsVdexEnabled ? (vdex_size_ - map_offset) : (oat_size_ - map_offset);
2872
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002873 std::string error_msg;
David Brazdil7b49e6c2016-09-01 11:06:18 +01002874 std::unique_ptr<MemMap> dex_files_map(MemMap::MapFile(
2875 length,
2876 PROT_READ | PROT_WRITE,
2877 MAP_SHARED,
2878 file->Fd(),
2879 kIsVdexEnabled ? map_offset : (oat_data_offset_ + map_offset),
2880 /* low_4gb */ false,
2881 file->GetPath().c_str(),
2882 &error_msg));
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002883 if (dex_files_map == nullptr) {
2884 LOG(ERROR) << "Failed to mmap() dex files from oat file. File: " << file->GetPath()
2885 << " error: " << error_msg;
2886 return false;
2887 }
2888 std::vector<std::unique_ptr<const DexFile>> dex_files;
2889 for (OatDexFile& oat_dex_file : oat_dex_files_) {
2890 // Make sure no one messed with input files while we were copying data.
2891 // At the very least we need consistent file size and number of class definitions.
2892 const uint8_t* raw_dex_file =
2893 dex_files_map->Begin() + oat_dex_file.dex_file_offset_ - map_offset;
2894 if (!ValidateDexFileHeader(raw_dex_file, oat_dex_file.GetLocation())) {
2895 // Note: ValidateDexFileHeader() already logged an error message.
2896 LOG(ERROR) << "Failed to verify written dex file header!"
2897 << " Output: " << file->GetPath() << " ~ " << std::hex << map_offset
2898 << " ~ " << static_cast<const void*>(raw_dex_file);
2899 return false;
2900 }
2901 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
2902 if (header->file_size_ != oat_dex_file.dex_file_size_) {
2903 LOG(ERROR) << "File size mismatch in written dex file header! Expected: "
2904 << oat_dex_file.dex_file_size_ << " Actual: " << header->file_size_
2905 << " Output: " << file->GetPath();
2906 return false;
2907 }
2908 if (header->class_defs_size_ != oat_dex_file.class_offsets_.size()) {
2909 LOG(ERROR) << "Class defs size mismatch in written dex file header! Expected: "
2910 << oat_dex_file.class_offsets_.size() << " Actual: " << header->class_defs_size_
2911 << " Output: " << file->GetPath();
2912 return false;
2913 }
2914
2915 // Now, open the dex file.
2916 dex_files.emplace_back(DexFile::Open(raw_dex_file,
2917 oat_dex_file.dex_file_size_,
2918 oat_dex_file.GetLocation(),
2919 oat_dex_file.dex_file_location_checksum_,
2920 /* oat_dex_file */ nullptr,
Andreas Gampe3a2bd292016-01-26 17:23:47 -08002921 verify,
Aart Bik37d6a3b2016-06-21 18:30:10 -07002922 verify,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002923 &error_msg));
2924 if (dex_files.back() == nullptr) {
Andreas Gampe3a2bd292016-01-26 17:23:47 -08002925 LOG(ERROR) << "Failed to open dex file from oat file. File: " << oat_dex_file.GetLocation()
2926 << " Error: " << error_msg;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002927 return false;
2928 }
2929 }
2930
2931 *opened_dex_files_map = std::move(dex_files_map);
2932 *opened_dex_files = std::move(dex_files);
2933 return true;
2934}
2935
2936bool OatWriter::WriteTypeLookupTables(
David Brazdil7b49e6c2016-09-01 11:06:18 +01002937 OutputStream* oat_rodata,
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002938 const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files) {
2939 TimingLogger::ScopedTiming split("WriteTypeLookupTables", timings_);
2940
David Brazdil7b49e6c2016-09-01 11:06:18 +01002941 uint32_t expected_offset = oat_data_offset_ + oat_size_;
2942 off_t actual_offset = oat_rodata->Seek(expected_offset, kSeekSet);
2943 if (static_cast<uint32_t>(actual_offset) != expected_offset) {
2944 PLOG(ERROR) << "Failed to seek to TypeLookupTable section. Actual: " << actual_offset
2945 << " Expected: " << expected_offset << " File: " << oat_rodata->GetLocation();
2946 return false;
2947 }
2948
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002949 DCHECK_EQ(opened_dex_files.size(), oat_dex_files_.size());
2950 for (size_t i = 0, size = opened_dex_files.size(); i != size; ++i) {
2951 OatDexFile* oat_dex_file = &oat_dex_files_[i];
David Brazdil181e1cc2016-09-01 16:38:47 +00002952 DCHECK_EQ(oat_dex_file->lookup_table_offset_, 0u);
2953
2954 if (oat_dex_file->create_type_lookup_table_ != CreateTypeLookupTable::kCreate ||
2955 oat_dex_file->class_offsets_.empty()) {
2956 continue;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00002957 }
David Brazdil181e1cc2016-09-01 16:38:47 +00002958
2959 size_t table_size = TypeLookupTable::RawDataLength(oat_dex_file->class_offsets_.size());
2960 if (table_size == 0u) {
2961 continue;
2962 }
2963
2964 // Create the lookup table. When `nullptr` is given as the storage buffer,
David Sehr9aa352e2016-09-15 18:13:52 -07002965 // TypeLookupTable allocates its own and OatDexFile takes ownership.
Mathieu Chartier1b868492016-11-16 16:22:37 -08002966 const DexFile& dex_file = *opened_dex_files[i];
2967 {
2968 std::unique_ptr<TypeLookupTable> type_lookup_table =
2969 TypeLookupTable::Create(dex_file, /* storage */ nullptr);
2970 type_lookup_table_oat_dex_files_.push_back(
2971 std::make_unique<art::OatDexFile>(std::move(type_lookup_table)));
2972 dex_file.SetOatDexFile(type_lookup_table_oat_dex_files_.back().get());
2973 }
2974 TypeLookupTable* const table = type_lookup_table_oat_dex_files_.back()->GetTypeLookupTable();
David Brazdil181e1cc2016-09-01 16:38:47 +00002975
2976 // Type tables are required to be 4 byte aligned.
David Brazdil7b49e6c2016-09-01 11:06:18 +01002977 size_t initial_offset = oat_size_;
2978 size_t rodata_offset = RoundUp(initial_offset, 4);
2979 size_t padding_size = rodata_offset - initial_offset;
David Brazdil181e1cc2016-09-01 16:38:47 +00002980
2981 if (padding_size != 0u) {
2982 std::vector<uint8_t> buffer(padding_size, 0u);
David Brazdil7b49e6c2016-09-01 11:06:18 +01002983 if (!oat_rodata->WriteFully(buffer.data(), padding_size)) {
David Brazdil181e1cc2016-09-01 16:38:47 +00002984 PLOG(ERROR) << "Failed to write lookup table alignment padding."
2985 << " File: " << oat_dex_file->GetLocation()
David Brazdil7b49e6c2016-09-01 11:06:18 +01002986 << " Output: " << oat_rodata->GetLocation();
David Brazdil181e1cc2016-09-01 16:38:47 +00002987 return false;
2988 }
2989 }
2990
2991 DCHECK_EQ(oat_data_offset_ + rodata_offset,
David Brazdil7b49e6c2016-09-01 11:06:18 +01002992 static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent)));
David Brazdil181e1cc2016-09-01 16:38:47 +00002993 DCHECK_EQ(table_size, table->RawDataLength());
2994
David Brazdil7b49e6c2016-09-01 11:06:18 +01002995 if (!oat_rodata->WriteFully(table->RawData(), table_size)) {
David Brazdil181e1cc2016-09-01 16:38:47 +00002996 PLOG(ERROR) << "Failed to write lookup table."
2997 << " File: " << oat_dex_file->GetLocation()
David Brazdil7b49e6c2016-09-01 11:06:18 +01002998 << " Output: " << oat_rodata->GetLocation();
David Brazdil181e1cc2016-09-01 16:38:47 +00002999 return false;
3000 }
3001
3002 oat_dex_file->lookup_table_offset_ = rodata_offset;
3003
David Brazdil7b49e6c2016-09-01 11:06:18 +01003004 oat_size_ += padding_size + table_size;
David Brazdil181e1cc2016-09-01 16:38:47 +00003005 size_oat_lookup_table_ += table_size;
3006 size_oat_lookup_table_alignment_ += padding_size;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003007 }
3008
David Brazdil7b49e6c2016-09-01 11:06:18 +01003009 if (!oat_rodata->Flush()) {
David Brazdil181e1cc2016-09-01 16:38:47 +00003010 PLOG(ERROR) << "Failed to flush stream after writing type lookup tables."
David Brazdil7b49e6c2016-09-01 11:06:18 +01003011 << " File: " << oat_rodata->GetLocation();
3012 return false;
3013 }
3014
3015 return true;
3016}
3017
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +00003018bool OatWriter::WriteChecksumsAndVdexHeader(OutputStream* vdex_out) {
David Brazdil5d5a36b2016-09-14 15:34:10 +01003019 if (!kIsVdexEnabled) {
3020 return true;
3021 }
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +00003022 // Write checksums
3023 off_t actual_offset = vdex_out->Seek(sizeof(VdexFile::Header), kSeekSet);
3024 if (actual_offset != sizeof(VdexFile::Header)) {
3025 PLOG(ERROR) << "Failed to seek to the checksum location of vdex file. Actual: " << actual_offset
3026 << " File: " << vdex_out->GetLocation();
3027 return false;
3028 }
3029
3030 for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
3031 OatDexFile* oat_dex_file = &oat_dex_files_[i];
3032 if (!vdex_out->WriteFully(
3033 &oat_dex_file->dex_file_location_checksum_, sizeof(VdexFile::VdexChecksum))) {
3034 PLOG(ERROR) << "Failed to write dex file location checksum. File: "
3035 << vdex_out->GetLocation();
3036 return false;
3037 }
3038 size_vdex_checksums_ += sizeof(VdexFile::VdexChecksum);
3039 }
3040
3041 // Write header.
3042 actual_offset = vdex_out->Seek(0, kSeekSet);
David Brazdil7b49e6c2016-09-01 11:06:18 +01003043 if (actual_offset != 0) {
3044 PLOG(ERROR) << "Failed to seek to the beginning of vdex file. Actual: " << actual_offset
3045 << " File: " << vdex_out->GetLocation();
3046 return false;
3047 }
3048
David Brazdil5d5a36b2016-09-14 15:34:10 +01003049 DCHECK_NE(vdex_dex_files_offset_, 0u);
3050 DCHECK_NE(vdex_verifier_deps_offset_, 0u);
3051
3052 size_t dex_section_size = vdex_verifier_deps_offset_ - vdex_dex_files_offset_;
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01003053 size_t verifier_deps_section_size = vdex_quickening_info_offset_ - vdex_verifier_deps_offset_;
3054 size_t quickening_info_section_size = vdex_size_ - vdex_quickening_info_offset_;
David Brazdil5d5a36b2016-09-14 15:34:10 +01003055
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +00003056 VdexFile::Header vdex_header(oat_dex_files_.size(),
3057 dex_section_size,
3058 verifier_deps_section_size,
3059 quickening_info_section_size);
David Brazdil7b49e6c2016-09-01 11:06:18 +01003060 if (!vdex_out->WriteFully(&vdex_header, sizeof(VdexFile::Header))) {
3061 PLOG(ERROR) << "Failed to write vdex header. File: " << vdex_out->GetLocation();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003062 return false;
3063 }
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +00003064 size_vdex_header_ = sizeof(VdexFile::Header);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003065
David Brazdil5d5a36b2016-09-14 15:34:10 +01003066 if (!vdex_out->Flush()) {
3067 PLOG(ERROR) << "Failed to flush stream after writing to vdex file."
3068 << " File: " << vdex_out->GetLocation();
3069 return false;
3070 }
3071
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003072 return true;
3073}
3074
Vladimir Markof4da6752014-08-01 19:04:18 +01003075bool OatWriter::WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01003076 return WriteUpTo16BytesAlignment(out, aligned_code_delta, &size_code_alignment_);
3077}
3078
3079bool OatWriter::WriteUpTo16BytesAlignment(OutputStream* out, uint32_t size, uint32_t* stat) {
Vladimir Markof4da6752014-08-01 19:04:18 +01003080 static const uint8_t kPadding[] = {
3081 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u
3082 };
Vladimir Marko0eb882b2017-05-15 13:39:18 +01003083 DCHECK_LE(size, sizeof(kPadding));
3084 if (UNLIKELY(!out->WriteFully(kPadding, size))) {
Vladimir Markof4da6752014-08-01 19:04:18 +01003085 return false;
3086 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01003087 *stat += size;
Vladimir Markof4da6752014-08-01 19:04:18 +01003088 return true;
3089}
3090
Vladimir Marko944da602016-02-19 12:27:55 +00003091void OatWriter::SetMultiOatRelativePatcherAdjustment() {
3092 DCHECK(dex_files_ != nullptr);
3093 DCHECK(relative_patcher_ != nullptr);
3094 DCHECK_NE(oat_data_offset_, 0u);
3095 if (image_writer_ != nullptr && !dex_files_->empty()) {
3096 // The oat data begin may not be initialized yet but the oat file offset is ready.
3097 size_t oat_index = image_writer_->GetOatIndexForDexFile(dex_files_->front());
3098 size_t elf_file_offset = image_writer_->GetOatFileOffset(oat_index);
3099 relative_patcher_->StartOatFile(elf_file_offset + oat_data_offset_);
Vladimir Markob163bb72015-03-31 21:49:49 +01003100 }
3101}
3102
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003103OatWriter::OatDexFile::OatDexFile(const char* dex_file_location,
3104 DexFileSource source,
3105 CreateTypeLookupTable create_type_lookup_table)
3106 : source_(source),
3107 create_type_lookup_table_(create_type_lookup_table),
3108 dex_file_size_(0),
3109 offset_(0),
3110 dex_file_location_size_(strlen(dex_file_location)),
3111 dex_file_location_data_(dex_file_location),
3112 dex_file_location_checksum_(0u),
3113 dex_file_offset_(0u),
3114 class_offsets_offset_(0u),
3115 lookup_table_offset_(0u),
Vladimir Marko0eb882b2017-05-15 13:39:18 +01003116 method_bss_mapping_offset_(0u),
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003117 class_offsets_() {
Brian Carlstrome24fa612011-09-29 00:53:55 -07003118}
3119
3120size_t OatWriter::OatDexFile::SizeOf() const {
3121 return sizeof(dex_file_location_size_)
3122 + dex_file_location_size_
Brian Carlstrom5b332c82012-02-01 15:02:31 -08003123 + sizeof(dex_file_location_checksum_)
Brian Carlstrom89521892011-12-07 22:05:07 -08003124 + sizeof(dex_file_offset_)
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003125 + sizeof(class_offsets_offset_)
Vladimir Marko0eb882b2017-05-15 13:39:18 +01003126 + sizeof(lookup_table_offset_)
3127 + sizeof(method_bss_mapping_offset_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003128}
3129
3130bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream* out) const {
3131 const size_t file_offset = oat_writer->oat_data_offset_;
Brian Carlstrom265091e2013-01-30 14:08:26 -08003132 DCHECK_OFFSET_();
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003133
Vladimir Markoe079e212016-05-25 12:49:49 +01003134 if (!out->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08003135 PLOG(ERROR) << "Failed to write dex file location length to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07003136 return false;
3137 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07003138 oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003139
Vladimir Markoe079e212016-05-25 12:49:49 +01003140 if (!out->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
Ian Rogers3d504072014-03-01 09:16:49 -08003141 PLOG(ERROR) << "Failed to write dex file location data to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07003142 return false;
3143 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07003144 oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003145
Vladimir Markoe079e212016-05-25 12:49:49 +01003146 if (!out->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08003147 PLOG(ERROR) << "Failed to write dex file location checksum to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07003148 return false;
3149 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07003150 oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003151
Vladimir Markoe079e212016-05-25 12:49:49 +01003152 if (!out->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08003153 PLOG(ERROR) << "Failed to write dex file offset to " << out->GetLocation();
Brian Carlstrom89521892011-12-07 22:05:07 -08003154 return false;
3155 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07003156 oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003157
Vladimir Markoe079e212016-05-25 12:49:49 +01003158 if (!out->WriteFully(&class_offsets_offset_, sizeof(class_offsets_offset_))) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003159 PLOG(ERROR) << "Failed to write class offsets offset to " << out->GetLocation();
3160 return false;
3161 }
3162 oat_writer->size_oat_dex_file_class_offsets_offset_ += sizeof(class_offsets_offset_);
3163
Vladimir Markoe079e212016-05-25 12:49:49 +01003164 if (!out->WriteFully(&lookup_table_offset_, sizeof(lookup_table_offset_))) {
Artem Udovichenkod9786b02015-10-14 16:36:55 +03003165 PLOG(ERROR) << "Failed to write lookup table offset to " << out->GetLocation();
3166 return false;
3167 }
Vladimir Marko49b0f452015-12-10 13:49:19 +00003168 oat_writer->size_oat_dex_file_lookup_table_offset_ += sizeof(lookup_table_offset_);
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003169
Vladimir Marko0eb882b2017-05-15 13:39:18 +01003170 if (!out->WriteFully(&method_bss_mapping_offset_, sizeof(method_bss_mapping_offset_))) {
3171 PLOG(ERROR) << "Failed to write method bss mapping offset to " << out->GetLocation();
3172 return false;
3173 }
3174 oat_writer->size_oat_dex_file_method_bss_mapping_offset_ += sizeof(method_bss_mapping_offset_);
3175
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003176 return true;
3177}
3178
3179bool OatWriter::OatDexFile::WriteClassOffsets(OatWriter* oat_writer, OutputStream* out) {
Vladimir Markoe079e212016-05-25 12:49:49 +01003180 if (!out->WriteFully(class_offsets_.data(), GetClassOffsetsRawSize())) {
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003181 PLOG(ERROR) << "Failed to write oat class offsets for " << GetLocation()
3182 << " to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07003183 return false;
3184 }
Vladimir Marko9bdf1082016-01-21 12:15:52 +00003185 oat_writer->size_oat_class_offsets_ += GetClassOffsetsRawSize();
Brian Carlstrome24fa612011-09-29 00:53:55 -07003186 return true;
3187}
3188
Brian Carlstromba150c32013-08-27 17:31:03 -07003189OatWriter::OatClass::OatClass(size_t offset,
Vladimir Marko49b0f452015-12-10 13:49:19 +00003190 const dchecked_vector<CompiledMethod*>& compiled_methods,
Brian Carlstromba150c32013-08-27 17:31:03 -07003191 uint32_t num_non_null_compiled_methods,
Vladimir Marko96c6ab92014-04-08 14:00:50 +01003192 mirror::Class::Status status)
3193 : compiled_methods_(compiled_methods) {
3194 uint32_t num_methods = compiled_methods.size();
Brian Carlstromba150c32013-08-27 17:31:03 -07003195 CHECK_LE(num_non_null_compiled_methods, num_methods);
3196
Brian Carlstrom265091e2013-01-30 14:08:26 -08003197 offset_ = offset;
Brian Carlstromba150c32013-08-27 17:31:03 -07003198 oat_method_offsets_offsets_from_oat_class_.resize(num_methods);
3199
3200 // Since both kOatClassNoneCompiled and kOatClassAllCompiled could
3201 // apply when there are 0 methods, we just arbitrarily say that 0
3202 // methods means kOatClassNoneCompiled and that we won't use
3203 // kOatClassAllCompiled unless there is at least one compiled
3204 // method. This means in an interpretter only system, we can assert
3205 // that all classes are kOatClassNoneCompiled.
3206 if (num_non_null_compiled_methods == 0) {
3207 type_ = kOatClassNoneCompiled;
3208 } else if (num_non_null_compiled_methods == num_methods) {
3209 type_ = kOatClassAllCompiled;
3210 } else {
3211 type_ = kOatClassSomeCompiled;
3212 }
3213
Brian Carlstrom0755ec52012-01-11 15:19:46 -08003214 status_ = status;
Brian Carlstromba150c32013-08-27 17:31:03 -07003215 method_offsets_.resize(num_non_null_compiled_methods);
Vladimir Marko8a630572014-04-09 18:45:35 +01003216 method_headers_.resize(num_non_null_compiled_methods);
Brian Carlstromba150c32013-08-27 17:31:03 -07003217
3218 uint32_t oat_method_offsets_offset_from_oat_class = sizeof(type_) + sizeof(status_);
3219 if (type_ == kOatClassSomeCompiled) {
Vladimir Marko49b0f452015-12-10 13:49:19 +00003220 method_bitmap_.reset(new BitVector(num_methods, false, Allocator::GetMallocAllocator()));
Brian Carlstromba150c32013-08-27 17:31:03 -07003221 method_bitmap_size_ = method_bitmap_->GetSizeOf();
3222 oat_method_offsets_offset_from_oat_class += sizeof(method_bitmap_size_);
3223 oat_method_offsets_offset_from_oat_class += method_bitmap_size_;
3224 } else {
Mathieu Chartier2cebb242015-04-21 16:50:40 -07003225 method_bitmap_ = nullptr;
Brian Carlstromba150c32013-08-27 17:31:03 -07003226 method_bitmap_size_ = 0;
3227 }
3228
3229 for (size_t i = 0; i < num_methods; i++) {
Vladimir Marko96c6ab92014-04-08 14:00:50 +01003230 CompiledMethod* compiled_method = compiled_methods_[i];
Mathieu Chartier2cebb242015-04-21 16:50:40 -07003231 if (compiled_method == nullptr) {
Brian Carlstromba150c32013-08-27 17:31:03 -07003232 oat_method_offsets_offsets_from_oat_class_[i] = 0;
3233 } else {
3234 oat_method_offsets_offsets_from_oat_class_[i] = oat_method_offsets_offset_from_oat_class;
3235 oat_method_offsets_offset_from_oat_class += sizeof(OatMethodOffsets);
3236 if (type_ == kOatClassSomeCompiled) {
3237 method_bitmap_->SetBit(i);
3238 }
3239 }
3240 }
Brian Carlstrome24fa612011-09-29 00:53:55 -07003241}
3242
Brian Carlstrom265091e2013-01-30 14:08:26 -08003243size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatHeader(
3244 size_t class_def_method_index_) const {
Brian Carlstromba150c32013-08-27 17:31:03 -07003245 uint32_t method_offset = GetOatMethodOffsetsOffsetFromOatClass(class_def_method_index_);
3246 if (method_offset == 0) {
3247 return 0;
3248 }
3249 return offset_ + method_offset;
Brian Carlstrom265091e2013-01-30 14:08:26 -08003250}
3251
3252size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatClass(
3253 size_t class_def_method_index_) const {
Brian Carlstromba150c32013-08-27 17:31:03 -07003254 return oat_method_offsets_offsets_from_oat_class_[class_def_method_index_];
Brian Carlstrom265091e2013-01-30 14:08:26 -08003255}
3256
3257size_t OatWriter::OatClass::SizeOf() const {
Brian Carlstromba150c32013-08-27 17:31:03 -07003258 return sizeof(status_)
3259 + sizeof(type_)
3260 + ((method_bitmap_size_ == 0) ? 0 : sizeof(method_bitmap_size_))
3261 + method_bitmap_size_
3262 + (sizeof(method_offsets_[0]) * method_offsets_.size());
Brian Carlstrome24fa612011-09-29 00:53:55 -07003263}
3264
Brian Carlstromc50d8e12013-07-23 22:35:16 -07003265bool OatWriter::OatClass::Write(OatWriter* oat_writer,
Ian Rogers3d504072014-03-01 09:16:49 -08003266 OutputStream* out,
Brian Carlstromc50d8e12013-07-23 22:35:16 -07003267 const size_t file_offset) const {
Brian Carlstrom265091e2013-01-30 14:08:26 -08003268 DCHECK_OFFSET_();
Vladimir Markoe079e212016-05-25 12:49:49 +01003269 if (!out->WriteFully(&status_, sizeof(status_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08003270 PLOG(ERROR) << "Failed to write class status to " << out->GetLocation();
Brian Carlstrom0755ec52012-01-11 15:19:46 -08003271 return false;
3272 }
Jeff Hao0aba0ba2013-06-03 14:49:28 -07003273 oat_writer->size_oat_class_status_ += sizeof(status_);
Vladimir Marko49b0f452015-12-10 13:49:19 +00003274
Vladimir Markoe079e212016-05-25 12:49:49 +01003275 if (!out->WriteFully(&type_, sizeof(type_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08003276 PLOG(ERROR) << "Failed to write oat class type to " << out->GetLocation();
Brian Carlstromba150c32013-08-27 17:31:03 -07003277 return false;
3278 }
3279 oat_writer->size_oat_class_type_ += sizeof(type_);
Vladimir Marko49b0f452015-12-10 13:49:19 +00003280
Brian Carlstromba150c32013-08-27 17:31:03 -07003281 if (method_bitmap_size_ != 0) {
3282 CHECK_EQ(kOatClassSomeCompiled, type_);
Vladimir Markoe079e212016-05-25 12:49:49 +01003283 if (!out->WriteFully(&method_bitmap_size_, sizeof(method_bitmap_size_))) {
Ian Rogers3d504072014-03-01 09:16:49 -08003284 PLOG(ERROR) << "Failed to write method bitmap size to " << out->GetLocation();
Brian Carlstromba150c32013-08-27 17:31:03 -07003285 return false;
3286 }
3287 oat_writer->size_oat_class_method_bitmaps_ += sizeof(method_bitmap_size_);
Vladimir Marko49b0f452015-12-10 13:49:19 +00003288
Vladimir Markoe079e212016-05-25 12:49:49 +01003289 if (!out->WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_size_)) {
Ian Rogers3d504072014-03-01 09:16:49 -08003290 PLOG(ERROR) << "Failed to write method bitmap to " << out->GetLocation();
Brian Carlstromba150c32013-08-27 17:31:03 -07003291 return false;
3292 }
3293 oat_writer->size_oat_class_method_bitmaps_ += method_bitmap_size_;
3294 }
Vladimir Marko49b0f452015-12-10 13:49:19 +00003295
Vladimir Markoe079e212016-05-25 12:49:49 +01003296 if (!out->WriteFully(method_offsets_.data(), GetMethodOffsetsRawSize())) {
Ian Rogers3d504072014-03-01 09:16:49 -08003297 PLOG(ERROR) << "Failed to write method offsets to " << out->GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -07003298 return false;
3299 }
Vladimir Marko49b0f452015-12-10 13:49:19 +00003300 oat_writer->size_oat_class_method_offsets_ += GetMethodOffsetsRawSize();
Brian Carlstrome24fa612011-09-29 00:53:55 -07003301 return true;
3302}
3303
Brian Carlstrome24fa612011-09-29 00:53:55 -07003304} // namespace art