1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2011 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "oat_writer.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include <unistd.h>
20*795d594fSAndroid Build Coastguard Worker #include <zlib.h>
21*795d594fSAndroid Build Coastguard Worker
22*795d594fSAndroid Build Coastguard Worker #include <algorithm>
23*795d594fSAndroid Build Coastguard Worker #include <memory>
24*795d594fSAndroid Build Coastguard Worker #include <vector>
25*795d594fSAndroid Build Coastguard Worker
26*795d594fSAndroid Build Coastguard Worker #include "arch/arm64/instruction_set_features_arm64.h"
27*795d594fSAndroid Build Coastguard Worker #include "art_method-inl.h"
28*795d594fSAndroid Build Coastguard Worker #include "base/allocator.h"
29*795d594fSAndroid Build Coastguard Worker #include "base/bit_vector-inl.h"
30*795d594fSAndroid Build Coastguard Worker #include "base/file_magic.h"
31*795d594fSAndroid Build Coastguard Worker #include "base/file_utils.h"
32*795d594fSAndroid Build Coastguard Worker #include "base/indenter.h"
33*795d594fSAndroid Build Coastguard Worker #include "base/logging.h" // For VLOG
34*795d594fSAndroid Build Coastguard Worker #include "base/os.h"
35*795d594fSAndroid Build Coastguard Worker #include "base/pointer_size.h"
36*795d594fSAndroid Build Coastguard Worker #include "base/safe_map.h"
37*795d594fSAndroid Build Coastguard Worker #include "base/stl_util.h"
38*795d594fSAndroid Build Coastguard Worker #include "base/unix_file/fd_file.h"
39*795d594fSAndroid Build Coastguard Worker #include "base/zip_archive.h"
40*795d594fSAndroid Build Coastguard Worker #include "class_linker.h"
41*795d594fSAndroid Build Coastguard Worker #include "class_table-inl.h"
42*795d594fSAndroid Build Coastguard Worker #include "code_info_table_deduper.h"
43*795d594fSAndroid Build Coastguard Worker #include "debug/method_debug_info.h"
44*795d594fSAndroid Build Coastguard Worker #include "dex/art_dex_file_loader.h"
45*795d594fSAndroid Build Coastguard Worker #include "dex/class_accessor-inl.h"
46*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file-inl.h"
47*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file_loader.h"
48*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file_types.h"
49*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file_verifier.h"
50*795d594fSAndroid Build Coastguard Worker #include "dex/proto_reference.h"
51*795d594fSAndroid Build Coastguard Worker #include "dex/standard_dex_file.h"
52*795d594fSAndroid Build Coastguard Worker #include "dex/type_lookup_table.h"
53*795d594fSAndroid Build Coastguard Worker #include "dex/verification_results.h"
54*795d594fSAndroid Build Coastguard Worker #include "driver/compiled_method-inl.h"
55*795d594fSAndroid Build Coastguard Worker #include "driver/compiler_driver-inl.h"
56*795d594fSAndroid Build Coastguard Worker #include "driver/compiler_options.h"
57*795d594fSAndroid Build Coastguard Worker #include "gc/space/image_space.h"
58*795d594fSAndroid Build Coastguard Worker #include "gc/space/space.h"
59*795d594fSAndroid Build Coastguard Worker #include "handle_scope-inl.h"
60*795d594fSAndroid Build Coastguard Worker #include "image_writer.h"
61*795d594fSAndroid Build Coastguard Worker #include "linker/index_bss_mapping_encoder.h"
62*795d594fSAndroid Build Coastguard Worker #include "linker/linker_patch.h"
63*795d594fSAndroid Build Coastguard Worker #include "linker/multi_oat_relative_patcher.h"
64*795d594fSAndroid Build Coastguard Worker #include "mirror/array.h"
65*795d594fSAndroid Build Coastguard Worker #include "mirror/class_loader.h"
66*795d594fSAndroid Build Coastguard Worker #include "mirror/dex_cache-inl.h"
67*795d594fSAndroid Build Coastguard Worker #include "mirror/object-inl.h"
68*795d594fSAndroid Build Coastguard Worker #include "oat/oat.h"
69*795d594fSAndroid Build Coastguard Worker #include "oat/oat_quick_method_header.h"
70*795d594fSAndroid Build Coastguard Worker #include "oat/stack_map.h"
71*795d594fSAndroid Build Coastguard Worker #include "profile/profile_compilation_info.h"
72*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change-inl.h"
73*795d594fSAndroid Build Coastguard Worker #include "stream/buffered_output_stream.h"
74*795d594fSAndroid Build Coastguard Worker #include "stream/file_output_stream.h"
75*795d594fSAndroid Build Coastguard Worker #include "stream/output_stream.h"
76*795d594fSAndroid Build Coastguard Worker #include "vdex_file.h"
77*795d594fSAndroid Build Coastguard Worker #include "verifier/verifier_deps.h"
78*795d594fSAndroid Build Coastguard Worker
79*795d594fSAndroid Build Coastguard Worker namespace art {
80*795d594fSAndroid Build Coastguard Worker namespace linker {
81*795d594fSAndroid Build Coastguard Worker
82*795d594fSAndroid Build Coastguard Worker namespace { // anonymous namespace
83*795d594fSAndroid Build Coastguard Worker
84*795d594fSAndroid Build Coastguard Worker // If we write dex layout info in the oat file.
85*795d594fSAndroid Build Coastguard Worker static constexpr bool kWriteDexLayoutInfo = true;
86*795d594fSAndroid Build Coastguard Worker
87*795d594fSAndroid Build Coastguard Worker // Force the OAT method layout to be sorted-by-name instead of
88*795d594fSAndroid Build Coastguard Worker // the default (class_def_idx, method_idx).
89*795d594fSAndroid Build Coastguard Worker //
90*795d594fSAndroid Build Coastguard Worker // Otherwise if profiles are used, that will act as
91*795d594fSAndroid Build Coastguard Worker // the primary sort order.
92*795d594fSAndroid Build Coastguard Worker //
93*795d594fSAndroid Build Coastguard Worker // A bit easier to use for development since oatdump can easily
94*795d594fSAndroid Build Coastguard Worker // show that things are being re-ordered when two methods aren't adjacent.
95*795d594fSAndroid Build Coastguard Worker static constexpr bool kOatWriterForceOatCodeLayout = false;
96*795d594fSAndroid Build Coastguard Worker
97*795d594fSAndroid Build Coastguard Worker static constexpr bool kOatWriterDebugOatCodeLayout = false;
98*795d594fSAndroid Build Coastguard Worker
99*795d594fSAndroid Build Coastguard Worker using UnalignedDexFileHeader __attribute__((__aligned__(1))) = DexFile::Header;
100*795d594fSAndroid Build Coastguard Worker
AsUnalignedDexFileHeader(const uint8_t * raw_data)101*795d594fSAndroid Build Coastguard Worker const UnalignedDexFileHeader* AsUnalignedDexFileHeader(const uint8_t* raw_data) {
102*795d594fSAndroid Build Coastguard Worker return reinterpret_cast<const UnalignedDexFileHeader*>(raw_data);
103*795d594fSAndroid Build Coastguard Worker }
104*795d594fSAndroid Build Coastguard Worker
CodeAlignmentSize(uint32_t header_offset,const CompiledMethod & compiled_method)105*795d594fSAndroid Build Coastguard Worker inline uint32_t CodeAlignmentSize(uint32_t header_offset, const CompiledMethod& compiled_method) {
106*795d594fSAndroid Build Coastguard Worker // We want to align the code rather than the preheader.
107*795d594fSAndroid Build Coastguard Worker uint32_t unaligned_code_offset = header_offset + sizeof(OatQuickMethodHeader);
108*795d594fSAndroid Build Coastguard Worker uint32_t aligned_code_offset = compiled_method.AlignCode(unaligned_code_offset);
109*795d594fSAndroid Build Coastguard Worker return aligned_code_offset - unaligned_code_offset;
110*795d594fSAndroid Build Coastguard Worker }
111*795d594fSAndroid Build Coastguard Worker
112*795d594fSAndroid Build Coastguard Worker } // anonymous namespace
113*795d594fSAndroid Build Coastguard Worker
114*795d594fSAndroid Build Coastguard Worker // .bss mapping offsets used for BCP DexFiles.
115*795d594fSAndroid Build Coastguard Worker struct OatWriter::BssMappingInfo {
116*795d594fSAndroid Build Coastguard Worker // Offsets set in PrepareLayout.
117*795d594fSAndroid Build Coastguard Worker uint32_t method_bss_mapping_offset = 0u;
118*795d594fSAndroid Build Coastguard Worker uint32_t type_bss_mapping_offset = 0u;
119*795d594fSAndroid Build Coastguard Worker uint32_t public_type_bss_mapping_offset = 0u;
120*795d594fSAndroid Build Coastguard Worker uint32_t package_type_bss_mapping_offset = 0u;
121*795d594fSAndroid Build Coastguard Worker uint32_t string_bss_mapping_offset = 0u;
122*795d594fSAndroid Build Coastguard Worker uint32_t method_type_bss_mapping_offset = 0u;
123*795d594fSAndroid Build Coastguard Worker
124*795d594fSAndroid Build Coastguard Worker // Offset of the BSSInfo start from beginning of OatHeader. It is used to validate file position
125*795d594fSAndroid Build Coastguard Worker // when writing.
126*795d594fSAndroid Build Coastguard Worker size_t offset_ = 0u;
127*795d594fSAndroid Build Coastguard Worker
SizeOfart::linker::OatWriter::BssMappingInfo128*795d594fSAndroid Build Coastguard Worker static size_t SizeOf() {
129*795d594fSAndroid Build Coastguard Worker return sizeof(method_bss_mapping_offset) +
130*795d594fSAndroid Build Coastguard Worker sizeof(type_bss_mapping_offset) +
131*795d594fSAndroid Build Coastguard Worker sizeof(public_type_bss_mapping_offset) +
132*795d594fSAndroid Build Coastguard Worker sizeof(package_type_bss_mapping_offset) +
133*795d594fSAndroid Build Coastguard Worker sizeof(string_bss_mapping_offset) +
134*795d594fSAndroid Build Coastguard Worker sizeof(method_type_bss_mapping_offset);
135*795d594fSAndroid Build Coastguard Worker }
136*795d594fSAndroid Build Coastguard Worker bool Write(OatWriter* oat_writer, OutputStream* out) const;
137*795d594fSAndroid Build Coastguard Worker };
138*795d594fSAndroid Build Coastguard Worker
139*795d594fSAndroid Build Coastguard Worker class OatWriter::ChecksumUpdatingOutputStream : public OutputStream {
140*795d594fSAndroid Build Coastguard Worker public:
ChecksumUpdatingOutputStream(OutputStream * out,OatWriter * writer)141*795d594fSAndroid Build Coastguard Worker ChecksumUpdatingOutputStream(OutputStream* out, OatWriter* writer)
142*795d594fSAndroid Build Coastguard Worker : OutputStream(out->GetLocation()), out_(out), writer_(writer) { }
143*795d594fSAndroid Build Coastguard Worker
WriteFully(const void * buffer,size_t byte_count)144*795d594fSAndroid Build Coastguard Worker bool WriteFully(const void* buffer, size_t byte_count) override {
145*795d594fSAndroid Build Coastguard Worker if (buffer != nullptr) {
146*795d594fSAndroid Build Coastguard Worker const uint8_t* bytes = reinterpret_cast<const uint8_t*>(buffer);
147*795d594fSAndroid Build Coastguard Worker uint32_t old_checksum = writer_->oat_checksum_;
148*795d594fSAndroid Build Coastguard Worker writer_->oat_checksum_ = adler32(old_checksum, bytes, byte_count);
149*795d594fSAndroid Build Coastguard Worker } else {
150*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(0U, byte_count);
151*795d594fSAndroid Build Coastguard Worker }
152*795d594fSAndroid Build Coastguard Worker return out_->WriteFully(buffer, byte_count);
153*795d594fSAndroid Build Coastguard Worker }
154*795d594fSAndroid Build Coastguard Worker
Seek(off_t offset,Whence whence)155*795d594fSAndroid Build Coastguard Worker off_t Seek(off_t offset, Whence whence) override {
156*795d594fSAndroid Build Coastguard Worker return out_->Seek(offset, whence);
157*795d594fSAndroid Build Coastguard Worker }
158*795d594fSAndroid Build Coastguard Worker
Flush()159*795d594fSAndroid Build Coastguard Worker bool Flush() override {
160*795d594fSAndroid Build Coastguard Worker return out_->Flush();
161*795d594fSAndroid Build Coastguard Worker }
162*795d594fSAndroid Build Coastguard Worker
163*795d594fSAndroid Build Coastguard Worker private:
164*795d594fSAndroid Build Coastguard Worker OutputStream* const out_;
165*795d594fSAndroid Build Coastguard Worker OatWriter* const writer_;
166*795d594fSAndroid Build Coastguard Worker };
167*795d594fSAndroid Build Coastguard Worker
168*795d594fSAndroid Build Coastguard Worker // OatClassHeader is the header only part of the oat class that is required even when compilation
169*795d594fSAndroid Build Coastguard Worker // is not enabled.
170*795d594fSAndroid Build Coastguard Worker class OatWriter::OatClassHeader {
171*795d594fSAndroid Build Coastguard Worker public:
OatClassHeader(uint32_t offset,uint32_t num_non_null_compiled_methods,uint32_t num_methods,ClassStatus status)172*795d594fSAndroid Build Coastguard Worker OatClassHeader(uint32_t offset,
173*795d594fSAndroid Build Coastguard Worker uint32_t num_non_null_compiled_methods,
174*795d594fSAndroid Build Coastguard Worker uint32_t num_methods,
175*795d594fSAndroid Build Coastguard Worker ClassStatus status)
176*795d594fSAndroid Build Coastguard Worker : status_(enum_cast<uint16_t>(status)),
177*795d594fSAndroid Build Coastguard Worker offset_(offset) {
178*795d594fSAndroid Build Coastguard Worker // We just arbitrarily say that 0 methods means OatClassType::kNoneCompiled and that we won't
179*795d594fSAndroid Build Coastguard Worker // use OatClassType::kAllCompiled unless there is at least one compiled method. This means in
180*795d594fSAndroid Build Coastguard Worker // an interpreter only system, we can assert that all classes are OatClassType::kNoneCompiled.
181*795d594fSAndroid Build Coastguard Worker if (num_non_null_compiled_methods == 0) {
182*795d594fSAndroid Build Coastguard Worker type_ = enum_cast<uint16_t>(OatClassType::kNoneCompiled);
183*795d594fSAndroid Build Coastguard Worker } else if (num_non_null_compiled_methods == num_methods) {
184*795d594fSAndroid Build Coastguard Worker type_ = enum_cast<uint16_t>(OatClassType::kAllCompiled);
185*795d594fSAndroid Build Coastguard Worker } else {
186*795d594fSAndroid Build Coastguard Worker type_ = enum_cast<uint16_t>(OatClassType::kSomeCompiled);
187*795d594fSAndroid Build Coastguard Worker }
188*795d594fSAndroid Build Coastguard Worker }
189*795d594fSAndroid Build Coastguard Worker
190*795d594fSAndroid Build Coastguard Worker bool Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const;
191*795d594fSAndroid Build Coastguard Worker
SizeOf()192*795d594fSAndroid Build Coastguard Worker static size_t SizeOf() {
193*795d594fSAndroid Build Coastguard Worker return sizeof(status_) + sizeof(type_);
194*795d594fSAndroid Build Coastguard Worker }
195*795d594fSAndroid Build Coastguard Worker
196*795d594fSAndroid Build Coastguard Worker // Data to write.
197*795d594fSAndroid Build Coastguard Worker static_assert(sizeof(ClassStatus) <= sizeof(uint16_t), "class status won't fit in 16bits");
198*795d594fSAndroid Build Coastguard Worker uint16_t status_;
199*795d594fSAndroid Build Coastguard Worker
200*795d594fSAndroid Build Coastguard Worker static_assert(sizeof(OatClassType) <= sizeof(uint16_t), "oat_class type won't fit in 16bits");
201*795d594fSAndroid Build Coastguard Worker uint16_t type_;
202*795d594fSAndroid Build Coastguard Worker
203*795d594fSAndroid Build Coastguard Worker // Offset of start of OatClass from beginning of OatHeader. It is
204*795d594fSAndroid Build Coastguard Worker // used to validate file position when writing.
205*795d594fSAndroid Build Coastguard Worker uint32_t offset_;
206*795d594fSAndroid Build Coastguard Worker };
207*795d594fSAndroid Build Coastguard Worker
208*795d594fSAndroid Build Coastguard Worker // The actual oat class body contains the information about compiled methods. It is only required
209*795d594fSAndroid Build Coastguard Worker // for compiler filters that have any compilation.
210*795d594fSAndroid Build Coastguard Worker class OatWriter::OatClass {
211*795d594fSAndroid Build Coastguard Worker public:
212*795d594fSAndroid Build Coastguard Worker OatClass(const dchecked_vector<CompiledMethod*>& compiled_methods,
213*795d594fSAndroid Build Coastguard Worker uint32_t compiled_methods_with_code,
214*795d594fSAndroid Build Coastguard Worker uint16_t oat_class_type);
215*795d594fSAndroid Build Coastguard Worker OatClass(OatClass&& src) = default;
216*795d594fSAndroid Build Coastguard Worker size_t SizeOf() const;
217*795d594fSAndroid Build Coastguard Worker bool Write(OatWriter* oat_writer, OutputStream* out) const;
218*795d594fSAndroid Build Coastguard Worker
GetCompiledMethod(size_t class_def_method_index) const219*795d594fSAndroid Build Coastguard Worker CompiledMethod* GetCompiledMethod(size_t class_def_method_index) const {
220*795d594fSAndroid Build Coastguard Worker return compiled_methods_[class_def_method_index];
221*795d594fSAndroid Build Coastguard Worker }
222*795d594fSAndroid Build Coastguard Worker
223*795d594fSAndroid Build Coastguard Worker // CompiledMethods for each class_def_method_index, or null if no method is available.
224*795d594fSAndroid Build Coastguard Worker dchecked_vector<CompiledMethod*> compiled_methods_;
225*795d594fSAndroid Build Coastguard Worker
226*795d594fSAndroid Build Coastguard Worker // Offset from OatClass::offset_ to the OatMethodOffsets for the
227*795d594fSAndroid Build Coastguard Worker // class_def_method_index. If 0, it means the corresponding
228*795d594fSAndroid Build Coastguard Worker // CompiledMethod entry in OatClass::compiled_methods_ should be
229*795d594fSAndroid Build Coastguard Worker // null and that the OatClass::type_ should be OatClassType::kSomeCompiled.
230*795d594fSAndroid Build Coastguard Worker dchecked_vector<uint32_t> oat_method_offsets_offsets_from_oat_class_;
231*795d594fSAndroid Build Coastguard Worker
232*795d594fSAndroid Build Coastguard Worker // Data to write.
233*795d594fSAndroid Build Coastguard Worker
234*795d594fSAndroid Build Coastguard Worker // Number of methods recorded in OatClass. For `OatClassType::kNoneCompiled`
235*795d594fSAndroid Build Coastguard Worker // this shall be zero and shall not be written to the file, otherwise it
236*795d594fSAndroid Build Coastguard Worker // shall be the number of methods in the class definition. It is used to
237*795d594fSAndroid Build Coastguard Worker // determine the size of `BitVector` data for `OatClassType::kSomeCompiled` and
238*795d594fSAndroid Build Coastguard Worker // the size of the `OatMethodOffsets` table for `OatClassType::kAllCompiled`.
239*795d594fSAndroid Build Coastguard Worker // (The size of the `OatMethodOffsets` table for `OatClassType::kSomeCompiled`
240*795d594fSAndroid Build Coastguard Worker // is determined by the number of bits set in the `BitVector` data.)
241*795d594fSAndroid Build Coastguard Worker uint32_t num_methods_;
242*795d594fSAndroid Build Coastguard Worker
243*795d594fSAndroid Build Coastguard Worker // Bit vector indexed by ClassDef method index. When OatClass::type_ is
244*795d594fSAndroid Build Coastguard Worker // OatClassType::kSomeCompiled, a set bit indicates the method has an
245*795d594fSAndroid Build Coastguard Worker // OatMethodOffsets in methods_offsets_, otherwise
246*795d594fSAndroid Build Coastguard Worker // the entry was omitted to save space. If OatClass::type_ is
247*795d594fSAndroid Build Coastguard Worker // not is OatClassType::kSomeCompiled, the bitmap will be null.
248*795d594fSAndroid Build Coastguard Worker std::unique_ptr<BitVector> method_bitmap_;
249*795d594fSAndroid Build Coastguard Worker
250*795d594fSAndroid Build Coastguard Worker // OatMethodOffsets and OatMethodHeaders for each CompiledMethod
251*795d594fSAndroid Build Coastguard Worker // present in the OatClass. Note that some may be missing if
252*795d594fSAndroid Build Coastguard Worker // OatClass::compiled_methods_ contains null values (and
253*795d594fSAndroid Build Coastguard Worker // oat_method_offsets_offsets_from_oat_class_ should contain 0
254*795d594fSAndroid Build Coastguard Worker // values in this case).
255*795d594fSAndroid Build Coastguard Worker dchecked_vector<OatMethodOffsets> method_offsets_;
256*795d594fSAndroid Build Coastguard Worker dchecked_vector<OatQuickMethodHeader> method_headers_;
257*795d594fSAndroid Build Coastguard Worker
258*795d594fSAndroid Build Coastguard Worker private:
GetMethodOffsetsRawSize() const259*795d594fSAndroid Build Coastguard Worker size_t GetMethodOffsetsRawSize() const {
260*795d594fSAndroid Build Coastguard Worker return method_offsets_.size() * sizeof(method_offsets_[0]);
261*795d594fSAndroid Build Coastguard Worker }
262*795d594fSAndroid Build Coastguard Worker
263*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(OatClass);
264*795d594fSAndroid Build Coastguard Worker };
265*795d594fSAndroid Build Coastguard Worker
266*795d594fSAndroid Build Coastguard Worker class OatWriter::OatDexFile {
267*795d594fSAndroid Build Coastguard Worker public:
268*795d594fSAndroid Build Coastguard Worker explicit OatDexFile(std::unique_ptr<const DexFile> dex_file);
269*795d594fSAndroid Build Coastguard Worker OatDexFile(OatDexFile&& src) = default;
270*795d594fSAndroid Build Coastguard Worker
GetDexFile() const271*795d594fSAndroid Build Coastguard Worker const DexFile* GetDexFile() const { return dex_file_.get(); }
272*795d594fSAndroid Build Coastguard Worker
GetLocation() const273*795d594fSAndroid Build Coastguard Worker const char* GetLocation() const {
274*795d594fSAndroid Build Coastguard Worker return dex_file_location_data_;
275*795d594fSAndroid Build Coastguard Worker }
276*795d594fSAndroid Build Coastguard Worker
277*795d594fSAndroid Build Coastguard Worker size_t SizeOf() const;
278*795d594fSAndroid Build Coastguard Worker bool Write(OatWriter* oat_writer, OutputStream* out) const;
279*795d594fSAndroid Build Coastguard Worker bool WriteClassOffsets(OatWriter* oat_writer, OutputStream* out);
280*795d594fSAndroid Build Coastguard Worker
GetClassOffsetsRawSize() const281*795d594fSAndroid Build Coastguard Worker size_t GetClassOffsetsRawSize() const {
282*795d594fSAndroid Build Coastguard Worker return class_offsets_.size() * sizeof(class_offsets_[0]);
283*795d594fSAndroid Build Coastguard Worker }
284*795d594fSAndroid Build Coastguard Worker
285*795d594fSAndroid Build Coastguard Worker std::unique_ptr<const DexFile> dex_file_;
286*795d594fSAndroid Build Coastguard Worker std::unique_ptr<std::string> dex_file_location_;
287*795d594fSAndroid Build Coastguard Worker
288*795d594fSAndroid Build Coastguard Worker // Dex file size. Passed in the constructor.
289*795d594fSAndroid Build Coastguard Worker size_t dex_file_size_;
290*795d594fSAndroid Build Coastguard Worker
291*795d594fSAndroid Build Coastguard Worker // Offset of start of OatDexFile from beginning of OatHeader. It is
292*795d594fSAndroid Build Coastguard Worker // used to validate file position when writing.
293*795d594fSAndroid Build Coastguard Worker size_t offset_;
294*795d594fSAndroid Build Coastguard Worker
295*795d594fSAndroid Build Coastguard Worker ///// Start of data to write to vdex/oat file.
296*795d594fSAndroid Build Coastguard Worker
297*795d594fSAndroid Build Coastguard Worker const uint32_t dex_file_location_size_;
298*795d594fSAndroid Build Coastguard Worker const char* const dex_file_location_data_;
299*795d594fSAndroid Build Coastguard Worker
300*795d594fSAndroid Build Coastguard Worker DexFile::Magic dex_file_magic_;
301*795d594fSAndroid Build Coastguard Worker
302*795d594fSAndroid Build Coastguard Worker // The checksum of the dex file.
303*795d594fSAndroid Build Coastguard Worker const uint32_t dex_file_location_checksum_;
304*795d594fSAndroid Build Coastguard Worker const DexFile::Sha1 dex_file_sha1_;
305*795d594fSAndroid Build Coastguard Worker
306*795d594fSAndroid Build Coastguard Worker // Offset of the dex file in the vdex file. Set when writing dex files in
307*795d594fSAndroid Build Coastguard Worker // SeekToDexFile.
308*795d594fSAndroid Build Coastguard Worker uint32_t dex_file_offset_;
309*795d594fSAndroid Build Coastguard Worker
310*795d594fSAndroid Build Coastguard Worker // The lookup table offset in the oat file. Set in WriteTypeLookupTables.
311*795d594fSAndroid Build Coastguard Worker uint32_t lookup_table_offset_;
312*795d594fSAndroid Build Coastguard Worker
313*795d594fSAndroid Build Coastguard Worker // Class and BSS offsets set in PrepareLayout.
314*795d594fSAndroid Build Coastguard Worker uint32_t class_offsets_offset_;
315*795d594fSAndroid Build Coastguard Worker uint32_t method_bss_mapping_offset_;
316*795d594fSAndroid Build Coastguard Worker uint32_t type_bss_mapping_offset_;
317*795d594fSAndroid Build Coastguard Worker uint32_t public_type_bss_mapping_offset_;
318*795d594fSAndroid Build Coastguard Worker uint32_t package_type_bss_mapping_offset_;
319*795d594fSAndroid Build Coastguard Worker uint32_t string_bss_mapping_offset_;
320*795d594fSAndroid Build Coastguard Worker uint32_t method_type_bss_mapping_offset_;
321*795d594fSAndroid Build Coastguard Worker
322*795d594fSAndroid Build Coastguard Worker // Offset of dex sections that will have different runtime madvise states.
323*795d594fSAndroid Build Coastguard Worker // Set in WriteDexLayoutSections.
324*795d594fSAndroid Build Coastguard Worker uint32_t dex_sections_layout_offset_;
325*795d594fSAndroid Build Coastguard Worker
326*795d594fSAndroid Build Coastguard Worker // Data to write to a separate section. We set the length
327*795d594fSAndroid Build Coastguard Worker // of the vector in OpenDexFiles.
328*795d594fSAndroid Build Coastguard Worker dchecked_vector<uint32_t> class_offsets_;
329*795d594fSAndroid Build Coastguard Worker
330*795d594fSAndroid Build Coastguard Worker // Dex section layout info to serialize.
331*795d594fSAndroid Build Coastguard Worker DexLayoutSections dex_sections_layout_;
332*795d594fSAndroid Build Coastguard Worker
333*795d594fSAndroid Build Coastguard Worker ///// End of data to write to vdex/oat file.
334*795d594fSAndroid Build Coastguard Worker private:
335*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(OatDexFile);
336*795d594fSAndroid Build Coastguard Worker };
337*795d594fSAndroid Build Coastguard Worker
338*795d594fSAndroid Build Coastguard Worker #define DCHECK_OFFSET() \
339*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out->Seek(0, kSeekCurrent)) \
340*795d594fSAndroid Build Coastguard Worker << "file_offset=" << file_offset << " relative_offset=" << relative_offset
341*795d594fSAndroid Build Coastguard Worker
342*795d594fSAndroid Build Coastguard Worker #define DCHECK_OFFSET_() \
343*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \
344*795d594fSAndroid Build Coastguard Worker << "file_offset=" << file_offset << " offset_=" << offset_
345*795d594fSAndroid Build Coastguard Worker
OatWriter(const CompilerOptions & compiler_options,TimingLogger * timings,ProfileCompilationInfo * info)346*795d594fSAndroid Build Coastguard Worker OatWriter::OatWriter(const CompilerOptions& compiler_options,
347*795d594fSAndroid Build Coastguard Worker TimingLogger* timings,
348*795d594fSAndroid Build Coastguard Worker ProfileCompilationInfo* info)
349*795d594fSAndroid Build Coastguard Worker : write_state_(WriteState::kAddingDexFileSources),
350*795d594fSAndroid Build Coastguard Worker timings_(timings),
351*795d594fSAndroid Build Coastguard Worker compiler_driver_(nullptr),
352*795d594fSAndroid Build Coastguard Worker compiler_options_(compiler_options),
353*795d594fSAndroid Build Coastguard Worker verification_results_(nullptr),
354*795d594fSAndroid Build Coastguard Worker image_writer_(nullptr),
355*795d594fSAndroid Build Coastguard Worker extract_dex_files_into_vdex_(true),
356*795d594fSAndroid Build Coastguard Worker vdex_begin_(nullptr),
357*795d594fSAndroid Build Coastguard Worker dex_files_(nullptr),
358*795d594fSAndroid Build Coastguard Worker primary_oat_file_(false),
359*795d594fSAndroid Build Coastguard Worker vdex_size_(0u),
360*795d594fSAndroid Build Coastguard Worker vdex_dex_files_offset_(0u),
361*795d594fSAndroid Build Coastguard Worker vdex_verifier_deps_offset_(0u),
362*795d594fSAndroid Build Coastguard Worker vdex_lookup_tables_offset_(0u),
363*795d594fSAndroid Build Coastguard Worker oat_checksum_(adler32(0L, Z_NULL, 0)),
364*795d594fSAndroid Build Coastguard Worker code_size_(0u),
365*795d594fSAndroid Build Coastguard Worker oat_size_(0u),
366*795d594fSAndroid Build Coastguard Worker data_img_rel_ro_start_(0u),
367*795d594fSAndroid Build Coastguard Worker data_img_rel_ro_size_(0u),
368*795d594fSAndroid Build Coastguard Worker data_img_rel_ro_app_image_offset_(0u),
369*795d594fSAndroid Build Coastguard Worker bss_start_(0u),
370*795d594fSAndroid Build Coastguard Worker bss_size_(0u),
371*795d594fSAndroid Build Coastguard Worker bss_methods_offset_(0u),
372*795d594fSAndroid Build Coastguard Worker bss_roots_offset_(0u),
373*795d594fSAndroid Build Coastguard Worker boot_image_rel_ro_entries_(),
374*795d594fSAndroid Build Coastguard Worker bss_method_entry_references_(),
375*795d594fSAndroid Build Coastguard Worker bss_type_entry_references_(),
376*795d594fSAndroid Build Coastguard Worker bss_public_type_entry_references_(),
377*795d594fSAndroid Build Coastguard Worker bss_package_type_entry_references_(),
378*795d594fSAndroid Build Coastguard Worker bss_string_entry_references_(),
379*795d594fSAndroid Build Coastguard Worker bss_method_type_entry_references_(),
380*795d594fSAndroid Build Coastguard Worker app_image_rel_ro_method_entries_(),
381*795d594fSAndroid Build Coastguard Worker bss_method_entries_(),
382*795d594fSAndroid Build Coastguard Worker app_image_rel_ro_type_entries_(),
383*795d594fSAndroid Build Coastguard Worker bss_type_entries_(),
384*795d594fSAndroid Build Coastguard Worker bss_public_type_entries_(),
385*795d594fSAndroid Build Coastguard Worker bss_package_type_entries_(),
386*795d594fSAndroid Build Coastguard Worker bss_string_entries_(),
387*795d594fSAndroid Build Coastguard Worker bss_method_type_entries_(),
388*795d594fSAndroid Build Coastguard Worker oat_data_offset_(0u),
389*795d594fSAndroid Build Coastguard Worker oat_header_(nullptr),
390*795d594fSAndroid Build Coastguard Worker relative_patcher_(nullptr),
391*795d594fSAndroid Build Coastguard Worker profile_compilation_info_(info) {}
392*795d594fSAndroid Build Coastguard Worker
ValidateDexFileHeader(const uint8_t * raw_header,const char * location)393*795d594fSAndroid Build Coastguard Worker static bool ValidateDexFileHeader(const uint8_t* raw_header, const char* location) {
394*795d594fSAndroid Build Coastguard Worker const bool valid_standard_dex_magic = DexFileLoader::IsMagicValid(raw_header);
395*795d594fSAndroid Build Coastguard Worker if (!valid_standard_dex_magic) {
396*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Invalid magic number in dex file header. " << " File: " << location;
397*795d594fSAndroid Build Coastguard Worker return false;
398*795d594fSAndroid Build Coastguard Worker }
399*795d594fSAndroid Build Coastguard Worker if (!DexFileLoader::IsVersionAndMagicValid(raw_header)) {
400*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Invalid version number in dex file header. " << " File: " << location;
401*795d594fSAndroid Build Coastguard Worker return false;
402*795d594fSAndroid Build Coastguard Worker }
403*795d594fSAndroid Build Coastguard Worker const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_header);
404*795d594fSAndroid Build Coastguard Worker if (header->file_size_ < sizeof(DexFile::Header)) {
405*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Dex file header specifies file size insufficient to contain the header."
406*795d594fSAndroid Build Coastguard Worker << " File: " << location;
407*795d594fSAndroid Build Coastguard Worker return false;
408*795d594fSAndroid Build Coastguard Worker }
409*795d594fSAndroid Build Coastguard Worker return true;
410*795d594fSAndroid Build Coastguard Worker }
411*795d594fSAndroid Build Coastguard Worker
AddDexFileSource(const char * filename,const char * location)412*795d594fSAndroid Build Coastguard Worker bool OatWriter::AddDexFileSource(const char* filename, const char* location) {
413*795d594fSAndroid Build Coastguard Worker DCHECK(write_state_ == WriteState::kAddingDexFileSources);
414*795d594fSAndroid Build Coastguard Worker File fd(filename, O_RDONLY, /* check_usage= */ false);
415*795d594fSAndroid Build Coastguard Worker if (fd.Fd() == -1) {
416*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to open dex file: '" << filename << "'";
417*795d594fSAndroid Build Coastguard Worker return false;
418*795d594fSAndroid Build Coastguard Worker }
419*795d594fSAndroid Build Coastguard Worker
420*795d594fSAndroid Build Coastguard Worker return AddDexFileSource(std::move(fd), location);
421*795d594fSAndroid Build Coastguard Worker }
422*795d594fSAndroid Build Coastguard Worker
423*795d594fSAndroid Build Coastguard Worker // Add dex file source(s) from a file specified by a file handle.
424*795d594fSAndroid Build Coastguard Worker // Note: The `dex_file_fd` specifies a plain dex file or a zip file.
AddDexFileSource(File && dex_file_fd,const char * location)425*795d594fSAndroid Build Coastguard Worker bool OatWriter::AddDexFileSource(File&& dex_file_fd, const char* location) {
426*795d594fSAndroid Build Coastguard Worker DCHECK(write_state_ == WriteState::kAddingDexFileSources);
427*795d594fSAndroid Build Coastguard Worker std::string error_msg;
428*795d594fSAndroid Build Coastguard Worker ArtDexFileLoader loader(&dex_file_fd, location);
429*795d594fSAndroid Build Coastguard Worker std::vector<std::unique_ptr<const DexFile>> dex_files;
430*795d594fSAndroid Build Coastguard Worker if (!loader.Open(/*verify=*/false,
431*795d594fSAndroid Build Coastguard Worker /*verify_checksum=*/false,
432*795d594fSAndroid Build Coastguard Worker &error_msg,
433*795d594fSAndroid Build Coastguard Worker &dex_files)) {
434*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed to open dex file '" << location << "': " << error_msg;
435*795d594fSAndroid Build Coastguard Worker return false;
436*795d594fSAndroid Build Coastguard Worker }
437*795d594fSAndroid Build Coastguard Worker for (auto& dex_file : dex_files) {
438*795d594fSAndroid Build Coastguard Worker oat_dex_files_.emplace_back(std::move(dex_file));
439*795d594fSAndroid Build Coastguard Worker }
440*795d594fSAndroid Build Coastguard Worker return true;
441*795d594fSAndroid Build Coastguard Worker }
442*795d594fSAndroid Build Coastguard Worker
443*795d594fSAndroid Build Coastguard Worker // Add dex file source(s) from a vdex file specified by a file handle.
AddVdexDexFilesSource(const VdexFile & vdex_file,const char * location)444*795d594fSAndroid Build Coastguard Worker bool OatWriter::AddVdexDexFilesSource(const VdexFile& vdex_file, const char* location) {
445*795d594fSAndroid Build Coastguard Worker DCHECK(write_state_ == WriteState::kAddingDexFileSources);
446*795d594fSAndroid Build Coastguard Worker DCHECK(vdex_file.HasDexSection());
447*795d594fSAndroid Build Coastguard Worker auto container = std::make_shared<MemoryDexFileContainer>(vdex_file.Begin(), vdex_file.End());
448*795d594fSAndroid Build Coastguard Worker const uint8_t* current_dex_data = nullptr;
449*795d594fSAndroid Build Coastguard Worker size_t i = 0;
450*795d594fSAndroid Build Coastguard Worker for (; i < vdex_file.GetNumberOfDexFiles(); ++i) {
451*795d594fSAndroid Build Coastguard Worker current_dex_data = vdex_file.GetNextDexFileData(current_dex_data, i);
452*795d594fSAndroid Build Coastguard Worker if (current_dex_data == nullptr) {
453*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
454*795d594fSAndroid Build Coastguard Worker return false;
455*795d594fSAndroid Build Coastguard Worker }
456*795d594fSAndroid Build Coastguard Worker
457*795d594fSAndroid Build Coastguard Worker if (!DexFileLoader::IsMagicValid(current_dex_data)) {
458*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Invalid magic in vdex file created from " << location;
459*795d594fSAndroid Build Coastguard Worker return false;
460*795d594fSAndroid Build Coastguard Worker }
461*795d594fSAndroid Build Coastguard Worker // We used `zipped_dex_file_locations_` to keep the strings in memory.
462*795d594fSAndroid Build Coastguard Worker std::string multidex_location = DexFileLoader::GetMultiDexLocation(i, location);
463*795d594fSAndroid Build Coastguard Worker if (!AddRawDexFileSource(container,
464*795d594fSAndroid Build Coastguard Worker current_dex_data,
465*795d594fSAndroid Build Coastguard Worker multidex_location.c_str(),
466*795d594fSAndroid Build Coastguard Worker vdex_file.GetLocationChecksum(i))) {
467*795d594fSAndroid Build Coastguard Worker return false;
468*795d594fSAndroid Build Coastguard Worker }
469*795d594fSAndroid Build Coastguard Worker }
470*795d594fSAndroid Build Coastguard Worker
471*795d594fSAndroid Build Coastguard Worker if (vdex_file.GetNextDexFileData(current_dex_data, i) != nullptr) {
472*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
473*795d594fSAndroid Build Coastguard Worker return false;
474*795d594fSAndroid Build Coastguard Worker }
475*795d594fSAndroid Build Coastguard Worker
476*795d594fSAndroid Build Coastguard Worker if (oat_dex_files_.empty()) {
477*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "No dex files in vdex file created from " << location;
478*795d594fSAndroid Build Coastguard Worker return false;
479*795d594fSAndroid Build Coastguard Worker }
480*795d594fSAndroid Build Coastguard Worker return true;
481*795d594fSAndroid Build Coastguard Worker }
482*795d594fSAndroid Build Coastguard Worker
483*795d594fSAndroid Build Coastguard Worker // Add dex file source from raw memory.
AddRawDexFileSource(const std::shared_ptr<DexFileContainer> & container,const uint8_t * dex_file_begin,const char * location,uint32_t location_checksum)484*795d594fSAndroid Build Coastguard Worker bool OatWriter::AddRawDexFileSource(const std::shared_ptr<DexFileContainer>& container,
485*795d594fSAndroid Build Coastguard Worker const uint8_t* dex_file_begin,
486*795d594fSAndroid Build Coastguard Worker const char* location,
487*795d594fSAndroid Build Coastguard Worker uint32_t location_checksum) {
488*795d594fSAndroid Build Coastguard Worker DCHECK(write_state_ == WriteState::kAddingDexFileSources);
489*795d594fSAndroid Build Coastguard Worker std::string error_msg;
490*795d594fSAndroid Build Coastguard Worker ArtDexFileLoader loader(container->Begin(), container->Size(), location);
491*795d594fSAndroid Build Coastguard Worker CHECK_GE(dex_file_begin, container->Begin());
492*795d594fSAndroid Build Coastguard Worker CHECK_LE(dex_file_begin, container->End());
493*795d594fSAndroid Build Coastguard Worker auto dex_file = loader.OpenOne(dex_file_begin - container->Begin(),
494*795d594fSAndroid Build Coastguard Worker location_checksum,
495*795d594fSAndroid Build Coastguard Worker nullptr,
496*795d594fSAndroid Build Coastguard Worker /*verify=*/false,
497*795d594fSAndroid Build Coastguard Worker /*verify_checksum=*/false,
498*795d594fSAndroid Build Coastguard Worker &error_msg);
499*795d594fSAndroid Build Coastguard Worker if (dex_file == nullptr) {
500*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed to open dex file '" << location << "': " << error_msg;
501*795d594fSAndroid Build Coastguard Worker return false;
502*795d594fSAndroid Build Coastguard Worker }
503*795d594fSAndroid Build Coastguard Worker oat_dex_files_.emplace_back(std::move(dex_file));
504*795d594fSAndroid Build Coastguard Worker return true;
505*795d594fSAndroid Build Coastguard Worker }
506*795d594fSAndroid Build Coastguard Worker
GetSourceLocations() const507*795d594fSAndroid Build Coastguard Worker dchecked_vector<std::string> OatWriter::GetSourceLocations() const {
508*795d594fSAndroid Build Coastguard Worker dchecked_vector<std::string> locations;
509*795d594fSAndroid Build Coastguard Worker locations.reserve(oat_dex_files_.size());
510*795d594fSAndroid Build Coastguard Worker for (const OatDexFile& oat_dex_file : oat_dex_files_) {
511*795d594fSAndroid Build Coastguard Worker locations.push_back(oat_dex_file.GetLocation());
512*795d594fSAndroid Build Coastguard Worker }
513*795d594fSAndroid Build Coastguard Worker return locations;
514*795d594fSAndroid Build Coastguard Worker }
515*795d594fSAndroid Build Coastguard Worker
MayHaveCompiledMethods() const516*795d594fSAndroid Build Coastguard Worker bool OatWriter::MayHaveCompiledMethods() const {
517*795d594fSAndroid Build Coastguard Worker return GetCompilerOptions().IsAnyCompilationEnabled();
518*795d594fSAndroid Build Coastguard Worker }
519*795d594fSAndroid Build Coastguard Worker
WriteAndOpenDexFiles(File * vdex_file,bool verify,bool use_existing_vdex,CopyOption copy_dex_files,std::vector<MemMap> * opened_dex_files_map,std::vector<std::unique_ptr<const DexFile>> * opened_dex_files)520*795d594fSAndroid Build Coastguard Worker bool OatWriter::WriteAndOpenDexFiles(
521*795d594fSAndroid Build Coastguard Worker File* vdex_file,
522*795d594fSAndroid Build Coastguard Worker bool verify,
523*795d594fSAndroid Build Coastguard Worker bool use_existing_vdex,
524*795d594fSAndroid Build Coastguard Worker CopyOption copy_dex_files,
525*795d594fSAndroid Build Coastguard Worker /*out*/ std::vector<MemMap>* opened_dex_files_map,
526*795d594fSAndroid Build Coastguard Worker /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
527*795d594fSAndroid Build Coastguard Worker CHECK(write_state_ == WriteState::kAddingDexFileSources);
528*795d594fSAndroid Build Coastguard Worker
529*795d594fSAndroid Build Coastguard Worker // Reserve space for Vdex header, sections, and checksums.
530*795d594fSAndroid Build Coastguard Worker size_vdex_header_ = sizeof(VdexFile::VdexFileHeader) +
531*795d594fSAndroid Build Coastguard Worker VdexSection::kNumberOfSections * sizeof(VdexFile::VdexSectionHeader);
532*795d594fSAndroid Build Coastguard Worker size_vdex_checksums_ = oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum);
533*795d594fSAndroid Build Coastguard Worker vdex_size_ = size_vdex_header_ + size_vdex_checksums_;
534*795d594fSAndroid Build Coastguard Worker
535*795d594fSAndroid Build Coastguard Worker // Write DEX files into VDEX, mmap and open them.
536*795d594fSAndroid Build Coastguard Worker std::vector<MemMap> dex_files_map;
537*795d594fSAndroid Build Coastguard Worker std::vector<std::unique_ptr<const DexFile>> dex_files;
538*795d594fSAndroid Build Coastguard Worker if (!WriteDexFiles(vdex_file, verify, use_existing_vdex, copy_dex_files, &dex_files_map) ||
539*795d594fSAndroid Build Coastguard Worker !OpenDexFiles(vdex_file, &dex_files_map, &dex_files)) {
540*795d594fSAndroid Build Coastguard Worker return false;
541*795d594fSAndroid Build Coastguard Worker }
542*795d594fSAndroid Build Coastguard Worker
543*795d594fSAndroid Build Coastguard Worker *opened_dex_files_map = std::move(dex_files_map);
544*795d594fSAndroid Build Coastguard Worker *opened_dex_files = std::move(dex_files);
545*795d594fSAndroid Build Coastguard Worker // Create type lookup tables to speed up lookups during compilation.
546*795d594fSAndroid Build Coastguard Worker InitializeTypeLookupTables(*opened_dex_files);
547*795d594fSAndroid Build Coastguard Worker write_state_ = WriteState::kStartRoData;
548*795d594fSAndroid Build Coastguard Worker return true;
549*795d594fSAndroid Build Coastguard Worker }
550*795d594fSAndroid Build Coastguard Worker
StartRoData(const std::vector<const DexFile * > & dex_files,OutputStream * oat_rodata,SafeMap<std::string,std::string> * key_value_store)551*795d594fSAndroid Build Coastguard Worker bool OatWriter::StartRoData(const std::vector<const DexFile*>& dex_files,
552*795d594fSAndroid Build Coastguard Worker OutputStream* oat_rodata,
553*795d594fSAndroid Build Coastguard Worker SafeMap<std::string, std::string>* key_value_store) {
554*795d594fSAndroid Build Coastguard Worker CHECK(write_state_ == WriteState::kStartRoData);
555*795d594fSAndroid Build Coastguard Worker
556*795d594fSAndroid Build Coastguard Worker // Record the ELF rodata section offset, i.e. the beginning of the OAT data.
557*795d594fSAndroid Build Coastguard Worker if (!RecordOatDataOffset(oat_rodata)) {
558*795d594fSAndroid Build Coastguard Worker return false;
559*795d594fSAndroid Build Coastguard Worker }
560*795d594fSAndroid Build Coastguard Worker
561*795d594fSAndroid Build Coastguard Worker // Record whether this is the primary oat file.
562*795d594fSAndroid Build Coastguard Worker primary_oat_file_ = (key_value_store != nullptr);
563*795d594fSAndroid Build Coastguard Worker
564*795d594fSAndroid Build Coastguard Worker // Initialize OAT header.
565*795d594fSAndroid Build Coastguard Worker oat_size_ = InitOatHeader(dchecked_integral_cast<uint32_t>(oat_dex_files_.size()),
566*795d594fSAndroid Build Coastguard Worker key_value_store);
567*795d594fSAndroid Build Coastguard Worker
568*795d594fSAndroid Build Coastguard Worker ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, this);
569*795d594fSAndroid Build Coastguard Worker
570*795d594fSAndroid Build Coastguard Worker // Write dex layout sections into the oat file.
571*795d594fSAndroid Build Coastguard Worker if (!WriteDexLayoutSections(&checksum_updating_rodata, dex_files)) {
572*795d594fSAndroid Build Coastguard Worker return false;
573*795d594fSAndroid Build Coastguard Worker }
574*795d594fSAndroid Build Coastguard Worker
575*795d594fSAndroid Build Coastguard Worker write_state_ = WriteState::kInitialize;
576*795d594fSAndroid Build Coastguard Worker return true;
577*795d594fSAndroid Build Coastguard Worker }
578*795d594fSAndroid Build Coastguard Worker
579*795d594fSAndroid Build Coastguard Worker // Initialize the writer with the given parameters.
Initialize(const CompilerDriver * compiler_driver,const VerificationResults * verification_results,ImageWriter * image_writer,const std::vector<const DexFile * > & dex_files)580*795d594fSAndroid Build Coastguard Worker void OatWriter::Initialize(const CompilerDriver* compiler_driver,
581*795d594fSAndroid Build Coastguard Worker const VerificationResults* verification_results,
582*795d594fSAndroid Build Coastguard Worker ImageWriter* image_writer,
583*795d594fSAndroid Build Coastguard Worker const std::vector<const DexFile*>& dex_files) {
584*795d594fSAndroid Build Coastguard Worker CHECK(write_state_ == WriteState::kInitialize);
585*795d594fSAndroid Build Coastguard Worker compiler_driver_ = compiler_driver;
586*795d594fSAndroid Build Coastguard Worker verification_results_ = verification_results;
587*795d594fSAndroid Build Coastguard Worker image_writer_ = image_writer;
588*795d594fSAndroid Build Coastguard Worker dex_files_ = &dex_files;
589*795d594fSAndroid Build Coastguard Worker write_state_ = WriteState::kPrepareLayout;
590*795d594fSAndroid Build Coastguard Worker }
591*795d594fSAndroid Build Coastguard Worker
PrepareLayout(MultiOatRelativePatcher * relative_patcher)592*795d594fSAndroid Build Coastguard Worker void OatWriter::PrepareLayout(MultiOatRelativePatcher* relative_patcher) {
593*795d594fSAndroid Build Coastguard Worker CHECK(write_state_ == WriteState::kPrepareLayout);
594*795d594fSAndroid Build Coastguard Worker
595*795d594fSAndroid Build Coastguard Worker relative_patcher_ = relative_patcher;
596*795d594fSAndroid Build Coastguard Worker SetMultiOatRelativePatcherAdjustment();
597*795d594fSAndroid Build Coastguard Worker
598*795d594fSAndroid Build Coastguard Worker if (GetCompilerOptions().IsBootImage() || GetCompilerOptions().IsBootImageExtension()) {
599*795d594fSAndroid Build Coastguard Worker CHECK(image_writer_ != nullptr);
600*795d594fSAndroid Build Coastguard Worker }
601*795d594fSAndroid Build Coastguard Worker InstructionSet instruction_set = compiler_options_.GetInstructionSet();
602*795d594fSAndroid Build Coastguard Worker CHECK_EQ(instruction_set, oat_header_->GetInstructionSet());
603*795d594fSAndroid Build Coastguard Worker
604*795d594fSAndroid Build Coastguard Worker {
605*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split("InitBssLayout", timings_);
606*795d594fSAndroid Build Coastguard Worker InitBssLayout(instruction_set);
607*795d594fSAndroid Build Coastguard Worker }
608*795d594fSAndroid Build Coastguard Worker
609*795d594fSAndroid Build Coastguard Worker uint32_t offset = oat_size_;
610*795d594fSAndroid Build Coastguard Worker {
611*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split("InitClassOffsets", timings_);
612*795d594fSAndroid Build Coastguard Worker offset = InitClassOffsets(offset);
613*795d594fSAndroid Build Coastguard Worker }
614*795d594fSAndroid Build Coastguard Worker {
615*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split("InitOatClasses", timings_);
616*795d594fSAndroid Build Coastguard Worker offset = InitOatClasses(offset);
617*795d594fSAndroid Build Coastguard Worker }
618*795d594fSAndroid Build Coastguard Worker {
619*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split("InitIndexBssMappings", timings_);
620*795d594fSAndroid Build Coastguard Worker offset = InitIndexBssMappings(offset);
621*795d594fSAndroid Build Coastguard Worker }
622*795d594fSAndroid Build Coastguard Worker {
623*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split("InitOatMaps", timings_);
624*795d594fSAndroid Build Coastguard Worker offset = InitOatMaps(offset);
625*795d594fSAndroid Build Coastguard Worker }
626*795d594fSAndroid Build Coastguard Worker {
627*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split("InitOatDexFiles", timings_);
628*795d594fSAndroid Build Coastguard Worker oat_header_->SetOatDexFilesOffset(offset);
629*795d594fSAndroid Build Coastguard Worker offset = InitOatDexFiles(offset);
630*795d594fSAndroid Build Coastguard Worker }
631*795d594fSAndroid Build Coastguard Worker {
632*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split("InitBcpBssInfo", timings_);
633*795d594fSAndroid Build Coastguard Worker offset = InitBcpBssInfo(offset);
634*795d594fSAndroid Build Coastguard Worker }
635*795d594fSAndroid Build Coastguard Worker {
636*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split("InitOatCode", timings_);
637*795d594fSAndroid Build Coastguard Worker offset = InitOatCode(offset);
638*795d594fSAndroid Build Coastguard Worker }
639*795d594fSAndroid Build Coastguard Worker {
640*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split("InitOatCodeDexFiles", timings_);
641*795d594fSAndroid Build Coastguard Worker offset = InitOatCodeDexFiles(offset);
642*795d594fSAndroid Build Coastguard Worker code_size_ = offset - GetOatHeader().GetExecutableOffset();
643*795d594fSAndroid Build Coastguard Worker }
644*795d594fSAndroid Build Coastguard Worker {
645*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split("InitDataImgRelRoLayout", timings_);
646*795d594fSAndroid Build Coastguard Worker offset = InitDataImgRelRoLayout(offset);
647*795d594fSAndroid Build Coastguard Worker }
648*795d594fSAndroid Build Coastguard Worker oat_size_ = offset; // .bss does not count towards oat_size_.
649*795d594fSAndroid Build Coastguard Worker bss_start_ = (bss_size_ != 0u) ? RoundUp(oat_size_, kElfSegmentAlignment) : 0u;
650*795d594fSAndroid Build Coastguard Worker
651*795d594fSAndroid Build Coastguard Worker CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
652*795d594fSAndroid Build Coastguard Worker
653*795d594fSAndroid Build Coastguard Worker write_state_ = WriteState::kWriteRoData;
654*795d594fSAndroid Build Coastguard Worker }
655*795d594fSAndroid Build Coastguard Worker
~OatWriter()656*795d594fSAndroid Build Coastguard Worker OatWriter::~OatWriter() {
657*795d594fSAndroid Build Coastguard Worker }
658*795d594fSAndroid Build Coastguard Worker
659*795d594fSAndroid Build Coastguard Worker class OatWriter::DexMethodVisitor {
660*795d594fSAndroid Build Coastguard Worker public:
DexMethodVisitor(OatWriter * writer,size_t offset)661*795d594fSAndroid Build Coastguard Worker DexMethodVisitor(OatWriter* writer, size_t offset)
662*795d594fSAndroid Build Coastguard Worker : writer_(writer),
663*795d594fSAndroid Build Coastguard Worker offset_(offset),
664*795d594fSAndroid Build Coastguard Worker dex_file_(nullptr),
665*795d594fSAndroid Build Coastguard Worker class_def_index_(dex::kDexNoIndex) {}
666*795d594fSAndroid Build Coastguard Worker
StartClass(const DexFile * dex_file,size_t class_def_index)667*795d594fSAndroid Build Coastguard Worker virtual bool StartClass(const DexFile* dex_file, size_t class_def_index) {
668*795d594fSAndroid Build Coastguard Worker DCHECK(dex_file_ == nullptr);
669*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(class_def_index_, dex::kDexNoIndex);
670*795d594fSAndroid Build Coastguard Worker dex_file_ = dex_file;
671*795d594fSAndroid Build Coastguard Worker class_def_index_ = class_def_index;
672*795d594fSAndroid Build Coastguard Worker return true;
673*795d594fSAndroid Build Coastguard Worker }
674*795d594fSAndroid Build Coastguard Worker
675*795d594fSAndroid Build Coastguard Worker virtual bool VisitMethod(size_t class_def_method_index, const ClassAccessor::Method& method) = 0;
676*795d594fSAndroid Build Coastguard Worker
EndClass()677*795d594fSAndroid Build Coastguard Worker virtual bool EndClass() {
678*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
679*795d594fSAndroid Build Coastguard Worker dex_file_ = nullptr;
680*795d594fSAndroid Build Coastguard Worker class_def_index_ = dex::kDexNoIndex;
681*795d594fSAndroid Build Coastguard Worker }
682*795d594fSAndroid Build Coastguard Worker return true;
683*795d594fSAndroid Build Coastguard Worker }
684*795d594fSAndroid Build Coastguard Worker
GetOffset() const685*795d594fSAndroid Build Coastguard Worker size_t GetOffset() const {
686*795d594fSAndroid Build Coastguard Worker return offset_;
687*795d594fSAndroid Build Coastguard Worker }
688*795d594fSAndroid Build Coastguard Worker
689*795d594fSAndroid Build Coastguard Worker protected:
~DexMethodVisitor()690*795d594fSAndroid Build Coastguard Worker virtual ~DexMethodVisitor() { }
691*795d594fSAndroid Build Coastguard Worker
692*795d594fSAndroid Build Coastguard Worker OatWriter* const writer_;
693*795d594fSAndroid Build Coastguard Worker
694*795d594fSAndroid Build Coastguard Worker // The offset is usually advanced for each visited method by the derived class.
695*795d594fSAndroid Build Coastguard Worker size_t offset_;
696*795d594fSAndroid Build Coastguard Worker
697*795d594fSAndroid Build Coastguard Worker // The dex file and class def index are set in StartClass().
698*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file_;
699*795d594fSAndroid Build Coastguard Worker size_t class_def_index_;
700*795d594fSAndroid Build Coastguard Worker };
701*795d594fSAndroid Build Coastguard Worker
702*795d594fSAndroid Build Coastguard Worker class OatWriter::OatDexMethodVisitor : public DexMethodVisitor {
703*795d594fSAndroid Build Coastguard Worker public:
OatDexMethodVisitor(OatWriter * writer,size_t offset)704*795d594fSAndroid Build Coastguard Worker OatDexMethodVisitor(OatWriter* writer, size_t offset)
705*795d594fSAndroid Build Coastguard Worker : DexMethodVisitor(writer, offset),
706*795d594fSAndroid Build Coastguard Worker oat_class_index_(0u),
707*795d594fSAndroid Build Coastguard Worker method_offsets_index_(0u) {}
708*795d594fSAndroid Build Coastguard Worker
StartClass(const DexFile * dex_file,size_t class_def_index)709*795d594fSAndroid Build Coastguard Worker bool StartClass(const DexFile* dex_file, size_t class_def_index) override {
710*795d594fSAndroid Build Coastguard Worker DexMethodVisitor::StartClass(dex_file, class_def_index);
711*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild && writer_->MayHaveCompiledMethods()) {
712*795d594fSAndroid Build Coastguard Worker // There are no oat classes if there aren't any compiled methods.
713*795d594fSAndroid Build Coastguard Worker CHECK_LT(oat_class_index_, writer_->oat_classes_.size());
714*795d594fSAndroid Build Coastguard Worker }
715*795d594fSAndroid Build Coastguard Worker method_offsets_index_ = 0u;
716*795d594fSAndroid Build Coastguard Worker return true;
717*795d594fSAndroid Build Coastguard Worker }
718*795d594fSAndroid Build Coastguard Worker
EndClass()719*795d594fSAndroid Build Coastguard Worker bool EndClass() override {
720*795d594fSAndroid Build Coastguard Worker ++oat_class_index_;
721*795d594fSAndroid Build Coastguard Worker return DexMethodVisitor::EndClass();
722*795d594fSAndroid Build Coastguard Worker }
723*795d594fSAndroid Build Coastguard Worker
724*795d594fSAndroid Build Coastguard Worker protected:
725*795d594fSAndroid Build Coastguard Worker size_t oat_class_index_;
726*795d594fSAndroid Build Coastguard Worker size_t method_offsets_index_;
727*795d594fSAndroid Build Coastguard Worker };
728*795d594fSAndroid Build Coastguard Worker
HasCompiledCode(const CompiledMethod * method)729*795d594fSAndroid Build Coastguard Worker static bool HasCompiledCode(const CompiledMethod* method) {
730*795d594fSAndroid Build Coastguard Worker return method != nullptr && !method->GetQuickCode().empty();
731*795d594fSAndroid Build Coastguard Worker }
732*795d594fSAndroid Build Coastguard Worker
733*795d594fSAndroid Build Coastguard Worker class OatWriter::InitBssLayoutMethodVisitor : public DexMethodVisitor {
734*795d594fSAndroid Build Coastguard Worker public:
InitBssLayoutMethodVisitor(OatWriter * writer)735*795d594fSAndroid Build Coastguard Worker explicit InitBssLayoutMethodVisitor(OatWriter* writer)
736*795d594fSAndroid Build Coastguard Worker : DexMethodVisitor(writer, /* offset */ 0u) {}
737*795d594fSAndroid Build Coastguard Worker
VisitMethod(size_t class_def_method_index,const ClassAccessor::Method & method)738*795d594fSAndroid Build Coastguard Worker bool VisitMethod([[maybe_unused]] size_t class_def_method_index,
739*795d594fSAndroid Build Coastguard Worker const ClassAccessor::Method& method) override {
740*795d594fSAndroid Build Coastguard Worker // Look for patches with .bss references and prepare maps with placeholders for their offsets.
741*795d594fSAndroid Build Coastguard Worker CompiledMethod* compiled_method = writer_->compiler_driver_->GetCompiledMethod(
742*795d594fSAndroid Build Coastguard Worker MethodReference(dex_file_, method.GetIndex()));
743*795d594fSAndroid Build Coastguard Worker if (HasCompiledCode(compiled_method)) {
744*795d594fSAndroid Build Coastguard Worker for (const LinkerPatch& patch : compiled_method->GetPatches()) {
745*795d594fSAndroid Build Coastguard Worker if (patch.GetType() == LinkerPatch::Type::kBootImageRelRo) {
746*795d594fSAndroid Build Coastguard Worker writer_->boot_image_rel_ro_entries_.Overwrite(patch.BootImageOffset(),
747*795d594fSAndroid Build Coastguard Worker /* placeholder */ 0u);
748*795d594fSAndroid Build Coastguard Worker } else if (patch.GetType() == LinkerPatch::Type::kMethodAppImageRelRo) {
749*795d594fSAndroid Build Coastguard Worker MethodReference target_method = patch.TargetMethod();
750*795d594fSAndroid Build Coastguard Worker writer_->app_image_rel_ro_method_entries_.Overwrite(target_method, /* placeholder */ 0u);
751*795d594fSAndroid Build Coastguard Worker } else if (patch.GetType() == LinkerPatch::Type::kMethodBssEntry) {
752*795d594fSAndroid Build Coastguard Worker MethodReference target_method = patch.TargetMethod();
753*795d594fSAndroid Build Coastguard Worker AddBssReference(target_method,
754*795d594fSAndroid Build Coastguard Worker target_method.dex_file->NumMethodIds(),
755*795d594fSAndroid Build Coastguard Worker &writer_->bss_method_entry_references_);
756*795d594fSAndroid Build Coastguard Worker writer_->bss_method_entries_.Overwrite(target_method, /* placeholder */ 0u);
757*795d594fSAndroid Build Coastguard Worker } else if (patch.GetType() == LinkerPatch::Type::kTypeAppImageRelRo) {
758*795d594fSAndroid Build Coastguard Worker writer_->app_image_rel_ro_type_entries_.Overwrite(patch.TargetType(),
759*795d594fSAndroid Build Coastguard Worker /* placeholder */ 0u);
760*795d594fSAndroid Build Coastguard Worker } else if (patch.GetType() == LinkerPatch::Type::kTypeBssEntry) {
761*795d594fSAndroid Build Coastguard Worker TypeReference target_type = patch.TargetType();
762*795d594fSAndroid Build Coastguard Worker AddBssReference(target_type,
763*795d594fSAndroid Build Coastguard Worker target_type.dex_file->NumTypeIds(),
764*795d594fSAndroid Build Coastguard Worker &writer_->bss_type_entry_references_);
765*795d594fSAndroid Build Coastguard Worker writer_->bss_type_entries_.Overwrite(target_type, /* placeholder */ 0u);
766*795d594fSAndroid Build Coastguard Worker } else if (patch.GetType() == LinkerPatch::Type::kPublicTypeBssEntry) {
767*795d594fSAndroid Build Coastguard Worker TypeReference target_type = patch.TargetType();
768*795d594fSAndroid Build Coastguard Worker AddBssReference(target_type,
769*795d594fSAndroid Build Coastguard Worker target_type.dex_file->NumTypeIds(),
770*795d594fSAndroid Build Coastguard Worker &writer_->bss_public_type_entry_references_);
771*795d594fSAndroid Build Coastguard Worker writer_->bss_public_type_entries_.Overwrite(target_type, /* placeholder */ 0u);
772*795d594fSAndroid Build Coastguard Worker } else if (patch.GetType() == LinkerPatch::Type::kPackageTypeBssEntry) {
773*795d594fSAndroid Build Coastguard Worker TypeReference target_type = patch.TargetType();
774*795d594fSAndroid Build Coastguard Worker AddBssReference(target_type,
775*795d594fSAndroid Build Coastguard Worker target_type.dex_file->NumTypeIds(),
776*795d594fSAndroid Build Coastguard Worker &writer_->bss_package_type_entry_references_);
777*795d594fSAndroid Build Coastguard Worker writer_->bss_package_type_entries_.Overwrite(target_type, /* placeholder */ 0u);
778*795d594fSAndroid Build Coastguard Worker } else if (patch.GetType() == LinkerPatch::Type::kStringBssEntry) {
779*795d594fSAndroid Build Coastguard Worker StringReference target_string = patch.TargetString();
780*795d594fSAndroid Build Coastguard Worker AddBssReference(target_string,
781*795d594fSAndroid Build Coastguard Worker target_string.dex_file->NumStringIds(),
782*795d594fSAndroid Build Coastguard Worker &writer_->bss_string_entry_references_);
783*795d594fSAndroid Build Coastguard Worker writer_->bss_string_entries_.Overwrite(target_string, /* placeholder */ 0u);
784*795d594fSAndroid Build Coastguard Worker } else if (patch.GetType() == LinkerPatch::Type::kMethodTypeBssEntry) {
785*795d594fSAndroid Build Coastguard Worker ProtoReference target_proto = patch.TargetProto();
786*795d594fSAndroid Build Coastguard Worker AddBssReference(target_proto,
787*795d594fSAndroid Build Coastguard Worker target_proto.dex_file->NumProtoIds(),
788*795d594fSAndroid Build Coastguard Worker &writer_->bss_method_type_entry_references_);
789*795d594fSAndroid Build Coastguard Worker writer_->bss_method_type_entries_.Overwrite(target_proto, /* placeholder */ 0u);
790*795d594fSAndroid Build Coastguard Worker }
791*795d594fSAndroid Build Coastguard Worker }
792*795d594fSAndroid Build Coastguard Worker } else {
793*795d594fSAndroid Build Coastguard Worker DCHECK(compiled_method == nullptr || compiled_method->GetPatches().empty());
794*795d594fSAndroid Build Coastguard Worker }
795*795d594fSAndroid Build Coastguard Worker return true;
796*795d594fSAndroid Build Coastguard Worker }
797*795d594fSAndroid Build Coastguard Worker
798*795d594fSAndroid Build Coastguard Worker private:
AddBssReference(const DexFileReference & ref,size_t number_of_indexes,SafeMap<const DexFile *,BitVector> * references)799*795d594fSAndroid Build Coastguard Worker void AddBssReference(const DexFileReference& ref,
800*795d594fSAndroid Build Coastguard Worker size_t number_of_indexes,
801*795d594fSAndroid Build Coastguard Worker /*inout*/ SafeMap<const DexFile*, BitVector>* references) {
802*795d594fSAndroid Build Coastguard Worker DCHECK(ContainsElement(*writer_->dex_files_, ref.dex_file) ||
803*795d594fSAndroid Build Coastguard Worker ContainsElement(Runtime::Current()->GetClassLinker()->GetBootClassPath(), ref.dex_file));
804*795d594fSAndroid Build Coastguard Worker DCHECK_LT(ref.index, number_of_indexes);
805*795d594fSAndroid Build Coastguard Worker
806*795d594fSAndroid Build Coastguard Worker auto refs_it = references->find(ref.dex_file);
807*795d594fSAndroid Build Coastguard Worker if (refs_it == references->end()) {
808*795d594fSAndroid Build Coastguard Worker refs_it = references->Put(
809*795d594fSAndroid Build Coastguard Worker ref.dex_file,
810*795d594fSAndroid Build Coastguard Worker BitVector(number_of_indexes, /* expandable */ false, Allocator::GetCallocAllocator()));
811*795d594fSAndroid Build Coastguard Worker }
812*795d594fSAndroid Build Coastguard Worker refs_it->second.SetBit(ref.index);
813*795d594fSAndroid Build Coastguard Worker }
814*795d594fSAndroid Build Coastguard Worker };
815*795d594fSAndroid Build Coastguard Worker
816*795d594fSAndroid Build Coastguard Worker class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor {
817*795d594fSAndroid Build Coastguard Worker public:
InitOatClassesMethodVisitor(OatWriter * writer,size_t offset)818*795d594fSAndroid Build Coastguard Worker InitOatClassesMethodVisitor(OatWriter* writer, size_t offset)
819*795d594fSAndroid Build Coastguard Worker : DexMethodVisitor(writer, offset),
820*795d594fSAndroid Build Coastguard Worker compiled_methods_(),
821*795d594fSAndroid Build Coastguard Worker compiled_methods_with_code_(0u) {
822*795d594fSAndroid Build Coastguard Worker size_t num_classes = 0u;
823*795d594fSAndroid Build Coastguard Worker for (const OatDexFile& oat_dex_file : writer_->oat_dex_files_) {
824*795d594fSAndroid Build Coastguard Worker num_classes += oat_dex_file.class_offsets_.size();
825*795d594fSAndroid Build Coastguard Worker }
826*795d594fSAndroid Build Coastguard Worker // If we aren't compiling only reserve headers.
827*795d594fSAndroid Build Coastguard Worker writer_->oat_class_headers_.reserve(num_classes);
828*795d594fSAndroid Build Coastguard Worker if (writer->MayHaveCompiledMethods()) {
829*795d594fSAndroid Build Coastguard Worker writer->oat_classes_.reserve(num_classes);
830*795d594fSAndroid Build Coastguard Worker }
831*795d594fSAndroid Build Coastguard Worker compiled_methods_.reserve(256u);
832*795d594fSAndroid Build Coastguard Worker // If there are any classes, the class offsets allocation aligns the offset.
833*795d594fSAndroid Build Coastguard Worker DCHECK(num_classes == 0u || IsAligned<4u>(offset));
834*795d594fSAndroid Build Coastguard Worker }
835*795d594fSAndroid Build Coastguard Worker
StartClass(const DexFile * dex_file,size_t class_def_index)836*795d594fSAndroid Build Coastguard Worker bool StartClass(const DexFile* dex_file, size_t class_def_index) override {
837*795d594fSAndroid Build Coastguard Worker DexMethodVisitor::StartClass(dex_file, class_def_index);
838*795d594fSAndroid Build Coastguard Worker compiled_methods_.clear();
839*795d594fSAndroid Build Coastguard Worker compiled_methods_with_code_ = 0u;
840*795d594fSAndroid Build Coastguard Worker return true;
841*795d594fSAndroid Build Coastguard Worker }
842*795d594fSAndroid Build Coastguard Worker
VisitMethod(size_t class_def_method_index,const ClassAccessor::Method & method)843*795d594fSAndroid Build Coastguard Worker bool VisitMethod([[maybe_unused]] size_t class_def_method_index,
844*795d594fSAndroid Build Coastguard Worker const ClassAccessor::Method& method) override {
845*795d594fSAndroid Build Coastguard Worker // Fill in the compiled_methods_ array for methods that have a
846*795d594fSAndroid Build Coastguard Worker // CompiledMethod. We track the number of non-null entries in
847*795d594fSAndroid Build Coastguard Worker // compiled_methods_with_code_ since we only want to allocate
848*795d594fSAndroid Build Coastguard Worker // OatMethodOffsets for the compiled methods.
849*795d594fSAndroid Build Coastguard Worker uint32_t method_idx = method.GetIndex();
850*795d594fSAndroid Build Coastguard Worker CompiledMethod* compiled_method =
851*795d594fSAndroid Build Coastguard Worker writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
852*795d594fSAndroid Build Coastguard Worker compiled_methods_.push_back(compiled_method);
853*795d594fSAndroid Build Coastguard Worker if (HasCompiledCode(compiled_method)) {
854*795d594fSAndroid Build Coastguard Worker ++compiled_methods_with_code_;
855*795d594fSAndroid Build Coastguard Worker }
856*795d594fSAndroid Build Coastguard Worker return true;
857*795d594fSAndroid Build Coastguard Worker }
858*795d594fSAndroid Build Coastguard Worker
EndClass()859*795d594fSAndroid Build Coastguard Worker bool EndClass() override {
860*795d594fSAndroid Build Coastguard Worker ClassReference class_ref(dex_file_, class_def_index_);
861*795d594fSAndroid Build Coastguard Worker ClassStatus status;
862*795d594fSAndroid Build Coastguard Worker bool found = writer_->compiler_driver_->GetCompiledClass(class_ref, &status);
863*795d594fSAndroid Build Coastguard Worker if (!found) {
864*795d594fSAndroid Build Coastguard Worker const VerificationResults* results = writer_->verification_results_;
865*795d594fSAndroid Build Coastguard Worker if (results != nullptr && results->IsClassRejected(class_ref)) {
866*795d594fSAndroid Build Coastguard Worker // The oat class status is used only for verification of resolved classes,
867*795d594fSAndroid Build Coastguard Worker // so use ClassStatus::kErrorResolved whether the class was resolved or unresolved
868*795d594fSAndroid Build Coastguard Worker // during compile-time verification.
869*795d594fSAndroid Build Coastguard Worker status = ClassStatus::kErrorResolved;
870*795d594fSAndroid Build Coastguard Worker } else {
871*795d594fSAndroid Build Coastguard Worker status = ClassStatus::kNotReady;
872*795d594fSAndroid Build Coastguard Worker }
873*795d594fSAndroid Build Coastguard Worker }
874*795d594fSAndroid Build Coastguard Worker // We never emit kRetryVerificationAtRuntime, instead we mark the class as
875*795d594fSAndroid Build Coastguard Worker // resolved and the class will therefore be re-verified at runtime.
876*795d594fSAndroid Build Coastguard Worker if (status == ClassStatus::kRetryVerificationAtRuntime) {
877*795d594fSAndroid Build Coastguard Worker status = ClassStatus::kResolved;
878*795d594fSAndroid Build Coastguard Worker }
879*795d594fSAndroid Build Coastguard Worker
880*795d594fSAndroid Build Coastguard Worker writer_->oat_class_headers_.emplace_back(offset_,
881*795d594fSAndroid Build Coastguard Worker compiled_methods_with_code_,
882*795d594fSAndroid Build Coastguard Worker compiled_methods_.size(),
883*795d594fSAndroid Build Coastguard Worker status);
884*795d594fSAndroid Build Coastguard Worker OatClassHeader& header = writer_->oat_class_headers_.back();
885*795d594fSAndroid Build Coastguard Worker offset_ += header.SizeOf();
886*795d594fSAndroid Build Coastguard Worker if (writer_->MayHaveCompiledMethods()) {
887*795d594fSAndroid Build Coastguard Worker writer_->oat_classes_.emplace_back(compiled_methods_,
888*795d594fSAndroid Build Coastguard Worker compiled_methods_with_code_,
889*795d594fSAndroid Build Coastguard Worker header.type_);
890*795d594fSAndroid Build Coastguard Worker offset_ += writer_->oat_classes_.back().SizeOf();
891*795d594fSAndroid Build Coastguard Worker }
892*795d594fSAndroid Build Coastguard Worker return DexMethodVisitor::EndClass();
893*795d594fSAndroid Build Coastguard Worker }
894*795d594fSAndroid Build Coastguard Worker
895*795d594fSAndroid Build Coastguard Worker private:
896*795d594fSAndroid Build Coastguard Worker dchecked_vector<CompiledMethod*> compiled_methods_;
897*795d594fSAndroid Build Coastguard Worker size_t compiled_methods_with_code_;
898*795d594fSAndroid Build Coastguard Worker };
899*795d594fSAndroid Build Coastguard Worker
900*795d594fSAndroid Build Coastguard Worker // CompiledMethod + metadata required to do ordered method layout.
901*795d594fSAndroid Build Coastguard Worker //
902*795d594fSAndroid Build Coastguard Worker // See also OrderedMethodVisitor.
903*795d594fSAndroid Build Coastguard Worker struct OatWriter::OrderedMethodData {
904*795d594fSAndroid Build Coastguard Worker uint32_t hotness_bits;
905*795d594fSAndroid Build Coastguard Worker OatClass* oat_class;
906*795d594fSAndroid Build Coastguard Worker CompiledMethod* compiled_method;
907*795d594fSAndroid Build Coastguard Worker MethodReference method_reference;
908*795d594fSAndroid Build Coastguard Worker size_t method_offsets_index;
909*795d594fSAndroid Build Coastguard Worker
910*795d594fSAndroid Build Coastguard Worker size_t class_def_index;
911*795d594fSAndroid Build Coastguard Worker uint32_t access_flags;
912*795d594fSAndroid Build Coastguard Worker const dex::CodeItem* code_item;
913*795d594fSAndroid Build Coastguard Worker
914*795d594fSAndroid Build Coastguard Worker // A value of -1 denotes missing debug info
915*795d594fSAndroid Build Coastguard Worker static constexpr size_t kDebugInfoIdxInvalid = static_cast<size_t>(-1);
916*795d594fSAndroid Build Coastguard Worker // Index into writer_->method_info_
917*795d594fSAndroid Build Coastguard Worker size_t debug_info_idx;
918*795d594fSAndroid Build Coastguard Worker
HasDebugInfoart::linker::OatWriter::OrderedMethodData919*795d594fSAndroid Build Coastguard Worker bool HasDebugInfo() const {
920*795d594fSAndroid Build Coastguard Worker return debug_info_idx != kDebugInfoIdxInvalid;
921*795d594fSAndroid Build Coastguard Worker }
922*795d594fSAndroid Build Coastguard Worker
923*795d594fSAndroid Build Coastguard Worker // Bin each method according to the profile flags.
924*795d594fSAndroid Build Coastguard Worker //
925*795d594fSAndroid Build Coastguard Worker // Groups by e.g.
926*795d594fSAndroid Build Coastguard Worker // -- startup and hot and poststartup
927*795d594fSAndroid Build Coastguard Worker // -- startup and hot
928*795d594fSAndroid Build Coastguard Worker // -- startup and post-startup
929*795d594fSAndroid Build Coastguard Worker // -- startup
930*795d594fSAndroid Build Coastguard Worker // -- hot and post-startup
931*795d594fSAndroid Build Coastguard Worker // -- hot
932*795d594fSAndroid Build Coastguard Worker // -- post-startup
933*795d594fSAndroid Build Coastguard Worker // -- not hot at all
934*795d594fSAndroid Build Coastguard Worker //
935*795d594fSAndroid Build Coastguard Worker // (See MethodHotness enum definition for up-to-date binning order.)
operator <art::linker::OatWriter::OrderedMethodData936*795d594fSAndroid Build Coastguard Worker bool operator<(const OrderedMethodData& other) const {
937*795d594fSAndroid Build Coastguard Worker if (kOatWriterForceOatCodeLayout) {
938*795d594fSAndroid Build Coastguard Worker // Development flag: Override default behavior by sorting by name.
939*795d594fSAndroid Build Coastguard Worker
940*795d594fSAndroid Build Coastguard Worker std::string name = method_reference.PrettyMethod();
941*795d594fSAndroid Build Coastguard Worker std::string other_name = other.method_reference.PrettyMethod();
942*795d594fSAndroid Build Coastguard Worker return name < other_name;
943*795d594fSAndroid Build Coastguard Worker }
944*795d594fSAndroid Build Coastguard Worker
945*795d594fSAndroid Build Coastguard Worker // Use the profile's method hotness to determine sort order, with startup
946*795d594fSAndroid Build Coastguard Worker // methods appearing first.
947*795d594fSAndroid Build Coastguard Worker if (hotness_bits > other.hotness_bits) {
948*795d594fSAndroid Build Coastguard Worker return true;
949*795d594fSAndroid Build Coastguard Worker }
950*795d594fSAndroid Build Coastguard Worker
951*795d594fSAndroid Build Coastguard Worker // Default: retain the original order.
952*795d594fSAndroid Build Coastguard Worker return false;
953*795d594fSAndroid Build Coastguard Worker }
954*795d594fSAndroid Build Coastguard Worker };
955*795d594fSAndroid Build Coastguard Worker
956*795d594fSAndroid Build Coastguard Worker // Given a queue of CompiledMethod in some total order,
957*795d594fSAndroid Build Coastguard Worker // visit each one in that order.
958*795d594fSAndroid Build Coastguard Worker class OatWriter::OrderedMethodVisitor {
959*795d594fSAndroid Build Coastguard Worker public:
OrderedMethodVisitor(OrderedMethodList ordered_methods)960*795d594fSAndroid Build Coastguard Worker explicit OrderedMethodVisitor(OrderedMethodList ordered_methods)
961*795d594fSAndroid Build Coastguard Worker : ordered_methods_(std::move(ordered_methods)) {
962*795d594fSAndroid Build Coastguard Worker }
963*795d594fSAndroid Build Coastguard Worker
~OrderedMethodVisitor()964*795d594fSAndroid Build Coastguard Worker virtual ~OrderedMethodVisitor() {}
965*795d594fSAndroid Build Coastguard Worker
966*795d594fSAndroid Build Coastguard Worker // Invoke VisitMethod in the order of `ordered_methods`, then invoke VisitComplete.
Visit()967*795d594fSAndroid Build Coastguard Worker bool Visit() REQUIRES_SHARED(Locks::mutator_lock_) {
968*795d594fSAndroid Build Coastguard Worker if (!VisitStart()) {
969*795d594fSAndroid Build Coastguard Worker return false;
970*795d594fSAndroid Build Coastguard Worker }
971*795d594fSAndroid Build Coastguard Worker
972*795d594fSAndroid Build Coastguard Worker for (const OrderedMethodData& method_data : ordered_methods_) {
973*795d594fSAndroid Build Coastguard Worker if (!VisitMethod(method_data)) {
974*795d594fSAndroid Build Coastguard Worker return false;
975*795d594fSAndroid Build Coastguard Worker }
976*795d594fSAndroid Build Coastguard Worker }
977*795d594fSAndroid Build Coastguard Worker
978*795d594fSAndroid Build Coastguard Worker return VisitComplete();
979*795d594fSAndroid Build Coastguard Worker }
980*795d594fSAndroid Build Coastguard Worker
981*795d594fSAndroid Build Coastguard Worker // Invoked once at the beginning, prior to visiting anything else.
982*795d594fSAndroid Build Coastguard Worker //
983*795d594fSAndroid Build Coastguard Worker // Return false to abort further visiting.
VisitStart()984*795d594fSAndroid Build Coastguard Worker virtual bool VisitStart() { return true; }
985*795d594fSAndroid Build Coastguard Worker
986*795d594fSAndroid Build Coastguard Worker // Invoked repeatedly in the order specified by `ordered_methods`.
987*795d594fSAndroid Build Coastguard Worker //
988*795d594fSAndroid Build Coastguard Worker // Return false to short-circuit and to stop visiting further methods.
989*795d594fSAndroid Build Coastguard Worker virtual bool VisitMethod(const OrderedMethodData& method_data)
990*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) = 0;
991*795d594fSAndroid Build Coastguard Worker
992*795d594fSAndroid Build Coastguard Worker // Invoked once at the end, after every other method has been successfully visited.
993*795d594fSAndroid Build Coastguard Worker //
994*795d594fSAndroid Build Coastguard Worker // Return false to indicate the overall `Visit` has failed.
995*795d594fSAndroid Build Coastguard Worker virtual bool VisitComplete() = 0;
996*795d594fSAndroid Build Coastguard Worker
ReleaseOrderedMethods()997*795d594fSAndroid Build Coastguard Worker OrderedMethodList ReleaseOrderedMethods() {
998*795d594fSAndroid Build Coastguard Worker return std::move(ordered_methods_);
999*795d594fSAndroid Build Coastguard Worker }
1000*795d594fSAndroid Build Coastguard Worker
1001*795d594fSAndroid Build Coastguard Worker private:
1002*795d594fSAndroid Build Coastguard Worker // List of compiled methods, sorted by the order defined in OrderedMethodData.
1003*795d594fSAndroid Build Coastguard Worker // Methods can be inserted more than once in case of duplicated methods.
1004*795d594fSAndroid Build Coastguard Worker OrderedMethodList ordered_methods_;
1005*795d594fSAndroid Build Coastguard Worker };
1006*795d594fSAndroid Build Coastguard Worker
1007*795d594fSAndroid Build Coastguard Worker // Visit every compiled method in order to determine its order within the OAT file.
1008*795d594fSAndroid Build Coastguard Worker // Methods from the same class do not need to be adjacent in the OAT code.
1009*795d594fSAndroid Build Coastguard Worker class OatWriter::LayoutCodeMethodVisitor final : public OatDexMethodVisitor {
1010*795d594fSAndroid Build Coastguard Worker public:
LayoutCodeMethodVisitor(OatWriter * writer,size_t offset)1011*795d594fSAndroid Build Coastguard Worker LayoutCodeMethodVisitor(OatWriter* writer, size_t offset)
1012*795d594fSAndroid Build Coastguard Worker : OatDexMethodVisitor(writer, offset),
1013*795d594fSAndroid Build Coastguard Worker profile_index_(ProfileCompilationInfo::MaxProfileIndex()),
1014*795d594fSAndroid Build Coastguard Worker profile_index_dex_file_(nullptr) {
1015*795d594fSAndroid Build Coastguard Worker }
1016*795d594fSAndroid Build Coastguard Worker
StartClass(const DexFile * dex_file,size_t class_def_index)1017*795d594fSAndroid Build Coastguard Worker bool StartClass(const DexFile* dex_file, size_t class_def_index) final {
1018*795d594fSAndroid Build Coastguard Worker // Update the cached `profile_index_` if needed. This happens only once per dex file
1019*795d594fSAndroid Build Coastguard Worker // because we visit all classes in a dex file together, so mark that as `UNLIKELY`.
1020*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(dex_file != profile_index_dex_file_)) {
1021*795d594fSAndroid Build Coastguard Worker if (writer_->profile_compilation_info_ != nullptr) {
1022*795d594fSAndroid Build Coastguard Worker profile_index_ = writer_->profile_compilation_info_->FindDexFile(*dex_file);
1023*795d594fSAndroid Build Coastguard Worker } else {
1024*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(profile_index_, ProfileCompilationInfo::MaxProfileIndex());
1025*795d594fSAndroid Build Coastguard Worker }
1026*795d594fSAndroid Build Coastguard Worker profile_index_dex_file_ = dex_file;
1027*795d594fSAndroid Build Coastguard Worker }
1028*795d594fSAndroid Build Coastguard Worker return OatDexMethodVisitor::StartClass(dex_file, class_def_index);
1029*795d594fSAndroid Build Coastguard Worker }
1030*795d594fSAndroid Build Coastguard Worker
VisitMethod(size_t class_def_method_index,const ClassAccessor::Method & method)1031*795d594fSAndroid Build Coastguard Worker bool VisitMethod(size_t class_def_method_index, const ClassAccessor::Method& method) final
1032*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
1033*795d594fSAndroid Build Coastguard Worker Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
1034*795d594fSAndroid Build Coastguard Worker
1035*795d594fSAndroid Build Coastguard Worker OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1036*795d594fSAndroid Build Coastguard Worker CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1037*795d594fSAndroid Build Coastguard Worker
1038*795d594fSAndroid Build Coastguard Worker if (HasCompiledCode(compiled_method)) {
1039*795d594fSAndroid Build Coastguard Worker size_t debug_info_idx = OrderedMethodData::kDebugInfoIdxInvalid;
1040*795d594fSAndroid Build Coastguard Worker
1041*795d594fSAndroid Build Coastguard Worker {
1042*795d594fSAndroid Build Coastguard Worker const CompilerOptions& compiler_options = writer_->GetCompilerOptions();
1043*795d594fSAndroid Build Coastguard Worker ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
1044*795d594fSAndroid Build Coastguard Worker uint32_t code_size = quick_code.size() * sizeof(uint8_t);
1045*795d594fSAndroid Build Coastguard Worker
1046*795d594fSAndroid Build Coastguard Worker // Debug method info must be pushed in the original order
1047*795d594fSAndroid Build Coastguard Worker // (i.e. all methods from the same class must be adjacent in the debug info sections)
1048*795d594fSAndroid Build Coastguard Worker // ElfCompilationUnitWriter::Write requires this.
1049*795d594fSAndroid Build Coastguard Worker if (compiler_options.GenerateAnyDebugInfo() && code_size != 0) {
1050*795d594fSAndroid Build Coastguard Worker debug::MethodDebugInfo info = debug::MethodDebugInfo();
1051*795d594fSAndroid Build Coastguard Worker writer_->method_info_.push_back(info);
1052*795d594fSAndroid Build Coastguard Worker
1053*795d594fSAndroid Build Coastguard Worker // The debug info is filled in LayoutReserveOffsetCodeMethodVisitor
1054*795d594fSAndroid Build Coastguard Worker // once we know the offsets.
1055*795d594fSAndroid Build Coastguard Worker //
1056*795d594fSAndroid Build Coastguard Worker // Store the index into writer_->method_info_ since future push-backs
1057*795d594fSAndroid Build Coastguard Worker // could reallocate and change the underlying data address.
1058*795d594fSAndroid Build Coastguard Worker debug_info_idx = writer_->method_info_.size() - 1;
1059*795d594fSAndroid Build Coastguard Worker }
1060*795d594fSAndroid Build Coastguard Worker }
1061*795d594fSAndroid Build Coastguard Worker
1062*795d594fSAndroid Build Coastguard Worker // Determine the `hotness_bits`, used to determine relative order
1063*795d594fSAndroid Build Coastguard Worker // for OAT code layout when determining binning.
1064*795d594fSAndroid Build Coastguard Worker uint32_t method_index = method.GetIndex();
1065*795d594fSAndroid Build Coastguard Worker MethodReference method_ref(dex_file_, method_index);
1066*795d594fSAndroid Build Coastguard Worker uint32_t hotness_bits = 0u;
1067*795d594fSAndroid Build Coastguard Worker if (profile_index_ != ProfileCompilationInfo::MaxProfileIndex()) {
1068*795d594fSAndroid Build Coastguard Worker ProfileCompilationInfo* pci = writer_->profile_compilation_info_;
1069*795d594fSAndroid Build Coastguard Worker DCHECK(pci != nullptr);
1070*795d594fSAndroid Build Coastguard Worker // Note: Bin-to-bin order does not matter. If the kernel does or does not read-ahead
1071*795d594fSAndroid Build Coastguard Worker // any memory, it only goes into the buffer cache and does not grow the PSS until the
1072*795d594fSAndroid Build Coastguard Worker // first time that memory is referenced in the process.
1073*795d594fSAndroid Build Coastguard Worker constexpr uint32_t kStartupBit = 4u;
1074*795d594fSAndroid Build Coastguard Worker constexpr uint32_t kHotBit = 2u;
1075*795d594fSAndroid Build Coastguard Worker constexpr uint32_t kPostStartupBit = 1u;
1076*795d594fSAndroid Build Coastguard Worker hotness_bits =
1077*795d594fSAndroid Build Coastguard Worker (pci->IsHotMethod(profile_index_, method_index) ? kHotBit : 0u) |
1078*795d594fSAndroid Build Coastguard Worker (pci->IsStartupMethod(profile_index_, method_index) ? kStartupBit : 0u) |
1079*795d594fSAndroid Build Coastguard Worker (pci->IsPostStartupMethod(profile_index_, method_index) ? kPostStartupBit : 0u);
1080*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
1081*795d594fSAndroid Build Coastguard Worker // Check for bins that are always-empty given a real profile.
1082*795d594fSAndroid Build Coastguard Worker if (hotness_bits == kHotBit) {
1083*795d594fSAndroid Build Coastguard Worker // This is not fatal, so only warn.
1084*795d594fSAndroid Build Coastguard Worker LOG(WARNING) << "Method " << method_ref.PrettyMethod() << " was hot but wasn't marked "
1085*795d594fSAndroid Build Coastguard Worker << "either start-up or post-startup. Possible corrupted profile?";
1086*795d594fSAndroid Build Coastguard Worker }
1087*795d594fSAndroid Build Coastguard Worker }
1088*795d594fSAndroid Build Coastguard Worker }
1089*795d594fSAndroid Build Coastguard Worker
1090*795d594fSAndroid Build Coastguard Worker // Handle duplicate methods by pushing them repeatedly.
1091*795d594fSAndroid Build Coastguard Worker OrderedMethodData method_data = {
1092*795d594fSAndroid Build Coastguard Worker hotness_bits,
1093*795d594fSAndroid Build Coastguard Worker oat_class,
1094*795d594fSAndroid Build Coastguard Worker compiled_method,
1095*795d594fSAndroid Build Coastguard Worker method_ref,
1096*795d594fSAndroid Build Coastguard Worker method_offsets_index_,
1097*795d594fSAndroid Build Coastguard Worker class_def_index_,
1098*795d594fSAndroid Build Coastguard Worker method.GetAccessFlags(),
1099*795d594fSAndroid Build Coastguard Worker method.GetCodeItem(),
1100*795d594fSAndroid Build Coastguard Worker debug_info_idx
1101*795d594fSAndroid Build Coastguard Worker };
1102*795d594fSAndroid Build Coastguard Worker ordered_methods_.push_back(method_data);
1103*795d594fSAndroid Build Coastguard Worker
1104*795d594fSAndroid Build Coastguard Worker method_offsets_index_++;
1105*795d594fSAndroid Build Coastguard Worker }
1106*795d594fSAndroid Build Coastguard Worker
1107*795d594fSAndroid Build Coastguard Worker return true;
1108*795d594fSAndroid Build Coastguard Worker }
1109*795d594fSAndroid Build Coastguard Worker
ReleaseOrderedMethods()1110*795d594fSAndroid Build Coastguard Worker OrderedMethodList ReleaseOrderedMethods() {
1111*795d594fSAndroid Build Coastguard Worker if (kOatWriterForceOatCodeLayout || writer_->profile_compilation_info_ != nullptr) {
1112*795d594fSAndroid Build Coastguard Worker // Sort by the method ordering criteria (in OrderedMethodData).
1113*795d594fSAndroid Build Coastguard Worker // Since most methods will have the same ordering criteria,
1114*795d594fSAndroid Build Coastguard Worker // we preserve the original insertion order within the same sort order.
1115*795d594fSAndroid Build Coastguard Worker std::stable_sort(ordered_methods_.begin(), ordered_methods_.end());
1116*795d594fSAndroid Build Coastguard Worker } else {
1117*795d594fSAndroid Build Coastguard Worker // The profile-less behavior is as if every method had 0 hotness
1118*795d594fSAndroid Build Coastguard Worker // associated with it.
1119*795d594fSAndroid Build Coastguard Worker //
1120*795d594fSAndroid Build Coastguard Worker // Since sorting all methods with hotness=0 should give back the same
1121*795d594fSAndroid Build Coastguard Worker // order as before, don't do anything.
1122*795d594fSAndroid Build Coastguard Worker DCHECK(std::is_sorted(ordered_methods_.begin(), ordered_methods_.end()));
1123*795d594fSAndroid Build Coastguard Worker }
1124*795d594fSAndroid Build Coastguard Worker
1125*795d594fSAndroid Build Coastguard Worker return std::move(ordered_methods_);
1126*795d594fSAndroid Build Coastguard Worker }
1127*795d594fSAndroid Build Coastguard Worker
1128*795d594fSAndroid Build Coastguard Worker private:
1129*795d594fSAndroid Build Coastguard Worker // Cached profile index for the current dex file.
1130*795d594fSAndroid Build Coastguard Worker ProfileCompilationInfo::ProfileIndexType profile_index_;
1131*795d594fSAndroid Build Coastguard Worker const DexFile* profile_index_dex_file_;
1132*795d594fSAndroid Build Coastguard Worker
1133*795d594fSAndroid Build Coastguard Worker // List of compiled methods, later to be sorted by order defined in OrderedMethodData.
1134*795d594fSAndroid Build Coastguard Worker // Methods can be inserted more than once in case of duplicated methods.
1135*795d594fSAndroid Build Coastguard Worker OrderedMethodList ordered_methods_;
1136*795d594fSAndroid Build Coastguard Worker };
1137*795d594fSAndroid Build Coastguard Worker
1138*795d594fSAndroid Build Coastguard Worker // Given a method order, reserve the offsets for each CompiledMethod in the OAT file.
1139*795d594fSAndroid Build Coastguard Worker class OatWriter::LayoutReserveOffsetCodeMethodVisitor : public OrderedMethodVisitor {
1140*795d594fSAndroid Build Coastguard Worker public:
LayoutReserveOffsetCodeMethodVisitor(OatWriter * writer,size_t offset,OrderedMethodList ordered_methods)1141*795d594fSAndroid Build Coastguard Worker LayoutReserveOffsetCodeMethodVisitor(OatWriter* writer,
1142*795d594fSAndroid Build Coastguard Worker size_t offset,
1143*795d594fSAndroid Build Coastguard Worker OrderedMethodList ordered_methods)
1144*795d594fSAndroid Build Coastguard Worker : LayoutReserveOffsetCodeMethodVisitor(writer,
1145*795d594fSAndroid Build Coastguard Worker offset,
1146*795d594fSAndroid Build Coastguard Worker writer->GetCompilerOptions(),
1147*795d594fSAndroid Build Coastguard Worker std::move(ordered_methods)) {
1148*795d594fSAndroid Build Coastguard Worker }
1149*795d594fSAndroid Build Coastguard Worker
VisitComplete()1150*795d594fSAndroid Build Coastguard Worker bool VisitComplete() override {
1151*795d594fSAndroid Build Coastguard Worker offset_ = writer_->relative_patcher_->ReserveSpaceEnd(offset_);
1152*795d594fSAndroid Build Coastguard Worker if (generate_debug_info_) {
1153*795d594fSAndroid Build Coastguard Worker std::vector<debug::MethodDebugInfo> thunk_infos =
1154*795d594fSAndroid Build Coastguard Worker relative_patcher_->GenerateThunkDebugInfo(executable_offset_);
1155*795d594fSAndroid Build Coastguard Worker writer_->method_info_.insert(writer_->method_info_.end(),
1156*795d594fSAndroid Build Coastguard Worker std::make_move_iterator(thunk_infos.begin()),
1157*795d594fSAndroid Build Coastguard Worker std::make_move_iterator(thunk_infos.end()));
1158*795d594fSAndroid Build Coastguard Worker }
1159*795d594fSAndroid Build Coastguard Worker return true;
1160*795d594fSAndroid Build Coastguard Worker }
1161*795d594fSAndroid Build Coastguard Worker
VisitMethod(const OrderedMethodData & method_data)1162*795d594fSAndroid Build Coastguard Worker bool VisitMethod(const OrderedMethodData& method_data) override
1163*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
1164*795d594fSAndroid Build Coastguard Worker OatClass* oat_class = method_data.oat_class;
1165*795d594fSAndroid Build Coastguard Worker CompiledMethod* compiled_method = method_data.compiled_method;
1166*795d594fSAndroid Build Coastguard Worker const MethodReference& method_ref = method_data.method_reference;
1167*795d594fSAndroid Build Coastguard Worker uint16_t method_offsets_index_ = method_data.method_offsets_index;
1168*795d594fSAndroid Build Coastguard Worker size_t class_def_index = method_data.class_def_index;
1169*795d594fSAndroid Build Coastguard Worker uint32_t access_flags = method_data.access_flags;
1170*795d594fSAndroid Build Coastguard Worker bool has_debug_info = method_data.HasDebugInfo();
1171*795d594fSAndroid Build Coastguard Worker size_t debug_info_idx = method_data.debug_info_idx;
1172*795d594fSAndroid Build Coastguard Worker
1173*795d594fSAndroid Build Coastguard Worker DCHECK(HasCompiledCode(compiled_method)) << method_ref.PrettyMethod();
1174*795d594fSAndroid Build Coastguard Worker
1175*795d594fSAndroid Build Coastguard Worker // Derived from CompiledMethod.
1176*795d594fSAndroid Build Coastguard Worker uint32_t quick_code_offset = 0;
1177*795d594fSAndroid Build Coastguard Worker
1178*795d594fSAndroid Build Coastguard Worker ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
1179*795d594fSAndroid Build Coastguard Worker uint32_t code_size = quick_code.size() * sizeof(uint8_t);
1180*795d594fSAndroid Build Coastguard Worker uint32_t thumb_offset = compiled_method->GetEntryPointAdjustment();
1181*795d594fSAndroid Build Coastguard Worker
1182*795d594fSAndroid Build Coastguard Worker // Deduplicate code arrays if we are not producing debuggable code.
1183*795d594fSAndroid Build Coastguard Worker bool deduped = true;
1184*795d594fSAndroid Build Coastguard Worker if (debuggable_) {
1185*795d594fSAndroid Build Coastguard Worker quick_code_offset = relative_patcher_->GetOffset(method_ref);
1186*795d594fSAndroid Build Coastguard Worker if (quick_code_offset != 0u) {
1187*795d594fSAndroid Build Coastguard Worker // Duplicate methods, we want the same code for both of them so that the oat writer puts
1188*795d594fSAndroid Build Coastguard Worker // the same code in both ArtMethods so that we do not get different oat code at runtime.
1189*795d594fSAndroid Build Coastguard Worker } else {
1190*795d594fSAndroid Build Coastguard Worker quick_code_offset = NewQuickCodeOffset(compiled_method, method_ref, thumb_offset);
1191*795d594fSAndroid Build Coastguard Worker deduped = false;
1192*795d594fSAndroid Build Coastguard Worker }
1193*795d594fSAndroid Build Coastguard Worker } else {
1194*795d594fSAndroid Build Coastguard Worker quick_code_offset = dedupe_map_.GetOrCreate(
1195*795d594fSAndroid Build Coastguard Worker compiled_method,
1196*795d594fSAndroid Build Coastguard Worker [this, &deduped, compiled_method, &method_ref, thumb_offset]() {
1197*795d594fSAndroid Build Coastguard Worker deduped = false;
1198*795d594fSAndroid Build Coastguard Worker return NewQuickCodeOffset(compiled_method, method_ref, thumb_offset);
1199*795d594fSAndroid Build Coastguard Worker });
1200*795d594fSAndroid Build Coastguard Worker }
1201*795d594fSAndroid Build Coastguard Worker
1202*795d594fSAndroid Build Coastguard Worker if (code_size != 0) {
1203*795d594fSAndroid Build Coastguard Worker if (relative_patcher_->GetOffset(method_ref) != 0u) {
1204*795d594fSAndroid Build Coastguard Worker // TODO: Should this be a hard failure?
1205*795d594fSAndroid Build Coastguard Worker LOG(WARNING) << "Multiple definitions of "
1206*795d594fSAndroid Build Coastguard Worker << method_ref.dex_file->PrettyMethod(method_ref.index)
1207*795d594fSAndroid Build Coastguard Worker << " offsets " << relative_patcher_->GetOffset(method_ref)
1208*795d594fSAndroid Build Coastguard Worker << " " << quick_code_offset;
1209*795d594fSAndroid Build Coastguard Worker } else {
1210*795d594fSAndroid Build Coastguard Worker relative_patcher_->SetOffset(method_ref, quick_code_offset);
1211*795d594fSAndroid Build Coastguard Worker }
1212*795d594fSAndroid Build Coastguard Worker }
1213*795d594fSAndroid Build Coastguard Worker
1214*795d594fSAndroid Build Coastguard Worker // Update quick method header.
1215*795d594fSAndroid Build Coastguard Worker DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size());
1216*795d594fSAndroid Build Coastguard Worker OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
1217*795d594fSAndroid Build Coastguard Worker uint32_t code_info_offset = method_header->GetCodeInfoOffset();
1218*795d594fSAndroid Build Coastguard Worker uint32_t code_offset = quick_code_offset - thumb_offset;
1219*795d594fSAndroid Build Coastguard Worker CHECK(!compiled_method->GetQuickCode().empty());
1220*795d594fSAndroid Build Coastguard Worker // If the code is compiled, we write the offset of the stack map relative
1221*795d594fSAndroid Build Coastguard Worker // to the code. The offset was previously stored relative to start of file.
1222*795d594fSAndroid Build Coastguard Worker if (code_info_offset != 0u) {
1223*795d594fSAndroid Build Coastguard Worker DCHECK_LT(code_info_offset, code_offset);
1224*795d594fSAndroid Build Coastguard Worker code_info_offset = code_offset - code_info_offset;
1225*795d594fSAndroid Build Coastguard Worker }
1226*795d594fSAndroid Build Coastguard Worker *method_header = OatQuickMethodHeader(code_info_offset);
1227*795d594fSAndroid Build Coastguard Worker
1228*795d594fSAndroid Build Coastguard Worker if (!deduped) {
1229*795d594fSAndroid Build Coastguard Worker // Update offsets. (Checksum is updated when writing.)
1230*795d594fSAndroid Build Coastguard Worker offset_ += sizeof(*method_header); // Method header is prepended before code.
1231*795d594fSAndroid Build Coastguard Worker offset_ += code_size;
1232*795d594fSAndroid Build Coastguard Worker }
1233*795d594fSAndroid Build Coastguard Worker
1234*795d594fSAndroid Build Coastguard Worker // Exclude dex methods without native code.
1235*795d594fSAndroid Build Coastguard Worker if (generate_debug_info_ && code_size != 0) {
1236*795d594fSAndroid Build Coastguard Worker DCHECK(has_debug_info);
1237*795d594fSAndroid Build Coastguard Worker const uint8_t* code_info = compiled_method->GetVmapTable().data();
1238*795d594fSAndroid Build Coastguard Worker DCHECK(code_info != nullptr);
1239*795d594fSAndroid Build Coastguard Worker
1240*795d594fSAndroid Build Coastguard Worker // Record debug information for this function if we are doing that.
1241*795d594fSAndroid Build Coastguard Worker debug::MethodDebugInfo& info = writer_->method_info_[debug_info_idx];
1242*795d594fSAndroid Build Coastguard Worker // Simpleperf relies on art_jni_trampoline to detect jni methods.
1243*795d594fSAndroid Build Coastguard Worker info.custom_name = (access_flags & kAccNative) ? "art_jni_trampoline" : "";
1244*795d594fSAndroid Build Coastguard Worker info.dex_file = method_ref.dex_file;
1245*795d594fSAndroid Build Coastguard Worker info.class_def_index = class_def_index;
1246*795d594fSAndroid Build Coastguard Worker info.dex_method_index = method_ref.index;
1247*795d594fSAndroid Build Coastguard Worker info.access_flags = access_flags;
1248*795d594fSAndroid Build Coastguard Worker // For intrinsics emitted by codegen, the code has no relation to the original code item.
1249*795d594fSAndroid Build Coastguard Worker info.code_item = compiled_method->IsIntrinsic() ? nullptr : method_data.code_item;
1250*795d594fSAndroid Build Coastguard Worker info.isa = compiled_method->GetInstructionSet();
1251*795d594fSAndroid Build Coastguard Worker info.deduped = deduped;
1252*795d594fSAndroid Build Coastguard Worker info.is_native_debuggable = native_debuggable_;
1253*795d594fSAndroid Build Coastguard Worker info.is_optimized = method_header->IsOptimized();
1254*795d594fSAndroid Build Coastguard Worker info.is_code_address_text_relative = true;
1255*795d594fSAndroid Build Coastguard Worker info.code_address = code_offset - executable_offset_;
1256*795d594fSAndroid Build Coastguard Worker info.code_size = code_size;
1257*795d594fSAndroid Build Coastguard Worker info.frame_size_in_bytes = CodeInfo::DecodeFrameInfo(code_info).FrameSizeInBytes();
1258*795d594fSAndroid Build Coastguard Worker info.code_info = code_info;
1259*795d594fSAndroid Build Coastguard Worker info.cfi = compiled_method->GetCFIInfo();
1260*795d594fSAndroid Build Coastguard Worker } else {
1261*795d594fSAndroid Build Coastguard Worker DCHECK(!has_debug_info);
1262*795d594fSAndroid Build Coastguard Worker }
1263*795d594fSAndroid Build Coastguard Worker
1264*795d594fSAndroid Build Coastguard Worker DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1265*795d594fSAndroid Build Coastguard Worker OatMethodOffsets* offsets = &oat_class->method_offsets_[method_offsets_index_];
1266*795d594fSAndroid Build Coastguard Worker offsets->code_offset_ = quick_code_offset;
1267*795d594fSAndroid Build Coastguard Worker
1268*795d594fSAndroid Build Coastguard Worker return true;
1269*795d594fSAndroid Build Coastguard Worker }
1270*795d594fSAndroid Build Coastguard Worker
GetOffset() const1271*795d594fSAndroid Build Coastguard Worker size_t GetOffset() const {
1272*795d594fSAndroid Build Coastguard Worker return offset_;
1273*795d594fSAndroid Build Coastguard Worker }
1274*795d594fSAndroid Build Coastguard Worker
1275*795d594fSAndroid Build Coastguard Worker private:
LayoutReserveOffsetCodeMethodVisitor(OatWriter * writer,size_t offset,const CompilerOptions & compiler_options,OrderedMethodList ordered_methods)1276*795d594fSAndroid Build Coastguard Worker LayoutReserveOffsetCodeMethodVisitor(OatWriter* writer,
1277*795d594fSAndroid Build Coastguard Worker size_t offset,
1278*795d594fSAndroid Build Coastguard Worker const CompilerOptions& compiler_options,
1279*795d594fSAndroid Build Coastguard Worker OrderedMethodList ordered_methods)
1280*795d594fSAndroid Build Coastguard Worker : OrderedMethodVisitor(std::move(ordered_methods)),
1281*795d594fSAndroid Build Coastguard Worker writer_(writer),
1282*795d594fSAndroid Build Coastguard Worker offset_(offset),
1283*795d594fSAndroid Build Coastguard Worker relative_patcher_(writer->relative_patcher_),
1284*795d594fSAndroid Build Coastguard Worker executable_offset_(writer->oat_header_->GetExecutableOffset()),
1285*795d594fSAndroid Build Coastguard Worker debuggable_(compiler_options.GetDebuggable()),
1286*795d594fSAndroid Build Coastguard Worker native_debuggable_(compiler_options.GetNativeDebuggable()),
1287*795d594fSAndroid Build Coastguard Worker generate_debug_info_(compiler_options.GenerateAnyDebugInfo()) {}
1288*795d594fSAndroid Build Coastguard Worker
1289*795d594fSAndroid Build Coastguard Worker struct CodeOffsetsKeyComparator {
operator ()art::linker::OatWriter::LayoutReserveOffsetCodeMethodVisitor::CodeOffsetsKeyComparator1290*795d594fSAndroid Build Coastguard Worker bool operator()(const CompiledMethod* lhs, const CompiledMethod* rhs) const {
1291*795d594fSAndroid Build Coastguard Worker // Code is deduplicated by CompilerDriver, compare only data pointers.
1292*795d594fSAndroid Build Coastguard Worker if (lhs->GetQuickCode().data() != rhs->GetQuickCode().data()) {
1293*795d594fSAndroid Build Coastguard Worker return lhs->GetQuickCode().data() < rhs->GetQuickCode().data();
1294*795d594fSAndroid Build Coastguard Worker }
1295*795d594fSAndroid Build Coastguard Worker // If the code is the same, all other fields are likely to be the same as well.
1296*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(lhs->GetVmapTable().data() != rhs->GetVmapTable().data())) {
1297*795d594fSAndroid Build Coastguard Worker return lhs->GetVmapTable().data() < rhs->GetVmapTable().data();
1298*795d594fSAndroid Build Coastguard Worker }
1299*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(lhs->GetPatches().data() != rhs->GetPatches().data())) {
1300*795d594fSAndroid Build Coastguard Worker return lhs->GetPatches().data() < rhs->GetPatches().data();
1301*795d594fSAndroid Build Coastguard Worker }
1302*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(lhs->IsIntrinsic() != rhs->IsIntrinsic())) {
1303*795d594fSAndroid Build Coastguard Worker return rhs->IsIntrinsic();
1304*795d594fSAndroid Build Coastguard Worker }
1305*795d594fSAndroid Build Coastguard Worker return false;
1306*795d594fSAndroid Build Coastguard Worker }
1307*795d594fSAndroid Build Coastguard Worker };
1308*795d594fSAndroid Build Coastguard Worker
NewQuickCodeOffset(CompiledMethod * compiled_method,const MethodReference & method_ref,uint32_t thumb_offset)1309*795d594fSAndroid Build Coastguard Worker uint32_t NewQuickCodeOffset(CompiledMethod* compiled_method,
1310*795d594fSAndroid Build Coastguard Worker const MethodReference& method_ref,
1311*795d594fSAndroid Build Coastguard Worker uint32_t thumb_offset) {
1312*795d594fSAndroid Build Coastguard Worker offset_ = relative_patcher_->ReserveSpace(offset_, compiled_method, method_ref);
1313*795d594fSAndroid Build Coastguard Worker offset_ += CodeAlignmentSize(offset_, *compiled_method);
1314*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader),
1315*795d594fSAndroid Build Coastguard Worker GetInstructionSetCodeAlignment(compiled_method->GetInstructionSet()));
1316*795d594fSAndroid Build Coastguard Worker return offset_ + sizeof(OatQuickMethodHeader) + thumb_offset;
1317*795d594fSAndroid Build Coastguard Worker }
1318*795d594fSAndroid Build Coastguard Worker
1319*795d594fSAndroid Build Coastguard Worker OatWriter* writer_;
1320*795d594fSAndroid Build Coastguard Worker
1321*795d594fSAndroid Build Coastguard Worker // Offset of the code of the compiled methods.
1322*795d594fSAndroid Build Coastguard Worker size_t offset_;
1323*795d594fSAndroid Build Coastguard Worker
1324*795d594fSAndroid Build Coastguard Worker // Deduplication is already done on a pointer basis by the compiler driver,
1325*795d594fSAndroid Build Coastguard Worker // so we can simply compare the pointers to find out if things are duplicated.
1326*795d594fSAndroid Build Coastguard Worker SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_;
1327*795d594fSAndroid Build Coastguard Worker
1328*795d594fSAndroid Build Coastguard Worker // Cache writer_'s members and compiler options.
1329*795d594fSAndroid Build Coastguard Worker MultiOatRelativePatcher* relative_patcher_;
1330*795d594fSAndroid Build Coastguard Worker uint32_t executable_offset_;
1331*795d594fSAndroid Build Coastguard Worker const bool debuggable_;
1332*795d594fSAndroid Build Coastguard Worker const bool native_debuggable_;
1333*795d594fSAndroid Build Coastguard Worker const bool generate_debug_info_;
1334*795d594fSAndroid Build Coastguard Worker };
1335*795d594fSAndroid Build Coastguard Worker
1336*795d594fSAndroid Build Coastguard Worker template <bool kDeduplicate>
1337*795d594fSAndroid Build Coastguard Worker class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor {
1338*795d594fSAndroid Build Coastguard Worker public:
InitMapMethodVisitor(OatWriter * writer,size_t offset)1339*795d594fSAndroid Build Coastguard Worker InitMapMethodVisitor(OatWriter* writer, size_t offset)
1340*795d594fSAndroid Build Coastguard Worker : OatDexMethodVisitor(writer, offset),
1341*795d594fSAndroid Build Coastguard Worker dedupe_bit_table_(&writer_->code_info_data_) {
1342*795d594fSAndroid Build Coastguard Worker if (kDeduplicate) {
1343*795d594fSAndroid Build Coastguard Worker // Reserve large buffers for `CodeInfo` and bit table deduplication except for
1344*795d594fSAndroid Build Coastguard Worker // multi-image compilation as we do not want to reserve multiple large buffers.
1345*795d594fSAndroid Build Coastguard Worker // User devices should not do any multi-image compilation.
1346*795d594fSAndroid Build Coastguard Worker const CompilerOptions& compiler_options = writer->GetCompilerOptions();
1347*795d594fSAndroid Build Coastguard Worker DCHECK(compiler_options.IsAnyCompilationEnabled());
1348*795d594fSAndroid Build Coastguard Worker if (compiler_options.DeduplicateCode() && !compiler_options.IsMultiImage()) {
1349*795d594fSAndroid Build Coastguard Worker size_t unique_code_infos =
1350*795d594fSAndroid Build Coastguard Worker writer->compiler_driver_->GetCompiledMethodStorage()->UniqueVMapTableEntries();
1351*795d594fSAndroid Build Coastguard Worker dedupe_code_info_.reserve(unique_code_infos);
1352*795d594fSAndroid Build Coastguard Worker dedupe_bit_table_.ReserveDedupeBuffer(unique_code_infos);
1353*795d594fSAndroid Build Coastguard Worker }
1354*795d594fSAndroid Build Coastguard Worker }
1355*795d594fSAndroid Build Coastguard Worker }
1356*795d594fSAndroid Build Coastguard Worker
VisitMethod(size_t class_def_method_index,const ClassAccessor::Method & method)1357*795d594fSAndroid Build Coastguard Worker bool VisitMethod(size_t class_def_method_index,
1358*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] const ClassAccessor::Method& method) override
1359*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
1360*795d594fSAndroid Build Coastguard Worker OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1361*795d594fSAndroid Build Coastguard Worker CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1362*795d594fSAndroid Build Coastguard Worker
1363*795d594fSAndroid Build Coastguard Worker if (HasCompiledCode(compiled_method)) {
1364*795d594fSAndroid Build Coastguard Worker DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1365*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].GetCodeInfoOffset(), 0u);
1366*795d594fSAndroid Build Coastguard Worker
1367*795d594fSAndroid Build Coastguard Worker ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
1368*795d594fSAndroid Build Coastguard Worker if (map.size() != 0u) {
1369*795d594fSAndroid Build Coastguard Worker size_t offset = offset_ + writer_->code_info_data_.size();
1370*795d594fSAndroid Build Coastguard Worker if (kDeduplicate) {
1371*795d594fSAndroid Build Coastguard Worker auto [it, inserted] = dedupe_code_info_.insert(std::make_pair(map.data(), offset));
1372*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(inserted, it->second == offset);
1373*795d594fSAndroid Build Coastguard Worker if (inserted) {
1374*795d594fSAndroid Build Coastguard Worker size_t dedupe_bit_table_offset = dedupe_bit_table_.Dedupe(map.data());
1375*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(offset, offset_ + dedupe_bit_table_offset);
1376*795d594fSAndroid Build Coastguard Worker } else {
1377*795d594fSAndroid Build Coastguard Worker offset = it->second;
1378*795d594fSAndroid Build Coastguard Worker }
1379*795d594fSAndroid Build Coastguard Worker } else {
1380*795d594fSAndroid Build Coastguard Worker writer_->code_info_data_.insert(writer_->code_info_data_.end(), map.begin(), map.end());
1381*795d594fSAndroid Build Coastguard Worker }
1382*795d594fSAndroid Build Coastguard Worker // Code offset is not initialized yet, so set file offset for now.
1383*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u);
1384*795d594fSAndroid Build Coastguard Worker oat_class->method_headers_[method_offsets_index_].SetCodeInfoOffset(offset);
1385*795d594fSAndroid Build Coastguard Worker }
1386*795d594fSAndroid Build Coastguard Worker ++method_offsets_index_;
1387*795d594fSAndroid Build Coastguard Worker }
1388*795d594fSAndroid Build Coastguard Worker
1389*795d594fSAndroid Build Coastguard Worker return true;
1390*795d594fSAndroid Build Coastguard Worker }
1391*795d594fSAndroid Build Coastguard Worker
1392*795d594fSAndroid Build Coastguard Worker private:
1393*795d594fSAndroid Build Coastguard Worker // Deduplicate at CodeInfo level. The value is byte offset within code_info_data_.
1394*795d594fSAndroid Build Coastguard Worker // This deduplicates the whole CodeInfo object without going into the inner tables.
1395*795d594fSAndroid Build Coastguard Worker // The compiler already deduplicated the pointers but it did not dedupe the tables.
1396*795d594fSAndroid Build Coastguard Worker HashMap<const uint8_t*, size_t> dedupe_code_info_;
1397*795d594fSAndroid Build Coastguard Worker
1398*795d594fSAndroid Build Coastguard Worker // Deduplicate at BitTable level.
1399*795d594fSAndroid Build Coastguard Worker CodeInfoTableDeduper dedupe_bit_table_;
1400*795d594fSAndroid Build Coastguard Worker };
1401*795d594fSAndroid Build Coastguard Worker
1402*795d594fSAndroid Build Coastguard Worker class OatWriter::InitImageMethodVisitor final : public OatDexMethodVisitor {
1403*795d594fSAndroid Build Coastguard Worker public:
InitImageMethodVisitor(OatWriter * writer,size_t offset,const std::vector<const DexFile * > * dex_files)1404*795d594fSAndroid Build Coastguard Worker InitImageMethodVisitor(OatWriter* writer,
1405*795d594fSAndroid Build Coastguard Worker size_t offset,
1406*795d594fSAndroid Build Coastguard Worker const std::vector<const DexFile*>* dex_files)
1407*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_)
1408*795d594fSAndroid Build Coastguard Worker : OatDexMethodVisitor(writer, offset),
1409*795d594fSAndroid Build Coastguard Worker pointer_size_(GetInstructionSetPointerSize(writer_->compiler_options_.GetInstructionSet())),
1410*795d594fSAndroid Build Coastguard Worker class_loader_(writer->image_writer_->GetAppClassLoader()),
1411*795d594fSAndroid Build Coastguard Worker dex_files_(dex_files),
1412*795d594fSAndroid Build Coastguard Worker class_linker_(Runtime::Current()->GetClassLinker()),
1413*795d594fSAndroid Build Coastguard Worker dex_cache_dex_file_(nullptr),
1414*795d594fSAndroid Build Coastguard Worker dex_cache_(nullptr),
1415*795d594fSAndroid Build Coastguard Worker klass_(nullptr) {}
1416*795d594fSAndroid Build Coastguard Worker
1417*795d594fSAndroid Build Coastguard Worker // Handle copied methods here. Copy pointer to quick code from
1418*795d594fSAndroid Build Coastguard Worker // an origin method to a copied method only if they are
1419*795d594fSAndroid Build Coastguard Worker // in the same oat file. If the origin and the copied methods are
1420*795d594fSAndroid Build Coastguard Worker // in different oat files don't touch the copied method.
1421*795d594fSAndroid Build Coastguard Worker // References to other oat files are not supported yet.
StartClass(const DexFile * dex_file,size_t class_def_index)1422*795d594fSAndroid Build Coastguard Worker bool StartClass(const DexFile* dex_file, size_t class_def_index) final
1423*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
1424*795d594fSAndroid Build Coastguard Worker OatDexMethodVisitor::StartClass(dex_file, class_def_index);
1425*795d594fSAndroid Build Coastguard Worker // Skip classes that are not in the image.
1426*795d594fSAndroid Build Coastguard Worker const dex::TypeId& type_id =
1427*795d594fSAndroid Build Coastguard Worker dex_file_->GetTypeId(dex_file->GetClassDef(class_def_index).class_idx_);
1428*795d594fSAndroid Build Coastguard Worker const char* class_descriptor = dex_file->GetTypeDescriptor(type_id);
1429*795d594fSAndroid Build Coastguard Worker if (!writer_->GetCompilerOptions().IsImageClass(class_descriptor)) {
1430*795d594fSAndroid Build Coastguard Worker klass_ = nullptr;
1431*795d594fSAndroid Build Coastguard Worker return true;
1432*795d594fSAndroid Build Coastguard Worker }
1433*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(dex_file != dex_cache_dex_file_)) {
1434*795d594fSAndroid Build Coastguard Worker dex_cache_ = class_linker_->FindDexCache(Thread::Current(), *dex_file);
1435*795d594fSAndroid Build Coastguard Worker DCHECK(dex_cache_ != nullptr);
1436*795d594fSAndroid Build Coastguard Worker DCHECK(dex_cache_->GetDexFile() == dex_file);
1437*795d594fSAndroid Build Coastguard Worker dex_cache_dex_file_ = dex_file;
1438*795d594fSAndroid Build Coastguard Worker }
1439*795d594fSAndroid Build Coastguard Worker const dex::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
1440*795d594fSAndroid Build Coastguard Worker klass_ = class_linker_->LookupResolvedType(class_def.class_idx_, dex_cache_, class_loader_);
1441*795d594fSAndroid Build Coastguard Worker if (klass_ != nullptr) {
1442*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(klass_->GetDexCache() != dex_cache_)) {
1443*795d594fSAndroid Build Coastguard Worker klass_ = nullptr; // This class definition is hidden by another dex file.
1444*795d594fSAndroid Build Coastguard Worker return true;
1445*795d594fSAndroid Build Coastguard Worker }
1446*795d594fSAndroid Build Coastguard Worker for (ArtMethod& method : klass_->GetCopiedMethods(pointer_size_)) {
1447*795d594fSAndroid Build Coastguard Worker // Find origin method. Declaring class and dex_method_idx
1448*795d594fSAndroid Build Coastguard Worker // in the copied method should be the same as in the origin
1449*795d594fSAndroid Build Coastguard Worker // method.
1450*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> declaring_class = method.GetDeclaringClass();
1451*795d594fSAndroid Build Coastguard Worker ArtMethod* origin = declaring_class->FindClassMethod(
1452*795d594fSAndroid Build Coastguard Worker declaring_class->GetDexCache(),
1453*795d594fSAndroid Build Coastguard Worker method.GetDexMethodIndex(),
1454*795d594fSAndroid Build Coastguard Worker pointer_size_);
1455*795d594fSAndroid Build Coastguard Worker CHECK(origin != nullptr);
1456*795d594fSAndroid Build Coastguard Worker CHECK(!origin->IsDirect());
1457*795d594fSAndroid Build Coastguard Worker CHECK(origin->GetDeclaringClass() == declaring_class);
1458*795d594fSAndroid Build Coastguard Worker if (IsInOatFile(&declaring_class->GetDexFile())) {
1459*795d594fSAndroid Build Coastguard Worker const void* code_ptr =
1460*795d594fSAndroid Build Coastguard Worker origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
1461*795d594fSAndroid Build Coastguard Worker if (code_ptr == nullptr) {
1462*795d594fSAndroid Build Coastguard Worker methods_to_process_.push_back(std::make_pair(&method, origin));
1463*795d594fSAndroid Build Coastguard Worker } else {
1464*795d594fSAndroid Build Coastguard Worker method.SetEntryPointFromQuickCompiledCodePtrSize(
1465*795d594fSAndroid Build Coastguard Worker code_ptr, pointer_size_);
1466*795d594fSAndroid Build Coastguard Worker }
1467*795d594fSAndroid Build Coastguard Worker }
1468*795d594fSAndroid Build Coastguard Worker }
1469*795d594fSAndroid Build Coastguard Worker }
1470*795d594fSAndroid Build Coastguard Worker return true;
1471*795d594fSAndroid Build Coastguard Worker }
1472*795d594fSAndroid Build Coastguard Worker
VisitMethod(size_t class_def_method_index,const ClassAccessor::Method & method)1473*795d594fSAndroid Build Coastguard Worker bool VisitMethod(size_t class_def_method_index, const ClassAccessor::Method& method) final
1474*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
1475*795d594fSAndroid Build Coastguard Worker // Skip methods that are not in the image.
1476*795d594fSAndroid Build Coastguard Worker if (klass_ == nullptr) {
1477*795d594fSAndroid Build Coastguard Worker return true;
1478*795d594fSAndroid Build Coastguard Worker }
1479*795d594fSAndroid Build Coastguard Worker
1480*795d594fSAndroid Build Coastguard Worker OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1481*795d594fSAndroid Build Coastguard Worker CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1482*795d594fSAndroid Build Coastguard Worker
1483*795d594fSAndroid Build Coastguard Worker if (HasCompiledCode(compiled_method)) {
1484*795d594fSAndroid Build Coastguard Worker DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1485*795d594fSAndroid Build Coastguard Worker OatMethodOffsets offsets = oat_class->method_offsets_[method_offsets_index_];
1486*795d594fSAndroid Build Coastguard Worker ++method_offsets_index_;
1487*795d594fSAndroid Build Coastguard Worker
1488*795d594fSAndroid Build Coastguard Worker // Do not try to use the `DexCache` via `ClassLinker::LookupResolvedMethod()`.
1489*795d594fSAndroid Build Coastguard Worker // As we're going over all methods, `DexCache` entries would be quickly evicted
1490*795d594fSAndroid Build Coastguard Worker // and we do not want the overhead of `hiddenapi` checks in the slow-path call
1491*795d594fSAndroid Build Coastguard Worker // to `ClassLinker::FindResolvedMethod()` for a method that we have compiled.
1492*795d594fSAndroid Build Coastguard Worker ArtMethod* resolved_method = klass_->IsInterface()
1493*795d594fSAndroid Build Coastguard Worker ? klass_->FindInterfaceMethod(dex_cache_, method.GetIndex(), pointer_size_)
1494*795d594fSAndroid Build Coastguard Worker : klass_->FindClassMethod(dex_cache_, method.GetIndex(), pointer_size_);
1495*795d594fSAndroid Build Coastguard Worker DCHECK(resolved_method != nullptr);
1496*795d594fSAndroid Build Coastguard Worker resolved_method->SetEntryPointFromQuickCompiledCodePtrSize(
1497*795d594fSAndroid Build Coastguard Worker reinterpret_cast<void*>(offsets.code_offset_), pointer_size_);
1498*795d594fSAndroid Build Coastguard Worker }
1499*795d594fSAndroid Build Coastguard Worker
1500*795d594fSAndroid Build Coastguard Worker return true;
1501*795d594fSAndroid Build Coastguard Worker }
1502*795d594fSAndroid Build Coastguard Worker
1503*795d594fSAndroid Build Coastguard Worker // Check whether specified dex file is in the compiled oat file.
IsInOatFile(const DexFile * dex_file)1504*795d594fSAndroid Build Coastguard Worker bool IsInOatFile(const DexFile* dex_file) {
1505*795d594fSAndroid Build Coastguard Worker return ContainsElement(*dex_files_, dex_file);
1506*795d594fSAndroid Build Coastguard Worker }
1507*795d594fSAndroid Build Coastguard Worker
1508*795d594fSAndroid Build Coastguard Worker // Assign a pointer to quick code for copied methods
1509*795d594fSAndroid Build Coastguard Worker // not handled in the method StartClass
Postprocess()1510*795d594fSAndroid Build Coastguard Worker void Postprocess() REQUIRES_SHARED(Locks::mutator_lock_) {
1511*795d594fSAndroid Build Coastguard Worker for (std::pair<ArtMethod*, ArtMethod*>& p : methods_to_process_) {
1512*795d594fSAndroid Build Coastguard Worker ArtMethod* method = p.first;
1513*795d594fSAndroid Build Coastguard Worker ArtMethod* origin = p.second;
1514*795d594fSAndroid Build Coastguard Worker const void* code_ptr =
1515*795d594fSAndroid Build Coastguard Worker origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
1516*795d594fSAndroid Build Coastguard Worker if (code_ptr != nullptr) {
1517*795d594fSAndroid Build Coastguard Worker method->SetEntryPointFromQuickCompiledCodePtrSize(code_ptr, pointer_size_);
1518*795d594fSAndroid Build Coastguard Worker }
1519*795d594fSAndroid Build Coastguard Worker }
1520*795d594fSAndroid Build Coastguard Worker }
1521*795d594fSAndroid Build Coastguard Worker
1522*795d594fSAndroid Build Coastguard Worker private:
1523*795d594fSAndroid Build Coastguard Worker const PointerSize pointer_size_;
1524*795d594fSAndroid Build Coastguard Worker const ObjPtr<mirror::ClassLoader> class_loader_;
1525*795d594fSAndroid Build Coastguard Worker const std::vector<const DexFile*>* dex_files_;
1526*795d594fSAndroid Build Coastguard Worker ClassLinker* const class_linker_;
1527*795d594fSAndroid Build Coastguard Worker const DexFile* dex_cache_dex_file_; // Updated in `StartClass()`.
1528*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::DexCache> dex_cache_; // Updated in `StartClass()`.
1529*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> klass_; // Updated in `StartClass()`.
1530*795d594fSAndroid Build Coastguard Worker std::vector<std::pair<ArtMethod*, ArtMethod*>> methods_to_process_;
1531*795d594fSAndroid Build Coastguard Worker };
1532*795d594fSAndroid Build Coastguard Worker
1533*795d594fSAndroid Build Coastguard Worker class OatWriter::WriteCodeMethodVisitor : public OrderedMethodVisitor {
1534*795d594fSAndroid Build Coastguard Worker public:
WriteCodeMethodVisitor(OatWriter * writer,OutputStream * out,const size_t file_offset,size_t relative_offset,OrderedMethodList ordered_methods)1535*795d594fSAndroid Build Coastguard Worker WriteCodeMethodVisitor(OatWriter* writer,
1536*795d594fSAndroid Build Coastguard Worker OutputStream* out,
1537*795d594fSAndroid Build Coastguard Worker const size_t file_offset,
1538*795d594fSAndroid Build Coastguard Worker size_t relative_offset,
1539*795d594fSAndroid Build Coastguard Worker OrderedMethodList ordered_methods)
1540*795d594fSAndroid Build Coastguard Worker : OrderedMethodVisitor(std::move(ordered_methods)),
1541*795d594fSAndroid Build Coastguard Worker writer_(writer),
1542*795d594fSAndroid Build Coastguard Worker offset_(relative_offset),
1543*795d594fSAndroid Build Coastguard Worker dex_file_(nullptr),
1544*795d594fSAndroid Build Coastguard Worker pointer_size_(GetInstructionSetPointerSize(writer_->compiler_options_.GetInstructionSet())),
1545*795d594fSAndroid Build Coastguard Worker class_loader_(writer->HasImage() ? writer->image_writer_->GetAppClassLoader() : nullptr),
1546*795d594fSAndroid Build Coastguard Worker out_(out),
1547*795d594fSAndroid Build Coastguard Worker file_offset_(file_offset),
1548*795d594fSAndroid Build Coastguard Worker class_linker_(Runtime::Current()->GetClassLinker()),
1549*795d594fSAndroid Build Coastguard Worker dex_cache_(nullptr),
1550*795d594fSAndroid Build Coastguard Worker no_thread_suspension_("OatWriter patching") {
1551*795d594fSAndroid Build Coastguard Worker patched_code_.reserve(16 * KB);
1552*795d594fSAndroid Build Coastguard Worker if (writer_->GetCompilerOptions().IsBootImage() ||
1553*795d594fSAndroid Build Coastguard Worker writer_->GetCompilerOptions().IsBootImageExtension()) {
1554*795d594fSAndroid Build Coastguard Worker // If we're creating the image, the address space must be ready so that we can apply patches.
1555*795d594fSAndroid Build Coastguard Worker CHECK(writer_->image_writer_->IsImageAddressSpaceReady());
1556*795d594fSAndroid Build Coastguard Worker }
1557*795d594fSAndroid Build Coastguard Worker }
1558*795d594fSAndroid Build Coastguard Worker
VisitStart()1559*795d594fSAndroid Build Coastguard Worker bool VisitStart() override {
1560*795d594fSAndroid Build Coastguard Worker return true;
1561*795d594fSAndroid Build Coastguard Worker }
1562*795d594fSAndroid Build Coastguard Worker
UpdateDexFileAndDexCache(const DexFile * dex_file)1563*795d594fSAndroid Build Coastguard Worker void UpdateDexFileAndDexCache(const DexFile* dex_file)
1564*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
1565*795d594fSAndroid Build Coastguard Worker dex_file_ = dex_file;
1566*795d594fSAndroid Build Coastguard Worker
1567*795d594fSAndroid Build Coastguard Worker // Ordered method visiting is only for compiled methods.
1568*795d594fSAndroid Build Coastguard Worker DCHECK(writer_->MayHaveCompiledMethods());
1569*795d594fSAndroid Build Coastguard Worker
1570*795d594fSAndroid Build Coastguard Worker if (writer_->GetCompilerOptions().IsAotCompilationEnabled()) {
1571*795d594fSAndroid Build Coastguard Worker // Only need to set the dex cache if we have compilation. Other modes might have unloaded it.
1572*795d594fSAndroid Build Coastguard Worker if (dex_cache_ == nullptr || dex_cache_->GetDexFile() != dex_file) {
1573*795d594fSAndroid Build Coastguard Worker dex_cache_ = class_linker_->FindDexCache(Thread::Current(), *dex_file);
1574*795d594fSAndroid Build Coastguard Worker DCHECK(dex_cache_ != nullptr);
1575*795d594fSAndroid Build Coastguard Worker }
1576*795d594fSAndroid Build Coastguard Worker }
1577*795d594fSAndroid Build Coastguard Worker }
1578*795d594fSAndroid Build Coastguard Worker
VisitComplete()1579*795d594fSAndroid Build Coastguard Worker bool VisitComplete() override {
1580*795d594fSAndroid Build Coastguard Worker offset_ = writer_->relative_patcher_->WriteThunks(out_, offset_);
1581*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(offset_ == 0u)) {
1582*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write final relative call thunks";
1583*795d594fSAndroid Build Coastguard Worker return false;
1584*795d594fSAndroid Build Coastguard Worker }
1585*795d594fSAndroid Build Coastguard Worker return true;
1586*795d594fSAndroid Build Coastguard Worker }
1587*795d594fSAndroid Build Coastguard Worker
VisitMethod(const OrderedMethodData & method_data)1588*795d594fSAndroid Build Coastguard Worker bool VisitMethod(const OrderedMethodData& method_data) override
1589*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
1590*795d594fSAndroid Build Coastguard Worker const MethodReference& method_ref = method_data.method_reference;
1591*795d594fSAndroid Build Coastguard Worker UpdateDexFileAndDexCache(method_ref.dex_file);
1592*795d594fSAndroid Build Coastguard Worker
1593*795d594fSAndroid Build Coastguard Worker OatClass* oat_class = method_data.oat_class;
1594*795d594fSAndroid Build Coastguard Worker CompiledMethod* compiled_method = method_data.compiled_method;
1595*795d594fSAndroid Build Coastguard Worker uint16_t method_offsets_index = method_data.method_offsets_index;
1596*795d594fSAndroid Build Coastguard Worker
1597*795d594fSAndroid Build Coastguard Worker // No thread suspension since dex_cache_ that may get invalidated if that occurs.
1598*795d594fSAndroid Build Coastguard Worker ScopedAssertNoThreadSuspension tsc(__FUNCTION__);
1599*795d594fSAndroid Build Coastguard Worker DCHECK(HasCompiledCode(compiled_method)) << method_ref.PrettyMethod();
1600*795d594fSAndroid Build Coastguard Worker
1601*795d594fSAndroid Build Coastguard Worker // TODO: cleanup DCHECK_OFFSET_ to accept file_offset as parameter.
1602*795d594fSAndroid Build Coastguard Worker size_t file_offset = file_offset_; // Used by DCHECK_OFFSET_ macro.
1603*795d594fSAndroid Build Coastguard Worker OutputStream* out = out_;
1604*795d594fSAndroid Build Coastguard Worker
1605*795d594fSAndroid Build Coastguard Worker ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
1606*795d594fSAndroid Build Coastguard Worker uint32_t code_size = quick_code.size() * sizeof(uint8_t);
1607*795d594fSAndroid Build Coastguard Worker
1608*795d594fSAndroid Build Coastguard Worker // Deduplicate code arrays.
1609*795d594fSAndroid Build Coastguard Worker const OatMethodOffsets& method_offsets = oat_class->method_offsets_[method_offsets_index];
1610*795d594fSAndroid Build Coastguard Worker if (method_offsets.code_offset_ > offset_) {
1611*795d594fSAndroid Build Coastguard Worker offset_ = writer_->relative_patcher_->WriteThunks(out, offset_);
1612*795d594fSAndroid Build Coastguard Worker if (offset_ == 0u) {
1613*795d594fSAndroid Build Coastguard Worker ReportWriteFailure("relative call thunk", method_ref);
1614*795d594fSAndroid Build Coastguard Worker return false;
1615*795d594fSAndroid Build Coastguard Worker }
1616*795d594fSAndroid Build Coastguard Worker uint32_t alignment_size = CodeAlignmentSize(offset_, *compiled_method);
1617*795d594fSAndroid Build Coastguard Worker if (alignment_size != 0) {
1618*795d594fSAndroid Build Coastguard Worker if (!writer_->WriteCodeAlignment(out, alignment_size)) {
1619*795d594fSAndroid Build Coastguard Worker ReportWriteFailure("code alignment padding", method_ref);
1620*795d594fSAndroid Build Coastguard Worker return false;
1621*795d594fSAndroid Build Coastguard Worker }
1622*795d594fSAndroid Build Coastguard Worker offset_ += alignment_size;
1623*795d594fSAndroid Build Coastguard Worker DCHECK_OFFSET_();
1624*795d594fSAndroid Build Coastguard Worker }
1625*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader),
1626*795d594fSAndroid Build Coastguard Worker GetInstructionSetCodeAlignment(compiled_method->GetInstructionSet()));
1627*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(
1628*795d594fSAndroid Build Coastguard Worker method_offsets.code_offset_,
1629*795d594fSAndroid Build Coastguard Worker offset_ + sizeof(OatQuickMethodHeader) + compiled_method->GetEntryPointAdjustment())
1630*795d594fSAndroid Build Coastguard Worker << dex_file_->PrettyMethod(method_ref.index);
1631*795d594fSAndroid Build Coastguard Worker const OatQuickMethodHeader& method_header =
1632*795d594fSAndroid Build Coastguard Worker oat_class->method_headers_[method_offsets_index];
1633*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&method_header, sizeof(method_header))) {
1634*795d594fSAndroid Build Coastguard Worker ReportWriteFailure("method header", method_ref);
1635*795d594fSAndroid Build Coastguard Worker return false;
1636*795d594fSAndroid Build Coastguard Worker }
1637*795d594fSAndroid Build Coastguard Worker writer_->size_method_header_ += sizeof(method_header);
1638*795d594fSAndroid Build Coastguard Worker offset_ += sizeof(method_header);
1639*795d594fSAndroid Build Coastguard Worker DCHECK_OFFSET_();
1640*795d594fSAndroid Build Coastguard Worker
1641*795d594fSAndroid Build Coastguard Worker if (!compiled_method->GetPatches().empty()) {
1642*795d594fSAndroid Build Coastguard Worker patched_code_.assign(quick_code.begin(), quick_code.end());
1643*795d594fSAndroid Build Coastguard Worker quick_code = ArrayRef<const uint8_t>(patched_code_);
1644*795d594fSAndroid Build Coastguard Worker for (const LinkerPatch& patch : compiled_method->GetPatches()) {
1645*795d594fSAndroid Build Coastguard Worker uint32_t literal_offset = patch.LiteralOffset();
1646*795d594fSAndroid Build Coastguard Worker switch (patch.GetType()) {
1647*795d594fSAndroid Build Coastguard Worker case LinkerPatch::Type::kIntrinsicReference: {
1648*795d594fSAndroid Build Coastguard Worker uint32_t target_offset = GetTargetIntrinsicReferenceOffset(patch);
1649*795d594fSAndroid Build Coastguard Worker writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1650*795d594fSAndroid Build Coastguard Worker patch,
1651*795d594fSAndroid Build Coastguard Worker offset_ + literal_offset,
1652*795d594fSAndroid Build Coastguard Worker target_offset);
1653*795d594fSAndroid Build Coastguard Worker break;
1654*795d594fSAndroid Build Coastguard Worker }
1655*795d594fSAndroid Build Coastguard Worker case LinkerPatch::Type::kBootImageRelRo: {
1656*795d594fSAndroid Build Coastguard Worker uint32_t target_offset =
1657*795d594fSAndroid Build Coastguard Worker writer_->data_img_rel_ro_start_ +
1658*795d594fSAndroid Build Coastguard Worker writer_->boot_image_rel_ro_entries_.Get(patch.BootImageOffset());
1659*795d594fSAndroid Build Coastguard Worker writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1660*795d594fSAndroid Build Coastguard Worker patch,
1661*795d594fSAndroid Build Coastguard Worker offset_ + literal_offset,
1662*795d594fSAndroid Build Coastguard Worker target_offset);
1663*795d594fSAndroid Build Coastguard Worker break;
1664*795d594fSAndroid Build Coastguard Worker }
1665*795d594fSAndroid Build Coastguard Worker case LinkerPatch::Type::kMethodBssEntry: {
1666*795d594fSAndroid Build Coastguard Worker uint32_t target_offset =
1667*795d594fSAndroid Build Coastguard Worker writer_->bss_start_ + writer_->bss_method_entries_.Get(patch.TargetMethod());
1668*795d594fSAndroid Build Coastguard Worker writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1669*795d594fSAndroid Build Coastguard Worker patch,
1670*795d594fSAndroid Build Coastguard Worker offset_ + literal_offset,
1671*795d594fSAndroid Build Coastguard Worker target_offset);
1672*795d594fSAndroid Build Coastguard Worker break;
1673*795d594fSAndroid Build Coastguard Worker }
1674*795d594fSAndroid Build Coastguard Worker case LinkerPatch::Type::kCallRelative: {
1675*795d594fSAndroid Build Coastguard Worker // NOTE: Relative calls across oat files are not supported.
1676*795d594fSAndroid Build Coastguard Worker uint32_t target_offset = GetTargetOffset(patch);
1677*795d594fSAndroid Build Coastguard Worker writer_->relative_patcher_->PatchCall(&patched_code_,
1678*795d594fSAndroid Build Coastguard Worker literal_offset,
1679*795d594fSAndroid Build Coastguard Worker offset_ + literal_offset,
1680*795d594fSAndroid Build Coastguard Worker target_offset);
1681*795d594fSAndroid Build Coastguard Worker break;
1682*795d594fSAndroid Build Coastguard Worker }
1683*795d594fSAndroid Build Coastguard Worker case LinkerPatch::Type::kStringRelative: {
1684*795d594fSAndroid Build Coastguard Worker uint32_t target_offset = GetTargetObjectOffset(GetTargetString(patch));
1685*795d594fSAndroid Build Coastguard Worker writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1686*795d594fSAndroid Build Coastguard Worker patch,
1687*795d594fSAndroid Build Coastguard Worker offset_ + literal_offset,
1688*795d594fSAndroid Build Coastguard Worker target_offset);
1689*795d594fSAndroid Build Coastguard Worker break;
1690*795d594fSAndroid Build Coastguard Worker }
1691*795d594fSAndroid Build Coastguard Worker case LinkerPatch::Type::kStringBssEntry: {
1692*795d594fSAndroid Build Coastguard Worker uint32_t target_offset =
1693*795d594fSAndroid Build Coastguard Worker writer_->bss_start_ + writer_->bss_string_entries_.Get(patch.TargetString());
1694*795d594fSAndroid Build Coastguard Worker writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1695*795d594fSAndroid Build Coastguard Worker patch,
1696*795d594fSAndroid Build Coastguard Worker offset_ + literal_offset,
1697*795d594fSAndroid Build Coastguard Worker target_offset);
1698*795d594fSAndroid Build Coastguard Worker break;
1699*795d594fSAndroid Build Coastguard Worker }
1700*795d594fSAndroid Build Coastguard Worker case LinkerPatch::Type::kMethodAppImageRelRo: {
1701*795d594fSAndroid Build Coastguard Worker uint32_t target_offset =
1702*795d594fSAndroid Build Coastguard Worker writer_->data_img_rel_ro_start_ +
1703*795d594fSAndroid Build Coastguard Worker writer_->app_image_rel_ro_method_entries_.Get(patch.TargetMethod());
1704*795d594fSAndroid Build Coastguard Worker writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1705*795d594fSAndroid Build Coastguard Worker patch,
1706*795d594fSAndroid Build Coastguard Worker offset_ + literal_offset,
1707*795d594fSAndroid Build Coastguard Worker target_offset);
1708*795d594fSAndroid Build Coastguard Worker break;
1709*795d594fSAndroid Build Coastguard Worker }
1710*795d594fSAndroid Build Coastguard Worker case LinkerPatch::Type::kMethodTypeBssEntry: {
1711*795d594fSAndroid Build Coastguard Worker uint32_t target_offset =
1712*795d594fSAndroid Build Coastguard Worker writer_->bss_start_ + writer_->bss_method_type_entries_.Get(patch.TargetProto());
1713*795d594fSAndroid Build Coastguard Worker writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1714*795d594fSAndroid Build Coastguard Worker patch,
1715*795d594fSAndroid Build Coastguard Worker offset_ + literal_offset,
1716*795d594fSAndroid Build Coastguard Worker target_offset);
1717*795d594fSAndroid Build Coastguard Worker break;
1718*795d594fSAndroid Build Coastguard Worker }
1719*795d594fSAndroid Build Coastguard Worker case LinkerPatch::Type::kTypeRelative: {
1720*795d594fSAndroid Build Coastguard Worker uint32_t target_offset = GetTargetObjectOffset(GetTargetType(patch));
1721*795d594fSAndroid Build Coastguard Worker writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1722*795d594fSAndroid Build Coastguard Worker patch,
1723*795d594fSAndroid Build Coastguard Worker offset_ + literal_offset,
1724*795d594fSAndroid Build Coastguard Worker target_offset);
1725*795d594fSAndroid Build Coastguard Worker break;
1726*795d594fSAndroid Build Coastguard Worker }
1727*795d594fSAndroid Build Coastguard Worker case LinkerPatch::Type::kTypeAppImageRelRo: {
1728*795d594fSAndroid Build Coastguard Worker uint32_t target_offset =
1729*795d594fSAndroid Build Coastguard Worker writer_->data_img_rel_ro_start_ +
1730*795d594fSAndroid Build Coastguard Worker writer_->app_image_rel_ro_type_entries_.Get(patch.TargetType());
1731*795d594fSAndroid Build Coastguard Worker writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1732*795d594fSAndroid Build Coastguard Worker patch,
1733*795d594fSAndroid Build Coastguard Worker offset_ + literal_offset,
1734*795d594fSAndroid Build Coastguard Worker target_offset);
1735*795d594fSAndroid Build Coastguard Worker break;
1736*795d594fSAndroid Build Coastguard Worker }
1737*795d594fSAndroid Build Coastguard Worker case LinkerPatch::Type::kTypeBssEntry: {
1738*795d594fSAndroid Build Coastguard Worker uint32_t target_offset =
1739*795d594fSAndroid Build Coastguard Worker writer_->bss_start_ + writer_->bss_type_entries_.Get(patch.TargetType());
1740*795d594fSAndroid Build Coastguard Worker writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1741*795d594fSAndroid Build Coastguard Worker patch,
1742*795d594fSAndroid Build Coastguard Worker offset_ + literal_offset,
1743*795d594fSAndroid Build Coastguard Worker target_offset);
1744*795d594fSAndroid Build Coastguard Worker break;
1745*795d594fSAndroid Build Coastguard Worker }
1746*795d594fSAndroid Build Coastguard Worker case LinkerPatch::Type::kPublicTypeBssEntry: {
1747*795d594fSAndroid Build Coastguard Worker uint32_t target_offset =
1748*795d594fSAndroid Build Coastguard Worker writer_->bss_start_ + writer_->bss_public_type_entries_.Get(patch.TargetType());
1749*795d594fSAndroid Build Coastguard Worker writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1750*795d594fSAndroid Build Coastguard Worker patch,
1751*795d594fSAndroid Build Coastguard Worker offset_ + literal_offset,
1752*795d594fSAndroid Build Coastguard Worker target_offset);
1753*795d594fSAndroid Build Coastguard Worker break;
1754*795d594fSAndroid Build Coastguard Worker }
1755*795d594fSAndroid Build Coastguard Worker case LinkerPatch::Type::kPackageTypeBssEntry: {
1756*795d594fSAndroid Build Coastguard Worker uint32_t target_offset =
1757*795d594fSAndroid Build Coastguard Worker writer_->bss_start_ + writer_->bss_package_type_entries_.Get(patch.TargetType());
1758*795d594fSAndroid Build Coastguard Worker writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1759*795d594fSAndroid Build Coastguard Worker patch,
1760*795d594fSAndroid Build Coastguard Worker offset_ + literal_offset,
1761*795d594fSAndroid Build Coastguard Worker target_offset);
1762*795d594fSAndroid Build Coastguard Worker break;
1763*795d594fSAndroid Build Coastguard Worker }
1764*795d594fSAndroid Build Coastguard Worker case LinkerPatch::Type::kMethodRelative: {
1765*795d594fSAndroid Build Coastguard Worker uint32_t target_offset = GetTargetMethodOffset(GetTargetMethod(patch));
1766*795d594fSAndroid Build Coastguard Worker writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1767*795d594fSAndroid Build Coastguard Worker patch,
1768*795d594fSAndroid Build Coastguard Worker offset_ + literal_offset,
1769*795d594fSAndroid Build Coastguard Worker target_offset);
1770*795d594fSAndroid Build Coastguard Worker break;
1771*795d594fSAndroid Build Coastguard Worker }
1772*795d594fSAndroid Build Coastguard Worker case LinkerPatch::Type::kJniEntrypointRelative: {
1773*795d594fSAndroid Build Coastguard Worker DCHECK(GetTargetMethod(patch)->IsNative());
1774*795d594fSAndroid Build Coastguard Worker uint32_t target_offset =
1775*795d594fSAndroid Build Coastguard Worker GetTargetMethodOffset(GetTargetMethod(patch)) +
1776*795d594fSAndroid Build Coastguard Worker ArtMethod::EntryPointFromJniOffset(pointer_size_).Uint32Value();
1777*795d594fSAndroid Build Coastguard Worker writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1778*795d594fSAndroid Build Coastguard Worker patch,
1779*795d594fSAndroid Build Coastguard Worker offset_ + literal_offset,
1780*795d594fSAndroid Build Coastguard Worker target_offset);
1781*795d594fSAndroid Build Coastguard Worker break;
1782*795d594fSAndroid Build Coastguard Worker }
1783*795d594fSAndroid Build Coastguard Worker case LinkerPatch::Type::kCallEntrypoint: {
1784*795d594fSAndroid Build Coastguard Worker writer_->relative_patcher_->PatchEntrypointCall(&patched_code_,
1785*795d594fSAndroid Build Coastguard Worker patch,
1786*795d594fSAndroid Build Coastguard Worker offset_ + literal_offset);
1787*795d594fSAndroid Build Coastguard Worker break;
1788*795d594fSAndroid Build Coastguard Worker }
1789*795d594fSAndroid Build Coastguard Worker case LinkerPatch::Type::kBakerReadBarrierBranch: {
1790*795d594fSAndroid Build Coastguard Worker writer_->relative_patcher_->PatchBakerReadBarrierBranch(&patched_code_,
1791*795d594fSAndroid Build Coastguard Worker patch,
1792*795d594fSAndroid Build Coastguard Worker offset_ + literal_offset);
1793*795d594fSAndroid Build Coastguard Worker break;
1794*795d594fSAndroid Build Coastguard Worker }
1795*795d594fSAndroid Build Coastguard Worker default: {
1796*795d594fSAndroid Build Coastguard Worker DCHECK(false) << "Unexpected linker patch type: " << patch.GetType();
1797*795d594fSAndroid Build Coastguard Worker break;
1798*795d594fSAndroid Build Coastguard Worker }
1799*795d594fSAndroid Build Coastguard Worker }
1800*795d594fSAndroid Build Coastguard Worker }
1801*795d594fSAndroid Build Coastguard Worker }
1802*795d594fSAndroid Build Coastguard Worker
1803*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(quick_code.data(), code_size)) {
1804*795d594fSAndroid Build Coastguard Worker ReportWriteFailure("method code", method_ref);
1805*795d594fSAndroid Build Coastguard Worker return false;
1806*795d594fSAndroid Build Coastguard Worker }
1807*795d594fSAndroid Build Coastguard Worker writer_->size_code_ += code_size;
1808*795d594fSAndroid Build Coastguard Worker offset_ += code_size;
1809*795d594fSAndroid Build Coastguard Worker }
1810*795d594fSAndroid Build Coastguard Worker DCHECK_OFFSET_();
1811*795d594fSAndroid Build Coastguard Worker
1812*795d594fSAndroid Build Coastguard Worker return true;
1813*795d594fSAndroid Build Coastguard Worker }
1814*795d594fSAndroid Build Coastguard Worker
GetOffset() const1815*795d594fSAndroid Build Coastguard Worker size_t GetOffset() const {
1816*795d594fSAndroid Build Coastguard Worker return offset_;
1817*795d594fSAndroid Build Coastguard Worker }
1818*795d594fSAndroid Build Coastguard Worker
1819*795d594fSAndroid Build Coastguard Worker private:
1820*795d594fSAndroid Build Coastguard Worker OatWriter* const writer_;
1821*795d594fSAndroid Build Coastguard Worker
1822*795d594fSAndroid Build Coastguard Worker // Updated in VisitMethod as methods are written out.
1823*795d594fSAndroid Build Coastguard Worker size_t offset_;
1824*795d594fSAndroid Build Coastguard Worker
1825*795d594fSAndroid Build Coastguard Worker // Potentially varies with every different VisitMethod.
1826*795d594fSAndroid Build Coastguard Worker // Used to determine which DexCache to use when finding ArtMethods.
1827*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file_;
1828*795d594fSAndroid Build Coastguard Worker
1829*795d594fSAndroid Build Coastguard Worker // Pointer size we are compiling to.
1830*795d594fSAndroid Build Coastguard Worker const PointerSize pointer_size_;
1831*795d594fSAndroid Build Coastguard Worker // The image writer's classloader, if there is one, else null.
1832*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::ClassLoader> class_loader_;
1833*795d594fSAndroid Build Coastguard Worker // Stream to output file, where the OAT code will be written to.
1834*795d594fSAndroid Build Coastguard Worker OutputStream* const out_;
1835*795d594fSAndroid Build Coastguard Worker const size_t file_offset_;
1836*795d594fSAndroid Build Coastguard Worker ClassLinker* const class_linker_;
1837*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::DexCache> dex_cache_;
1838*795d594fSAndroid Build Coastguard Worker std::vector<uint8_t> patched_code_;
1839*795d594fSAndroid Build Coastguard Worker const ScopedAssertNoThreadSuspension no_thread_suspension_;
1840*795d594fSAndroid Build Coastguard Worker
ReportWriteFailure(const char * what,const MethodReference & method_ref)1841*795d594fSAndroid Build Coastguard Worker void ReportWriteFailure(const char* what, const MethodReference& method_ref) {
1842*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write " << what << " for "
1843*795d594fSAndroid Build Coastguard Worker << method_ref.PrettyMethod() << " to " << out_->GetLocation();
1844*795d594fSAndroid Build Coastguard Worker }
1845*795d594fSAndroid Build Coastguard Worker
GetTargetMethod(const LinkerPatch & patch)1846*795d594fSAndroid Build Coastguard Worker ArtMethod* GetTargetMethod(const LinkerPatch& patch)
1847*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
1848*795d594fSAndroid Build Coastguard Worker MethodReference ref = patch.TargetMethod();
1849*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::DexCache> dex_cache =
1850*795d594fSAndroid Build Coastguard Worker (dex_file_ == ref.dex_file) ? dex_cache_ : class_linker_->FindDexCache(
1851*795d594fSAndroid Build Coastguard Worker Thread::Current(), *ref.dex_file);
1852*795d594fSAndroid Build Coastguard Worker ArtMethod* method =
1853*795d594fSAndroid Build Coastguard Worker class_linker_->LookupResolvedMethod(ref.index, dex_cache, class_loader_);
1854*795d594fSAndroid Build Coastguard Worker CHECK(method != nullptr);
1855*795d594fSAndroid Build Coastguard Worker return method;
1856*795d594fSAndroid Build Coastguard Worker }
1857*795d594fSAndroid Build Coastguard Worker
GetTargetOffset(const LinkerPatch & patch)1858*795d594fSAndroid Build Coastguard Worker uint32_t GetTargetOffset(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
1859*795d594fSAndroid Build Coastguard Worker uint32_t target_offset = writer_->relative_patcher_->GetOffset(patch.TargetMethod());
1860*795d594fSAndroid Build Coastguard Worker // If there's no new compiled code, we need to point to the correct trampoline.
1861*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(target_offset == 0)) {
1862*795d594fSAndroid Build Coastguard Worker ArtMethod* target = GetTargetMethod(patch);
1863*795d594fSAndroid Build Coastguard Worker DCHECK(target != nullptr);
1864*795d594fSAndroid Build Coastguard Worker // TODO: Remove kCallRelative? This patch type is currently not in use.
1865*795d594fSAndroid Build Coastguard Worker // If we want to use it again, we should make sure that we either use it
1866*795d594fSAndroid Build Coastguard Worker // only for target methods that were actually compiled, or call the
1867*795d594fSAndroid Build Coastguard Worker // method dispatch thunk. Currently, ARM/ARM64 patchers would emit the
1868*795d594fSAndroid Build Coastguard Worker // thunk for far `target_offset` (so we could teach them to use the
1869*795d594fSAndroid Build Coastguard Worker // thunk for `target_offset == 0`) but x86/x86-64 patchers do not.
1870*795d594fSAndroid Build Coastguard Worker // (When this was originally implemented, every oat file contained
1871*795d594fSAndroid Build Coastguard Worker // trampolines, so we could just return their offset here. Now only
1872*795d594fSAndroid Build Coastguard Worker // the boot image contains them, so this is not always an option.)
1873*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "The target method was not compiled.";
1874*795d594fSAndroid Build Coastguard Worker }
1875*795d594fSAndroid Build Coastguard Worker return target_offset;
1876*795d594fSAndroid Build Coastguard Worker }
1877*795d594fSAndroid Build Coastguard Worker
GetDexCache(const DexFile * target_dex_file)1878*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::DexCache> GetDexCache(const DexFile* target_dex_file)
1879*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
1880*795d594fSAndroid Build Coastguard Worker return (target_dex_file == dex_file_)
1881*795d594fSAndroid Build Coastguard Worker ? dex_cache_
1882*795d594fSAndroid Build Coastguard Worker : class_linker_->FindDexCache(Thread::Current(), *target_dex_file);
1883*795d594fSAndroid Build Coastguard Worker }
1884*795d594fSAndroid Build Coastguard Worker
GetTargetType(const LinkerPatch & patch)1885*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> GetTargetType(const LinkerPatch& patch)
1886*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
1887*795d594fSAndroid Build Coastguard Worker DCHECK(writer_->HasImage());
1888*795d594fSAndroid Build Coastguard Worker TypeReference target_type = patch.TargetType();
1889*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::DexCache> dex_cache = GetDexCache(target_type.dex_file);
1890*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> type =
1891*795d594fSAndroid Build Coastguard Worker class_linker_->LookupResolvedType(target_type.TypeIndex(), dex_cache, class_loader_);
1892*795d594fSAndroid Build Coastguard Worker CHECK(type != nullptr);
1893*795d594fSAndroid Build Coastguard Worker return type;
1894*795d594fSAndroid Build Coastguard Worker }
1895*795d594fSAndroid Build Coastguard Worker
GetTargetString(const LinkerPatch & patch)1896*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::String> GetTargetString(const LinkerPatch& patch)
1897*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
1898*795d594fSAndroid Build Coastguard Worker ClassLinker* linker = Runtime::Current()->GetClassLinker();
1899*795d594fSAndroid Build Coastguard Worker StringReference target_string = patch.TargetString();
1900*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::String> string =
1901*795d594fSAndroid Build Coastguard Worker linker->LookupString(target_string.StringIndex(), GetDexCache(target_string.dex_file));
1902*795d594fSAndroid Build Coastguard Worker DCHECK(string != nullptr);
1903*795d594fSAndroid Build Coastguard Worker DCHECK(writer_->GetCompilerOptions().IsBootImage() ||
1904*795d594fSAndroid Build Coastguard Worker writer_->GetCompilerOptions().IsBootImageExtension());
1905*795d594fSAndroid Build Coastguard Worker return string;
1906*795d594fSAndroid Build Coastguard Worker }
1907*795d594fSAndroid Build Coastguard Worker
GetTargetIntrinsicReferenceOffset(const LinkerPatch & patch)1908*795d594fSAndroid Build Coastguard Worker uint32_t GetTargetIntrinsicReferenceOffset(const LinkerPatch& patch)
1909*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
1910*795d594fSAndroid Build Coastguard Worker DCHECK(writer_->GetCompilerOptions().IsBootImage());
1911*795d594fSAndroid Build Coastguard Worker const void* address =
1912*795d594fSAndroid Build Coastguard Worker writer_->image_writer_->GetIntrinsicReferenceAddress(patch.IntrinsicData());
1913*795d594fSAndroid Build Coastguard Worker size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
1914*795d594fSAndroid Build Coastguard Worker uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
1915*795d594fSAndroid Build Coastguard Worker // TODO: Clean up offset types. The target offset must be treated as signed.
1916*795d594fSAndroid Build Coastguard Worker return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(address) - oat_data_begin);
1917*795d594fSAndroid Build Coastguard Worker }
1918*795d594fSAndroid Build Coastguard Worker
GetTargetMethodOffset(ArtMethod * method)1919*795d594fSAndroid Build Coastguard Worker uint32_t GetTargetMethodOffset(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
1920*795d594fSAndroid Build Coastguard Worker DCHECK(writer_->GetCompilerOptions().IsBootImage() ||
1921*795d594fSAndroid Build Coastguard Worker writer_->GetCompilerOptions().IsBootImageExtension());
1922*795d594fSAndroid Build Coastguard Worker method = writer_->image_writer_->GetImageMethodAddress(method);
1923*795d594fSAndroid Build Coastguard Worker size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
1924*795d594fSAndroid Build Coastguard Worker uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
1925*795d594fSAndroid Build Coastguard Worker // TODO: Clean up offset types. The target offset must be treated as signed.
1926*795d594fSAndroid Build Coastguard Worker return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(method) - oat_data_begin);
1927*795d594fSAndroid Build Coastguard Worker }
1928*795d594fSAndroid Build Coastguard Worker
GetTargetObjectOffset(ObjPtr<mirror::Object> object)1929*795d594fSAndroid Build Coastguard Worker uint32_t GetTargetObjectOffset(ObjPtr<mirror::Object> object)
1930*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
1931*795d594fSAndroid Build Coastguard Worker DCHECK(writer_->GetCompilerOptions().IsBootImage() ||
1932*795d594fSAndroid Build Coastguard Worker writer_->GetCompilerOptions().IsBootImageExtension());
1933*795d594fSAndroid Build Coastguard Worker object = writer_->image_writer_->GetImageAddress(object.Ptr());
1934*795d594fSAndroid Build Coastguard Worker size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
1935*795d594fSAndroid Build Coastguard Worker uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
1936*795d594fSAndroid Build Coastguard Worker // TODO: Clean up offset types. The target offset must be treated as signed.
1937*795d594fSAndroid Build Coastguard Worker return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(object.Ptr()) - oat_data_begin);
1938*795d594fSAndroid Build Coastguard Worker }
1939*795d594fSAndroid Build Coastguard Worker };
1940*795d594fSAndroid Build Coastguard Worker
1941*795d594fSAndroid Build Coastguard Worker // Visit all methods from all classes in all dex files with the specified visitor.
VisitDexMethods(DexMethodVisitor * visitor)1942*795d594fSAndroid Build Coastguard Worker bool OatWriter::VisitDexMethods(DexMethodVisitor* visitor) {
1943*795d594fSAndroid Build Coastguard Worker for (const DexFile* dex_file : *dex_files_) {
1944*795d594fSAndroid Build Coastguard Worker for (ClassAccessor accessor : dex_file->GetClasses()) {
1945*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(!visitor->StartClass(dex_file, accessor.GetClassDefIndex()))) {
1946*795d594fSAndroid Build Coastguard Worker return false;
1947*795d594fSAndroid Build Coastguard Worker }
1948*795d594fSAndroid Build Coastguard Worker if (MayHaveCompiledMethods()) {
1949*795d594fSAndroid Build Coastguard Worker size_t class_def_method_index = 0u;
1950*795d594fSAndroid Build Coastguard Worker for (const ClassAccessor::Method& method : accessor.GetMethods()) {
1951*795d594fSAndroid Build Coastguard Worker if (!visitor->VisitMethod(class_def_method_index, method)) {
1952*795d594fSAndroid Build Coastguard Worker return false;
1953*795d594fSAndroid Build Coastguard Worker }
1954*795d594fSAndroid Build Coastguard Worker ++class_def_method_index;
1955*795d594fSAndroid Build Coastguard Worker }
1956*795d594fSAndroid Build Coastguard Worker }
1957*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(!visitor->EndClass())) {
1958*795d594fSAndroid Build Coastguard Worker return false;
1959*795d594fSAndroid Build Coastguard Worker }
1960*795d594fSAndroid Build Coastguard Worker }
1961*795d594fSAndroid Build Coastguard Worker }
1962*795d594fSAndroid Build Coastguard Worker return true;
1963*795d594fSAndroid Build Coastguard Worker }
1964*795d594fSAndroid Build Coastguard Worker
InitOatHeader(uint32_t num_dex_files,SafeMap<std::string,std::string> * key_value_store)1965*795d594fSAndroid Build Coastguard Worker size_t OatWriter::InitOatHeader(uint32_t num_dex_files,
1966*795d594fSAndroid Build Coastguard Worker SafeMap<std::string, std::string>* key_value_store) {
1967*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split("InitOatHeader", timings_);
1968*795d594fSAndroid Build Coastguard Worker // Check that oat version when runtime was compiled matches the oat version
1969*795d594fSAndroid Build Coastguard Worker // when dex2oat was compiled. We have seen cases where they got out of sync.
1970*795d594fSAndroid Build Coastguard Worker constexpr std::array<uint8_t, 4> dex2oat_oat_version = OatHeader::kOatVersion;
1971*795d594fSAndroid Build Coastguard Worker OatHeader::CheckOatVersion(dex2oat_oat_version);
1972*795d594fSAndroid Build Coastguard Worker oat_header_.reset(OatHeader::Create(GetCompilerOptions().GetInstructionSet(),
1973*795d594fSAndroid Build Coastguard Worker GetCompilerOptions().GetInstructionSetFeatures(),
1974*795d594fSAndroid Build Coastguard Worker num_dex_files,
1975*795d594fSAndroid Build Coastguard Worker key_value_store));
1976*795d594fSAndroid Build Coastguard Worker size_oat_header_ += sizeof(OatHeader);
1977*795d594fSAndroid Build Coastguard Worker size_oat_header_key_value_store_ += oat_header_->GetHeaderSize() - sizeof(OatHeader);
1978*795d594fSAndroid Build Coastguard Worker return oat_header_->GetHeaderSize();
1979*795d594fSAndroid Build Coastguard Worker }
1980*795d594fSAndroid Build Coastguard Worker
InitClassOffsets(size_t offset)1981*795d594fSAndroid Build Coastguard Worker size_t OatWriter::InitClassOffsets(size_t offset) {
1982*795d594fSAndroid Build Coastguard Worker // Reserve space for class offsets in OAT and update class_offsets_offset_.
1983*795d594fSAndroid Build Coastguard Worker for (OatDexFile& oat_dex_file : oat_dex_files_) {
1984*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(oat_dex_file.class_offsets_offset_, 0u);
1985*795d594fSAndroid Build Coastguard Worker if (!oat_dex_file.class_offsets_.empty()) {
1986*795d594fSAndroid Build Coastguard Worker // Class offsets are required to be 4 byte aligned.
1987*795d594fSAndroid Build Coastguard Worker offset = RoundUp(offset, 4u);
1988*795d594fSAndroid Build Coastguard Worker oat_dex_file.class_offsets_offset_ = offset;
1989*795d594fSAndroid Build Coastguard Worker offset += oat_dex_file.GetClassOffsetsRawSize();
1990*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(offset, 4u);
1991*795d594fSAndroid Build Coastguard Worker }
1992*795d594fSAndroid Build Coastguard Worker }
1993*795d594fSAndroid Build Coastguard Worker return offset;
1994*795d594fSAndroid Build Coastguard Worker }
1995*795d594fSAndroid Build Coastguard Worker
InitOatClasses(size_t offset)1996*795d594fSAndroid Build Coastguard Worker size_t OatWriter::InitOatClasses(size_t offset) {
1997*795d594fSAndroid Build Coastguard Worker // calculate the offsets within OatDexFiles to OatClasses
1998*795d594fSAndroid Build Coastguard Worker InitOatClassesMethodVisitor visitor(this, offset);
1999*795d594fSAndroid Build Coastguard Worker bool success = VisitDexMethods(&visitor);
2000*795d594fSAndroid Build Coastguard Worker CHECK(success);
2001*795d594fSAndroid Build Coastguard Worker offset = visitor.GetOffset();
2002*795d594fSAndroid Build Coastguard Worker
2003*795d594fSAndroid Build Coastguard Worker // Update oat_dex_files_.
2004*795d594fSAndroid Build Coastguard Worker auto oat_class_it = oat_class_headers_.begin();
2005*795d594fSAndroid Build Coastguard Worker for (OatDexFile& oat_dex_file : oat_dex_files_) {
2006*795d594fSAndroid Build Coastguard Worker for (uint32_t& class_offset : oat_dex_file.class_offsets_) {
2007*795d594fSAndroid Build Coastguard Worker DCHECK(oat_class_it != oat_class_headers_.end());
2008*795d594fSAndroid Build Coastguard Worker class_offset = oat_class_it->offset_;
2009*795d594fSAndroid Build Coastguard Worker ++oat_class_it;
2010*795d594fSAndroid Build Coastguard Worker }
2011*795d594fSAndroid Build Coastguard Worker }
2012*795d594fSAndroid Build Coastguard Worker CHECK(oat_class_it == oat_class_headers_.end());
2013*795d594fSAndroid Build Coastguard Worker
2014*795d594fSAndroid Build Coastguard Worker return offset;
2015*795d594fSAndroid Build Coastguard Worker }
2016*795d594fSAndroid Build Coastguard Worker
InitOatMaps(size_t offset)2017*795d594fSAndroid Build Coastguard Worker size_t OatWriter::InitOatMaps(size_t offset) {
2018*795d594fSAndroid Build Coastguard Worker if (!MayHaveCompiledMethods()) {
2019*795d594fSAndroid Build Coastguard Worker return offset;
2020*795d594fSAndroid Build Coastguard Worker }
2021*795d594fSAndroid Build Coastguard Worker if (GetCompilerOptions().DeduplicateCode()) {
2022*795d594fSAndroid Build Coastguard Worker InitMapMethodVisitor</*kDeduplicate=*/ true> visitor(this, offset);
2023*795d594fSAndroid Build Coastguard Worker bool success = VisitDexMethods(&visitor);
2024*795d594fSAndroid Build Coastguard Worker DCHECK(success);
2025*795d594fSAndroid Build Coastguard Worker } else {
2026*795d594fSAndroid Build Coastguard Worker InitMapMethodVisitor</*kDeduplicate=*/ false> visitor(this, offset);
2027*795d594fSAndroid Build Coastguard Worker bool success = VisitDexMethods(&visitor);
2028*795d594fSAndroid Build Coastguard Worker DCHECK(success);
2029*795d594fSAndroid Build Coastguard Worker }
2030*795d594fSAndroid Build Coastguard Worker code_info_data_.shrink_to_fit();
2031*795d594fSAndroid Build Coastguard Worker offset += code_info_data_.size();
2032*795d594fSAndroid Build Coastguard Worker return offset;
2033*795d594fSAndroid Build Coastguard Worker }
2034*795d594fSAndroid Build Coastguard Worker
2035*795d594fSAndroid Build Coastguard Worker template <typename GetBssOffset>
CalculateNumberOfIndexBssMappingEntries(size_t number_of_indexes,size_t slot_size,const BitVector & indexes,GetBssOffset get_bss_offset)2036*795d594fSAndroid Build Coastguard Worker static size_t CalculateNumberOfIndexBssMappingEntries(size_t number_of_indexes,
2037*795d594fSAndroid Build Coastguard Worker size_t slot_size,
2038*795d594fSAndroid Build Coastguard Worker const BitVector& indexes,
2039*795d594fSAndroid Build Coastguard Worker GetBssOffset get_bss_offset) {
2040*795d594fSAndroid Build Coastguard Worker IndexBssMappingEncoder encoder(number_of_indexes, slot_size);
2041*795d594fSAndroid Build Coastguard Worker size_t number_of_entries = 0u;
2042*795d594fSAndroid Build Coastguard Worker bool first_index = true;
2043*795d594fSAndroid Build Coastguard Worker for (uint32_t index : indexes.Indexes()) {
2044*795d594fSAndroid Build Coastguard Worker uint32_t bss_offset = get_bss_offset(index);
2045*795d594fSAndroid Build Coastguard Worker if (first_index || !encoder.TryMerge(index, bss_offset)) {
2046*795d594fSAndroid Build Coastguard Worker encoder.Reset(index, bss_offset);
2047*795d594fSAndroid Build Coastguard Worker ++number_of_entries;
2048*795d594fSAndroid Build Coastguard Worker first_index = false;
2049*795d594fSAndroid Build Coastguard Worker }
2050*795d594fSAndroid Build Coastguard Worker }
2051*795d594fSAndroid Build Coastguard Worker DCHECK_NE(number_of_entries, 0u);
2052*795d594fSAndroid Build Coastguard Worker return number_of_entries;
2053*795d594fSAndroid Build Coastguard Worker }
2054*795d594fSAndroid Build Coastguard Worker
2055*795d594fSAndroid Build Coastguard Worker template <typename GetBssOffset>
CalculateIndexBssMappingSize(size_t number_of_indexes,size_t slot_size,const BitVector & indexes,GetBssOffset get_bss_offset)2056*795d594fSAndroid Build Coastguard Worker static size_t CalculateIndexBssMappingSize(size_t number_of_indexes,
2057*795d594fSAndroid Build Coastguard Worker size_t slot_size,
2058*795d594fSAndroid Build Coastguard Worker const BitVector& indexes,
2059*795d594fSAndroid Build Coastguard Worker GetBssOffset get_bss_offset) {
2060*795d594fSAndroid Build Coastguard Worker size_t number_of_entries = CalculateNumberOfIndexBssMappingEntries(number_of_indexes,
2061*795d594fSAndroid Build Coastguard Worker slot_size,
2062*795d594fSAndroid Build Coastguard Worker indexes,
2063*795d594fSAndroid Build Coastguard Worker get_bss_offset);
2064*795d594fSAndroid Build Coastguard Worker return IndexBssMapping::ComputeSize(number_of_entries);
2065*795d594fSAndroid Build Coastguard Worker }
2066*795d594fSAndroid Build Coastguard Worker
CalculateIndexBssMappingSize(const DexFile * dex_file,const BitVector & type_indexes,const SafeMap<TypeReference,size_t,TypeReferenceValueComparator> & bss_entries)2067*795d594fSAndroid Build Coastguard Worker static size_t CalculateIndexBssMappingSize(
2068*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file,
2069*795d594fSAndroid Build Coastguard Worker const BitVector& type_indexes,
2070*795d594fSAndroid Build Coastguard Worker const SafeMap<TypeReference, size_t, TypeReferenceValueComparator>& bss_entries) {
2071*795d594fSAndroid Build Coastguard Worker return CalculateIndexBssMappingSize(
2072*795d594fSAndroid Build Coastguard Worker dex_file->NumTypeIds(),
2073*795d594fSAndroid Build Coastguard Worker sizeof(GcRoot<mirror::Class>),
2074*795d594fSAndroid Build Coastguard Worker type_indexes,
2075*795d594fSAndroid Build Coastguard Worker [=](uint32_t index) { return bss_entries.Get({dex_file, dex::TypeIndex(index)}); });
2076*795d594fSAndroid Build Coastguard Worker }
2077*795d594fSAndroid Build Coastguard Worker
InitIndexBssMappings(size_t offset)2078*795d594fSAndroid Build Coastguard Worker size_t OatWriter::InitIndexBssMappings(size_t offset) {
2079*795d594fSAndroid Build Coastguard Worker if (bss_method_entry_references_.empty() &&
2080*795d594fSAndroid Build Coastguard Worker bss_type_entry_references_.empty() &&
2081*795d594fSAndroid Build Coastguard Worker bss_public_type_entry_references_.empty() &&
2082*795d594fSAndroid Build Coastguard Worker bss_package_type_entry_references_.empty() &&
2083*795d594fSAndroid Build Coastguard Worker bss_string_entry_references_.empty() &&
2084*795d594fSAndroid Build Coastguard Worker bss_method_type_entry_references_.empty()) {
2085*795d594fSAndroid Build Coastguard Worker return offset;
2086*795d594fSAndroid Build Coastguard Worker }
2087*795d594fSAndroid Build Coastguard Worker // If there are any classes, the class offsets allocation aligns the offset
2088*795d594fSAndroid Build Coastguard Worker // and we cannot have any index bss mappings without class offsets.
2089*795d594fSAndroid Build Coastguard Worker static_assert(alignof(IndexBssMapping) == 4u, "IndexBssMapping alignment check.");
2090*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(offset, 4u);
2091*795d594fSAndroid Build Coastguard Worker
2092*795d594fSAndroid Build Coastguard Worker size_t number_of_method_dex_files = 0u;
2093*795d594fSAndroid Build Coastguard Worker size_t number_of_type_dex_files = 0u;
2094*795d594fSAndroid Build Coastguard Worker size_t number_of_public_type_dex_files = 0u;
2095*795d594fSAndroid Build Coastguard Worker size_t number_of_package_type_dex_files = 0u;
2096*795d594fSAndroid Build Coastguard Worker size_t number_of_string_dex_files = 0u;
2097*795d594fSAndroid Build Coastguard Worker size_t number_of_method_type_dex_files = 0u;
2098*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
2099*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file = (*dex_files_)[i];
2100*795d594fSAndroid Build Coastguard Worker offset = InitIndexBssMappingsHelper(offset,
2101*795d594fSAndroid Build Coastguard Worker dex_file,
2102*795d594fSAndroid Build Coastguard Worker number_of_method_dex_files,
2103*795d594fSAndroid Build Coastguard Worker number_of_type_dex_files,
2104*795d594fSAndroid Build Coastguard Worker number_of_public_type_dex_files,
2105*795d594fSAndroid Build Coastguard Worker number_of_package_type_dex_files,
2106*795d594fSAndroid Build Coastguard Worker number_of_string_dex_files,
2107*795d594fSAndroid Build Coastguard Worker number_of_method_type_dex_files,
2108*795d594fSAndroid Build Coastguard Worker oat_dex_files_[i].method_bss_mapping_offset_,
2109*795d594fSAndroid Build Coastguard Worker oat_dex_files_[i].type_bss_mapping_offset_,
2110*795d594fSAndroid Build Coastguard Worker oat_dex_files_[i].public_type_bss_mapping_offset_,
2111*795d594fSAndroid Build Coastguard Worker oat_dex_files_[i].package_type_bss_mapping_offset_,
2112*795d594fSAndroid Build Coastguard Worker oat_dex_files_[i].string_bss_mapping_offset_,
2113*795d594fSAndroid Build Coastguard Worker oat_dex_files_[i].method_type_bss_mapping_offset_);
2114*795d594fSAndroid Build Coastguard Worker }
2115*795d594fSAndroid Build Coastguard Worker
2116*795d594fSAndroid Build Coastguard Worker if (!compiler_options_.IsBootImage()) {
2117*795d594fSAndroid Build Coastguard Worker ArrayRef<const DexFile* const> boot_class_path(
2118*795d594fSAndroid Build Coastguard Worker Runtime::Current()->GetClassLinker()->GetBootClassPath());
2119*795d594fSAndroid Build Coastguard Worker // We initialize bcp_bss_info except for the boot image case.
2120*795d594fSAndroid Build Coastguard Worker // Note that we have an early break at the beginning of the method, so `bcp_bss_info_` will also
2121*795d594fSAndroid Build Coastguard Worker // be empty in the case of having no mappings at all.
2122*795d594fSAndroid Build Coastguard Worker
2123*795d594fSAndroid Build Coastguard Worker if (compiler_options_.IsBootImageExtension()) {
2124*795d594fSAndroid Build Coastguard Worker // For boot image extension, the boot_class_path ends with the compiled dex files. In multi
2125*795d594fSAndroid Build Coastguard Worker // image, we might have several oat writers so we have to get all of the compiled dex files
2126*795d594fSAndroid Build Coastguard Worker // and not just the one we are compiling right now. Remove them to have the correct number of
2127*795d594fSAndroid Build Coastguard Worker // references.
2128*795d594fSAndroid Build Coastguard Worker ArrayRef<const DexFile* const> to_exclude(compiler_options_.GetDexFilesForOatFile());
2129*795d594fSAndroid Build Coastguard Worker DCHECK_GE(boot_class_path.size(), to_exclude.size());
2130*795d594fSAndroid Build Coastguard Worker DCHECK(std::equal(to_exclude.rbegin(), to_exclude.rend(), boot_class_path.rbegin()));
2131*795d594fSAndroid Build Coastguard Worker boot_class_path = boot_class_path.SubArray(0, boot_class_path.size() - to_exclude.size());
2132*795d594fSAndroid Build Coastguard Worker }
2133*795d594fSAndroid Build Coastguard Worker
2134*795d594fSAndroid Build Coastguard Worker DCHECK(bcp_bss_info_.empty());
2135*795d594fSAndroid Build Coastguard Worker bcp_bss_info_.resize(boot_class_path.size());
2136*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, size = bcp_bss_info_.size(); i != size; ++i) {
2137*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file = boot_class_path[i];
2138*795d594fSAndroid Build Coastguard Worker DCHECK(!ContainsElement(*dex_files_, dex_file));
2139*795d594fSAndroid Build Coastguard Worker offset = InitIndexBssMappingsHelper(offset,
2140*795d594fSAndroid Build Coastguard Worker dex_file,
2141*795d594fSAndroid Build Coastguard Worker number_of_method_dex_files,
2142*795d594fSAndroid Build Coastguard Worker number_of_type_dex_files,
2143*795d594fSAndroid Build Coastguard Worker number_of_public_type_dex_files,
2144*795d594fSAndroid Build Coastguard Worker number_of_package_type_dex_files,
2145*795d594fSAndroid Build Coastguard Worker number_of_string_dex_files,
2146*795d594fSAndroid Build Coastguard Worker number_of_method_type_dex_files,
2147*795d594fSAndroid Build Coastguard Worker bcp_bss_info_[i].method_bss_mapping_offset,
2148*795d594fSAndroid Build Coastguard Worker bcp_bss_info_[i].type_bss_mapping_offset,
2149*795d594fSAndroid Build Coastguard Worker bcp_bss_info_[i].public_type_bss_mapping_offset,
2150*795d594fSAndroid Build Coastguard Worker bcp_bss_info_[i].package_type_bss_mapping_offset,
2151*795d594fSAndroid Build Coastguard Worker bcp_bss_info_[i].string_bss_mapping_offset,
2152*795d594fSAndroid Build Coastguard Worker bcp_bss_info_[i].method_type_bss_mapping_offset);
2153*795d594fSAndroid Build Coastguard Worker }
2154*795d594fSAndroid Build Coastguard Worker }
2155*795d594fSAndroid Build Coastguard Worker
2156*795d594fSAndroid Build Coastguard Worker // Check that all dex files targeted by bss entries are in `*dex_files_`, or in the bootclaspath's
2157*795d594fSAndroid Build Coastguard Worker // DexFiles in the single image case.
2158*795d594fSAndroid Build Coastguard Worker CHECK_EQ(number_of_method_dex_files, bss_method_entry_references_.size());
2159*795d594fSAndroid Build Coastguard Worker CHECK_EQ(number_of_type_dex_files, bss_type_entry_references_.size());
2160*795d594fSAndroid Build Coastguard Worker CHECK_EQ(number_of_public_type_dex_files, bss_public_type_entry_references_.size());
2161*795d594fSAndroid Build Coastguard Worker CHECK_EQ(number_of_package_type_dex_files, bss_package_type_entry_references_.size());
2162*795d594fSAndroid Build Coastguard Worker CHECK_EQ(number_of_string_dex_files, bss_string_entry_references_.size());
2163*795d594fSAndroid Build Coastguard Worker CHECK_EQ(number_of_method_type_dex_files, bss_method_type_entry_references_.size());
2164*795d594fSAndroid Build Coastguard Worker
2165*795d594fSAndroid Build Coastguard Worker return offset;
2166*795d594fSAndroid Build Coastguard Worker }
2167*795d594fSAndroid Build Coastguard Worker
InitIndexBssMappingsHelper(size_t offset,const DexFile * dex_file,size_t & number_of_method_dex_files,size_t & number_of_type_dex_files,size_t & number_of_public_type_dex_files,size_t & number_of_package_type_dex_files,size_t & number_of_string_dex_files,size_t & number_of_method_type_dex_files,uint32_t & method_bss_mapping_offset,uint32_t & type_bss_mapping_offset,uint32_t & public_type_bss_mapping_offset,uint32_t & package_type_bss_mapping_offset,uint32_t & string_bss_mapping_offset,uint32_t & method_type_bss_mapping_offset)2168*795d594fSAndroid Build Coastguard Worker size_t OatWriter::InitIndexBssMappingsHelper(size_t offset,
2169*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file,
2170*795d594fSAndroid Build Coastguard Worker /*inout*/ size_t& number_of_method_dex_files,
2171*795d594fSAndroid Build Coastguard Worker /*inout*/ size_t& number_of_type_dex_files,
2172*795d594fSAndroid Build Coastguard Worker /*inout*/ size_t& number_of_public_type_dex_files,
2173*795d594fSAndroid Build Coastguard Worker /*inout*/ size_t& number_of_package_type_dex_files,
2174*795d594fSAndroid Build Coastguard Worker /*inout*/ size_t& number_of_string_dex_files,
2175*795d594fSAndroid Build Coastguard Worker /*inout*/ size_t& number_of_method_type_dex_files,
2176*795d594fSAndroid Build Coastguard Worker /*inout*/ uint32_t& method_bss_mapping_offset,
2177*795d594fSAndroid Build Coastguard Worker /*inout*/ uint32_t& type_bss_mapping_offset,
2178*795d594fSAndroid Build Coastguard Worker /*inout*/ uint32_t& public_type_bss_mapping_offset,
2179*795d594fSAndroid Build Coastguard Worker /*inout*/ uint32_t& package_type_bss_mapping_offset,
2180*795d594fSAndroid Build Coastguard Worker /*inout*/ uint32_t& string_bss_mapping_offset,
2181*795d594fSAndroid Build Coastguard Worker /*inout*/ uint32_t& method_type_bss_mapping_offset) {
2182*795d594fSAndroid Build Coastguard Worker const PointerSize pointer_size = GetInstructionSetPointerSize(oat_header_->GetInstructionSet());
2183*795d594fSAndroid Build Coastguard Worker auto method_it = bss_method_entry_references_.find(dex_file);
2184*795d594fSAndroid Build Coastguard Worker if (method_it != bss_method_entry_references_.end()) {
2185*795d594fSAndroid Build Coastguard Worker const BitVector& method_indexes = method_it->second;
2186*795d594fSAndroid Build Coastguard Worker ++number_of_method_dex_files;
2187*795d594fSAndroid Build Coastguard Worker method_bss_mapping_offset = offset;
2188*795d594fSAndroid Build Coastguard Worker offset += CalculateIndexBssMappingSize(dex_file->NumMethodIds(),
2189*795d594fSAndroid Build Coastguard Worker static_cast<size_t>(pointer_size),
2190*795d594fSAndroid Build Coastguard Worker method_indexes,
2191*795d594fSAndroid Build Coastguard Worker [this, dex_file](uint32_t index) {
2192*795d594fSAndroid Build Coastguard Worker return bss_method_entries_.Get({dex_file, index});
2193*795d594fSAndroid Build Coastguard Worker });
2194*795d594fSAndroid Build Coastguard Worker }
2195*795d594fSAndroid Build Coastguard Worker
2196*795d594fSAndroid Build Coastguard Worker auto type_it = bss_type_entry_references_.find(dex_file);
2197*795d594fSAndroid Build Coastguard Worker if (type_it != bss_type_entry_references_.end()) {
2198*795d594fSAndroid Build Coastguard Worker const BitVector& type_indexes = type_it->second;
2199*795d594fSAndroid Build Coastguard Worker ++number_of_type_dex_files;
2200*795d594fSAndroid Build Coastguard Worker type_bss_mapping_offset = offset;
2201*795d594fSAndroid Build Coastguard Worker offset += CalculateIndexBssMappingSize(dex_file, type_indexes, bss_type_entries_);
2202*795d594fSAndroid Build Coastguard Worker }
2203*795d594fSAndroid Build Coastguard Worker
2204*795d594fSAndroid Build Coastguard Worker auto public_type_it = bss_public_type_entry_references_.find(dex_file);
2205*795d594fSAndroid Build Coastguard Worker if (public_type_it != bss_public_type_entry_references_.end()) {
2206*795d594fSAndroid Build Coastguard Worker const BitVector& type_indexes = public_type_it->second;
2207*795d594fSAndroid Build Coastguard Worker ++number_of_public_type_dex_files;
2208*795d594fSAndroid Build Coastguard Worker public_type_bss_mapping_offset = offset;
2209*795d594fSAndroid Build Coastguard Worker offset += CalculateIndexBssMappingSize(dex_file, type_indexes, bss_public_type_entries_);
2210*795d594fSAndroid Build Coastguard Worker }
2211*795d594fSAndroid Build Coastguard Worker
2212*795d594fSAndroid Build Coastguard Worker auto package_type_it = bss_package_type_entry_references_.find(dex_file);
2213*795d594fSAndroid Build Coastguard Worker if (package_type_it != bss_package_type_entry_references_.end()) {
2214*795d594fSAndroid Build Coastguard Worker const BitVector& type_indexes = package_type_it->second;
2215*795d594fSAndroid Build Coastguard Worker ++number_of_package_type_dex_files;
2216*795d594fSAndroid Build Coastguard Worker package_type_bss_mapping_offset = offset;
2217*795d594fSAndroid Build Coastguard Worker offset += CalculateIndexBssMappingSize(dex_file, type_indexes, bss_package_type_entries_);
2218*795d594fSAndroid Build Coastguard Worker }
2219*795d594fSAndroid Build Coastguard Worker
2220*795d594fSAndroid Build Coastguard Worker auto string_it = bss_string_entry_references_.find(dex_file);
2221*795d594fSAndroid Build Coastguard Worker if (string_it != bss_string_entry_references_.end()) {
2222*795d594fSAndroid Build Coastguard Worker const BitVector& string_indexes = string_it->second;
2223*795d594fSAndroid Build Coastguard Worker ++number_of_string_dex_files;
2224*795d594fSAndroid Build Coastguard Worker string_bss_mapping_offset = offset;
2225*795d594fSAndroid Build Coastguard Worker offset += CalculateIndexBssMappingSize(
2226*795d594fSAndroid Build Coastguard Worker dex_file->NumStringIds(),
2227*795d594fSAndroid Build Coastguard Worker sizeof(GcRoot<mirror::String>),
2228*795d594fSAndroid Build Coastguard Worker string_indexes,
2229*795d594fSAndroid Build Coastguard Worker [this, dex_file](uint32_t index) {
2230*795d594fSAndroid Build Coastguard Worker return bss_string_entries_.Get({dex_file, dex::StringIndex(index)});
2231*795d594fSAndroid Build Coastguard Worker });
2232*795d594fSAndroid Build Coastguard Worker }
2233*795d594fSAndroid Build Coastguard Worker
2234*795d594fSAndroid Build Coastguard Worker auto method_type_it = bss_method_type_entry_references_.find(dex_file);
2235*795d594fSAndroid Build Coastguard Worker if (method_type_it != bss_method_type_entry_references_.end()) {
2236*795d594fSAndroid Build Coastguard Worker const BitVector& proto_indexes = method_type_it->second;
2237*795d594fSAndroid Build Coastguard Worker ++number_of_method_type_dex_files;
2238*795d594fSAndroid Build Coastguard Worker method_type_bss_mapping_offset = offset;
2239*795d594fSAndroid Build Coastguard Worker offset += CalculateIndexBssMappingSize(
2240*795d594fSAndroid Build Coastguard Worker dex_file->NumProtoIds(),
2241*795d594fSAndroid Build Coastguard Worker sizeof(GcRoot<mirror::MethodType>),
2242*795d594fSAndroid Build Coastguard Worker proto_indexes,
2243*795d594fSAndroid Build Coastguard Worker [this, dex_file](uint32_t index) {
2244*795d594fSAndroid Build Coastguard Worker return bss_method_type_entries_.Get({dex_file, dex::ProtoIndex(index)});
2245*795d594fSAndroid Build Coastguard Worker });
2246*795d594fSAndroid Build Coastguard Worker }
2247*795d594fSAndroid Build Coastguard Worker
2248*795d594fSAndroid Build Coastguard Worker return offset;
2249*795d594fSAndroid Build Coastguard Worker }
2250*795d594fSAndroid Build Coastguard Worker
InitOatDexFiles(size_t offset)2251*795d594fSAndroid Build Coastguard Worker size_t OatWriter::InitOatDexFiles(size_t offset) {
2252*795d594fSAndroid Build Coastguard Worker // Initialize offsets of oat dex files.
2253*795d594fSAndroid Build Coastguard Worker for (OatDexFile& oat_dex_file : oat_dex_files_) {
2254*795d594fSAndroid Build Coastguard Worker oat_dex_file.offset_ = offset;
2255*795d594fSAndroid Build Coastguard Worker offset += oat_dex_file.SizeOf();
2256*795d594fSAndroid Build Coastguard Worker }
2257*795d594fSAndroid Build Coastguard Worker return offset;
2258*795d594fSAndroid Build Coastguard Worker }
2259*795d594fSAndroid Build Coastguard Worker
InitBcpBssInfo(size_t offset)2260*795d594fSAndroid Build Coastguard Worker size_t OatWriter::InitBcpBssInfo(size_t offset) {
2261*795d594fSAndroid Build Coastguard Worker if (bcp_bss_info_.size() == 0) {
2262*795d594fSAndroid Build Coastguard Worker return offset;
2263*795d594fSAndroid Build Coastguard Worker }
2264*795d594fSAndroid Build Coastguard Worker
2265*795d594fSAndroid Build Coastguard Worker // We first increase the offset to make room to store the number of BCP DexFiles, if we have at
2266*795d594fSAndroid Build Coastguard Worker // least one entry.
2267*795d594fSAndroid Build Coastguard Worker oat_header_->SetBcpBssInfoOffset(offset);
2268*795d594fSAndroid Build Coastguard Worker offset += sizeof(uint32_t);
2269*795d594fSAndroid Build Coastguard Worker
2270*795d594fSAndroid Build Coastguard Worker for (BssMappingInfo& info : bcp_bss_info_) {
2271*795d594fSAndroid Build Coastguard Worker info.offset_ = offset;
2272*795d594fSAndroid Build Coastguard Worker offset += BssMappingInfo::SizeOf();
2273*795d594fSAndroid Build Coastguard Worker }
2274*795d594fSAndroid Build Coastguard Worker return offset;
2275*795d594fSAndroid Build Coastguard Worker }
2276*795d594fSAndroid Build Coastguard Worker
InitOatCode(size_t offset)2277*795d594fSAndroid Build Coastguard Worker size_t OatWriter::InitOatCode(size_t offset) {
2278*795d594fSAndroid Build Coastguard Worker // calculate the offsets within OatHeader to executable code
2279*795d594fSAndroid Build Coastguard Worker size_t old_offset = offset;
2280*795d594fSAndroid Build Coastguard Worker // required to be on a new page boundary
2281*795d594fSAndroid Build Coastguard Worker offset = RoundUp(offset, kElfSegmentAlignment);
2282*795d594fSAndroid Build Coastguard Worker oat_header_->SetExecutableOffset(offset);
2283*795d594fSAndroid Build Coastguard Worker size_executable_offset_alignment_ = offset - old_offset;
2284*795d594fSAndroid Build Coastguard Worker InstructionSet instruction_set = compiler_options_.GetInstructionSet();
2285*795d594fSAndroid Build Coastguard Worker if (GetCompilerOptions().IsBootImage() && primary_oat_file_) {
2286*795d594fSAndroid Build Coastguard Worker const bool generate_debug_info = GetCompilerOptions().GenerateAnyDebugInfo();
2287*795d594fSAndroid Build Coastguard Worker size_t adjusted_offset = offset;
2288*795d594fSAndroid Build Coastguard Worker
2289*795d594fSAndroid Build Coastguard Worker #define DO_TRAMPOLINE(field, fn_name) \
2290*795d594fSAndroid Build Coastguard Worker /* Pad with at least four 0xFFs so we can do DCHECKs in OatQuickMethodHeader */ \
2291*795d594fSAndroid Build Coastguard Worker offset = CompiledCode::AlignCode(offset + 4, instruction_set); \
2292*795d594fSAndroid Build Coastguard Worker adjusted_offset = offset + GetInstructionSetEntryPointAdjustment(instruction_set); \
2293*795d594fSAndroid Build Coastguard Worker oat_header_->Set ## fn_name ## Offset(adjusted_offset); \
2294*795d594fSAndroid Build Coastguard Worker (field) = compiler_driver_->Create ## fn_name(); \
2295*795d594fSAndroid Build Coastguard Worker if (generate_debug_info) { \
2296*795d594fSAndroid Build Coastguard Worker debug::MethodDebugInfo info = {}; \
2297*795d594fSAndroid Build Coastguard Worker info.custom_name = #fn_name; \
2298*795d594fSAndroid Build Coastguard Worker info.isa = instruction_set; \
2299*795d594fSAndroid Build Coastguard Worker info.is_code_address_text_relative = true; \
2300*795d594fSAndroid Build Coastguard Worker /* Use the code offset rather than the `adjusted_offset`. */ \
2301*795d594fSAndroid Build Coastguard Worker info.code_address = offset - oat_header_->GetExecutableOffset(); \
2302*795d594fSAndroid Build Coastguard Worker info.code_size = (field)->size(); \
2303*795d594fSAndroid Build Coastguard Worker method_info_.push_back(std::move(info)); \
2304*795d594fSAndroid Build Coastguard Worker } \
2305*795d594fSAndroid Build Coastguard Worker offset += (field)->size();
2306*795d594fSAndroid Build Coastguard Worker
2307*795d594fSAndroid Build Coastguard Worker DO_TRAMPOLINE(jni_dlsym_lookup_trampoline_, JniDlsymLookupTrampoline);
2308*795d594fSAndroid Build Coastguard Worker DO_TRAMPOLINE(jni_dlsym_lookup_critical_trampoline_, JniDlsymLookupCriticalTrampoline);
2309*795d594fSAndroid Build Coastguard Worker DO_TRAMPOLINE(quick_generic_jni_trampoline_, QuickGenericJniTrampoline);
2310*795d594fSAndroid Build Coastguard Worker DO_TRAMPOLINE(quick_imt_conflict_trampoline_, QuickImtConflictTrampoline);
2311*795d594fSAndroid Build Coastguard Worker DO_TRAMPOLINE(quick_resolution_trampoline_, QuickResolutionTrampoline);
2312*795d594fSAndroid Build Coastguard Worker DO_TRAMPOLINE(quick_to_interpreter_bridge_, QuickToInterpreterBridge);
2313*795d594fSAndroid Build Coastguard Worker DO_TRAMPOLINE(nterp_trampoline_, NterpTrampoline);
2314*795d594fSAndroid Build Coastguard Worker
2315*795d594fSAndroid Build Coastguard Worker #undef DO_TRAMPOLINE
2316*795d594fSAndroid Build Coastguard Worker } else {
2317*795d594fSAndroid Build Coastguard Worker oat_header_->SetJniDlsymLookupTrampolineOffset(0);
2318*795d594fSAndroid Build Coastguard Worker oat_header_->SetJniDlsymLookupCriticalTrampolineOffset(0);
2319*795d594fSAndroid Build Coastguard Worker oat_header_->SetQuickGenericJniTrampolineOffset(0);
2320*795d594fSAndroid Build Coastguard Worker oat_header_->SetQuickImtConflictTrampolineOffset(0);
2321*795d594fSAndroid Build Coastguard Worker oat_header_->SetQuickResolutionTrampolineOffset(0);
2322*795d594fSAndroid Build Coastguard Worker oat_header_->SetQuickToInterpreterBridgeOffset(0);
2323*795d594fSAndroid Build Coastguard Worker oat_header_->SetNterpTrampolineOffset(0);
2324*795d594fSAndroid Build Coastguard Worker }
2325*795d594fSAndroid Build Coastguard Worker return offset;
2326*795d594fSAndroid Build Coastguard Worker }
2327*795d594fSAndroid Build Coastguard Worker
InitOatCodeDexFiles(size_t offset)2328*795d594fSAndroid Build Coastguard Worker size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
2329*795d594fSAndroid Build Coastguard Worker if (!GetCompilerOptions().IsAnyCompilationEnabled()) {
2330*795d594fSAndroid Build Coastguard Worker if (kOatWriterDebugOatCodeLayout) {
2331*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "InitOatCodeDexFiles: OatWriter("
2332*795d594fSAndroid Build Coastguard Worker << this << "), "
2333*795d594fSAndroid Build Coastguard Worker << "compilation is disabled";
2334*795d594fSAndroid Build Coastguard Worker }
2335*795d594fSAndroid Build Coastguard Worker
2336*795d594fSAndroid Build Coastguard Worker return offset;
2337*795d594fSAndroid Build Coastguard Worker }
2338*795d594fSAndroid Build Coastguard Worker bool success = false;
2339*795d594fSAndroid Build Coastguard Worker
2340*795d594fSAndroid Build Coastguard Worker {
2341*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
2342*795d594fSAndroid Build Coastguard Worker
2343*795d594fSAndroid Build Coastguard Worker LayoutCodeMethodVisitor layout_code_visitor(this, offset);
2344*795d594fSAndroid Build Coastguard Worker success = VisitDexMethods(&layout_code_visitor);
2345*795d594fSAndroid Build Coastguard Worker DCHECK(success);
2346*795d594fSAndroid Build Coastguard Worker
2347*795d594fSAndroid Build Coastguard Worker LayoutReserveOffsetCodeMethodVisitor layout_reserve_code_visitor(
2348*795d594fSAndroid Build Coastguard Worker this,
2349*795d594fSAndroid Build Coastguard Worker offset,
2350*795d594fSAndroid Build Coastguard Worker layout_code_visitor.ReleaseOrderedMethods());
2351*795d594fSAndroid Build Coastguard Worker success = layout_reserve_code_visitor.Visit();
2352*795d594fSAndroid Build Coastguard Worker DCHECK(success);
2353*795d594fSAndroid Build Coastguard Worker offset = layout_reserve_code_visitor.GetOffset();
2354*795d594fSAndroid Build Coastguard Worker
2355*795d594fSAndroid Build Coastguard Worker // Save the method order because the WriteCodeMethodVisitor will need this
2356*795d594fSAndroid Build Coastguard Worker // order again.
2357*795d594fSAndroid Build Coastguard Worker DCHECK(ordered_methods_ == nullptr);
2358*795d594fSAndroid Build Coastguard Worker ordered_methods_.reset(
2359*795d594fSAndroid Build Coastguard Worker new OrderedMethodList(
2360*795d594fSAndroid Build Coastguard Worker layout_reserve_code_visitor.ReleaseOrderedMethods()));
2361*795d594fSAndroid Build Coastguard Worker
2362*795d594fSAndroid Build Coastguard Worker if (kOatWriterDebugOatCodeLayout) {
2363*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "IniatOatCodeDexFiles: method order: ";
2364*795d594fSAndroid Build Coastguard Worker for (const OrderedMethodData& ordered_method : *ordered_methods_) {
2365*795d594fSAndroid Build Coastguard Worker std::string pretty_name = ordered_method.method_reference.PrettyMethod();
2366*795d594fSAndroid Build Coastguard Worker LOG(INFO) << pretty_name
2367*795d594fSAndroid Build Coastguard Worker << "@ offset "
2368*795d594fSAndroid Build Coastguard Worker << relative_patcher_->GetOffset(ordered_method.method_reference)
2369*795d594fSAndroid Build Coastguard Worker << " X hotness "
2370*795d594fSAndroid Build Coastguard Worker << ordered_method.hotness_bits;
2371*795d594fSAndroid Build Coastguard Worker }
2372*795d594fSAndroid Build Coastguard Worker }
2373*795d594fSAndroid Build Coastguard Worker }
2374*795d594fSAndroid Build Coastguard Worker
2375*795d594fSAndroid Build Coastguard Worker if (HasImage()) {
2376*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
2377*795d594fSAndroid Build Coastguard Worker ScopedAssertNoThreadSuspension sants("Init image method visitor");
2378*795d594fSAndroid Build Coastguard Worker InitImageMethodVisitor image_visitor(this, offset, dex_files_);
2379*795d594fSAndroid Build Coastguard Worker success = VisitDexMethods(&image_visitor);
2380*795d594fSAndroid Build Coastguard Worker image_visitor.Postprocess();
2381*795d594fSAndroid Build Coastguard Worker DCHECK(success);
2382*795d594fSAndroid Build Coastguard Worker offset = image_visitor.GetOffset();
2383*795d594fSAndroid Build Coastguard Worker }
2384*795d594fSAndroid Build Coastguard Worker
2385*795d594fSAndroid Build Coastguard Worker return offset;
2386*795d594fSAndroid Build Coastguard Worker }
2387*795d594fSAndroid Build Coastguard Worker
InitDataImgRelRoLayout(size_t offset)2388*795d594fSAndroid Build Coastguard Worker size_t OatWriter::InitDataImgRelRoLayout(size_t offset) {
2389*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(data_img_rel_ro_size_, 0u);
2390*795d594fSAndroid Build Coastguard Worker if (boot_image_rel_ro_entries_.empty() &&
2391*795d594fSAndroid Build Coastguard Worker app_image_rel_ro_method_entries_.empty() &&
2392*795d594fSAndroid Build Coastguard Worker app_image_rel_ro_type_entries_.empty()) {
2393*795d594fSAndroid Build Coastguard Worker // Nothing to put to the .data.img.rel.ro section.
2394*795d594fSAndroid Build Coastguard Worker return offset;
2395*795d594fSAndroid Build Coastguard Worker }
2396*795d594fSAndroid Build Coastguard Worker
2397*795d594fSAndroid Build Coastguard Worker data_img_rel_ro_start_ = RoundUp(offset, kElfSegmentAlignment);
2398*795d594fSAndroid Build Coastguard Worker
2399*795d594fSAndroid Build Coastguard Worker for (auto& entry : boot_image_rel_ro_entries_) {
2400*795d594fSAndroid Build Coastguard Worker size_t& entry_offset = entry.second;
2401*795d594fSAndroid Build Coastguard Worker entry_offset = data_img_rel_ro_size_;
2402*795d594fSAndroid Build Coastguard Worker data_img_rel_ro_size_ += sizeof(uint32_t);
2403*795d594fSAndroid Build Coastguard Worker }
2404*795d594fSAndroid Build Coastguard Worker
2405*795d594fSAndroid Build Coastguard Worker data_img_rel_ro_app_image_offset_ = data_img_rel_ro_size_;
2406*795d594fSAndroid Build Coastguard Worker
2407*795d594fSAndroid Build Coastguard Worker for (auto& entry : app_image_rel_ro_method_entries_) {
2408*795d594fSAndroid Build Coastguard Worker size_t& entry_offset = entry.second;
2409*795d594fSAndroid Build Coastguard Worker entry_offset = data_img_rel_ro_size_;
2410*795d594fSAndroid Build Coastguard Worker data_img_rel_ro_size_ += sizeof(uint32_t);
2411*795d594fSAndroid Build Coastguard Worker }
2412*795d594fSAndroid Build Coastguard Worker
2413*795d594fSAndroid Build Coastguard Worker for (auto& entry : app_image_rel_ro_type_entries_) {
2414*795d594fSAndroid Build Coastguard Worker size_t& entry_offset = entry.second;
2415*795d594fSAndroid Build Coastguard Worker entry_offset = data_img_rel_ro_size_;
2416*795d594fSAndroid Build Coastguard Worker data_img_rel_ro_size_ += sizeof(uint32_t);
2417*795d594fSAndroid Build Coastguard Worker }
2418*795d594fSAndroid Build Coastguard Worker
2419*795d594fSAndroid Build Coastguard Worker offset = data_img_rel_ro_start_ + data_img_rel_ro_size_;
2420*795d594fSAndroid Build Coastguard Worker return offset;
2421*795d594fSAndroid Build Coastguard Worker }
2422*795d594fSAndroid Build Coastguard Worker
InitBssLayout(InstructionSet instruction_set)2423*795d594fSAndroid Build Coastguard Worker void OatWriter::InitBssLayout(InstructionSet instruction_set) {
2424*795d594fSAndroid Build Coastguard Worker {
2425*795d594fSAndroid Build Coastguard Worker InitBssLayoutMethodVisitor visitor(this);
2426*795d594fSAndroid Build Coastguard Worker bool success = VisitDexMethods(&visitor);
2427*795d594fSAndroid Build Coastguard Worker DCHECK(success);
2428*795d594fSAndroid Build Coastguard Worker }
2429*795d594fSAndroid Build Coastguard Worker
2430*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(bss_size_, 0u);
2431*795d594fSAndroid Build Coastguard Worker if (bss_method_entries_.empty() &&
2432*795d594fSAndroid Build Coastguard Worker bss_type_entries_.empty() &&
2433*795d594fSAndroid Build Coastguard Worker bss_public_type_entries_.empty() &&
2434*795d594fSAndroid Build Coastguard Worker bss_package_type_entries_.empty() &&
2435*795d594fSAndroid Build Coastguard Worker bss_string_entries_.empty() &&
2436*795d594fSAndroid Build Coastguard Worker bss_method_type_entries_.empty()) {
2437*795d594fSAndroid Build Coastguard Worker // Nothing to put to the .bss section.
2438*795d594fSAndroid Build Coastguard Worker return;
2439*795d594fSAndroid Build Coastguard Worker }
2440*795d594fSAndroid Build Coastguard Worker
2441*795d594fSAndroid Build Coastguard Worker PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set);
2442*795d594fSAndroid Build Coastguard Worker bss_methods_offset_ = bss_size_;
2443*795d594fSAndroid Build Coastguard Worker
2444*795d594fSAndroid Build Coastguard Worker // Prepare offsets for .bss ArtMethod entries.
2445*795d594fSAndroid Build Coastguard Worker for (auto& entry : bss_method_entries_) {
2446*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(entry.second, 0u);
2447*795d594fSAndroid Build Coastguard Worker entry.second = bss_size_;
2448*795d594fSAndroid Build Coastguard Worker bss_size_ += static_cast<size_t>(pointer_size);
2449*795d594fSAndroid Build Coastguard Worker }
2450*795d594fSAndroid Build Coastguard Worker
2451*795d594fSAndroid Build Coastguard Worker bss_roots_offset_ = bss_size_;
2452*795d594fSAndroid Build Coastguard Worker
2453*795d594fSAndroid Build Coastguard Worker // Prepare offsets for .bss Class entries.
2454*795d594fSAndroid Build Coastguard Worker for (auto& entry : bss_type_entries_) {
2455*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(entry.second, 0u);
2456*795d594fSAndroid Build Coastguard Worker entry.second = bss_size_;
2457*795d594fSAndroid Build Coastguard Worker bss_size_ += sizeof(GcRoot<mirror::Class>);
2458*795d594fSAndroid Build Coastguard Worker }
2459*795d594fSAndroid Build Coastguard Worker // Prepare offsets for .bss public Class entries.
2460*795d594fSAndroid Build Coastguard Worker for (auto& entry : bss_public_type_entries_) {
2461*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(entry.second, 0u);
2462*795d594fSAndroid Build Coastguard Worker entry.second = bss_size_;
2463*795d594fSAndroid Build Coastguard Worker bss_size_ += sizeof(GcRoot<mirror::Class>);
2464*795d594fSAndroid Build Coastguard Worker }
2465*795d594fSAndroid Build Coastguard Worker // Prepare offsets for .bss package Class entries.
2466*795d594fSAndroid Build Coastguard Worker for (auto& entry : bss_package_type_entries_) {
2467*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(entry.second, 0u);
2468*795d594fSAndroid Build Coastguard Worker entry.second = bss_size_;
2469*795d594fSAndroid Build Coastguard Worker bss_size_ += sizeof(GcRoot<mirror::Class>);
2470*795d594fSAndroid Build Coastguard Worker }
2471*795d594fSAndroid Build Coastguard Worker // Prepare offsets for .bss String entries.
2472*795d594fSAndroid Build Coastguard Worker for (auto& entry : bss_string_entries_) {
2473*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(entry.second, 0u);
2474*795d594fSAndroid Build Coastguard Worker entry.second = bss_size_;
2475*795d594fSAndroid Build Coastguard Worker bss_size_ += sizeof(GcRoot<mirror::String>);
2476*795d594fSAndroid Build Coastguard Worker }
2477*795d594fSAndroid Build Coastguard Worker // Prepare offsets for .bss MethodType entries.
2478*795d594fSAndroid Build Coastguard Worker for (auto& entry : bss_method_type_entries_) {
2479*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(entry.second, 0u);
2480*795d594fSAndroid Build Coastguard Worker entry.second = bss_size_;
2481*795d594fSAndroid Build Coastguard Worker bss_size_ += sizeof(GcRoot<mirror::MethodType>);
2482*795d594fSAndroid Build Coastguard Worker }
2483*795d594fSAndroid Build Coastguard Worker }
2484*795d594fSAndroid Build Coastguard Worker
WriteRodata(OutputStream * out)2485*795d594fSAndroid Build Coastguard Worker bool OatWriter::WriteRodata(OutputStream* out) {
2486*795d594fSAndroid Build Coastguard Worker CHECK(write_state_ == WriteState::kWriteRoData);
2487*795d594fSAndroid Build Coastguard Worker
2488*795d594fSAndroid Build Coastguard Worker size_t file_offset = oat_data_offset_;
2489*795d594fSAndroid Build Coastguard Worker off_t current_offset = out->Seek(0, kSeekCurrent);
2490*795d594fSAndroid Build Coastguard Worker if (current_offset == static_cast<off_t>(-1)) {
2491*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to retrieve current position in " << out->GetLocation();
2492*795d594fSAndroid Build Coastguard Worker }
2493*795d594fSAndroid Build Coastguard Worker DCHECK_GE(static_cast<size_t>(current_offset), file_offset + oat_header_->GetHeaderSize());
2494*795d594fSAndroid Build Coastguard Worker size_t relative_offset = current_offset - file_offset;
2495*795d594fSAndroid Build Coastguard Worker
2496*795d594fSAndroid Build Coastguard Worker // Wrap out to update checksum with each write.
2497*795d594fSAndroid Build Coastguard Worker ChecksumUpdatingOutputStream checksum_updating_out(out, this);
2498*795d594fSAndroid Build Coastguard Worker out = &checksum_updating_out;
2499*795d594fSAndroid Build Coastguard Worker
2500*795d594fSAndroid Build Coastguard Worker relative_offset = WriteClassOffsets(out, file_offset, relative_offset);
2501*795d594fSAndroid Build Coastguard Worker if (relative_offset == 0) {
2502*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write class offsets to " << out->GetLocation();
2503*795d594fSAndroid Build Coastguard Worker return false;
2504*795d594fSAndroid Build Coastguard Worker }
2505*795d594fSAndroid Build Coastguard Worker
2506*795d594fSAndroid Build Coastguard Worker relative_offset = WriteClasses(out, file_offset, relative_offset);
2507*795d594fSAndroid Build Coastguard Worker if (relative_offset == 0) {
2508*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write classes to " << out->GetLocation();
2509*795d594fSAndroid Build Coastguard Worker return false;
2510*795d594fSAndroid Build Coastguard Worker }
2511*795d594fSAndroid Build Coastguard Worker
2512*795d594fSAndroid Build Coastguard Worker relative_offset = WriteIndexBssMappings(out, file_offset, relative_offset);
2513*795d594fSAndroid Build Coastguard Worker if (relative_offset == 0) {
2514*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write method bss mappings to " << out->GetLocation();
2515*795d594fSAndroid Build Coastguard Worker return false;
2516*795d594fSAndroid Build Coastguard Worker }
2517*795d594fSAndroid Build Coastguard Worker
2518*795d594fSAndroid Build Coastguard Worker relative_offset = WriteMaps(out, file_offset, relative_offset);
2519*795d594fSAndroid Build Coastguard Worker if (relative_offset == 0) {
2520*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
2521*795d594fSAndroid Build Coastguard Worker return false;
2522*795d594fSAndroid Build Coastguard Worker }
2523*795d594fSAndroid Build Coastguard Worker
2524*795d594fSAndroid Build Coastguard Worker relative_offset = WriteOatDexFiles(out, file_offset, relative_offset);
2525*795d594fSAndroid Build Coastguard Worker if (relative_offset == 0) {
2526*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write oat dex information to " << out->GetLocation();
2527*795d594fSAndroid Build Coastguard Worker return false;
2528*795d594fSAndroid Build Coastguard Worker }
2529*795d594fSAndroid Build Coastguard Worker
2530*795d594fSAndroid Build Coastguard Worker relative_offset = WriteBcpBssInfo(out, file_offset, relative_offset);
2531*795d594fSAndroid Build Coastguard Worker if (relative_offset == 0) {
2532*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write BCP bss information to " << out->GetLocation();
2533*795d594fSAndroid Build Coastguard Worker return false;
2534*795d594fSAndroid Build Coastguard Worker }
2535*795d594fSAndroid Build Coastguard Worker
2536*795d594fSAndroid Build Coastguard Worker // Write padding.
2537*795d594fSAndroid Build Coastguard Worker off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent);
2538*795d594fSAndroid Build Coastguard Worker relative_offset += size_executable_offset_alignment_;
2539*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(relative_offset, oat_header_->GetExecutableOffset());
2540*795d594fSAndroid Build Coastguard Worker size_t expected_file_offset = file_offset + relative_offset;
2541*795d594fSAndroid Build Coastguard Worker if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
2542*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
2543*795d594fSAndroid Build Coastguard Worker << " Expected: " << expected_file_offset << " File: " << out->GetLocation();
2544*795d594fSAndroid Build Coastguard Worker return false;
2545*795d594fSAndroid Build Coastguard Worker }
2546*795d594fSAndroid Build Coastguard Worker DCHECK_OFFSET();
2547*795d594fSAndroid Build Coastguard Worker
2548*795d594fSAndroid Build Coastguard Worker write_state_ = WriteState::kWriteText;
2549*795d594fSAndroid Build Coastguard Worker return true;
2550*795d594fSAndroid Build Coastguard Worker }
2551*795d594fSAndroid Build Coastguard Worker
WriteVerifierDeps(verifier::VerifierDeps * verifier_deps,std::vector<uint8_t> * buffer)2552*795d594fSAndroid Build Coastguard Worker void OatWriter::WriteVerifierDeps(verifier::VerifierDeps* verifier_deps,
2553*795d594fSAndroid Build Coastguard Worker /*out*/std::vector<uint8_t>* buffer) {
2554*795d594fSAndroid Build Coastguard Worker if (verifier_deps == nullptr) {
2555*795d594fSAndroid Build Coastguard Worker // Nothing to write. Record the offset, but no need
2556*795d594fSAndroid Build Coastguard Worker // for alignment.
2557*795d594fSAndroid Build Coastguard Worker vdex_verifier_deps_offset_ = vdex_size_;
2558*795d594fSAndroid Build Coastguard Worker return;
2559*795d594fSAndroid Build Coastguard Worker }
2560*795d594fSAndroid Build Coastguard Worker
2561*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split("VDEX verifier deps", timings_);
2562*795d594fSAndroid Build Coastguard Worker
2563*795d594fSAndroid Build Coastguard Worker DCHECK(buffer->empty());
2564*795d594fSAndroid Build Coastguard Worker verifier_deps->Encode(*dex_files_, buffer);
2565*795d594fSAndroid Build Coastguard Worker size_verifier_deps_ = buffer->size();
2566*795d594fSAndroid Build Coastguard Worker
2567*795d594fSAndroid Build Coastguard Worker // Verifier deps data should be 4 byte aligned.
2568*795d594fSAndroid Build Coastguard Worker size_verifier_deps_alignment_ = RoundUp(vdex_size_, 4u) - vdex_size_;
2569*795d594fSAndroid Build Coastguard Worker buffer->insert(buffer->begin(), size_verifier_deps_alignment_, 0u);
2570*795d594fSAndroid Build Coastguard Worker
2571*795d594fSAndroid Build Coastguard Worker vdex_size_ += size_verifier_deps_alignment_;
2572*795d594fSAndroid Build Coastguard Worker vdex_verifier_deps_offset_ = vdex_size_;
2573*795d594fSAndroid Build Coastguard Worker vdex_size_ += size_verifier_deps_;
2574*795d594fSAndroid Build Coastguard Worker }
2575*795d594fSAndroid Build Coastguard Worker
WriteCode(OutputStream * out)2576*795d594fSAndroid Build Coastguard Worker bool OatWriter::WriteCode(OutputStream* out) {
2577*795d594fSAndroid Build Coastguard Worker CHECK(write_state_ == WriteState::kWriteText);
2578*795d594fSAndroid Build Coastguard Worker
2579*795d594fSAndroid Build Coastguard Worker // Wrap out to update checksum with each write.
2580*795d594fSAndroid Build Coastguard Worker ChecksumUpdatingOutputStream checksum_updating_out(out, this);
2581*795d594fSAndroid Build Coastguard Worker out = &checksum_updating_out;
2582*795d594fSAndroid Build Coastguard Worker
2583*795d594fSAndroid Build Coastguard Worker SetMultiOatRelativePatcherAdjustment();
2584*795d594fSAndroid Build Coastguard Worker
2585*795d594fSAndroid Build Coastguard Worker const size_t file_offset = oat_data_offset_;
2586*795d594fSAndroid Build Coastguard Worker size_t relative_offset = oat_header_->GetExecutableOffset();
2587*795d594fSAndroid Build Coastguard Worker DCHECK_OFFSET();
2588*795d594fSAndroid Build Coastguard Worker
2589*795d594fSAndroid Build Coastguard Worker relative_offset = WriteCode(out, file_offset, relative_offset);
2590*795d594fSAndroid Build Coastguard Worker if (relative_offset == 0) {
2591*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
2592*795d594fSAndroid Build Coastguard Worker return false;
2593*795d594fSAndroid Build Coastguard Worker }
2594*795d594fSAndroid Build Coastguard Worker
2595*795d594fSAndroid Build Coastguard Worker relative_offset = WriteCodeDexFiles(out, file_offset, relative_offset);
2596*795d594fSAndroid Build Coastguard Worker if (relative_offset == 0) {
2597*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed to write oat code for dex files to " << out->GetLocation();
2598*795d594fSAndroid Build Coastguard Worker return false;
2599*795d594fSAndroid Build Coastguard Worker }
2600*795d594fSAndroid Build Coastguard Worker
2601*795d594fSAndroid Build Coastguard Worker if (data_img_rel_ro_size_ != 0u) {
2602*795d594fSAndroid Build Coastguard Worker write_state_ = WriteState::kWriteDataImgRelRo;
2603*795d594fSAndroid Build Coastguard Worker } else {
2604*795d594fSAndroid Build Coastguard Worker if (!CheckOatSize(out, file_offset, relative_offset)) {
2605*795d594fSAndroid Build Coastguard Worker return false;
2606*795d594fSAndroid Build Coastguard Worker }
2607*795d594fSAndroid Build Coastguard Worker write_state_ = WriteState::kWriteHeader;
2608*795d594fSAndroid Build Coastguard Worker }
2609*795d594fSAndroid Build Coastguard Worker return true;
2610*795d594fSAndroid Build Coastguard Worker }
2611*795d594fSAndroid Build Coastguard Worker
WriteDataImgRelRo(OutputStream * out)2612*795d594fSAndroid Build Coastguard Worker bool OatWriter::WriteDataImgRelRo(OutputStream* out) {
2613*795d594fSAndroid Build Coastguard Worker CHECK(write_state_ == WriteState::kWriteDataImgRelRo);
2614*795d594fSAndroid Build Coastguard Worker
2615*795d594fSAndroid Build Coastguard Worker // Wrap out to update checksum with each write.
2616*795d594fSAndroid Build Coastguard Worker ChecksumUpdatingOutputStream checksum_updating_out(out, this);
2617*795d594fSAndroid Build Coastguard Worker out = &checksum_updating_out;
2618*795d594fSAndroid Build Coastguard Worker
2619*795d594fSAndroid Build Coastguard Worker const size_t file_offset = oat_data_offset_;
2620*795d594fSAndroid Build Coastguard Worker size_t relative_offset = data_img_rel_ro_start_;
2621*795d594fSAndroid Build Coastguard Worker
2622*795d594fSAndroid Build Coastguard Worker // Record the padding before the .data.img.rel.ro section.
2623*795d594fSAndroid Build Coastguard Worker // Do not write anything, this zero-filled part was skipped (Seek()) when starting the section.
2624*795d594fSAndroid Build Coastguard Worker size_t code_end = GetOatHeader().GetExecutableOffset() + code_size_;
2625*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(RoundUp(code_end, kElfSegmentAlignment), relative_offset);
2626*795d594fSAndroid Build Coastguard Worker size_t padding_size = relative_offset - code_end;
2627*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(size_data_img_rel_ro_alignment_, 0u);
2628*795d594fSAndroid Build Coastguard Worker size_data_img_rel_ro_alignment_ = padding_size;
2629*795d594fSAndroid Build Coastguard Worker
2630*795d594fSAndroid Build Coastguard Worker relative_offset = WriteDataImgRelRo(out, file_offset, relative_offset);
2631*795d594fSAndroid Build Coastguard Worker if (relative_offset == 0) {
2632*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed to write boot image relocations to " << out->GetLocation();
2633*795d594fSAndroid Build Coastguard Worker return false;
2634*795d594fSAndroid Build Coastguard Worker }
2635*795d594fSAndroid Build Coastguard Worker
2636*795d594fSAndroid Build Coastguard Worker if (!CheckOatSize(out, file_offset, relative_offset)) {
2637*795d594fSAndroid Build Coastguard Worker return false;
2638*795d594fSAndroid Build Coastguard Worker }
2639*795d594fSAndroid Build Coastguard Worker write_state_ = WriteState::kWriteHeader;
2640*795d594fSAndroid Build Coastguard Worker return true;
2641*795d594fSAndroid Build Coastguard Worker }
2642*795d594fSAndroid Build Coastguard Worker
CheckOatSize(OutputStream * out,size_t file_offset,size_t relative_offset)2643*795d594fSAndroid Build Coastguard Worker bool OatWriter::CheckOatSize(OutputStream* out, size_t file_offset, size_t relative_offset) {
2644*795d594fSAndroid Build Coastguard Worker const off_t oat_end_file_offset = out->Seek(0, kSeekCurrent);
2645*795d594fSAndroid Build Coastguard Worker if (oat_end_file_offset == static_cast<off_t>(-1)) {
2646*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed to get oat end file offset in " << out->GetLocation();
2647*795d594fSAndroid Build Coastguard Worker return false;
2648*795d594fSAndroid Build Coastguard Worker }
2649*795d594fSAndroid Build Coastguard Worker
2650*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
2651*795d594fSAndroid Build Coastguard Worker uint32_t size_total = 0;
2652*795d594fSAndroid Build Coastguard Worker #define DO_STAT(x) \
2653*795d594fSAndroid Build Coastguard Worker VLOG(compiler) << #x "=" << PrettySize(x) << " (" << (x) << "B)"; \
2654*795d594fSAndroid Build Coastguard Worker size_total += (x);
2655*795d594fSAndroid Build Coastguard Worker
2656*795d594fSAndroid Build Coastguard Worker DO_STAT(size_vdex_header_);
2657*795d594fSAndroid Build Coastguard Worker DO_STAT(size_vdex_checksums_);
2658*795d594fSAndroid Build Coastguard Worker DO_STAT(size_dex_file_alignment_);
2659*795d594fSAndroid Build Coastguard Worker DO_STAT(size_executable_offset_alignment_);
2660*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_header_);
2661*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_header_key_value_store_);
2662*795d594fSAndroid Build Coastguard Worker DO_STAT(size_dex_file_);
2663*795d594fSAndroid Build Coastguard Worker DO_STAT(size_verifier_deps_);
2664*795d594fSAndroid Build Coastguard Worker DO_STAT(size_verifier_deps_alignment_);
2665*795d594fSAndroid Build Coastguard Worker DO_STAT(size_vdex_lookup_table_);
2666*795d594fSAndroid Build Coastguard Worker DO_STAT(size_vdex_lookup_table_alignment_);
2667*795d594fSAndroid Build Coastguard Worker DO_STAT(size_interpreter_to_interpreter_bridge_);
2668*795d594fSAndroid Build Coastguard Worker DO_STAT(size_interpreter_to_compiled_code_bridge_);
2669*795d594fSAndroid Build Coastguard Worker DO_STAT(size_jni_dlsym_lookup_trampoline_);
2670*795d594fSAndroid Build Coastguard Worker DO_STAT(size_jni_dlsym_lookup_critical_trampoline_);
2671*795d594fSAndroid Build Coastguard Worker DO_STAT(size_quick_generic_jni_trampoline_);
2672*795d594fSAndroid Build Coastguard Worker DO_STAT(size_quick_imt_conflict_trampoline_);
2673*795d594fSAndroid Build Coastguard Worker DO_STAT(size_quick_resolution_trampoline_);
2674*795d594fSAndroid Build Coastguard Worker DO_STAT(size_quick_to_interpreter_bridge_);
2675*795d594fSAndroid Build Coastguard Worker DO_STAT(size_nterp_trampoline_);
2676*795d594fSAndroid Build Coastguard Worker DO_STAT(size_trampoline_alignment_);
2677*795d594fSAndroid Build Coastguard Worker DO_STAT(size_method_header_);
2678*795d594fSAndroid Build Coastguard Worker DO_STAT(size_code_);
2679*795d594fSAndroid Build Coastguard Worker DO_STAT(size_code_alignment_);
2680*795d594fSAndroid Build Coastguard Worker DO_STAT(size_data_img_rel_ro_);
2681*795d594fSAndroid Build Coastguard Worker DO_STAT(size_data_img_rel_ro_alignment_);
2682*795d594fSAndroid Build Coastguard Worker DO_STAT(size_relative_call_thunks_);
2683*795d594fSAndroid Build Coastguard Worker DO_STAT(size_misc_thunks_);
2684*795d594fSAndroid Build Coastguard Worker DO_STAT(size_vmap_table_);
2685*795d594fSAndroid Build Coastguard Worker DO_STAT(size_method_info_);
2686*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_dex_file_location_size_);
2687*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_dex_file_location_data_);
2688*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_dex_file_magic_);
2689*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_dex_file_location_checksum_);
2690*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_dex_file_sha1_);
2691*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_dex_file_offset_);
2692*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_dex_file_class_offsets_offset_);
2693*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_dex_file_lookup_table_offset_);
2694*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_dex_file_dex_layout_sections_offset_);
2695*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_dex_file_dex_layout_sections_);
2696*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_dex_file_dex_layout_sections_alignment_);
2697*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_dex_file_method_bss_mapping_offset_);
2698*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_dex_file_type_bss_mapping_offset_);
2699*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_dex_file_public_type_bss_mapping_offset_);
2700*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_dex_file_package_type_bss_mapping_offset_);
2701*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_dex_file_string_bss_mapping_offset_);
2702*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_dex_file_method_type_bss_mapping_offset_);
2703*795d594fSAndroid Build Coastguard Worker DO_STAT(size_bcp_bss_info_size_);
2704*795d594fSAndroid Build Coastguard Worker DO_STAT(size_bcp_bss_info_method_bss_mapping_offset_);
2705*795d594fSAndroid Build Coastguard Worker DO_STAT(size_bcp_bss_info_type_bss_mapping_offset_);
2706*795d594fSAndroid Build Coastguard Worker DO_STAT(size_bcp_bss_info_public_type_bss_mapping_offset_);
2707*795d594fSAndroid Build Coastguard Worker DO_STAT(size_bcp_bss_info_package_type_bss_mapping_offset_);
2708*795d594fSAndroid Build Coastguard Worker DO_STAT(size_bcp_bss_info_string_bss_mapping_offset_);
2709*795d594fSAndroid Build Coastguard Worker DO_STAT(size_bcp_bss_info_method_type_bss_mapping_offset_);
2710*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_class_offsets_alignment_);
2711*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_class_offsets_);
2712*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_class_type_);
2713*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_class_status_);
2714*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_class_num_methods_);
2715*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_class_method_bitmaps_);
2716*795d594fSAndroid Build Coastguard Worker DO_STAT(size_oat_class_method_offsets_);
2717*795d594fSAndroid Build Coastguard Worker DO_STAT(size_method_bss_mappings_);
2718*795d594fSAndroid Build Coastguard Worker DO_STAT(size_type_bss_mappings_);
2719*795d594fSAndroid Build Coastguard Worker DO_STAT(size_public_type_bss_mappings_);
2720*795d594fSAndroid Build Coastguard Worker DO_STAT(size_package_type_bss_mappings_);
2721*795d594fSAndroid Build Coastguard Worker DO_STAT(size_string_bss_mappings_);
2722*795d594fSAndroid Build Coastguard Worker DO_STAT(size_method_type_bss_mappings_);
2723*795d594fSAndroid Build Coastguard Worker #undef DO_STAT
2724*795d594fSAndroid Build Coastguard Worker
2725*795d594fSAndroid Build Coastguard Worker VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)";
2726*795d594fSAndroid Build Coastguard Worker
2727*795d594fSAndroid Build Coastguard Worker CHECK_EQ(vdex_size_ + oat_size_, size_total);
2728*795d594fSAndroid Build Coastguard Worker CHECK_EQ(file_offset + size_total - vdex_size_, static_cast<size_t>(oat_end_file_offset));
2729*795d594fSAndroid Build Coastguard Worker }
2730*795d594fSAndroid Build Coastguard Worker
2731*795d594fSAndroid Build Coastguard Worker CHECK_EQ(file_offset + oat_size_, static_cast<size_t>(oat_end_file_offset));
2732*795d594fSAndroid Build Coastguard Worker CHECK_EQ(oat_size_, relative_offset);
2733*795d594fSAndroid Build Coastguard Worker
2734*795d594fSAndroid Build Coastguard Worker write_state_ = WriteState::kWriteHeader;
2735*795d594fSAndroid Build Coastguard Worker return true;
2736*795d594fSAndroid Build Coastguard Worker }
2737*795d594fSAndroid Build Coastguard Worker
WriteHeader(OutputStream * out)2738*795d594fSAndroid Build Coastguard Worker bool OatWriter::WriteHeader(OutputStream* out) {
2739*795d594fSAndroid Build Coastguard Worker CHECK(write_state_ == WriteState::kWriteHeader);
2740*795d594fSAndroid Build Coastguard Worker
2741*795d594fSAndroid Build Coastguard Worker // Update checksum with header data.
2742*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(oat_header_->GetChecksum(), 0u); // For checksum calculation.
2743*795d594fSAndroid Build Coastguard Worker const uint8_t* header_begin = reinterpret_cast<const uint8_t*>(oat_header_.get());
2744*795d594fSAndroid Build Coastguard Worker const uint8_t* header_end = oat_header_->GetKeyValueStore() + oat_header_->GetKeyValueStoreSize();
2745*795d594fSAndroid Build Coastguard Worker uint32_t old_checksum = oat_checksum_;
2746*795d594fSAndroid Build Coastguard Worker oat_checksum_ = adler32(old_checksum, header_begin, header_end - header_begin);
2747*795d594fSAndroid Build Coastguard Worker oat_header_->SetChecksum(oat_checksum_);
2748*795d594fSAndroid Build Coastguard Worker
2749*795d594fSAndroid Build Coastguard Worker const size_t file_offset = oat_data_offset_;
2750*795d594fSAndroid Build Coastguard Worker
2751*795d594fSAndroid Build Coastguard Worker off_t current_offset = out->Seek(0, kSeekCurrent);
2752*795d594fSAndroid Build Coastguard Worker if (current_offset == static_cast<off_t>(-1)) {
2753*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to get current offset from " << out->GetLocation();
2754*795d594fSAndroid Build Coastguard Worker return false;
2755*795d594fSAndroid Build Coastguard Worker }
2756*795d594fSAndroid Build Coastguard Worker if (out->Seek(file_offset, kSeekSet) == static_cast<off_t>(-1)) {
2757*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to seek to oat header position in " << out->GetLocation();
2758*795d594fSAndroid Build Coastguard Worker return false;
2759*795d594fSAndroid Build Coastguard Worker }
2760*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(file_offset, static_cast<size_t>(out->Seek(0, kSeekCurrent)));
2761*795d594fSAndroid Build Coastguard Worker
2762*795d594fSAndroid Build Coastguard Worker // Flush all other data before writing the header.
2763*795d594fSAndroid Build Coastguard Worker if (!out->Flush()) {
2764*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to flush before writing oat header to " << out->GetLocation();
2765*795d594fSAndroid Build Coastguard Worker return false;
2766*795d594fSAndroid Build Coastguard Worker }
2767*795d594fSAndroid Build Coastguard Worker // Write the header.
2768*795d594fSAndroid Build Coastguard Worker size_t header_size = oat_header_->GetHeaderSize();
2769*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(oat_header_.get(), header_size)) {
2770*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write oat header to " << out->GetLocation();
2771*795d594fSAndroid Build Coastguard Worker return false;
2772*795d594fSAndroid Build Coastguard Worker }
2773*795d594fSAndroid Build Coastguard Worker // Flush the header data.
2774*795d594fSAndroid Build Coastguard Worker if (!out->Flush()) {
2775*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to flush after writing oat header to " << out->GetLocation();
2776*795d594fSAndroid Build Coastguard Worker return false;
2777*795d594fSAndroid Build Coastguard Worker }
2778*795d594fSAndroid Build Coastguard Worker
2779*795d594fSAndroid Build Coastguard Worker if (out->Seek(current_offset, kSeekSet) == static_cast<off_t>(-1)) {
2780*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to seek back after writing oat header to " << out->GetLocation();
2781*795d594fSAndroid Build Coastguard Worker return false;
2782*795d594fSAndroid Build Coastguard Worker }
2783*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(current_offset, out->Seek(0, kSeekCurrent));
2784*795d594fSAndroid Build Coastguard Worker
2785*795d594fSAndroid Build Coastguard Worker write_state_ = WriteState::kDone;
2786*795d594fSAndroid Build Coastguard Worker return true;
2787*795d594fSAndroid Build Coastguard Worker }
2788*795d594fSAndroid Build Coastguard Worker
WriteClassOffsets(OutputStream * out,size_t file_offset,size_t relative_offset)2789*795d594fSAndroid Build Coastguard Worker size_t OatWriter::WriteClassOffsets(OutputStream* out, size_t file_offset, size_t relative_offset) {
2790*795d594fSAndroid Build Coastguard Worker for (OatDexFile& oat_dex_file : oat_dex_files_) {
2791*795d594fSAndroid Build Coastguard Worker if (oat_dex_file.class_offsets_offset_ != 0u) {
2792*795d594fSAndroid Build Coastguard Worker // Class offsets are required to be 4 byte aligned.
2793*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(!IsAligned<4u>(relative_offset))) {
2794*795d594fSAndroid Build Coastguard Worker size_t padding_size = RoundUp(relative_offset, 4u) - relative_offset;
2795*795d594fSAndroid Build Coastguard Worker if (!WriteUpTo16BytesAlignment(out, padding_size, &size_oat_class_offsets_alignment_)) {
2796*795d594fSAndroid Build Coastguard Worker return 0u;
2797*795d594fSAndroid Build Coastguard Worker }
2798*795d594fSAndroid Build Coastguard Worker relative_offset += padding_size;
2799*795d594fSAndroid Build Coastguard Worker }
2800*795d594fSAndroid Build Coastguard Worker DCHECK_OFFSET();
2801*795d594fSAndroid Build Coastguard Worker if (!oat_dex_file.WriteClassOffsets(this, out)) {
2802*795d594fSAndroid Build Coastguard Worker return 0u;
2803*795d594fSAndroid Build Coastguard Worker }
2804*795d594fSAndroid Build Coastguard Worker relative_offset += oat_dex_file.GetClassOffsetsRawSize();
2805*795d594fSAndroid Build Coastguard Worker }
2806*795d594fSAndroid Build Coastguard Worker }
2807*795d594fSAndroid Build Coastguard Worker return relative_offset;
2808*795d594fSAndroid Build Coastguard Worker }
2809*795d594fSAndroid Build Coastguard Worker
WriteClasses(OutputStream * out,size_t file_offset,size_t relative_offset)2810*795d594fSAndroid Build Coastguard Worker size_t OatWriter::WriteClasses(OutputStream* out, size_t file_offset, size_t relative_offset) {
2811*795d594fSAndroid Build Coastguard Worker const bool may_have_compiled = MayHaveCompiledMethods();
2812*795d594fSAndroid Build Coastguard Worker if (may_have_compiled) {
2813*795d594fSAndroid Build Coastguard Worker CHECK_EQ(oat_class_headers_.size(), oat_classes_.size());
2814*795d594fSAndroid Build Coastguard Worker }
2815*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < oat_class_headers_.size(); ++i) {
2816*795d594fSAndroid Build Coastguard Worker // If there are any classes, the class offsets allocation aligns the offset.
2817*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(relative_offset, 4u);
2818*795d594fSAndroid Build Coastguard Worker DCHECK_OFFSET();
2819*795d594fSAndroid Build Coastguard Worker if (!oat_class_headers_[i].Write(this, out, oat_data_offset_)) {
2820*795d594fSAndroid Build Coastguard Worker return 0u;
2821*795d594fSAndroid Build Coastguard Worker }
2822*795d594fSAndroid Build Coastguard Worker relative_offset += oat_class_headers_[i].SizeOf();
2823*795d594fSAndroid Build Coastguard Worker if (may_have_compiled) {
2824*795d594fSAndroid Build Coastguard Worker if (!oat_classes_[i].Write(this, out)) {
2825*795d594fSAndroid Build Coastguard Worker return 0u;
2826*795d594fSAndroid Build Coastguard Worker }
2827*795d594fSAndroid Build Coastguard Worker relative_offset += oat_classes_[i].SizeOf();
2828*795d594fSAndroid Build Coastguard Worker }
2829*795d594fSAndroid Build Coastguard Worker }
2830*795d594fSAndroid Build Coastguard Worker return relative_offset;
2831*795d594fSAndroid Build Coastguard Worker }
2832*795d594fSAndroid Build Coastguard Worker
WriteMaps(OutputStream * out,size_t file_offset,size_t relative_offset)2833*795d594fSAndroid Build Coastguard Worker size_t OatWriter::WriteMaps(OutputStream* out, size_t file_offset, size_t relative_offset) {
2834*795d594fSAndroid Build Coastguard Worker {
2835*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(!out->WriteFully(code_info_data_.data(), code_info_data_.size()))) {
2836*795d594fSAndroid Build Coastguard Worker return 0;
2837*795d594fSAndroid Build Coastguard Worker }
2838*795d594fSAndroid Build Coastguard Worker relative_offset += code_info_data_.size();
2839*795d594fSAndroid Build Coastguard Worker size_vmap_table_ = code_info_data_.size();
2840*795d594fSAndroid Build Coastguard Worker DCHECK_OFFSET();
2841*795d594fSAndroid Build Coastguard Worker }
2842*795d594fSAndroid Build Coastguard Worker
2843*795d594fSAndroid Build Coastguard Worker return relative_offset;
2844*795d594fSAndroid Build Coastguard Worker }
2845*795d594fSAndroid Build Coastguard Worker
2846*795d594fSAndroid Build Coastguard Worker
2847*795d594fSAndroid Build Coastguard Worker template <typename GetBssOffset>
WriteIndexBssMapping(OutputStream * out,size_t number_of_indexes,size_t slot_size,const BitVector & indexes,GetBssOffset get_bss_offset)2848*795d594fSAndroid Build Coastguard Worker size_t WriteIndexBssMapping(OutputStream* out,
2849*795d594fSAndroid Build Coastguard Worker size_t number_of_indexes,
2850*795d594fSAndroid Build Coastguard Worker size_t slot_size,
2851*795d594fSAndroid Build Coastguard Worker const BitVector& indexes,
2852*795d594fSAndroid Build Coastguard Worker GetBssOffset get_bss_offset) {
2853*795d594fSAndroid Build Coastguard Worker // Allocate the IndexBssMapping.
2854*795d594fSAndroid Build Coastguard Worker size_t number_of_entries = CalculateNumberOfIndexBssMappingEntries(
2855*795d594fSAndroid Build Coastguard Worker number_of_indexes, slot_size, indexes, get_bss_offset);
2856*795d594fSAndroid Build Coastguard Worker size_t mappings_size = IndexBssMapping::ComputeSize(number_of_entries);
2857*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(mappings_size, sizeof(uint32_t));
2858*795d594fSAndroid Build Coastguard Worker std::unique_ptr<uint32_t[]> storage(new uint32_t[mappings_size / sizeof(uint32_t)]);
2859*795d594fSAndroid Build Coastguard Worker IndexBssMapping* mappings = new(storage.get()) IndexBssMapping(number_of_entries);
2860*795d594fSAndroid Build Coastguard Worker mappings->ClearPadding();
2861*795d594fSAndroid Build Coastguard Worker // Encode the IndexBssMapping.
2862*795d594fSAndroid Build Coastguard Worker IndexBssMappingEncoder encoder(number_of_indexes, slot_size);
2863*795d594fSAndroid Build Coastguard Worker auto init_it = mappings->begin();
2864*795d594fSAndroid Build Coastguard Worker bool first_index = true;
2865*795d594fSAndroid Build Coastguard Worker for (uint32_t index : indexes.Indexes()) {
2866*795d594fSAndroid Build Coastguard Worker size_t bss_offset = get_bss_offset(index);
2867*795d594fSAndroid Build Coastguard Worker if (first_index) {
2868*795d594fSAndroid Build Coastguard Worker first_index = false;
2869*795d594fSAndroid Build Coastguard Worker encoder.Reset(index, bss_offset);
2870*795d594fSAndroid Build Coastguard Worker } else if (!encoder.TryMerge(index, bss_offset)) {
2871*795d594fSAndroid Build Coastguard Worker *init_it = encoder.GetEntry();
2872*795d594fSAndroid Build Coastguard Worker ++init_it;
2873*795d594fSAndroid Build Coastguard Worker encoder.Reset(index, bss_offset);
2874*795d594fSAndroid Build Coastguard Worker }
2875*795d594fSAndroid Build Coastguard Worker }
2876*795d594fSAndroid Build Coastguard Worker // Store the last entry.
2877*795d594fSAndroid Build Coastguard Worker *init_it = encoder.GetEntry();
2878*795d594fSAndroid Build Coastguard Worker ++init_it;
2879*795d594fSAndroid Build Coastguard Worker DCHECK(init_it == mappings->end());
2880*795d594fSAndroid Build Coastguard Worker
2881*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(storage.get(), mappings_size)) {
2882*795d594fSAndroid Build Coastguard Worker return 0u;
2883*795d594fSAndroid Build Coastguard Worker }
2884*795d594fSAndroid Build Coastguard Worker return mappings_size;
2885*795d594fSAndroid Build Coastguard Worker }
2886*795d594fSAndroid Build Coastguard Worker
WriteIndexBssMapping(OutputStream * out,const DexFile * dex_file,const BitVector & type_indexes,const SafeMap<TypeReference,size_t,TypeReferenceValueComparator> & bss_entries)2887*795d594fSAndroid Build Coastguard Worker size_t WriteIndexBssMapping(
2888*795d594fSAndroid Build Coastguard Worker OutputStream* out,
2889*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file,
2890*795d594fSAndroid Build Coastguard Worker const BitVector& type_indexes,
2891*795d594fSAndroid Build Coastguard Worker const SafeMap<TypeReference, size_t, TypeReferenceValueComparator>& bss_entries) {
2892*795d594fSAndroid Build Coastguard Worker return WriteIndexBssMapping(
2893*795d594fSAndroid Build Coastguard Worker out,
2894*795d594fSAndroid Build Coastguard Worker dex_file->NumTypeIds(),
2895*795d594fSAndroid Build Coastguard Worker sizeof(GcRoot<mirror::Class>),
2896*795d594fSAndroid Build Coastguard Worker type_indexes,
2897*795d594fSAndroid Build Coastguard Worker [=](uint32_t index) { return bss_entries.Get({dex_file, dex::TypeIndex(index)}); });
2898*795d594fSAndroid Build Coastguard Worker }
2899*795d594fSAndroid Build Coastguard Worker
WriteIndexBssMappingsHelper(OutputStream * out,size_t file_offset,size_t relative_offset,const DexFile * dex_file,uint32_t method_bss_mapping_offset,uint32_t type_bss_mapping_offset,uint32_t public_type_bss_mapping_offset,uint32_t package_type_bss_mapping_offset,uint32_t string_bss_mapping_offset,uint32_t method_type_bss_mapping_offset)2900*795d594fSAndroid Build Coastguard Worker size_t OatWriter::WriteIndexBssMappingsHelper(OutputStream* out,
2901*795d594fSAndroid Build Coastguard Worker size_t file_offset,
2902*795d594fSAndroid Build Coastguard Worker size_t relative_offset,
2903*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file,
2904*795d594fSAndroid Build Coastguard Worker uint32_t method_bss_mapping_offset,
2905*795d594fSAndroid Build Coastguard Worker uint32_t type_bss_mapping_offset,
2906*795d594fSAndroid Build Coastguard Worker uint32_t public_type_bss_mapping_offset,
2907*795d594fSAndroid Build Coastguard Worker uint32_t package_type_bss_mapping_offset,
2908*795d594fSAndroid Build Coastguard Worker uint32_t string_bss_mapping_offset,
2909*795d594fSAndroid Build Coastguard Worker uint32_t method_type_bss_mapping_offset) {
2910*795d594fSAndroid Build Coastguard Worker const PointerSize pointer_size = GetInstructionSetPointerSize(oat_header_->GetInstructionSet());
2911*795d594fSAndroid Build Coastguard Worker auto method_it = bss_method_entry_references_.find(dex_file);
2912*795d594fSAndroid Build Coastguard Worker if (method_it != bss_method_entry_references_.end()) {
2913*795d594fSAndroid Build Coastguard Worker const BitVector& method_indexes = method_it->second;
2914*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(relative_offset, method_bss_mapping_offset);
2915*795d594fSAndroid Build Coastguard Worker DCHECK_OFFSET();
2916*795d594fSAndroid Build Coastguard Worker size_t method_mappings_size =
2917*795d594fSAndroid Build Coastguard Worker WriteIndexBssMapping(out,
2918*795d594fSAndroid Build Coastguard Worker dex_file->NumMethodIds(),
2919*795d594fSAndroid Build Coastguard Worker static_cast<size_t>(pointer_size),
2920*795d594fSAndroid Build Coastguard Worker method_indexes,
2921*795d594fSAndroid Build Coastguard Worker [this, dex_file](uint32_t index) {
2922*795d594fSAndroid Build Coastguard Worker return bss_method_entries_.Get({dex_file, index});
2923*795d594fSAndroid Build Coastguard Worker });
2924*795d594fSAndroid Build Coastguard Worker if (method_mappings_size == 0u) {
2925*795d594fSAndroid Build Coastguard Worker return 0u;
2926*795d594fSAndroid Build Coastguard Worker }
2927*795d594fSAndroid Build Coastguard Worker size_method_bss_mappings_ += method_mappings_size;
2928*795d594fSAndroid Build Coastguard Worker relative_offset += method_mappings_size;
2929*795d594fSAndroid Build Coastguard Worker } else {
2930*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(0u, method_bss_mapping_offset);
2931*795d594fSAndroid Build Coastguard Worker }
2932*795d594fSAndroid Build Coastguard Worker
2933*795d594fSAndroid Build Coastguard Worker auto type_it = bss_type_entry_references_.find(dex_file);
2934*795d594fSAndroid Build Coastguard Worker if (type_it != bss_type_entry_references_.end()) {
2935*795d594fSAndroid Build Coastguard Worker const BitVector& type_indexes = type_it->second;
2936*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(relative_offset, type_bss_mapping_offset);
2937*795d594fSAndroid Build Coastguard Worker DCHECK_OFFSET();
2938*795d594fSAndroid Build Coastguard Worker size_t type_mappings_size =
2939*795d594fSAndroid Build Coastguard Worker WriteIndexBssMapping(out, dex_file, type_indexes, bss_type_entries_);
2940*795d594fSAndroid Build Coastguard Worker if (type_mappings_size == 0u) {
2941*795d594fSAndroid Build Coastguard Worker return 0u;
2942*795d594fSAndroid Build Coastguard Worker }
2943*795d594fSAndroid Build Coastguard Worker size_type_bss_mappings_ += type_mappings_size;
2944*795d594fSAndroid Build Coastguard Worker relative_offset += type_mappings_size;
2945*795d594fSAndroid Build Coastguard Worker } else {
2946*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(0u, type_bss_mapping_offset);
2947*795d594fSAndroid Build Coastguard Worker }
2948*795d594fSAndroid Build Coastguard Worker
2949*795d594fSAndroid Build Coastguard Worker auto public_type_it = bss_public_type_entry_references_.find(dex_file);
2950*795d594fSAndroid Build Coastguard Worker if (public_type_it != bss_public_type_entry_references_.end()) {
2951*795d594fSAndroid Build Coastguard Worker const BitVector& type_indexes = public_type_it->second;
2952*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(relative_offset, public_type_bss_mapping_offset);
2953*795d594fSAndroid Build Coastguard Worker DCHECK_OFFSET();
2954*795d594fSAndroid Build Coastguard Worker size_t public_type_mappings_size =
2955*795d594fSAndroid Build Coastguard Worker WriteIndexBssMapping(out, dex_file, type_indexes, bss_public_type_entries_);
2956*795d594fSAndroid Build Coastguard Worker if (public_type_mappings_size == 0u) {
2957*795d594fSAndroid Build Coastguard Worker return 0u;
2958*795d594fSAndroid Build Coastguard Worker }
2959*795d594fSAndroid Build Coastguard Worker size_public_type_bss_mappings_ += public_type_mappings_size;
2960*795d594fSAndroid Build Coastguard Worker relative_offset += public_type_mappings_size;
2961*795d594fSAndroid Build Coastguard Worker } else {
2962*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(0u, public_type_bss_mapping_offset);
2963*795d594fSAndroid Build Coastguard Worker }
2964*795d594fSAndroid Build Coastguard Worker
2965*795d594fSAndroid Build Coastguard Worker auto package_type_it = bss_package_type_entry_references_.find(dex_file);
2966*795d594fSAndroid Build Coastguard Worker if (package_type_it != bss_package_type_entry_references_.end()) {
2967*795d594fSAndroid Build Coastguard Worker const BitVector& type_indexes = package_type_it->second;
2968*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(relative_offset, package_type_bss_mapping_offset);
2969*795d594fSAndroid Build Coastguard Worker DCHECK_OFFSET();
2970*795d594fSAndroid Build Coastguard Worker size_t package_type_mappings_size =
2971*795d594fSAndroid Build Coastguard Worker WriteIndexBssMapping(out, dex_file, type_indexes, bss_package_type_entries_);
2972*795d594fSAndroid Build Coastguard Worker if (package_type_mappings_size == 0u) {
2973*795d594fSAndroid Build Coastguard Worker return 0u;
2974*795d594fSAndroid Build Coastguard Worker }
2975*795d594fSAndroid Build Coastguard Worker size_package_type_bss_mappings_ += package_type_mappings_size;
2976*795d594fSAndroid Build Coastguard Worker relative_offset += package_type_mappings_size;
2977*795d594fSAndroid Build Coastguard Worker } else {
2978*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(0u, package_type_bss_mapping_offset);
2979*795d594fSAndroid Build Coastguard Worker }
2980*795d594fSAndroid Build Coastguard Worker
2981*795d594fSAndroid Build Coastguard Worker auto string_it = bss_string_entry_references_.find(dex_file);
2982*795d594fSAndroid Build Coastguard Worker if (string_it != bss_string_entry_references_.end()) {
2983*795d594fSAndroid Build Coastguard Worker const BitVector& string_indexes = string_it->second;
2984*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(relative_offset, string_bss_mapping_offset);
2985*795d594fSAndroid Build Coastguard Worker DCHECK_OFFSET();
2986*795d594fSAndroid Build Coastguard Worker size_t string_mappings_size =
2987*795d594fSAndroid Build Coastguard Worker WriteIndexBssMapping(out,
2988*795d594fSAndroid Build Coastguard Worker dex_file->NumStringIds(),
2989*795d594fSAndroid Build Coastguard Worker sizeof(GcRoot<mirror::String>),
2990*795d594fSAndroid Build Coastguard Worker string_indexes,
2991*795d594fSAndroid Build Coastguard Worker [this, dex_file](uint32_t index) {
2992*795d594fSAndroid Build Coastguard Worker return bss_string_entries_.Get({dex_file, dex::StringIndex(index)});
2993*795d594fSAndroid Build Coastguard Worker });
2994*795d594fSAndroid Build Coastguard Worker if (string_mappings_size == 0u) {
2995*795d594fSAndroid Build Coastguard Worker return 0u;
2996*795d594fSAndroid Build Coastguard Worker }
2997*795d594fSAndroid Build Coastguard Worker size_string_bss_mappings_ += string_mappings_size;
2998*795d594fSAndroid Build Coastguard Worker relative_offset += string_mappings_size;
2999*795d594fSAndroid Build Coastguard Worker } else {
3000*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(0u, string_bss_mapping_offset);
3001*795d594fSAndroid Build Coastguard Worker }
3002*795d594fSAndroid Build Coastguard Worker
3003*795d594fSAndroid Build Coastguard Worker auto method_type_it = bss_method_type_entry_references_.find(dex_file);
3004*795d594fSAndroid Build Coastguard Worker if (method_type_it != bss_method_type_entry_references_.end()) {
3005*795d594fSAndroid Build Coastguard Worker const BitVector& method_type_indexes = method_type_it->second;
3006*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(relative_offset, method_type_bss_mapping_offset);
3007*795d594fSAndroid Build Coastguard Worker DCHECK_OFFSET();
3008*795d594fSAndroid Build Coastguard Worker size_t method_type_mappings_size =
3009*795d594fSAndroid Build Coastguard Worker WriteIndexBssMapping(out,
3010*795d594fSAndroid Build Coastguard Worker dex_file->NumProtoIds(),
3011*795d594fSAndroid Build Coastguard Worker sizeof(GcRoot<mirror::MethodType>),
3012*795d594fSAndroid Build Coastguard Worker method_type_indexes,
3013*795d594fSAndroid Build Coastguard Worker [this, dex_file](uint32_t index) {
3014*795d594fSAndroid Build Coastguard Worker return bss_method_type_entries_
3015*795d594fSAndroid Build Coastguard Worker .Get({dex_file, dex::ProtoIndex(index)});
3016*795d594fSAndroid Build Coastguard Worker });
3017*795d594fSAndroid Build Coastguard Worker if (method_type_mappings_size == 0u) {
3018*795d594fSAndroid Build Coastguard Worker return 0u;
3019*795d594fSAndroid Build Coastguard Worker }
3020*795d594fSAndroid Build Coastguard Worker size_method_type_bss_mappings_ += method_type_mappings_size;
3021*795d594fSAndroid Build Coastguard Worker relative_offset += method_type_mappings_size;
3022*795d594fSAndroid Build Coastguard Worker } else {
3023*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(0u, method_type_bss_mapping_offset);
3024*795d594fSAndroid Build Coastguard Worker }
3025*795d594fSAndroid Build Coastguard Worker
3026*795d594fSAndroid Build Coastguard Worker return relative_offset;
3027*795d594fSAndroid Build Coastguard Worker }
3028*795d594fSAndroid Build Coastguard Worker
WriteIndexBssMappings(OutputStream * out,size_t file_offset,size_t relative_offset)3029*795d594fSAndroid Build Coastguard Worker size_t OatWriter::WriteIndexBssMappings(OutputStream* out,
3030*795d594fSAndroid Build Coastguard Worker size_t file_offset,
3031*795d594fSAndroid Build Coastguard Worker size_t relative_offset) {
3032*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split("WriteMethodBssMappings", timings_);
3033*795d594fSAndroid Build Coastguard Worker if (bss_method_entry_references_.empty() &&
3034*795d594fSAndroid Build Coastguard Worker bss_type_entry_references_.empty() &&
3035*795d594fSAndroid Build Coastguard Worker bss_public_type_entry_references_.empty() &&
3036*795d594fSAndroid Build Coastguard Worker bss_package_type_entry_references_.empty() &&
3037*795d594fSAndroid Build Coastguard Worker bss_string_entry_references_.empty() &&
3038*795d594fSAndroid Build Coastguard Worker bss_method_type_entry_references_.empty()) {
3039*795d594fSAndroid Build Coastguard Worker return relative_offset;
3040*795d594fSAndroid Build Coastguard Worker }
3041*795d594fSAndroid Build Coastguard Worker // If there are any classes, the class offsets allocation aligns the offset
3042*795d594fSAndroid Build Coastguard Worker // and we cannot have method bss mappings without class offsets.
3043*795d594fSAndroid Build Coastguard Worker static_assert(alignof(IndexBssMapping) == sizeof(uint32_t), "IndexBssMapping alignment check.");
3044*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(relative_offset, sizeof(uint32_t));
3045*795d594fSAndroid Build Coastguard Worker
3046*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
3047*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file = (*dex_files_)[i];
3048*795d594fSAndroid Build Coastguard Worker OatDexFile* oat_dex_file = &oat_dex_files_[i];
3049*795d594fSAndroid Build Coastguard Worker relative_offset = WriteIndexBssMappingsHelper(out,
3050*795d594fSAndroid Build Coastguard Worker file_offset,
3051*795d594fSAndroid Build Coastguard Worker relative_offset,
3052*795d594fSAndroid Build Coastguard Worker dex_file,
3053*795d594fSAndroid Build Coastguard Worker oat_dex_file->method_bss_mapping_offset_,
3054*795d594fSAndroid Build Coastguard Worker oat_dex_file->type_bss_mapping_offset_,
3055*795d594fSAndroid Build Coastguard Worker oat_dex_file->public_type_bss_mapping_offset_,
3056*795d594fSAndroid Build Coastguard Worker oat_dex_file->package_type_bss_mapping_offset_,
3057*795d594fSAndroid Build Coastguard Worker oat_dex_file->string_bss_mapping_offset_,
3058*795d594fSAndroid Build Coastguard Worker oat_dex_file->method_type_bss_mapping_offset_);
3059*795d594fSAndroid Build Coastguard Worker if (relative_offset == 0u) {
3060*795d594fSAndroid Build Coastguard Worker return 0u;
3061*795d594fSAndroid Build Coastguard Worker }
3062*795d594fSAndroid Build Coastguard Worker }
3063*795d594fSAndroid Build Coastguard Worker
3064*795d594fSAndroid Build Coastguard Worker if (!compiler_options_.IsBootImage()) {
3065*795d594fSAndroid Build Coastguard Worker ArrayRef<const DexFile* const> boot_class_path(
3066*795d594fSAndroid Build Coastguard Worker Runtime::Current()->GetClassLinker()->GetBootClassPath());
3067*795d594fSAndroid Build Coastguard Worker
3068*795d594fSAndroid Build Coastguard Worker if (compiler_options_.IsBootImageExtension()) {
3069*795d594fSAndroid Build Coastguard Worker // For boot image extension, the boot_class_path ends with the compiled dex files. In multi
3070*795d594fSAndroid Build Coastguard Worker // image, we might have several oat writers so we have to get all of the compiled dex files
3071*795d594fSAndroid Build Coastguard Worker // and not just the one we are compiling right now. Remove them to have the correct number of
3072*795d594fSAndroid Build Coastguard Worker // references.
3073*795d594fSAndroid Build Coastguard Worker ArrayRef<const DexFile* const> to_exclude(compiler_options_.GetDexFilesForOatFile());
3074*795d594fSAndroid Build Coastguard Worker DCHECK_GE(boot_class_path.size(), to_exclude.size());
3075*795d594fSAndroid Build Coastguard Worker DCHECK(std::equal(to_exclude.rbegin(), to_exclude.rend(), boot_class_path.rbegin()));
3076*795d594fSAndroid Build Coastguard Worker boot_class_path = boot_class_path.SubArray(0, boot_class_path.size() - to_exclude.size());
3077*795d594fSAndroid Build Coastguard Worker }
3078*795d594fSAndroid Build Coastguard Worker
3079*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, size = bcp_bss_info_.size(); i != size; ++i) {
3080*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file = boot_class_path[i];
3081*795d594fSAndroid Build Coastguard Worker DCHECK(!ContainsElement(*dex_files_, dex_file));
3082*795d594fSAndroid Build Coastguard Worker relative_offset =
3083*795d594fSAndroid Build Coastguard Worker WriteIndexBssMappingsHelper(out,
3084*795d594fSAndroid Build Coastguard Worker file_offset,
3085*795d594fSAndroid Build Coastguard Worker relative_offset,
3086*795d594fSAndroid Build Coastguard Worker dex_file,
3087*795d594fSAndroid Build Coastguard Worker bcp_bss_info_[i].method_bss_mapping_offset,
3088*795d594fSAndroid Build Coastguard Worker bcp_bss_info_[i].type_bss_mapping_offset,
3089*795d594fSAndroid Build Coastguard Worker bcp_bss_info_[i].public_type_bss_mapping_offset,
3090*795d594fSAndroid Build Coastguard Worker bcp_bss_info_[i].package_type_bss_mapping_offset,
3091*795d594fSAndroid Build Coastguard Worker bcp_bss_info_[i].string_bss_mapping_offset,
3092*795d594fSAndroid Build Coastguard Worker bcp_bss_info_[i].method_type_bss_mapping_offset);
3093*795d594fSAndroid Build Coastguard Worker if (relative_offset == 0u) {
3094*795d594fSAndroid Build Coastguard Worker return 0u;
3095*795d594fSAndroid Build Coastguard Worker }
3096*795d594fSAndroid Build Coastguard Worker }
3097*795d594fSAndroid Build Coastguard Worker }
3098*795d594fSAndroid Build Coastguard Worker return relative_offset;
3099*795d594fSAndroid Build Coastguard Worker }
3100*795d594fSAndroid Build Coastguard Worker
WriteOatDexFiles(OutputStream * out,size_t file_offset,size_t relative_offset)3101*795d594fSAndroid Build Coastguard Worker size_t OatWriter::WriteOatDexFiles(OutputStream* out, size_t file_offset, size_t relative_offset) {
3102*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split("WriteOatDexFiles", timings_);
3103*795d594fSAndroid Build Coastguard Worker
3104*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
3105*795d594fSAndroid Build Coastguard Worker OatDexFile* oat_dex_file = &oat_dex_files_[i];
3106*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(relative_offset, oat_dex_file->offset_);
3107*795d594fSAndroid Build Coastguard Worker DCHECK_OFFSET();
3108*795d594fSAndroid Build Coastguard Worker
3109*795d594fSAndroid Build Coastguard Worker // Write OatDexFile.
3110*795d594fSAndroid Build Coastguard Worker if (!oat_dex_file->Write(this, out)) {
3111*795d594fSAndroid Build Coastguard Worker return 0u;
3112*795d594fSAndroid Build Coastguard Worker }
3113*795d594fSAndroid Build Coastguard Worker relative_offset += oat_dex_file->SizeOf();
3114*795d594fSAndroid Build Coastguard Worker }
3115*795d594fSAndroid Build Coastguard Worker
3116*795d594fSAndroid Build Coastguard Worker return relative_offset;
3117*795d594fSAndroid Build Coastguard Worker }
3118*795d594fSAndroid Build Coastguard Worker
WriteBcpBssInfo(OutputStream * out,size_t file_offset,size_t relative_offset)3119*795d594fSAndroid Build Coastguard Worker size_t OatWriter::WriteBcpBssInfo(OutputStream* out, size_t file_offset, size_t relative_offset) {
3120*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split("WriteBcpBssInfo", timings_);
3121*795d594fSAndroid Build Coastguard Worker
3122*795d594fSAndroid Build Coastguard Worker const uint32_t number_of_bcp_dexfiles = bcp_bss_info_.size();
3123*795d594fSAndroid Build Coastguard Worker // We skip adding the number of DexFiles if we have no .bss mappings.
3124*795d594fSAndroid Build Coastguard Worker if (number_of_bcp_dexfiles == 0) {
3125*795d594fSAndroid Build Coastguard Worker return relative_offset;
3126*795d594fSAndroid Build Coastguard Worker }
3127*795d594fSAndroid Build Coastguard Worker
3128*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&number_of_bcp_dexfiles, sizeof(number_of_bcp_dexfiles))) {
3129*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write the number of BCP dexfiles to " << out->GetLocation();
3130*795d594fSAndroid Build Coastguard Worker return false;
3131*795d594fSAndroid Build Coastguard Worker }
3132*795d594fSAndroid Build Coastguard Worker size_bcp_bss_info_size_ = sizeof(number_of_bcp_dexfiles);
3133*795d594fSAndroid Build Coastguard Worker relative_offset += size_bcp_bss_info_size_;
3134*795d594fSAndroid Build Coastguard Worker
3135*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, size = number_of_bcp_dexfiles; i != size; ++i) {
3136*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(relative_offset, bcp_bss_info_[i].offset_);
3137*795d594fSAndroid Build Coastguard Worker DCHECK_OFFSET();
3138*795d594fSAndroid Build Coastguard Worker if (!bcp_bss_info_[i].Write(this, out)) {
3139*795d594fSAndroid Build Coastguard Worker return 0u;
3140*795d594fSAndroid Build Coastguard Worker }
3141*795d594fSAndroid Build Coastguard Worker relative_offset += BssMappingInfo::SizeOf();
3142*795d594fSAndroid Build Coastguard Worker }
3143*795d594fSAndroid Build Coastguard Worker
3144*795d594fSAndroid Build Coastguard Worker return relative_offset;
3145*795d594fSAndroid Build Coastguard Worker }
3146*795d594fSAndroid Build Coastguard Worker
WriteCode(OutputStream * out,size_t file_offset,size_t relative_offset)3147*795d594fSAndroid Build Coastguard Worker size_t OatWriter::WriteCode(OutputStream* out, size_t file_offset, size_t relative_offset) {
3148*795d594fSAndroid Build Coastguard Worker InstructionSet instruction_set = compiler_options_.GetInstructionSet();
3149*795d594fSAndroid Build Coastguard Worker if (GetCompilerOptions().IsBootImage() && primary_oat_file_) {
3150*795d594fSAndroid Build Coastguard Worker #define DO_TRAMPOLINE(field) \
3151*795d594fSAndroid Build Coastguard Worker do { \
3152*795d594fSAndroid Build Coastguard Worker /* Pad with at least four 0xFFs so we can do DCHECKs in OatQuickMethodHeader */ \
3153*795d594fSAndroid Build Coastguard Worker uint32_t aligned_offset = CompiledCode::AlignCode(relative_offset + 4, instruction_set); \
3154*795d594fSAndroid Build Coastguard Worker uint32_t alignment_padding = aligned_offset - relative_offset; \
3155*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < alignment_padding; i++) { \
3156*795d594fSAndroid Build Coastguard Worker uint8_t padding = 0xFF; \
3157*795d594fSAndroid Build Coastguard Worker out->WriteFully(&padding, 1); \
3158*795d594fSAndroid Build Coastguard Worker } \
3159*795d594fSAndroid Build Coastguard Worker size_trampoline_alignment_ += alignment_padding; \
3160*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully((field)->data(), (field)->size())) { \
3161*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write " # field " to " << out->GetLocation(); \
3162*795d594fSAndroid Build Coastguard Worker return false; \
3163*795d594fSAndroid Build Coastguard Worker } \
3164*795d594fSAndroid Build Coastguard Worker size_ ## field += (field)->size(); \
3165*795d594fSAndroid Build Coastguard Worker relative_offset += alignment_padding + (field)->size(); \
3166*795d594fSAndroid Build Coastguard Worker DCHECK_OFFSET(); \
3167*795d594fSAndroid Build Coastguard Worker } while (false)
3168*795d594fSAndroid Build Coastguard Worker
3169*795d594fSAndroid Build Coastguard Worker DO_TRAMPOLINE(jni_dlsym_lookup_trampoline_);
3170*795d594fSAndroid Build Coastguard Worker DO_TRAMPOLINE(jni_dlsym_lookup_critical_trampoline_);
3171*795d594fSAndroid Build Coastguard Worker DO_TRAMPOLINE(quick_generic_jni_trampoline_);
3172*795d594fSAndroid Build Coastguard Worker DO_TRAMPOLINE(quick_imt_conflict_trampoline_);
3173*795d594fSAndroid Build Coastguard Worker DO_TRAMPOLINE(quick_resolution_trampoline_);
3174*795d594fSAndroid Build Coastguard Worker DO_TRAMPOLINE(quick_to_interpreter_bridge_);
3175*795d594fSAndroid Build Coastguard Worker DO_TRAMPOLINE(nterp_trampoline_);
3176*795d594fSAndroid Build Coastguard Worker #undef DO_TRAMPOLINE
3177*795d594fSAndroid Build Coastguard Worker }
3178*795d594fSAndroid Build Coastguard Worker return relative_offset;
3179*795d594fSAndroid Build Coastguard Worker }
3180*795d594fSAndroid Build Coastguard Worker
WriteCodeDexFiles(OutputStream * out,size_t file_offset,size_t relative_offset)3181*795d594fSAndroid Build Coastguard Worker size_t OatWriter::WriteCodeDexFiles(OutputStream* out,
3182*795d594fSAndroid Build Coastguard Worker size_t file_offset,
3183*795d594fSAndroid Build Coastguard Worker size_t relative_offset) {
3184*795d594fSAndroid Build Coastguard Worker if (!GetCompilerOptions().IsAnyCompilationEnabled()) {
3185*795d594fSAndroid Build Coastguard Worker // As with InitOatCodeDexFiles, also skip the writer if
3186*795d594fSAndroid Build Coastguard Worker // compilation was disabled.
3187*795d594fSAndroid Build Coastguard Worker if (kOatWriterDebugOatCodeLayout) {
3188*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "WriteCodeDexFiles: OatWriter("
3189*795d594fSAndroid Build Coastguard Worker << this << "), "
3190*795d594fSAndroid Build Coastguard Worker << "compilation is disabled";
3191*795d594fSAndroid Build Coastguard Worker }
3192*795d594fSAndroid Build Coastguard Worker
3193*795d594fSAndroid Build Coastguard Worker return relative_offset;
3194*795d594fSAndroid Build Coastguard Worker }
3195*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
3196*795d594fSAndroid Build Coastguard Worker DCHECK(ordered_methods_ != nullptr);
3197*795d594fSAndroid Build Coastguard Worker std::unique_ptr<OrderedMethodList> ordered_methods_ptr =
3198*795d594fSAndroid Build Coastguard Worker std::move(ordered_methods_);
3199*795d594fSAndroid Build Coastguard Worker WriteCodeMethodVisitor visitor(this,
3200*795d594fSAndroid Build Coastguard Worker out,
3201*795d594fSAndroid Build Coastguard Worker file_offset,
3202*795d594fSAndroid Build Coastguard Worker relative_offset,
3203*795d594fSAndroid Build Coastguard Worker std::move(*ordered_methods_ptr));
3204*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(!visitor.Visit())) {
3205*795d594fSAndroid Build Coastguard Worker return 0;
3206*795d594fSAndroid Build Coastguard Worker }
3207*795d594fSAndroid Build Coastguard Worker relative_offset = visitor.GetOffset();
3208*795d594fSAndroid Build Coastguard Worker
3209*795d594fSAndroid Build Coastguard Worker size_code_alignment_ += relative_patcher_->CodeAlignmentSize();
3210*795d594fSAndroid Build Coastguard Worker size_relative_call_thunks_ += relative_patcher_->RelativeCallThunksSize();
3211*795d594fSAndroid Build Coastguard Worker size_misc_thunks_ += relative_patcher_->MiscThunksSize();
3212*795d594fSAndroid Build Coastguard Worker
3213*795d594fSAndroid Build Coastguard Worker return relative_offset;
3214*795d594fSAndroid Build Coastguard Worker }
3215*795d594fSAndroid Build Coastguard Worker
WriteDataImgRelRo(OutputStream * out,size_t file_offset,size_t relative_offset)3216*795d594fSAndroid Build Coastguard Worker size_t OatWriter::WriteDataImgRelRo(OutputStream* out,
3217*795d594fSAndroid Build Coastguard Worker size_t file_offset,
3218*795d594fSAndroid Build Coastguard Worker size_t relative_offset) {
3219*795d594fSAndroid Build Coastguard Worker size_t size = boot_image_rel_ro_entries_.size() +
3220*795d594fSAndroid Build Coastguard Worker app_image_rel_ro_method_entries_.size() +
3221*795d594fSAndroid Build Coastguard Worker app_image_rel_ro_type_entries_.size();
3222*795d594fSAndroid Build Coastguard Worker if (size == 0u) {
3223*795d594fSAndroid Build Coastguard Worker return relative_offset;
3224*795d594fSAndroid Build Coastguard Worker }
3225*795d594fSAndroid Build Coastguard Worker
3226*795d594fSAndroid Build Coastguard Worker // Write the entire .data.img.rel.ro with a single WriteFully().
3227*795d594fSAndroid Build Coastguard Worker std::vector<uint32_t> data;
3228*795d594fSAndroid Build Coastguard Worker data.reserve(size);
3229*795d594fSAndroid Build Coastguard Worker for (const auto& entry : boot_image_rel_ro_entries_) {
3230*795d594fSAndroid Build Coastguard Worker uint32_t boot_image_offset = entry.first;
3231*795d594fSAndroid Build Coastguard Worker data.push_back(boot_image_offset);
3232*795d594fSAndroid Build Coastguard Worker }
3233*795d594fSAndroid Build Coastguard Worker if (!app_image_rel_ro_method_entries_.empty() || !app_image_rel_ro_type_entries_.empty()) {
3234*795d594fSAndroid Build Coastguard Worker DCHECK(GetCompilerOptions().IsAppImage());
3235*795d594fSAndroid Build Coastguard Worker ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
3236*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
3237*795d594fSAndroid Build Coastguard Worker const DexFile* last_dex_file = nullptr;
3238*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::DexCache> dex_cache = nullptr;
3239*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::ClassLoader> class_loader = nullptr;
3240*795d594fSAndroid Build Coastguard Worker auto update_for_dex_file = [&](const DexFile* dex_file) REQUIRES_SHARED(Locks::mutator_lock_) {
3241*795d594fSAndroid Build Coastguard Worker if (dex_file != last_dex_file) {
3242*795d594fSAndroid Build Coastguard Worker dex_cache = class_linker->FindDexCache(soa.Self(), *dex_file);
3243*795d594fSAndroid Build Coastguard Worker class_loader = dex_cache->GetClassLoader();
3244*795d594fSAndroid Build Coastguard Worker last_dex_file = dex_file;
3245*795d594fSAndroid Build Coastguard Worker }
3246*795d594fSAndroid Build Coastguard Worker };
3247*795d594fSAndroid Build Coastguard Worker for (const auto& entry : app_image_rel_ro_method_entries_) {
3248*795d594fSAndroid Build Coastguard Worker MethodReference target_method = entry.first;
3249*795d594fSAndroid Build Coastguard Worker update_for_dex_file(target_method.dex_file);
3250*795d594fSAndroid Build Coastguard Worker ArtMethod* method =
3251*795d594fSAndroid Build Coastguard Worker class_linker->LookupResolvedMethod(target_method.index, dex_cache, class_loader);
3252*795d594fSAndroid Build Coastguard Worker CHECK(method != nullptr);
3253*795d594fSAndroid Build Coastguard Worker uint32_t app_image_offset = image_writer_->GetGlobalImageOffset(method);
3254*795d594fSAndroid Build Coastguard Worker data.push_back(app_image_offset);
3255*795d594fSAndroid Build Coastguard Worker }
3256*795d594fSAndroid Build Coastguard Worker for (const auto& entry : app_image_rel_ro_type_entries_) {
3257*795d594fSAndroid Build Coastguard Worker TypeReference target_type = entry.first;
3258*795d594fSAndroid Build Coastguard Worker update_for_dex_file(target_type.dex_file);
3259*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> type =
3260*795d594fSAndroid Build Coastguard Worker class_linker->LookupResolvedType(target_type.TypeIndex(), dex_cache, class_loader);
3261*795d594fSAndroid Build Coastguard Worker CHECK(type != nullptr);
3262*795d594fSAndroid Build Coastguard Worker uint32_t app_image_offset = image_writer_->GetGlobalImageOffset(type.Ptr());
3263*795d594fSAndroid Build Coastguard Worker data.push_back(app_image_offset);
3264*795d594fSAndroid Build Coastguard Worker }
3265*795d594fSAndroid Build Coastguard Worker }
3266*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(data.size(), size);
3267*795d594fSAndroid Build Coastguard Worker DCHECK_OFFSET();
3268*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(data.data(), data.size() * sizeof(data[0]))) {
3269*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write .data.img.rel.ro in " << out->GetLocation();
3270*795d594fSAndroid Build Coastguard Worker return 0u;
3271*795d594fSAndroid Build Coastguard Worker }
3272*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(size_data_img_rel_ro_, 0u);
3273*795d594fSAndroid Build Coastguard Worker size_data_img_rel_ro_ = data.size() * sizeof(data[0]);
3274*795d594fSAndroid Build Coastguard Worker relative_offset += size_data_img_rel_ro_;
3275*795d594fSAndroid Build Coastguard Worker return relative_offset;
3276*795d594fSAndroid Build Coastguard Worker }
3277*795d594fSAndroid Build Coastguard Worker
RecordOatDataOffset(OutputStream * out)3278*795d594fSAndroid Build Coastguard Worker bool OatWriter::RecordOatDataOffset(OutputStream* out) {
3279*795d594fSAndroid Build Coastguard Worker // Get the elf file offset of the oat file.
3280*795d594fSAndroid Build Coastguard Worker const off_t raw_file_offset = out->Seek(0, kSeekCurrent);
3281*795d594fSAndroid Build Coastguard Worker if (raw_file_offset == static_cast<off_t>(-1)) {
3282*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed to get file offset in " << out->GetLocation();
3283*795d594fSAndroid Build Coastguard Worker return false;
3284*795d594fSAndroid Build Coastguard Worker }
3285*795d594fSAndroid Build Coastguard Worker oat_data_offset_ = static_cast<size_t>(raw_file_offset);
3286*795d594fSAndroid Build Coastguard Worker return true;
3287*795d594fSAndroid Build Coastguard Worker }
3288*795d594fSAndroid Build Coastguard Worker
WriteDexFiles(File * file,bool verify,bool use_existing_vdex,CopyOption copy_dex_files,std::vector<MemMap> * opened_dex_files_map)3289*795d594fSAndroid Build Coastguard Worker bool OatWriter::WriteDexFiles(File* file,
3290*795d594fSAndroid Build Coastguard Worker bool verify,
3291*795d594fSAndroid Build Coastguard Worker bool use_existing_vdex,
3292*795d594fSAndroid Build Coastguard Worker CopyOption copy_dex_files,
3293*795d594fSAndroid Build Coastguard Worker /*out*/ std::vector<MemMap>* opened_dex_files_map) {
3294*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split("Write Dex files", timings_);
3295*795d594fSAndroid Build Coastguard Worker
3296*795d594fSAndroid Build Coastguard Worker // If extraction is enabled, only do it if not all the dex files are aligned and uncompressed.
3297*795d594fSAndroid Build Coastguard Worker if (copy_dex_files == CopyOption::kOnlyIfCompressed) {
3298*795d594fSAndroid Build Coastguard Worker extract_dex_files_into_vdex_ = false;
3299*795d594fSAndroid Build Coastguard Worker for (OatDexFile& oat_dex_file : oat_dex_files_) {
3300*795d594fSAndroid Build Coastguard Worker const DexFileContainer* container = oat_dex_file.GetDexFile()->GetContainer().get();
3301*795d594fSAndroid Build Coastguard Worker if (!container->IsFileMap()) {
3302*795d594fSAndroid Build Coastguard Worker extract_dex_files_into_vdex_ = true;
3303*795d594fSAndroid Build Coastguard Worker break;
3304*795d594fSAndroid Build Coastguard Worker }
3305*795d594fSAndroid Build Coastguard Worker }
3306*795d594fSAndroid Build Coastguard Worker } else if (copy_dex_files == CopyOption::kAlways) {
3307*795d594fSAndroid Build Coastguard Worker extract_dex_files_into_vdex_ = true;
3308*795d594fSAndroid Build Coastguard Worker } else {
3309*795d594fSAndroid Build Coastguard Worker DCHECK(copy_dex_files == CopyOption::kNever);
3310*795d594fSAndroid Build Coastguard Worker extract_dex_files_into_vdex_ = false;
3311*795d594fSAndroid Build Coastguard Worker }
3312*795d594fSAndroid Build Coastguard Worker
3313*795d594fSAndroid Build Coastguard Worker if (verify) {
3314*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split2("Verify input Dex files", timings_);
3315*795d594fSAndroid Build Coastguard Worker for (OatDexFile& oat_dex_file : oat_dex_files_) {
3316*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file = oat_dex_file.GetDexFile();
3317*795d594fSAndroid Build Coastguard Worker std::string error_msg;
3318*795d594fSAndroid Build Coastguard Worker if (!dex::Verify(dex_file,
3319*795d594fSAndroid Build Coastguard Worker dex_file->GetLocation().c_str(),
3320*795d594fSAndroid Build Coastguard Worker /*verify_checksum=*/true,
3321*795d594fSAndroid Build Coastguard Worker &error_msg)) {
3322*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed to verify " << dex_file->GetLocation() << ": " << error_msg;
3323*795d594fSAndroid Build Coastguard Worker return false;
3324*795d594fSAndroid Build Coastguard Worker }
3325*795d594fSAndroid Build Coastguard Worker }
3326*795d594fSAndroid Build Coastguard Worker }
3327*795d594fSAndroid Build Coastguard Worker
3328*795d594fSAndroid Build Coastguard Worker if (extract_dex_files_into_vdex_) {
3329*795d594fSAndroid Build Coastguard Worker vdex_dex_files_offset_ = vdex_size_;
3330*795d594fSAndroid Build Coastguard Worker
3331*795d594fSAndroid Build Coastguard Worker // Calculate the total size after the dex files.
3332*795d594fSAndroid Build Coastguard Worker size_t vdex_size_with_dex_files = vdex_size_;
3333*795d594fSAndroid Build Coastguard Worker for (OatDexFile& oat_dex_file : oat_dex_files_) {
3334*795d594fSAndroid Build Coastguard Worker // Dex files are required to be 4 byte aligned.
3335*795d594fSAndroid Build Coastguard Worker vdex_size_with_dex_files = RoundUp(vdex_size_with_dex_files, 4u);
3336*795d594fSAndroid Build Coastguard Worker // Record offset for the dex file.
3337*795d594fSAndroid Build Coastguard Worker oat_dex_file.dex_file_offset_ = vdex_size_with_dex_files;
3338*795d594fSAndroid Build Coastguard Worker // Add the size of the dex file.
3339*795d594fSAndroid Build Coastguard Worker if (oat_dex_file.dex_file_size_ < sizeof(DexFile::Header)) {
3340*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Dex file " << oat_dex_file.GetLocation() << " is too short: "
3341*795d594fSAndroid Build Coastguard Worker << oat_dex_file.dex_file_size_ << " < " << sizeof(DexFile::Header);
3342*795d594fSAndroid Build Coastguard Worker return false;
3343*795d594fSAndroid Build Coastguard Worker }
3344*795d594fSAndroid Build Coastguard Worker vdex_size_with_dex_files += oat_dex_file.dex_file_size_;
3345*795d594fSAndroid Build Coastguard Worker }
3346*795d594fSAndroid Build Coastguard Worker
3347*795d594fSAndroid Build Coastguard Worker // Extend the file and include the full page at the end as we need to write
3348*795d594fSAndroid Build Coastguard Worker // additional data there and do not want to mmap that page twice.
3349*795d594fSAndroid Build Coastguard Worker //
3350*795d594fSAndroid Build Coastguard Worker // The page size value here is used to figure out the size of the mapping below,
3351*795d594fSAndroid Build Coastguard Worker // however it doesn't affect the file contents or its size, so should not be
3352*795d594fSAndroid Build Coastguard Worker // replaced with kElfSegmentAlignment.
3353*795d594fSAndroid Build Coastguard Worker size_t page_aligned_size = RoundUp(vdex_size_with_dex_files, MemMap::GetPageSize());
3354*795d594fSAndroid Build Coastguard Worker if (!use_existing_vdex) {
3355*795d594fSAndroid Build Coastguard Worker if (file->SetLength(page_aligned_size) != 0) {
3356*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to resize vdex file " << file->GetPath();
3357*795d594fSAndroid Build Coastguard Worker return false;
3358*795d594fSAndroid Build Coastguard Worker }
3359*795d594fSAndroid Build Coastguard Worker }
3360*795d594fSAndroid Build Coastguard Worker
3361*795d594fSAndroid Build Coastguard Worker std::string error_msg;
3362*795d594fSAndroid Build Coastguard Worker MemMap dex_files_map = MemMap::MapFile(
3363*795d594fSAndroid Build Coastguard Worker page_aligned_size,
3364*795d594fSAndroid Build Coastguard Worker use_existing_vdex ? PROT_READ : PROT_READ | PROT_WRITE,
3365*795d594fSAndroid Build Coastguard Worker MAP_SHARED,
3366*795d594fSAndroid Build Coastguard Worker file->Fd(),
3367*795d594fSAndroid Build Coastguard Worker /*start=*/ 0u,
3368*795d594fSAndroid Build Coastguard Worker /*low_4gb=*/ false,
3369*795d594fSAndroid Build Coastguard Worker file->GetPath().c_str(),
3370*795d594fSAndroid Build Coastguard Worker &error_msg);
3371*795d594fSAndroid Build Coastguard Worker if (!dex_files_map.IsValid()) {
3372*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed to mmap() dex files from oat file. File: " << file->GetPath()
3373*795d594fSAndroid Build Coastguard Worker << " error: " << error_msg;
3374*795d594fSAndroid Build Coastguard Worker return false;
3375*795d594fSAndroid Build Coastguard Worker }
3376*795d594fSAndroid Build Coastguard Worker vdex_begin_ = dex_files_map.Begin();
3377*795d594fSAndroid Build Coastguard Worker
3378*795d594fSAndroid Build Coastguard Worker // Write dex files.
3379*795d594fSAndroid Build Coastguard Worker for (OatDexFile& oat_dex_file : oat_dex_files_) {
3380*795d594fSAndroid Build Coastguard Worker // Dex files are required to be 4 byte aligned.
3381*795d594fSAndroid Build Coastguard Worker size_t old_vdex_size = vdex_size_;
3382*795d594fSAndroid Build Coastguard Worker vdex_size_ = RoundUp(vdex_size_, 4u);
3383*795d594fSAndroid Build Coastguard Worker size_dex_file_alignment_ += vdex_size_ - old_vdex_size;
3384*795d594fSAndroid Build Coastguard Worker // Write the actual dex file.
3385*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(vdex_size_, oat_dex_file.dex_file_offset_);
3386*795d594fSAndroid Build Coastguard Worker uint8_t* out = vdex_begin_ + oat_dex_file.dex_file_offset_;
3387*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file = oat_dex_file.GetDexFile();
3388*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(oat_dex_file.dex_file_size_, dex_file->Size());
3389*795d594fSAndroid Build Coastguard Worker if (use_existing_vdex) {
3390*795d594fSAndroid Build Coastguard Worker // The vdex already contains the data.
3391*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(memcmp(out, dex_file->Begin(), dex_file->Size()), 0);
3392*795d594fSAndroid Build Coastguard Worker } else {
3393*795d594fSAndroid Build Coastguard Worker memcpy(out, dex_file->Begin(), dex_file->Size());
3394*795d594fSAndroid Build Coastguard Worker }
3395*795d594fSAndroid Build Coastguard Worker
3396*795d594fSAndroid Build Coastguard Worker // Update current size and account for the written data.
3397*795d594fSAndroid Build Coastguard Worker vdex_size_ += oat_dex_file.dex_file_size_;
3398*795d594fSAndroid Build Coastguard Worker size_dex_file_ += oat_dex_file.dex_file_size_;
3399*795d594fSAndroid Build Coastguard Worker }
3400*795d594fSAndroid Build Coastguard Worker
3401*795d594fSAndroid Build Coastguard Worker opened_dex_files_map->push_back(std::move(dex_files_map));
3402*795d594fSAndroid Build Coastguard Worker }
3403*795d594fSAndroid Build Coastguard Worker
3404*795d594fSAndroid Build Coastguard Worker if (use_existing_vdex) {
3405*795d594fSAndroid Build Coastguard Worker // If we re-use an existing vdex, artificially set the verifier deps size,
3406*795d594fSAndroid Build Coastguard Worker // so the compiler has a correct computation of the vdex size.
3407*795d594fSAndroid Build Coastguard Worker size_t actual_size = file->GetLength();
3408*795d594fSAndroid Build Coastguard Worker size_verifier_deps_ = actual_size - vdex_size_;
3409*795d594fSAndroid Build Coastguard Worker vdex_size_ = actual_size;
3410*795d594fSAndroid Build Coastguard Worker }
3411*795d594fSAndroid Build Coastguard Worker
3412*795d594fSAndroid Build Coastguard Worker return true;
3413*795d594fSAndroid Build Coastguard Worker }
3414*795d594fSAndroid Build Coastguard Worker
CloseSources()3415*795d594fSAndroid Build Coastguard Worker void OatWriter::CloseSources() {
3416*795d594fSAndroid Build Coastguard Worker for (OatDexFile& oat_dex_file : oat_dex_files_) {
3417*795d594fSAndroid Build Coastguard Worker oat_dex_file.dex_file_.reset();
3418*795d594fSAndroid Build Coastguard Worker }
3419*795d594fSAndroid Build Coastguard Worker }
3420*795d594fSAndroid Build Coastguard Worker
OpenDexFiles(File * file,std::vector<MemMap> * opened_dex_files_map,std::vector<std::unique_ptr<const DexFile>> * opened_dex_files)3421*795d594fSAndroid Build Coastguard Worker bool OatWriter::OpenDexFiles(
3422*795d594fSAndroid Build Coastguard Worker File* file,
3423*795d594fSAndroid Build Coastguard Worker /*inout*/ std::vector<MemMap>* opened_dex_files_map,
3424*795d594fSAndroid Build Coastguard Worker /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
3425*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split("OpenDexFiles", timings_);
3426*795d594fSAndroid Build Coastguard Worker
3427*795d594fSAndroid Build Coastguard Worker if (oat_dex_files_.empty()) {
3428*795d594fSAndroid Build Coastguard Worker // Nothing to do.
3429*795d594fSAndroid Build Coastguard Worker return true;
3430*795d594fSAndroid Build Coastguard Worker }
3431*795d594fSAndroid Build Coastguard Worker
3432*795d594fSAndroid Build Coastguard Worker if (!extract_dex_files_into_vdex_) {
3433*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(opened_dex_files_map->size(), 0u);
3434*795d594fSAndroid Build Coastguard Worker std::vector<std::unique_ptr<const DexFile>> dex_files;
3435*795d594fSAndroid Build Coastguard Worker for (OatDexFile& oat_dex_file : oat_dex_files_) {
3436*795d594fSAndroid Build Coastguard Worker // The dex file is already open, release the reference.
3437*795d594fSAndroid Build Coastguard Worker dex_files.emplace_back(std::move(oat_dex_file.dex_file_));
3438*795d594fSAndroid Build Coastguard Worker oat_dex_file.class_offsets_.resize(dex_files.back()->GetHeader().class_defs_size_);
3439*795d594fSAndroid Build Coastguard Worker }
3440*795d594fSAndroid Build Coastguard Worker *opened_dex_files = std::move(dex_files);
3441*795d594fSAndroid Build Coastguard Worker CloseSources();
3442*795d594fSAndroid Build Coastguard Worker return true;
3443*795d594fSAndroid Build Coastguard Worker }
3444*795d594fSAndroid Build Coastguard Worker // We could have closed the sources at the point of writing the dex files, but to
3445*795d594fSAndroid Build Coastguard Worker // make it consistent with the case we're not writing the dex files, we close them now.
3446*795d594fSAndroid Build Coastguard Worker CloseSources();
3447*795d594fSAndroid Build Coastguard Worker
3448*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(opened_dex_files_map->size(), 1u);
3449*795d594fSAndroid Build Coastguard Worker DCHECK(vdex_begin_ == opened_dex_files_map->front().Begin());
3450*795d594fSAndroid Build Coastguard Worker std::vector<std::unique_ptr<const DexFile>> dex_files;
3451*795d594fSAndroid Build Coastguard Worker auto dex_container = std::make_shared<MemoryDexFileContainer>(vdex_begin_, vdex_size_);
3452*795d594fSAndroid Build Coastguard Worker for (OatDexFile& oat_dex_file : oat_dex_files_) {
3453*795d594fSAndroid Build Coastguard Worker const uint8_t* raw_dex_file = vdex_begin_ + oat_dex_file.dex_file_offset_;
3454*795d594fSAndroid Build Coastguard Worker
3455*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
3456*795d594fSAndroid Build Coastguard Worker // Check the validity of the input files.
3457*795d594fSAndroid Build Coastguard Worker // Note that ValidateDexFileHeader() logs error messages.
3458*795d594fSAndroid Build Coastguard Worker CHECK(ValidateDexFileHeader(raw_dex_file, oat_dex_file.GetLocation()))
3459*795d594fSAndroid Build Coastguard Worker << "Failed to verify written dex file header!"
3460*795d594fSAndroid Build Coastguard Worker << " Output: " << file->GetPath()
3461*795d594fSAndroid Build Coastguard Worker << " ~ " << std::hex << static_cast<const void*>(raw_dex_file);
3462*795d594fSAndroid Build Coastguard Worker
3463*795d594fSAndroid Build Coastguard Worker const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
3464*795d594fSAndroid Build Coastguard Worker CHECK_EQ(header->file_size_, oat_dex_file.dex_file_size_)
3465*795d594fSAndroid Build Coastguard Worker << "File size mismatch in written dex file header! Expected: "
3466*795d594fSAndroid Build Coastguard Worker << oat_dex_file.dex_file_size_ << " Actual: " << header->file_size_
3467*795d594fSAndroid Build Coastguard Worker << " Output: " << file->GetPath();
3468*795d594fSAndroid Build Coastguard Worker }
3469*795d594fSAndroid Build Coastguard Worker
3470*795d594fSAndroid Build Coastguard Worker // Now, open the dex file.
3471*795d594fSAndroid Build Coastguard Worker std::string error_msg;
3472*795d594fSAndroid Build Coastguard Worker ArtDexFileLoader dex_file_loader(dex_container, oat_dex_file.GetLocation());
3473*795d594fSAndroid Build Coastguard Worker // All dex files have been already verified in WriteDexFiles before we copied them.
3474*795d594fSAndroid Build Coastguard Worker dex_files.emplace_back(dex_file_loader.OpenOne(oat_dex_file.dex_file_offset_,
3475*795d594fSAndroid Build Coastguard Worker oat_dex_file.dex_file_location_checksum_,
3476*795d594fSAndroid Build Coastguard Worker /*oat_dex_file=*/nullptr,
3477*795d594fSAndroid Build Coastguard Worker /*verify=*/false,
3478*795d594fSAndroid Build Coastguard Worker /*verify_checksum=*/false,
3479*795d594fSAndroid Build Coastguard Worker &error_msg));
3480*795d594fSAndroid Build Coastguard Worker if (dex_files.back() == nullptr) {
3481*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed to open dex file from oat file. File: " << oat_dex_file.GetLocation()
3482*795d594fSAndroid Build Coastguard Worker << " Error: " << error_msg;
3483*795d594fSAndroid Build Coastguard Worker return false;
3484*795d594fSAndroid Build Coastguard Worker }
3485*795d594fSAndroid Build Coastguard Worker
3486*795d594fSAndroid Build Coastguard Worker // Set the class_offsets size now that we have easy access to the DexFile and
3487*795d594fSAndroid Build Coastguard Worker // it has been verified in dex_file_loader.Open.
3488*795d594fSAndroid Build Coastguard Worker oat_dex_file.class_offsets_.resize(dex_files.back()->GetHeader().class_defs_size_);
3489*795d594fSAndroid Build Coastguard Worker }
3490*795d594fSAndroid Build Coastguard Worker
3491*795d594fSAndroid Build Coastguard Worker *opened_dex_files = std::move(dex_files);
3492*795d594fSAndroid Build Coastguard Worker return true;
3493*795d594fSAndroid Build Coastguard Worker }
3494*795d594fSAndroid Build Coastguard Worker
InitializeTypeLookupTables(const std::vector<std::unique_ptr<const DexFile>> & opened_dex_files)3495*795d594fSAndroid Build Coastguard Worker void OatWriter::InitializeTypeLookupTables(
3496*795d594fSAndroid Build Coastguard Worker const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files) {
3497*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split("InitializeTypeLookupTables", timings_);
3498*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(opened_dex_files.size(), oat_dex_files_.size());
3499*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, size = opened_dex_files.size(); i != size; ++i) {
3500*795d594fSAndroid Build Coastguard Worker OatDexFile* oat_dex_file = &oat_dex_files_[i];
3501*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(oat_dex_file->lookup_table_offset_, 0u);
3502*795d594fSAndroid Build Coastguard Worker
3503*795d594fSAndroid Build Coastguard Worker size_t table_size = TypeLookupTable::RawDataLength(oat_dex_file->class_offsets_.size());
3504*795d594fSAndroid Build Coastguard Worker if (table_size == 0u) {
3505*795d594fSAndroid Build Coastguard Worker // We want a 1:1 mapping between `dex_files_` and `type_lookup_table_oat_dex_files_`,
3506*795d594fSAndroid Build Coastguard Worker // to simplify `WriteTypeLookupTables`. We push a null entry to notify
3507*795d594fSAndroid Build Coastguard Worker // that the dex file at index `i` does not have a type lookup table.
3508*795d594fSAndroid Build Coastguard Worker type_lookup_table_oat_dex_files_.push_back(nullptr);
3509*795d594fSAndroid Build Coastguard Worker continue;
3510*795d594fSAndroid Build Coastguard Worker }
3511*795d594fSAndroid Build Coastguard Worker
3512*795d594fSAndroid Build Coastguard Worker const DexFile& dex_file = *opened_dex_files[i].get();
3513*795d594fSAndroid Build Coastguard Worker TypeLookupTable type_lookup_table = TypeLookupTable::Create(dex_file);
3514*795d594fSAndroid Build Coastguard Worker type_lookup_table_oat_dex_files_.push_back(
3515*795d594fSAndroid Build Coastguard Worker std::make_unique<art::OatDexFile>(std::move(type_lookup_table)));
3516*795d594fSAndroid Build Coastguard Worker dex_file.SetOatDexFile(type_lookup_table_oat_dex_files_.back().get());
3517*795d594fSAndroid Build Coastguard Worker }
3518*795d594fSAndroid Build Coastguard Worker }
3519*795d594fSAndroid Build Coastguard Worker
WriteDexLayoutSections(OutputStream * oat_rodata,const std::vector<const DexFile * > & opened_dex_files)3520*795d594fSAndroid Build Coastguard Worker bool OatWriter::WriteDexLayoutSections(OutputStream* oat_rodata,
3521*795d594fSAndroid Build Coastguard Worker const std::vector<const DexFile*>& opened_dex_files) {
3522*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split(__FUNCTION__, timings_);
3523*795d594fSAndroid Build Coastguard Worker
3524*795d594fSAndroid Build Coastguard Worker if (!kWriteDexLayoutInfo) {
3525*795d594fSAndroid Build Coastguard Worker return true;
3526*795d594fSAndroid Build Coastguard Worker }
3527*795d594fSAndroid Build Coastguard Worker
3528*795d594fSAndroid Build Coastguard Worker uint32_t expected_offset = oat_data_offset_ + oat_size_;
3529*795d594fSAndroid Build Coastguard Worker off_t actual_offset = oat_rodata->Seek(expected_offset, kSeekSet);
3530*795d594fSAndroid Build Coastguard Worker if (static_cast<uint32_t>(actual_offset) != expected_offset) {
3531*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to seek to dex layout section offset section. Actual: " << actual_offset
3532*795d594fSAndroid Build Coastguard Worker << " Expected: " << expected_offset << " File: " << oat_rodata->GetLocation();
3533*795d594fSAndroid Build Coastguard Worker return false;
3534*795d594fSAndroid Build Coastguard Worker }
3535*795d594fSAndroid Build Coastguard Worker
3536*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(opened_dex_files.size(), oat_dex_files_.size());
3537*795d594fSAndroid Build Coastguard Worker size_t rodata_offset = oat_size_;
3538*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, size = opened_dex_files.size(); i != size; ++i) {
3539*795d594fSAndroid Build Coastguard Worker OatDexFile* oat_dex_file = &oat_dex_files_[i];
3540*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(oat_dex_file->dex_sections_layout_offset_, 0u);
3541*795d594fSAndroid Build Coastguard Worker
3542*795d594fSAndroid Build Coastguard Worker // Write dex layout section alignment bytes.
3543*795d594fSAndroid Build Coastguard Worker const size_t padding_size =
3544*795d594fSAndroid Build Coastguard Worker RoundUp(rodata_offset, alignof(DexLayoutSections)) - rodata_offset;
3545*795d594fSAndroid Build Coastguard Worker if (padding_size != 0u) {
3546*795d594fSAndroid Build Coastguard Worker std::vector<uint8_t> buffer(padding_size, 0u);
3547*795d594fSAndroid Build Coastguard Worker if (!oat_rodata->WriteFully(buffer.data(), padding_size)) {
3548*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write lookup table alignment padding."
3549*795d594fSAndroid Build Coastguard Worker << " File: " << oat_dex_file->GetLocation()
3550*795d594fSAndroid Build Coastguard Worker << " Output: " << oat_rodata->GetLocation();
3551*795d594fSAndroid Build Coastguard Worker return false;
3552*795d594fSAndroid Build Coastguard Worker }
3553*795d594fSAndroid Build Coastguard Worker size_oat_dex_file_dex_layout_sections_alignment_ += padding_size;
3554*795d594fSAndroid Build Coastguard Worker rodata_offset += padding_size;
3555*795d594fSAndroid Build Coastguard Worker }
3556*795d594fSAndroid Build Coastguard Worker
3557*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(rodata_offset, alignof(DexLayoutSections));
3558*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(oat_data_offset_ + rodata_offset,
3559*795d594fSAndroid Build Coastguard Worker static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent)));
3560*795d594fSAndroid Build Coastguard Worker DCHECK(oat_dex_file != nullptr);
3561*795d594fSAndroid Build Coastguard Worker if (!oat_rodata->WriteFully(&oat_dex_file->dex_sections_layout_,
3562*795d594fSAndroid Build Coastguard Worker sizeof(oat_dex_file->dex_sections_layout_))) {
3563*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write dex layout sections."
3564*795d594fSAndroid Build Coastguard Worker << " File: " << oat_dex_file->GetLocation()
3565*795d594fSAndroid Build Coastguard Worker << " Output: " << oat_rodata->GetLocation();
3566*795d594fSAndroid Build Coastguard Worker return false;
3567*795d594fSAndroid Build Coastguard Worker }
3568*795d594fSAndroid Build Coastguard Worker oat_dex_file->dex_sections_layout_offset_ = rodata_offset;
3569*795d594fSAndroid Build Coastguard Worker size_oat_dex_file_dex_layout_sections_ += sizeof(oat_dex_file->dex_sections_layout_);
3570*795d594fSAndroid Build Coastguard Worker rodata_offset += sizeof(oat_dex_file->dex_sections_layout_);
3571*795d594fSAndroid Build Coastguard Worker }
3572*795d594fSAndroid Build Coastguard Worker oat_size_ = rodata_offset;
3573*795d594fSAndroid Build Coastguard Worker
3574*795d594fSAndroid Build Coastguard Worker if (!oat_rodata->Flush()) {
3575*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to flush stream after writing type dex layout sections."
3576*795d594fSAndroid Build Coastguard Worker << " File: " << oat_rodata->GetLocation();
3577*795d594fSAndroid Build Coastguard Worker return false;
3578*795d594fSAndroid Build Coastguard Worker }
3579*795d594fSAndroid Build Coastguard Worker
3580*795d594fSAndroid Build Coastguard Worker return true;
3581*795d594fSAndroid Build Coastguard Worker }
3582*795d594fSAndroid Build Coastguard Worker
WriteTypeLookupTables(std::vector<uint8_t> * buffer)3583*795d594fSAndroid Build Coastguard Worker void OatWriter::WriteTypeLookupTables(/*out*/std::vector<uint8_t>* buffer) {
3584*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split("WriteTypeLookupTables", timings_);
3585*795d594fSAndroid Build Coastguard Worker size_t type_lookup_table_size = 0u;
3586*795d594fSAndroid Build Coastguard Worker for (const DexFile* dex_file : *dex_files_) {
3587*795d594fSAndroid Build Coastguard Worker type_lookup_table_size +=
3588*795d594fSAndroid Build Coastguard Worker sizeof(uint32_t) + TypeLookupTable::RawDataLength(dex_file->NumClassDefs());
3589*795d594fSAndroid Build Coastguard Worker }
3590*795d594fSAndroid Build Coastguard Worker // Reserve the space to avoid reallocations later on.
3591*795d594fSAndroid Build Coastguard Worker buffer->reserve(buffer->size() + type_lookup_table_size);
3592*795d594fSAndroid Build Coastguard Worker
3593*795d594fSAndroid Build Coastguard Worker // Align the start of the first type lookup table.
3594*795d594fSAndroid Build Coastguard Worker size_t initial_offset = vdex_size_;
3595*795d594fSAndroid Build Coastguard Worker size_t table_offset = RoundUp(initial_offset, 4);
3596*795d594fSAndroid Build Coastguard Worker size_t padding_size = table_offset - initial_offset;
3597*795d594fSAndroid Build Coastguard Worker
3598*795d594fSAndroid Build Coastguard Worker size_vdex_lookup_table_alignment_ += padding_size;
3599*795d594fSAndroid Build Coastguard Worker for (uint32_t j = 0; j < padding_size; ++j) {
3600*795d594fSAndroid Build Coastguard Worker buffer->push_back(0);
3601*795d594fSAndroid Build Coastguard Worker }
3602*795d594fSAndroid Build Coastguard Worker vdex_size_ += padding_size;
3603*795d594fSAndroid Build Coastguard Worker vdex_lookup_tables_offset_ = vdex_size_;
3604*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, size = type_lookup_table_oat_dex_files_.size(); i != size; ++i) {
3605*795d594fSAndroid Build Coastguard Worker OatDexFile* oat_dex_file = &oat_dex_files_[i];
3606*795d594fSAndroid Build Coastguard Worker if (type_lookup_table_oat_dex_files_[i] == nullptr) {
3607*795d594fSAndroid Build Coastguard Worker buffer->insert(buffer->end(), {0u, 0u, 0u, 0u});
3608*795d594fSAndroid Build Coastguard Worker size_vdex_lookup_table_ += sizeof(uint32_t);
3609*795d594fSAndroid Build Coastguard Worker vdex_size_ += sizeof(uint32_t);
3610*795d594fSAndroid Build Coastguard Worker oat_dex_file->lookup_table_offset_ = 0u;
3611*795d594fSAndroid Build Coastguard Worker } else {
3612*795d594fSAndroid Build Coastguard Worker oat_dex_file->lookup_table_offset_ = vdex_size_ + sizeof(uint32_t);
3613*795d594fSAndroid Build Coastguard Worker const TypeLookupTable& table = type_lookup_table_oat_dex_files_[i]->GetTypeLookupTable();
3614*795d594fSAndroid Build Coastguard Worker uint32_t table_size = table.RawDataLength();
3615*795d594fSAndroid Build Coastguard Worker DCHECK_NE(0u, table_size);
3616*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(table_size, 4);
3617*795d594fSAndroid Build Coastguard Worker size_t old_buffer_size = buffer->size();
3618*795d594fSAndroid Build Coastguard Worker buffer->resize(old_buffer_size + table.RawDataLength() + sizeof(uint32_t), 0u);
3619*795d594fSAndroid Build Coastguard Worker memcpy(buffer->data() + old_buffer_size, &table_size, sizeof(uint32_t));
3620*795d594fSAndroid Build Coastguard Worker memcpy(buffer->data() + old_buffer_size + sizeof(uint32_t), table.RawData(), table_size);
3621*795d594fSAndroid Build Coastguard Worker vdex_size_ += table_size + sizeof(uint32_t);
3622*795d594fSAndroid Build Coastguard Worker size_vdex_lookup_table_ += table_size + sizeof(uint32_t);
3623*795d594fSAndroid Build Coastguard Worker }
3624*795d594fSAndroid Build Coastguard Worker }
3625*795d594fSAndroid Build Coastguard Worker }
3626*795d594fSAndroid Build Coastguard Worker
FinishVdexFile(File * vdex_file,verifier::VerifierDeps * verifier_deps)3627*795d594fSAndroid Build Coastguard Worker bool OatWriter::FinishVdexFile(File* vdex_file, verifier::VerifierDeps* verifier_deps) {
3628*795d594fSAndroid Build Coastguard Worker size_t old_vdex_size = vdex_size_;
3629*795d594fSAndroid Build Coastguard Worker std::vector<uint8_t> buffer;
3630*795d594fSAndroid Build Coastguard Worker buffer.reserve(64 * KB);
3631*795d594fSAndroid Build Coastguard Worker WriteVerifierDeps(verifier_deps, &buffer);
3632*795d594fSAndroid Build Coastguard Worker WriteTypeLookupTables(&buffer);
3633*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(vdex_size_, old_vdex_size + buffer.size());
3634*795d594fSAndroid Build Coastguard Worker
3635*795d594fSAndroid Build Coastguard Worker // Resize the vdex file.
3636*795d594fSAndroid Build Coastguard Worker if (vdex_file->SetLength(vdex_size_) != 0) {
3637*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to resize vdex file " << vdex_file->GetPath();
3638*795d594fSAndroid Build Coastguard Worker return false;
3639*795d594fSAndroid Build Coastguard Worker }
3640*795d594fSAndroid Build Coastguard Worker
3641*795d594fSAndroid Build Coastguard Worker uint8_t* vdex_begin = vdex_begin_;
3642*795d594fSAndroid Build Coastguard Worker MemMap extra_map;
3643*795d594fSAndroid Build Coastguard Worker if (extract_dex_files_into_vdex_) {
3644*795d594fSAndroid Build Coastguard Worker DCHECK(vdex_begin != nullptr);
3645*795d594fSAndroid Build Coastguard Worker // Write data to the last already mmapped page of the vdex file.
3646*795d594fSAndroid Build Coastguard Worker // The size should match the page_aligned_size in the OatWriter::WriteDexFiles.
3647*795d594fSAndroid Build Coastguard Worker size_t mmapped_vdex_size = RoundUp(old_vdex_size, MemMap::GetPageSize());
3648*795d594fSAndroid Build Coastguard Worker size_t first_chunk_size = std::min(buffer.size(), mmapped_vdex_size - old_vdex_size);
3649*795d594fSAndroid Build Coastguard Worker memcpy(vdex_begin + old_vdex_size, buffer.data(), first_chunk_size);
3650*795d594fSAndroid Build Coastguard Worker
3651*795d594fSAndroid Build Coastguard Worker if (first_chunk_size != buffer.size()) {
3652*795d594fSAndroid Build Coastguard Worker size_t tail_size = buffer.size() - first_chunk_size;
3653*795d594fSAndroid Build Coastguard Worker std::string error_msg;
3654*795d594fSAndroid Build Coastguard Worker extra_map = MemMap::MapFile(
3655*795d594fSAndroid Build Coastguard Worker tail_size,
3656*795d594fSAndroid Build Coastguard Worker PROT_READ | PROT_WRITE,
3657*795d594fSAndroid Build Coastguard Worker MAP_SHARED,
3658*795d594fSAndroid Build Coastguard Worker vdex_file->Fd(),
3659*795d594fSAndroid Build Coastguard Worker /*start=*/ mmapped_vdex_size,
3660*795d594fSAndroid Build Coastguard Worker /*low_4gb=*/ false,
3661*795d594fSAndroid Build Coastguard Worker vdex_file->GetPath().c_str(),
3662*795d594fSAndroid Build Coastguard Worker &error_msg);
3663*795d594fSAndroid Build Coastguard Worker if (!extra_map.IsValid()) {
3664*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed to mmap() vdex file tail. File: " << vdex_file->GetPath()
3665*795d594fSAndroid Build Coastguard Worker << " error: " << error_msg;
3666*795d594fSAndroid Build Coastguard Worker return false;
3667*795d594fSAndroid Build Coastguard Worker }
3668*795d594fSAndroid Build Coastguard Worker memcpy(extra_map.Begin(), buffer.data() + first_chunk_size, tail_size);
3669*795d594fSAndroid Build Coastguard Worker }
3670*795d594fSAndroid Build Coastguard Worker } else {
3671*795d594fSAndroid Build Coastguard Worker DCHECK(vdex_begin == nullptr);
3672*795d594fSAndroid Build Coastguard Worker std::string error_msg;
3673*795d594fSAndroid Build Coastguard Worker extra_map = MemMap::MapFile(
3674*795d594fSAndroid Build Coastguard Worker vdex_size_,
3675*795d594fSAndroid Build Coastguard Worker PROT_READ | PROT_WRITE,
3676*795d594fSAndroid Build Coastguard Worker MAP_SHARED,
3677*795d594fSAndroid Build Coastguard Worker vdex_file->Fd(),
3678*795d594fSAndroid Build Coastguard Worker /*start=*/ 0u,
3679*795d594fSAndroid Build Coastguard Worker /*low_4gb=*/ false,
3680*795d594fSAndroid Build Coastguard Worker vdex_file->GetPath().c_str(),
3681*795d594fSAndroid Build Coastguard Worker &error_msg);
3682*795d594fSAndroid Build Coastguard Worker if (!extra_map.IsValid()) {
3683*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed to mmap() vdex file. File: " << vdex_file->GetPath()
3684*795d594fSAndroid Build Coastguard Worker << " error: " << error_msg;
3685*795d594fSAndroid Build Coastguard Worker return false;
3686*795d594fSAndroid Build Coastguard Worker }
3687*795d594fSAndroid Build Coastguard Worker vdex_begin = extra_map.Begin();
3688*795d594fSAndroid Build Coastguard Worker memcpy(vdex_begin + old_vdex_size, buffer.data(), buffer.size());
3689*795d594fSAndroid Build Coastguard Worker }
3690*795d594fSAndroid Build Coastguard Worker
3691*795d594fSAndroid Build Coastguard Worker // Write checksums
3692*795d594fSAndroid Build Coastguard Worker off_t checksums_offset = VdexFile::GetChecksumsOffset();
3693*795d594fSAndroid Build Coastguard Worker VdexFile::VdexChecksum* checksums_data =
3694*795d594fSAndroid Build Coastguard Worker reinterpret_cast<VdexFile::VdexChecksum*>(vdex_begin + checksums_offset);
3695*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
3696*795d594fSAndroid Build Coastguard Worker OatDexFile* oat_dex_file = &oat_dex_files_[i];
3697*795d594fSAndroid Build Coastguard Worker checksums_data[i] = oat_dex_file->dex_file_location_checksum_;
3698*795d594fSAndroid Build Coastguard Worker }
3699*795d594fSAndroid Build Coastguard Worker
3700*795d594fSAndroid Build Coastguard Worker // Write sections.
3701*795d594fSAndroid Build Coastguard Worker uint8_t* ptr = vdex_begin + sizeof(VdexFile::VdexFileHeader);
3702*795d594fSAndroid Build Coastguard Worker
3703*795d594fSAndroid Build Coastguard Worker // Checksums section.
3704*795d594fSAndroid Build Coastguard Worker new (ptr) VdexFile::VdexSectionHeader(VdexSection::kChecksumSection,
3705*795d594fSAndroid Build Coastguard Worker checksums_offset,
3706*795d594fSAndroid Build Coastguard Worker size_vdex_checksums_);
3707*795d594fSAndroid Build Coastguard Worker ptr += sizeof(VdexFile::VdexSectionHeader);
3708*795d594fSAndroid Build Coastguard Worker
3709*795d594fSAndroid Build Coastguard Worker // Dex section.
3710*795d594fSAndroid Build Coastguard Worker new (ptr) VdexFile::VdexSectionHeader(
3711*795d594fSAndroid Build Coastguard Worker VdexSection::kDexFileSection,
3712*795d594fSAndroid Build Coastguard Worker extract_dex_files_into_vdex_ ? vdex_dex_files_offset_ : 0u,
3713*795d594fSAndroid Build Coastguard Worker extract_dex_files_into_vdex_ ? vdex_verifier_deps_offset_ - vdex_dex_files_offset_ : 0u);
3714*795d594fSAndroid Build Coastguard Worker ptr += sizeof(VdexFile::VdexSectionHeader);
3715*795d594fSAndroid Build Coastguard Worker
3716*795d594fSAndroid Build Coastguard Worker // VerifierDeps section.
3717*795d594fSAndroid Build Coastguard Worker new (ptr) VdexFile::VdexSectionHeader(VdexSection::kVerifierDepsSection,
3718*795d594fSAndroid Build Coastguard Worker vdex_verifier_deps_offset_,
3719*795d594fSAndroid Build Coastguard Worker size_verifier_deps_);
3720*795d594fSAndroid Build Coastguard Worker ptr += sizeof(VdexFile::VdexSectionHeader);
3721*795d594fSAndroid Build Coastguard Worker
3722*795d594fSAndroid Build Coastguard Worker // TypeLookupTable section.
3723*795d594fSAndroid Build Coastguard Worker new (ptr) VdexFile::VdexSectionHeader(VdexSection::kTypeLookupTableSection,
3724*795d594fSAndroid Build Coastguard Worker vdex_lookup_tables_offset_,
3725*795d594fSAndroid Build Coastguard Worker vdex_size_ - vdex_lookup_tables_offset_);
3726*795d594fSAndroid Build Coastguard Worker
3727*795d594fSAndroid Build Coastguard Worker // All the contents (except the header) of the vdex file has been emitted in memory. Flush it
3728*795d594fSAndroid Build Coastguard Worker // to disk.
3729*795d594fSAndroid Build Coastguard Worker {
3730*795d594fSAndroid Build Coastguard Worker TimingLogger::ScopedTiming split("VDEX flush contents", timings_);
3731*795d594fSAndroid Build Coastguard Worker // Sync the data to the disk while the header is invalid. We do not want to end up with
3732*795d594fSAndroid Build Coastguard Worker // a valid header and invalid data if the process is suddenly killed.
3733*795d594fSAndroid Build Coastguard Worker if (extract_dex_files_into_vdex_) {
3734*795d594fSAndroid Build Coastguard Worker // Note: We passed the ownership of the vdex dex file MemMap to the caller,
3735*795d594fSAndroid Build Coastguard Worker // so we need to use msync() for the range explicitly.
3736*795d594fSAndroid Build Coastguard Worker //
3737*795d594fSAndroid Build Coastguard Worker // The page size here is not replaced with kElfSegmentAlignment as the
3738*795d594fSAndroid Build Coastguard Worker // rounded up size should match the page_aligned_size in OatWriter::WriteDexFiles
3739*795d594fSAndroid Build Coastguard Worker // which is the size the original (non-extra) mapping created there.
3740*795d594fSAndroid Build Coastguard Worker if (msync(vdex_begin, RoundUp(old_vdex_size, MemMap::GetPageSize()), MS_SYNC) != 0) {
3741*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to sync vdex file contents" << vdex_file->GetPath();
3742*795d594fSAndroid Build Coastguard Worker return false;
3743*795d594fSAndroid Build Coastguard Worker }
3744*795d594fSAndroid Build Coastguard Worker }
3745*795d594fSAndroid Build Coastguard Worker if (extra_map.IsValid() && !extra_map.Sync()) {
3746*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to sync vdex file contents" << vdex_file->GetPath();
3747*795d594fSAndroid Build Coastguard Worker return false;
3748*795d594fSAndroid Build Coastguard Worker }
3749*795d594fSAndroid Build Coastguard Worker }
3750*795d594fSAndroid Build Coastguard Worker
3751*795d594fSAndroid Build Coastguard Worker // Now that we know all contents have been flushed to disk, we can write
3752*795d594fSAndroid Build Coastguard Worker // the header which will mke the vdex usable.
3753*795d594fSAndroid Build Coastguard Worker bool has_dex_section = extract_dex_files_into_vdex_;
3754*795d594fSAndroid Build Coastguard Worker new (vdex_begin) VdexFile::VdexFileHeader(has_dex_section);
3755*795d594fSAndroid Build Coastguard Worker
3756*795d594fSAndroid Build Coastguard Worker // Note: If `extract_dex_files_into_vdex_`, we passed the ownership of the vdex dex file
3757*795d594fSAndroid Build Coastguard Worker // MemMap to the caller, so we need to use msync() for the range explicitly.
3758*795d594fSAndroid Build Coastguard Worker //
3759*795d594fSAndroid Build Coastguard Worker // The page size here should not be replaced with kElfSegmentAlignment as the size
3760*795d594fSAndroid Build Coastguard Worker // here should match the header size rounded up to the page size. Any higher value
3761*795d594fSAndroid Build Coastguard Worker // might happen to be larger than the size of the mapping which can in some circumstances
3762*795d594fSAndroid Build Coastguard Worker // cause msync to fail.
3763*795d594fSAndroid Build Coastguard Worker if (msync(vdex_begin, MemMap::GetPageSize(), MS_SYNC) != 0) {
3764*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to sync vdex file header " << vdex_file->GetPath();
3765*795d594fSAndroid Build Coastguard Worker return false;
3766*795d594fSAndroid Build Coastguard Worker }
3767*795d594fSAndroid Build Coastguard Worker
3768*795d594fSAndroid Build Coastguard Worker return true;
3769*795d594fSAndroid Build Coastguard Worker }
3770*795d594fSAndroid Build Coastguard Worker
WriteCodeAlignment(OutputStream * out,uint32_t aligned_code_delta)3771*795d594fSAndroid Build Coastguard Worker bool OatWriter::WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta) {
3772*795d594fSAndroid Build Coastguard Worker return WriteUpTo16BytesAlignment(out, aligned_code_delta, &size_code_alignment_);
3773*795d594fSAndroid Build Coastguard Worker }
3774*795d594fSAndroid Build Coastguard Worker
WriteUpTo16BytesAlignment(OutputStream * out,uint32_t size,uint32_t * stat)3775*795d594fSAndroid Build Coastguard Worker bool OatWriter::WriteUpTo16BytesAlignment(OutputStream* out, uint32_t size, uint32_t* stat) {
3776*795d594fSAndroid Build Coastguard Worker static const uint8_t kPadding[] = {
3777*795d594fSAndroid Build Coastguard Worker 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u
3778*795d594fSAndroid Build Coastguard Worker };
3779*795d594fSAndroid Build Coastguard Worker DCHECK_LE(size, sizeof(kPadding));
3780*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(!out->WriteFully(kPadding, size))) {
3781*795d594fSAndroid Build Coastguard Worker return false;
3782*795d594fSAndroid Build Coastguard Worker }
3783*795d594fSAndroid Build Coastguard Worker *stat += size;
3784*795d594fSAndroid Build Coastguard Worker return true;
3785*795d594fSAndroid Build Coastguard Worker }
3786*795d594fSAndroid Build Coastguard Worker
SetMultiOatRelativePatcherAdjustment()3787*795d594fSAndroid Build Coastguard Worker void OatWriter::SetMultiOatRelativePatcherAdjustment() {
3788*795d594fSAndroid Build Coastguard Worker DCHECK(dex_files_ != nullptr);
3789*795d594fSAndroid Build Coastguard Worker DCHECK(relative_patcher_ != nullptr);
3790*795d594fSAndroid Build Coastguard Worker DCHECK_NE(oat_data_offset_, 0u);
3791*795d594fSAndroid Build Coastguard Worker if (image_writer_ != nullptr && !dex_files_->empty()) {
3792*795d594fSAndroid Build Coastguard Worker // The oat data begin may not be initialized yet but the oat file offset is ready.
3793*795d594fSAndroid Build Coastguard Worker size_t oat_index = image_writer_->GetOatIndexForDexFile(dex_files_->front());
3794*795d594fSAndroid Build Coastguard Worker size_t elf_file_offset = image_writer_->GetOatFileOffset(oat_index);
3795*795d594fSAndroid Build Coastguard Worker relative_patcher_->StartOatFile(elf_file_offset + oat_data_offset_);
3796*795d594fSAndroid Build Coastguard Worker }
3797*795d594fSAndroid Build Coastguard Worker }
3798*795d594fSAndroid Build Coastguard Worker
OatDexFile(std::unique_ptr<const DexFile> dex_file)3799*795d594fSAndroid Build Coastguard Worker OatWriter::OatDexFile::OatDexFile(std::unique_ptr<const DexFile> dex_file)
3800*795d594fSAndroid Build Coastguard Worker : dex_file_(std::move(dex_file)),
3801*795d594fSAndroid Build Coastguard Worker dex_file_location_(std::make_unique<std::string>(dex_file_->GetLocation())),
3802*795d594fSAndroid Build Coastguard Worker dex_file_size_(dex_file_->Size()),
3803*795d594fSAndroid Build Coastguard Worker offset_(0),
3804*795d594fSAndroid Build Coastguard Worker dex_file_location_size_(strlen(dex_file_location_->c_str())),
3805*795d594fSAndroid Build Coastguard Worker dex_file_location_data_(dex_file_location_->c_str()),
3806*795d594fSAndroid Build Coastguard Worker dex_file_magic_(dex_file_->GetHeader().magic_),
3807*795d594fSAndroid Build Coastguard Worker dex_file_location_checksum_(dex_file_->GetLocationChecksum()),
3808*795d594fSAndroid Build Coastguard Worker dex_file_sha1_(dex_file_->GetSha1()),
3809*795d594fSAndroid Build Coastguard Worker dex_file_offset_(0u),
3810*795d594fSAndroid Build Coastguard Worker lookup_table_offset_(0u),
3811*795d594fSAndroid Build Coastguard Worker class_offsets_offset_(0u),
3812*795d594fSAndroid Build Coastguard Worker method_bss_mapping_offset_(0u),
3813*795d594fSAndroid Build Coastguard Worker type_bss_mapping_offset_(0u),
3814*795d594fSAndroid Build Coastguard Worker public_type_bss_mapping_offset_(0u),
3815*795d594fSAndroid Build Coastguard Worker package_type_bss_mapping_offset_(0u),
3816*795d594fSAndroid Build Coastguard Worker string_bss_mapping_offset_(0u),
3817*795d594fSAndroid Build Coastguard Worker method_type_bss_mapping_offset_(0u),
3818*795d594fSAndroid Build Coastguard Worker dex_sections_layout_offset_(0u),
3819*795d594fSAndroid Build Coastguard Worker class_offsets_() {}
3820*795d594fSAndroid Build Coastguard Worker
SizeOf() const3821*795d594fSAndroid Build Coastguard Worker size_t OatWriter::OatDexFile::SizeOf() const {
3822*795d594fSAndroid Build Coastguard Worker return sizeof(dex_file_location_size_) + dex_file_location_size_ + sizeof(dex_file_magic_) +
3823*795d594fSAndroid Build Coastguard Worker sizeof(dex_file_location_checksum_) + sizeof(dex_file_sha1_) + sizeof(dex_file_offset_) +
3824*795d594fSAndroid Build Coastguard Worker sizeof(class_offsets_offset_) + sizeof(lookup_table_offset_) +
3825*795d594fSAndroid Build Coastguard Worker sizeof(method_bss_mapping_offset_) + sizeof(type_bss_mapping_offset_) +
3826*795d594fSAndroid Build Coastguard Worker sizeof(public_type_bss_mapping_offset_) + sizeof(package_type_bss_mapping_offset_) +
3827*795d594fSAndroid Build Coastguard Worker sizeof(string_bss_mapping_offset_) + sizeof(method_type_bss_mapping_offset_) +
3828*795d594fSAndroid Build Coastguard Worker sizeof(dex_sections_layout_offset_);
3829*795d594fSAndroid Build Coastguard Worker }
3830*795d594fSAndroid Build Coastguard Worker
Write(OatWriter * oat_writer,OutputStream * out) const3831*795d594fSAndroid Build Coastguard Worker bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream* out) const {
3832*795d594fSAndroid Build Coastguard Worker const size_t file_offset = oat_writer->oat_data_offset_;
3833*795d594fSAndroid Build Coastguard Worker DCHECK_OFFSET_();
3834*795d594fSAndroid Build Coastguard Worker
3835*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
3836*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write dex file location length to " << out->GetLocation();
3837*795d594fSAndroid Build Coastguard Worker return false;
3838*795d594fSAndroid Build Coastguard Worker }
3839*795d594fSAndroid Build Coastguard Worker oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
3840*795d594fSAndroid Build Coastguard Worker
3841*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
3842*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write dex file location data to " << out->GetLocation();
3843*795d594fSAndroid Build Coastguard Worker return false;
3844*795d594fSAndroid Build Coastguard Worker }
3845*795d594fSAndroid Build Coastguard Worker oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
3846*795d594fSAndroid Build Coastguard Worker
3847*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&dex_file_magic_, sizeof(dex_file_magic_))) {
3848*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write dex file magic to " << out->GetLocation();
3849*795d594fSAndroid Build Coastguard Worker return false;
3850*795d594fSAndroid Build Coastguard Worker }
3851*795d594fSAndroid Build Coastguard Worker oat_writer->size_oat_dex_file_magic_ += sizeof(dex_file_magic_);
3852*795d594fSAndroid Build Coastguard Worker
3853*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
3854*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write dex file location checksum to " << out->GetLocation();
3855*795d594fSAndroid Build Coastguard Worker return false;
3856*795d594fSAndroid Build Coastguard Worker }
3857*795d594fSAndroid Build Coastguard Worker oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
3858*795d594fSAndroid Build Coastguard Worker
3859*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&dex_file_sha1_, sizeof(dex_file_sha1_))) {
3860*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write dex file sha1 to " << out->GetLocation();
3861*795d594fSAndroid Build Coastguard Worker return false;
3862*795d594fSAndroid Build Coastguard Worker }
3863*795d594fSAndroid Build Coastguard Worker oat_writer->size_oat_dex_file_sha1_ += sizeof(dex_file_sha1_);
3864*795d594fSAndroid Build Coastguard Worker
3865*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
3866*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write dex file offset to " << out->GetLocation();
3867*795d594fSAndroid Build Coastguard Worker return false;
3868*795d594fSAndroid Build Coastguard Worker }
3869*795d594fSAndroid Build Coastguard Worker oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
3870*795d594fSAndroid Build Coastguard Worker
3871*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&class_offsets_offset_, sizeof(class_offsets_offset_))) {
3872*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write class offsets offset to " << out->GetLocation();
3873*795d594fSAndroid Build Coastguard Worker return false;
3874*795d594fSAndroid Build Coastguard Worker }
3875*795d594fSAndroid Build Coastguard Worker oat_writer->size_oat_dex_file_class_offsets_offset_ += sizeof(class_offsets_offset_);
3876*795d594fSAndroid Build Coastguard Worker
3877*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&lookup_table_offset_, sizeof(lookup_table_offset_))) {
3878*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write lookup table offset to " << out->GetLocation();
3879*795d594fSAndroid Build Coastguard Worker return false;
3880*795d594fSAndroid Build Coastguard Worker }
3881*795d594fSAndroid Build Coastguard Worker oat_writer->size_oat_dex_file_lookup_table_offset_ += sizeof(lookup_table_offset_);
3882*795d594fSAndroid Build Coastguard Worker
3883*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&dex_sections_layout_offset_, sizeof(dex_sections_layout_offset_))) {
3884*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write dex section layout info to " << out->GetLocation();
3885*795d594fSAndroid Build Coastguard Worker return false;
3886*795d594fSAndroid Build Coastguard Worker }
3887*795d594fSAndroid Build Coastguard Worker oat_writer->size_oat_dex_file_dex_layout_sections_offset_ += sizeof(dex_sections_layout_offset_);
3888*795d594fSAndroid Build Coastguard Worker
3889*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&method_bss_mapping_offset_, sizeof(method_bss_mapping_offset_))) {
3890*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write method bss mapping offset to " << out->GetLocation();
3891*795d594fSAndroid Build Coastguard Worker return false;
3892*795d594fSAndroid Build Coastguard Worker }
3893*795d594fSAndroid Build Coastguard Worker oat_writer->size_oat_dex_file_method_bss_mapping_offset_ += sizeof(method_bss_mapping_offset_);
3894*795d594fSAndroid Build Coastguard Worker
3895*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&type_bss_mapping_offset_, sizeof(type_bss_mapping_offset_))) {
3896*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write type bss mapping offset to " << out->GetLocation();
3897*795d594fSAndroid Build Coastguard Worker return false;
3898*795d594fSAndroid Build Coastguard Worker }
3899*795d594fSAndroid Build Coastguard Worker oat_writer->size_oat_dex_file_type_bss_mapping_offset_ += sizeof(type_bss_mapping_offset_);
3900*795d594fSAndroid Build Coastguard Worker
3901*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&public_type_bss_mapping_offset_, sizeof(public_type_bss_mapping_offset_))) {
3902*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write public type bss mapping offset to " << out->GetLocation();
3903*795d594fSAndroid Build Coastguard Worker return false;
3904*795d594fSAndroid Build Coastguard Worker }
3905*795d594fSAndroid Build Coastguard Worker oat_writer->size_oat_dex_file_public_type_bss_mapping_offset_ +=
3906*795d594fSAndroid Build Coastguard Worker sizeof(public_type_bss_mapping_offset_);
3907*795d594fSAndroid Build Coastguard Worker
3908*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&package_type_bss_mapping_offset_,
3909*795d594fSAndroid Build Coastguard Worker sizeof(package_type_bss_mapping_offset_))) {
3910*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write package type bss mapping offset to " << out->GetLocation();
3911*795d594fSAndroid Build Coastguard Worker return false;
3912*795d594fSAndroid Build Coastguard Worker }
3913*795d594fSAndroid Build Coastguard Worker oat_writer->size_oat_dex_file_package_type_bss_mapping_offset_ +=
3914*795d594fSAndroid Build Coastguard Worker sizeof(package_type_bss_mapping_offset_);
3915*795d594fSAndroid Build Coastguard Worker
3916*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&string_bss_mapping_offset_, sizeof(string_bss_mapping_offset_))) {
3917*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write string bss mapping offset to " << out->GetLocation();
3918*795d594fSAndroid Build Coastguard Worker return false;
3919*795d594fSAndroid Build Coastguard Worker }
3920*795d594fSAndroid Build Coastguard Worker oat_writer->size_oat_dex_file_string_bss_mapping_offset_ += sizeof(string_bss_mapping_offset_);
3921*795d594fSAndroid Build Coastguard Worker
3922*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&method_type_bss_mapping_offset_, sizeof(method_type_bss_mapping_offset_))) {
3923*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write MethodType bss mapping offset to " << out->GetLocation();
3924*795d594fSAndroid Build Coastguard Worker return false;
3925*795d594fSAndroid Build Coastguard Worker }
3926*795d594fSAndroid Build Coastguard Worker oat_writer->size_oat_dex_file_method_type_bss_mapping_offset_ +=
3927*795d594fSAndroid Build Coastguard Worker sizeof(method_type_bss_mapping_offset_);
3928*795d594fSAndroid Build Coastguard Worker
3929*795d594fSAndroid Build Coastguard Worker return true;
3930*795d594fSAndroid Build Coastguard Worker }
3931*795d594fSAndroid Build Coastguard Worker
Write(OatWriter * oat_writer,OutputStream * out) const3932*795d594fSAndroid Build Coastguard Worker bool OatWriter::BssMappingInfo::Write(OatWriter* oat_writer, OutputStream* out) const {
3933*795d594fSAndroid Build Coastguard Worker const size_t file_offset = oat_writer->oat_data_offset_;
3934*795d594fSAndroid Build Coastguard Worker DCHECK_OFFSET_();
3935*795d594fSAndroid Build Coastguard Worker
3936*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&method_bss_mapping_offset, sizeof(method_bss_mapping_offset))) {
3937*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write method bss mapping offset to " << out->GetLocation();
3938*795d594fSAndroid Build Coastguard Worker return false;
3939*795d594fSAndroid Build Coastguard Worker }
3940*795d594fSAndroid Build Coastguard Worker oat_writer->size_bcp_bss_info_method_bss_mapping_offset_ += sizeof(method_bss_mapping_offset);
3941*795d594fSAndroid Build Coastguard Worker
3942*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&type_bss_mapping_offset, sizeof(type_bss_mapping_offset))) {
3943*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write type bss mapping offset to " << out->GetLocation();
3944*795d594fSAndroid Build Coastguard Worker return false;
3945*795d594fSAndroid Build Coastguard Worker }
3946*795d594fSAndroid Build Coastguard Worker oat_writer->size_bcp_bss_info_type_bss_mapping_offset_ += sizeof(type_bss_mapping_offset);
3947*795d594fSAndroid Build Coastguard Worker
3948*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&public_type_bss_mapping_offset, sizeof(public_type_bss_mapping_offset))) {
3949*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write public type bss mapping offset to " << out->GetLocation();
3950*795d594fSAndroid Build Coastguard Worker return false;
3951*795d594fSAndroid Build Coastguard Worker }
3952*795d594fSAndroid Build Coastguard Worker oat_writer->size_bcp_bss_info_public_type_bss_mapping_offset_ +=
3953*795d594fSAndroid Build Coastguard Worker sizeof(public_type_bss_mapping_offset);
3954*795d594fSAndroid Build Coastguard Worker
3955*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&package_type_bss_mapping_offset, sizeof(package_type_bss_mapping_offset))) {
3956*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write package type bss mapping offset to " << out->GetLocation();
3957*795d594fSAndroid Build Coastguard Worker return false;
3958*795d594fSAndroid Build Coastguard Worker }
3959*795d594fSAndroid Build Coastguard Worker oat_writer->size_bcp_bss_info_package_type_bss_mapping_offset_ +=
3960*795d594fSAndroid Build Coastguard Worker sizeof(package_type_bss_mapping_offset);
3961*795d594fSAndroid Build Coastguard Worker
3962*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&string_bss_mapping_offset, sizeof(string_bss_mapping_offset))) {
3963*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write string bss mapping offset to " << out->GetLocation();
3964*795d594fSAndroid Build Coastguard Worker return false;
3965*795d594fSAndroid Build Coastguard Worker }
3966*795d594fSAndroid Build Coastguard Worker oat_writer->size_bcp_bss_info_string_bss_mapping_offset_ += sizeof(string_bss_mapping_offset);
3967*795d594fSAndroid Build Coastguard Worker
3968*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&method_type_bss_mapping_offset, sizeof(method_type_bss_mapping_offset))) {
3969*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write method type bss mapping offset to " << out->GetLocation();
3970*795d594fSAndroid Build Coastguard Worker return false;
3971*795d594fSAndroid Build Coastguard Worker }
3972*795d594fSAndroid Build Coastguard Worker oat_writer->size_bcp_bss_info_method_type_bss_mapping_offset_ +=
3973*795d594fSAndroid Build Coastguard Worker sizeof(method_type_bss_mapping_offset);
3974*795d594fSAndroid Build Coastguard Worker
3975*795d594fSAndroid Build Coastguard Worker return true;
3976*795d594fSAndroid Build Coastguard Worker }
3977*795d594fSAndroid Build Coastguard Worker
WriteClassOffsets(OatWriter * oat_writer,OutputStream * out)3978*795d594fSAndroid Build Coastguard Worker bool OatWriter::OatDexFile::WriteClassOffsets(OatWriter* oat_writer, OutputStream* out) {
3979*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(class_offsets_.data(), GetClassOffsetsRawSize())) {
3980*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write oat class offsets for " << GetLocation()
3981*795d594fSAndroid Build Coastguard Worker << " to " << out->GetLocation();
3982*795d594fSAndroid Build Coastguard Worker return false;
3983*795d594fSAndroid Build Coastguard Worker }
3984*795d594fSAndroid Build Coastguard Worker oat_writer->size_oat_class_offsets_ += GetClassOffsetsRawSize();
3985*795d594fSAndroid Build Coastguard Worker return true;
3986*795d594fSAndroid Build Coastguard Worker }
3987*795d594fSAndroid Build Coastguard Worker
OatClass(const dchecked_vector<CompiledMethod * > & compiled_methods,uint32_t compiled_methods_with_code,uint16_t oat_class_type)3988*795d594fSAndroid Build Coastguard Worker OatWriter::OatClass::OatClass(const dchecked_vector<CompiledMethod*>& compiled_methods,
3989*795d594fSAndroid Build Coastguard Worker uint32_t compiled_methods_with_code,
3990*795d594fSAndroid Build Coastguard Worker uint16_t oat_class_type)
3991*795d594fSAndroid Build Coastguard Worker : compiled_methods_(compiled_methods) {
3992*795d594fSAndroid Build Coastguard Worker const uint32_t num_methods = compiled_methods.size();
3993*795d594fSAndroid Build Coastguard Worker CHECK_LE(compiled_methods_with_code, num_methods);
3994*795d594fSAndroid Build Coastguard Worker
3995*795d594fSAndroid Build Coastguard Worker oat_method_offsets_offsets_from_oat_class_.resize(num_methods);
3996*795d594fSAndroid Build Coastguard Worker
3997*795d594fSAndroid Build Coastguard Worker method_offsets_.resize(compiled_methods_with_code);
3998*795d594fSAndroid Build Coastguard Worker method_headers_.resize(compiled_methods_with_code);
3999*795d594fSAndroid Build Coastguard Worker
4000*795d594fSAndroid Build Coastguard Worker uint32_t oat_method_offsets_offset_from_oat_class = OatClassHeader::SizeOf();
4001*795d594fSAndroid Build Coastguard Worker // We only write method-related data if there are at least some compiled methods.
4002*795d594fSAndroid Build Coastguard Worker num_methods_ = 0u;
4003*795d594fSAndroid Build Coastguard Worker DCHECK(method_bitmap_ == nullptr);
4004*795d594fSAndroid Build Coastguard Worker if (oat_class_type != enum_cast<uint16_t>(OatClassType::kNoneCompiled)) {
4005*795d594fSAndroid Build Coastguard Worker num_methods_ = num_methods;
4006*795d594fSAndroid Build Coastguard Worker oat_method_offsets_offset_from_oat_class += sizeof(num_methods_);
4007*795d594fSAndroid Build Coastguard Worker if (oat_class_type == enum_cast<uint16_t>(OatClassType::kSomeCompiled)) {
4008*795d594fSAndroid Build Coastguard Worker method_bitmap_.reset(new BitVector(num_methods, false, Allocator::GetCallocAllocator()));
4009*795d594fSAndroid Build Coastguard Worker uint32_t bitmap_size = BitVector::BitsToWords(num_methods) * BitVector::kWordBytes;
4010*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(bitmap_size, method_bitmap_->GetSizeOf());
4011*795d594fSAndroid Build Coastguard Worker oat_method_offsets_offset_from_oat_class += bitmap_size;
4012*795d594fSAndroid Build Coastguard Worker }
4013*795d594fSAndroid Build Coastguard Worker }
4014*795d594fSAndroid Build Coastguard Worker
4015*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < num_methods; i++) {
4016*795d594fSAndroid Build Coastguard Worker CompiledMethod* compiled_method = compiled_methods_[i];
4017*795d594fSAndroid Build Coastguard Worker if (HasCompiledCode(compiled_method)) {
4018*795d594fSAndroid Build Coastguard Worker oat_method_offsets_offsets_from_oat_class_[i] = oat_method_offsets_offset_from_oat_class;
4019*795d594fSAndroid Build Coastguard Worker oat_method_offsets_offset_from_oat_class += sizeof(OatMethodOffsets);
4020*795d594fSAndroid Build Coastguard Worker if (oat_class_type == enum_cast<uint16_t>(OatClassType::kSomeCompiled)) {
4021*795d594fSAndroid Build Coastguard Worker method_bitmap_->SetBit(i);
4022*795d594fSAndroid Build Coastguard Worker }
4023*795d594fSAndroid Build Coastguard Worker } else {
4024*795d594fSAndroid Build Coastguard Worker oat_method_offsets_offsets_from_oat_class_[i] = 0;
4025*795d594fSAndroid Build Coastguard Worker }
4026*795d594fSAndroid Build Coastguard Worker }
4027*795d594fSAndroid Build Coastguard Worker }
4028*795d594fSAndroid Build Coastguard Worker
SizeOf() const4029*795d594fSAndroid Build Coastguard Worker size_t OatWriter::OatClass::SizeOf() const {
4030*795d594fSAndroid Build Coastguard Worker return ((num_methods_ == 0) ? 0 : sizeof(num_methods_)) +
4031*795d594fSAndroid Build Coastguard Worker ((method_bitmap_ != nullptr) ? method_bitmap_->GetSizeOf() : 0u) +
4032*795d594fSAndroid Build Coastguard Worker (sizeof(method_offsets_[0]) * method_offsets_.size());
4033*795d594fSAndroid Build Coastguard Worker }
4034*795d594fSAndroid Build Coastguard Worker
Write(OatWriter * oat_writer,OutputStream * out,const size_t file_offset) const4035*795d594fSAndroid Build Coastguard Worker bool OatWriter::OatClassHeader::Write(OatWriter* oat_writer,
4036*795d594fSAndroid Build Coastguard Worker OutputStream* out,
4037*795d594fSAndroid Build Coastguard Worker const size_t file_offset) const {
4038*795d594fSAndroid Build Coastguard Worker DCHECK_OFFSET_();
4039*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&status_, sizeof(status_))) {
4040*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write class status to " << out->GetLocation();
4041*795d594fSAndroid Build Coastguard Worker return false;
4042*795d594fSAndroid Build Coastguard Worker }
4043*795d594fSAndroid Build Coastguard Worker oat_writer->size_oat_class_status_ += sizeof(status_);
4044*795d594fSAndroid Build Coastguard Worker
4045*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&type_, sizeof(type_))) {
4046*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write oat class type to " << out->GetLocation();
4047*795d594fSAndroid Build Coastguard Worker return false;
4048*795d594fSAndroid Build Coastguard Worker }
4049*795d594fSAndroid Build Coastguard Worker oat_writer->size_oat_class_type_ += sizeof(type_);
4050*795d594fSAndroid Build Coastguard Worker return true;
4051*795d594fSAndroid Build Coastguard Worker }
4052*795d594fSAndroid Build Coastguard Worker
Write(OatWriter * oat_writer,OutputStream * out) const4053*795d594fSAndroid Build Coastguard Worker bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream* out) const {
4054*795d594fSAndroid Build Coastguard Worker if (num_methods_ != 0u) {
4055*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(&num_methods_, sizeof(num_methods_))) {
4056*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write number of methods to " << out->GetLocation();
4057*795d594fSAndroid Build Coastguard Worker return false;
4058*795d594fSAndroid Build Coastguard Worker }
4059*795d594fSAndroid Build Coastguard Worker oat_writer->size_oat_class_num_methods_ += sizeof(num_methods_);
4060*795d594fSAndroid Build Coastguard Worker }
4061*795d594fSAndroid Build Coastguard Worker
4062*795d594fSAndroid Build Coastguard Worker if (method_bitmap_ != nullptr) {
4063*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_->GetSizeOf())) {
4064*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write method bitmap to " << out->GetLocation();
4065*795d594fSAndroid Build Coastguard Worker return false;
4066*795d594fSAndroid Build Coastguard Worker }
4067*795d594fSAndroid Build Coastguard Worker oat_writer->size_oat_class_method_bitmaps_ += method_bitmap_->GetSizeOf();
4068*795d594fSAndroid Build Coastguard Worker }
4069*795d594fSAndroid Build Coastguard Worker
4070*795d594fSAndroid Build Coastguard Worker if (!out->WriteFully(method_offsets_.data(), GetMethodOffsetsRawSize())) {
4071*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write method offsets to " << out->GetLocation();
4072*795d594fSAndroid Build Coastguard Worker return false;
4073*795d594fSAndroid Build Coastguard Worker }
4074*795d594fSAndroid Build Coastguard Worker oat_writer->size_oat_class_method_offsets_ += GetMethodOffsetsRawSize();
4075*795d594fSAndroid Build Coastguard Worker return true;
4076*795d594fSAndroid Build Coastguard Worker }
4077*795d594fSAndroid Build Coastguard Worker
GetDebugInfo() const4078*795d594fSAndroid Build Coastguard Worker debug::DebugInfo OatWriter::GetDebugInfo() const {
4079*795d594fSAndroid Build Coastguard Worker debug::DebugInfo debug_info{};
4080*795d594fSAndroid Build Coastguard Worker debug_info.compiled_methods = ArrayRef<const debug::MethodDebugInfo>(method_info_);
4081*795d594fSAndroid Build Coastguard Worker if (VdexWillContainDexFiles()) {
4082*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(dex_files_->size(), oat_dex_files_.size());
4083*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
4084*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file = (*dex_files_)[i];
4085*795d594fSAndroid Build Coastguard Worker const OatDexFile& oat_dex_file = oat_dex_files_[i];
4086*795d594fSAndroid Build Coastguard Worker uint32_t dex_file_offset = oat_dex_file.dex_file_offset_;
4087*795d594fSAndroid Build Coastguard Worker if (dex_file_offset != 0) {
4088*795d594fSAndroid Build Coastguard Worker debug_info.dex_files.emplace(dex_file_offset, dex_file);
4089*795d594fSAndroid Build Coastguard Worker }
4090*795d594fSAndroid Build Coastguard Worker }
4091*795d594fSAndroid Build Coastguard Worker }
4092*795d594fSAndroid Build Coastguard Worker return debug_info;
4093*795d594fSAndroid Build Coastguard Worker }
4094*795d594fSAndroid Build Coastguard Worker
4095*795d594fSAndroid Build Coastguard Worker } // namespace linker
4096*795d594fSAndroid Build Coastguard Worker } // namespace art
4097