blob: 622010bd8bbcbf4dcf6ca20dae89829bf9b52b7e [file] [log] [blame]
Elliott Hughes2faa5f12012-01-30 14:42:07 -08001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Brian Carlstrome24fa612011-09-29 00:53:55 -070016
17#include "oat_writer.h"
18
Elliott Hughesa0e18062012-04-13 15:59:59 -070019#include <zlib.h>
20
Elliott Hughes1aa246d2012-12-13 09:29:36 -080021#include "base/stl_util.h"
Elliott Hughes76160052012-12-12 16:31:20 -080022#include "base/unix_file/fd_file.h"
Brian Carlstrome24fa612011-09-29 00:53:55 -070023#include "class_linker.h"
Ian Rogers4f6ad8a2013-03-18 15:27:28 -070024#include "dex_file-inl.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080025#include "mirror/abstract_method-inl.h"
26#include "mirror/array.h"
27#include "mirror/class_loader.h"
Ian Rogers4f6ad8a2013-03-18 15:27:28 -070028#include "mirror/object-inl.h"
Brian Carlstrome24fa612011-09-29 00:53:55 -070029#include "os.h"
Brian Carlstromcd60ac72013-01-20 17:09:51 -080030#include "output_stream.h"
Elliott Hughesa0e18062012-04-13 15:59:59 -070031#include "safe_map.h"
Ian Rogers00f7d0e2012-07-19 15:28:27 -070032#include "scoped_thread_state_change.h"
Mathieu Chartier7469ebf2012-09-24 16:28:36 -070033#include "gc/space.h"
jeffhaoec014232012-09-05 10:42:25 -070034#include "verifier/method_verifier.h"
Brian Carlstrome24fa612011-09-29 00:53:55 -070035
36namespace art {
37
Brian Carlstromcd60ac72013-01-20 17:09:51 -080038bool OatWriter::Create(OutputStream& output_stream,
jeffhao10037c82012-01-23 15:06:23 -080039 const std::vector<const DexFile*>& dex_files,
Brian Carlstrom28db0122012-10-18 16:20:41 -070040 uint32_t image_file_location_oat_checksum,
41 uint32_t image_file_location_oat_begin,
Brian Carlstrom81f3ca12012-03-17 00:27:35 -070042 const std::string& image_file_location,
Ian Rogers1212a022013-03-04 10:48:41 -080043 const CompilerDriver& driver) {
Brian Carlstrom81f3ca12012-03-17 00:27:35 -070044 OatWriter oat_writer(dex_files,
Brian Carlstrom28db0122012-10-18 16:20:41 -070045 image_file_location_oat_checksum,
46 image_file_location_oat_begin,
Brian Carlstrom81f3ca12012-03-17 00:27:35 -070047 image_file_location,
Ian Rogers1212a022013-03-04 10:48:41 -080048 &driver);
Brian Carlstromcd60ac72013-01-20 17:09:51 -080049 return oat_writer.Write(output_stream);
Brian Carlstrome24fa612011-09-29 00:53:55 -070050}
51
Brian Carlstrom3320cf42011-10-04 14:58:28 -070052OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
Brian Carlstrom28db0122012-10-18 16:20:41 -070053 uint32_t image_file_location_oat_checksum,
54 uint32_t image_file_location_oat_begin,
Brian Carlstrom81f3ca12012-03-17 00:27:35 -070055 const std::string& image_file_location,
Ian Rogers1212a022013-03-04 10:48:41 -080056 const CompilerDriver* compiler)
57 : compiler_driver_(compiler) {
Brian Carlstrom28db0122012-10-18 16:20:41 -070058 image_file_location_oat_checksum_ = image_file_location_oat_checksum;
59 image_file_location_oat_begin_ = image_file_location_oat_begin;
Brian Carlstrom81f3ca12012-03-17 00:27:35 -070060 image_file_location_ = image_file_location;
Brian Carlstrome24fa612011-09-29 00:53:55 -070061 dex_files_ = &dex_files;
Ian Rogers0571d352011-11-03 19:51:38 -070062 oat_header_ = NULL;
63 executable_offset_padding_length_ = 0;
Brian Carlstrome24fa612011-09-29 00:53:55 -070064
Brian Carlstrom81f3ca12012-03-17 00:27:35 -070065 size_t offset = InitOatHeader();
Brian Carlstrome24fa612011-09-29 00:53:55 -070066 offset = InitOatDexFiles(offset);
Brian Carlstrom89521892011-12-07 22:05:07 -080067 offset = InitDexFiles(offset);
Brian Carlstrom389efb02012-01-11 12:06:26 -080068 offset = InitOatClasses(offset);
Brian Carlstrome24fa612011-09-29 00:53:55 -070069 offset = InitOatCode(offset);
70 offset = InitOatCodeDexFiles(offset);
71
72 CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
Brian Carlstrome24fa612011-09-29 00:53:55 -070073}
74
Ian Rogers0571d352011-11-03 19:51:38 -070075OatWriter::~OatWriter() {
76 delete oat_header_;
77 STLDeleteElements(&oat_dex_files_);
Brian Carlstrom389efb02012-01-11 12:06:26 -080078 STLDeleteElements(&oat_classes_);
Ian Rogers0571d352011-11-03 19:51:38 -070079}
80
Brian Carlstrom81f3ca12012-03-17 00:27:35 -070081size_t OatWriter::InitOatHeader() {
Brian Carlstrome24fa612011-09-29 00:53:55 -070082 // create the OatHeader
Ian Rogers1212a022013-03-04 10:48:41 -080083 oat_header_ = new OatHeader(compiler_driver_->GetInstructionSet(),
Brian Carlstrom81f3ca12012-03-17 00:27:35 -070084 dex_files_,
Brian Carlstrom28db0122012-10-18 16:20:41 -070085 image_file_location_oat_checksum_,
86 image_file_location_oat_begin_,
Brian Carlstrom81f3ca12012-03-17 00:27:35 -070087 image_file_location_);
Brian Carlstrome24fa612011-09-29 00:53:55 -070088 size_t offset = sizeof(*oat_header_);
Brian Carlstrom81f3ca12012-03-17 00:27:35 -070089 offset += image_file_location_.size();
Brian Carlstrome24fa612011-09-29 00:53:55 -070090 return offset;
91}
92
93size_t OatWriter::InitOatDexFiles(size_t offset) {
94 // create the OatDexFiles
95 for (size_t i = 0; i != dex_files_->size(); ++i) {
96 const DexFile* dex_file = (*dex_files_)[i];
97 CHECK(dex_file != NULL);
Brian Carlstrom265091e2013-01-30 14:08:26 -080098 OatDexFile* oat_dex_file = new OatDexFile(offset, *dex_file);
Brian Carlstrome24fa612011-09-29 00:53:55 -070099 oat_dex_files_.push_back(oat_dex_file);
100 offset += oat_dex_file->SizeOf();
101 }
102 return offset;
103}
104
Brian Carlstrom89521892011-12-07 22:05:07 -0800105size_t OatWriter::InitDexFiles(size_t offset) {
106 // calculate the offsets within OatDexFiles to the DexFiles
107 for (size_t i = 0; i != dex_files_->size(); ++i) {
108 // dex files are required to be 4 byte aligned
109 offset = RoundUp(offset, 4);
110
111 // set offset in OatDexFile to DexFile
112 oat_dex_files_[i]->dex_file_offset_ = offset;
113
114 const DexFile* dex_file = (*dex_files_)[i];
115 offset += dex_file->GetHeader().file_size_;
116 }
117 return offset;
118}
119
Brian Carlstrom389efb02012-01-11 12:06:26 -0800120size_t OatWriter::InitOatClasses(size_t offset) {
121 // create the OatClasses
122 // calculate the offsets within OatDexFiles to OatClasses
Brian Carlstrome24fa612011-09-29 00:53:55 -0700123 for (size_t i = 0; i != dex_files_->size(); ++i) {
124 const DexFile* dex_file = (*dex_files_)[i];
125 for (size_t class_def_index = 0;
126 class_def_index < dex_file->NumClassDefs();
Ian Rogersc20a83e2012-01-18 18:15:32 -0800127 class_def_index++) {
Brian Carlstrom6e3b1d92012-01-11 01:36:32 -0800128 oat_dex_files_[i]->methods_offsets_[class_def_index] = offset;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700129 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
130 const byte* class_data = dex_file->GetClassData(class_def);
Ian Rogers0571d352011-11-03 19:51:38 -0700131 uint32_t num_methods = 0;
132 if (class_data != NULL) { // ie not an empty class, such as a marker interface
133 ClassDataItemIterator it(*dex_file, class_data);
134 size_t num_direct_methods = it.NumDirectMethods();
135 size_t num_virtual_methods = it.NumVirtualMethods();
136 num_methods = num_direct_methods + num_virtual_methods;
137 }
Brian Carlstrom0755ec52012-01-11 15:19:46 -0800138
Ian Rogers1212a022013-03-04 10:48:41 -0800139 CompilerDriver::ClassReference class_ref = CompilerDriver::ClassReference(dex_file, class_def_index);
140 CompiledClass* compiled_class = compiler_driver_->GetCompiledClass(class_ref);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800141 mirror::Class::Status status;
jeffhaoec014232012-09-05 10:42:25 -0700142 if (compiled_class != NULL) {
143 status = compiled_class->GetStatus();
144 } else if (verifier::MethodVerifier::IsClassRejected(class_ref)) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800145 status = mirror::Class::kStatusError;
jeffhaoec014232012-09-05 10:42:25 -0700146 } else {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800147 status = mirror::Class::kStatusNotReady;
jeffhaoec014232012-09-05 10:42:25 -0700148 }
Brian Carlstrom0755ec52012-01-11 15:19:46 -0800149
Brian Carlstrom265091e2013-01-30 14:08:26 -0800150 OatClass* oat_class = new OatClass(offset, status, num_methods);
Brian Carlstrom389efb02012-01-11 12:06:26 -0800151 oat_classes_.push_back(oat_class);
152 offset += oat_class->SizeOf();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700153 }
Brian Carlstrom6e3b1d92012-01-11 01:36:32 -0800154 oat_dex_files_[i]->UpdateChecksum(*oat_header_);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700155 }
156 return offset;
157}
158
159size_t OatWriter::InitOatCode(size_t offset) {
160 // calculate the offsets within OatHeader to executable code
161 size_t old_offset = offset;
162 // required to be on a new page boundary
163 offset = RoundUp(offset, kPageSize);
164 oat_header_->SetExecutableOffset(offset);
165 executable_offset_padding_length_ = offset - old_offset;
166 return offset;
167}
168
169size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
Brian Carlstrome24fa612011-09-29 00:53:55 -0700170 size_t oat_class_index = 0;
171 for (size_t i = 0; i != dex_files_->size(); ++i) {
172 const DexFile* dex_file = (*dex_files_)[i];
173 CHECK(dex_file != NULL);
174 offset = InitOatCodeDexFile(offset, oat_class_index, *dex_file);
175 }
176 return offset;
177}
178
179size_t OatWriter::InitOatCodeDexFile(size_t offset,
180 size_t& oat_class_index,
181 const DexFile& dex_file) {
Elliott Hughesba8eee12012-01-24 20:25:24 -0800182 for (size_t class_def_index = 0;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700183 class_def_index < dex_file.NumClassDefs();
184 class_def_index++, oat_class_index++) {
185 const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
Ian Rogersc20a83e2012-01-18 18:15:32 -0800186 offset = InitOatCodeClassDef(offset, oat_class_index, class_def_index, dex_file, class_def);
Brian Carlstrom389efb02012-01-11 12:06:26 -0800187 oat_classes_[oat_class_index]->UpdateChecksum(*oat_header_);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700188 }
189 return offset;
190}
191
192size_t OatWriter::InitOatCodeClassDef(size_t offset,
Ian Rogersc20a83e2012-01-18 18:15:32 -0800193 size_t oat_class_index, size_t class_def_index,
Brian Carlstrome24fa612011-09-29 00:53:55 -0700194 const DexFile& dex_file,
195 const DexFile::ClassDef& class_def) {
196 const byte* class_data = dex_file.GetClassData(class_def);
Ian Rogers0571d352011-11-03 19:51:38 -0700197 if (class_data == NULL) {
198 // empty class, such as a marker interface
Ian Rogers387b6992011-10-31 17:52:37 -0700199 return offset;
200 }
Ian Rogers0571d352011-11-03 19:51:38 -0700201 ClassDataItemIterator it(dex_file, class_data);
Brian Carlstrom389efb02012-01-11 12:06:26 -0800202 CHECK_EQ(oat_classes_[oat_class_index]->method_offsets_.size(),
Ian Rogers0571d352011-11-03 19:51:38 -0700203 it.NumDirectMethods() + it.NumVirtualMethods());
204 // Skip fields
205 while (it.HasNextStaticField()) {
206 it.Next();
207 }
208 while (it.HasNextInstanceField()) {
209 it.Next();
210 }
211 // Process methods
Brian Carlstrome24fa612011-09-29 00:53:55 -0700212 size_t class_def_method_index = 0;
Ian Rogers0571d352011-11-03 19:51:38 -0700213 while (it.HasNextDirectMethod()) {
Ian Rogersc20a83e2012-01-18 18:15:32 -0800214 bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0;
Ian Rogers08f753d2012-08-24 14:35:25 -0700215 offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index,
216 is_native, it.GetMethodInvokeType(class_def), it.GetMemberIndex(),
217 &dex_file);
Ian Rogers0571d352011-11-03 19:51:38 -0700218 class_def_method_index++;
219 it.Next();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700220 }
Ian Rogers0571d352011-11-03 19:51:38 -0700221 while (it.HasNextVirtualMethod()) {
Ian Rogersc20a83e2012-01-18 18:15:32 -0800222 bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0;
Ian Rogers08f753d2012-08-24 14:35:25 -0700223 offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index,
224 is_native, it.GetMethodInvokeType(class_def), it.GetMemberIndex(),
225 &dex_file);
Ian Rogers0571d352011-11-03 19:51:38 -0700226 class_def_method_index++;
227 it.Next();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700228 }
Ian Rogers0571d352011-11-03 19:51:38 -0700229 DCHECK(!it.HasNext());
Brian Carlstrome24fa612011-09-29 00:53:55 -0700230 return offset;
231}
232
Elliott Hughes1bac54f2012-03-16 12:48:31 -0700233size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index,
234 size_t __attribute__((unused)) class_def_index,
235 size_t class_def_method_index,
236 bool __attribute__((unused)) is_native,
Brian Carlstrom265091e2013-01-30 14:08:26 -0800237 InvokeType invoke_type,
Elliott Hughes1bac54f2012-03-16 12:48:31 -0700238 uint32_t method_idx, const DexFile* dex_file) {
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700239 // derived from CompiledMethod if available
240 uint32_t code_offset = 0;
241 uint32_t frame_size_in_bytes = kStackAlignment;
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700242 uint32_t core_spill_mask = 0;
243 uint32_t fp_spill_mask = 0;
244 uint32_t mapping_table_offset = 0;
245 uint32_t vmap_table_offset = 0;
Brian Carlstrome7d856b2012-01-11 18:10:55 -0800246 uint32_t gc_map_offset = 0;
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700247 // derived from CompiledInvokeStub if available
248 uint32_t invoke_stub_offset = 0;
Ian Rogersc928de92013-02-27 14:30:44 -0800249#if defined(ART_USE_PORTABLE_COMPILER)
Logan Chien971bf3f2012-05-01 15:47:55 +0800250 uint32_t proxy_stub_offset = 0;
Brian Carlstromfd2ec542012-05-02 15:08:57 -0700251#endif
Brian Carlstrome24fa612011-09-29 00:53:55 -0700252
Brian Carlstrom265091e2013-01-30 14:08:26 -0800253 OatClass* oat_class = oat_classes_[oat_class_index];
254#if defined(ART_USE_PORTABLE_COMPILER)
255 size_t oat_method_offsets_offset =
256 oat_class->GetOatMethodOffsetsOffsetFromOatHeader(class_def_method_index);
257#endif
258
Ian Rogers0571d352011-11-03 19:51:38 -0700259 CompiledMethod* compiled_method =
Ian Rogers1212a022013-03-04 10:48:41 -0800260 compiler_driver_->GetCompiledMethod(CompilerDriver::MethodReference(dex_file, method_idx));
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700261 if (compiled_method != NULL) {
Brian Carlstrom265091e2013-01-30 14:08:26 -0800262#if defined(ART_USE_PORTABLE_COMPILER)
263 compiled_method->AddOatdataOffsetToCompliledCodeOffset(
264 oat_method_offsets_offset + OFFSETOF_MEMBER(OatMethodOffsets, code_offset_));
265#else
266 const std::vector<uint8_t>& code = compiled_method->GetCode();
Logan Chien971bf3f2012-05-01 15:47:55 +0800267 offset = compiled_method->AlignCode(offset);
268 DCHECK_ALIGNED(offset, kArmAlignment);
Logan Chien971bf3f2012-05-01 15:47:55 +0800269 uint32_t code_size = code.size() * sizeof(code[0]);
270 CHECK_NE(code_size, 0U);
271 uint32_t thumb_offset = compiled_method->CodeDelta();
272 code_offset = offset + sizeof(code_size) + thumb_offset;
273
274 // Deduplicate code arrays
275 SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code);
276 if (code_iter != code_offsets_.end()) {
277 code_offset = code_iter->second;
jeffhao55d78212011-11-02 11:41:50 -0700278 } else {
Logan Chien971bf3f2012-05-01 15:47:55 +0800279 code_offsets_.Put(&code, code_offset);
280 offset += sizeof(code_size); // code size is prepended before code
281 offset += code_size;
282 oat_header_->UpdateChecksum(&code[0], code_size);
283 }
Brian Carlstrom265091e2013-01-30 14:08:26 -0800284#endif
Logan Chien971bf3f2012-05-01 15:47:55 +0800285 frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
286 core_spill_mask = compiled_method->GetCoreSpillMask();
287 fp_spill_mask = compiled_method->GetFpSpillMask();
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700288
Logan Chien971bf3f2012-05-01 15:47:55 +0800289 const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
290 size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
291 mapping_table_offset = (mapping_table_size == 0) ? 0 : offset;
jeffhao55d78212011-11-02 11:41:50 -0700292
Logan Chien971bf3f2012-05-01 15:47:55 +0800293 // Deduplicate mapping tables
294 SafeMap<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter = mapping_table_offsets_.find(&mapping_table);
295 if (mapping_iter != mapping_table_offsets_.end()) {
296 mapping_table_offset = mapping_iter->second;
297 } else {
298 mapping_table_offsets_.Put(&mapping_table, mapping_table_offset);
299 offset += mapping_table_size;
300 oat_header_->UpdateChecksum(&mapping_table[0], mapping_table_size);
301 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700302
Logan Chien971bf3f2012-05-01 15:47:55 +0800303 const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
304 size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
305 vmap_table_offset = (vmap_table_size == 0) ? 0 : offset;
jeffhao55d78212011-11-02 11:41:50 -0700306
Logan Chien971bf3f2012-05-01 15:47:55 +0800307 // Deduplicate vmap tables
308 SafeMap<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter = vmap_table_offsets_.find(&vmap_table);
309 if (vmap_iter != vmap_table_offsets_.end()) {
310 vmap_table_offset = vmap_iter->second;
311 } else {
312 vmap_table_offsets_.Put(&vmap_table, vmap_table_offset);
313 offset += vmap_table_size;
314 oat_header_->UpdateChecksum(&vmap_table[0], vmap_table_size);
315 }
Brian Carlstrome7d856b2012-01-11 18:10:55 -0800316
Ian Rogers0c7abda2012-09-19 13:33:42 -0700317 const std::vector<uint8_t>& gc_map = compiled_method->GetNativeGcMap();
Logan Chien971bf3f2012-05-01 15:47:55 +0800318 size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]);
319 gc_map_offset = (gc_map_size == 0) ? 0 : offset;
Logan Chienccb7bf12012-03-28 12:52:32 +0800320
TDYa127ce4cc0d2012-11-18 16:59:53 -0800321#if !defined(NDEBUG)
Logan Chien971bf3f2012-05-01 15:47:55 +0800322 // We expect GC maps except when the class hasn't been verified or the method is native
Ian Rogers1212a022013-03-04 10:48:41 -0800323 CompilerDriver::ClassReference class_ref = CompilerDriver::ClassReference(dex_file, class_def_index);
324 CompiledClass* compiled_class = compiler_driver_->GetCompiledClass(class_ref);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800325 mirror::Class::Status status;
jeffhaoec014232012-09-05 10:42:25 -0700326 if (compiled_class != NULL) {
327 status = compiled_class->GetStatus();
328 } else if (verifier::MethodVerifier::IsClassRejected(class_ref)) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800329 status = mirror::Class::kStatusError;
jeffhaoec014232012-09-05 10:42:25 -0700330 } else {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800331 status = mirror::Class::kStatusNotReady;
jeffhaoec014232012-09-05 10:42:25 -0700332 }
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800333 CHECK(gc_map_size != 0 || is_native || status < mirror::Class::kStatusVerified)
334 << &gc_map << " " << gc_map_size << " " << (is_native ? "true" : "false") << " "
335 << (status < mirror::Class::kStatusVerified) << " " << status << " "
336 << PrettyMethod(method_idx, *dex_file);
Ian Rogersc20a83e2012-01-18 18:15:32 -0800337#endif
338
Logan Chien971bf3f2012-05-01 15:47:55 +0800339 // Deduplicate GC maps
340 SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter = gc_map_offsets_.find(&gc_map);
341 if (gc_map_iter != gc_map_offsets_.end()) {
342 gc_map_offset = gc_map_iter->second;
343 } else {
344 gc_map_offsets_.Put(&gc_map, gc_map_offset);
345 offset += gc_map_size;
346 oat_header_->UpdateChecksum(&gc_map[0], gc_map_size);
Brian Carlstrome7d856b2012-01-11 18:10:55 -0800347 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700348 }
349
Ian Rogers0571d352011-11-03 19:51:38 -0700350 const char* shorty = dex_file->GetMethodShorty(dex_file->GetMethodId(method_idx));
Brian Carlstrom265091e2013-01-30 14:08:26 -0800351 CompiledInvokeStub* compiled_invoke_stub = compiler_driver_->FindInvokeStub(invoke_type == kStatic,
352 shorty);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700353 if (compiled_invoke_stub != NULL) {
Brian Carlstrom265091e2013-01-30 14:08:26 -0800354#if defined(ART_USE_PORTABLE_COMPILER)
355 compiled_invoke_stub->AddOatdataOffsetToCompliledCodeOffset(
356 oat_method_offsets_offset + OFFSETOF_MEMBER(OatMethodOffsets, invoke_stub_offset_));
357#else
358 const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
Ian Rogers1212a022013-03-04 10:48:41 -0800359 offset = CompiledMethod::AlignCode(offset, compiler_driver_->GetInstructionSet());
Logan Chien971bf3f2012-05-01 15:47:55 +0800360 DCHECK_ALIGNED(offset, kArmAlignment);
Logan Chien971bf3f2012-05-01 15:47:55 +0800361 uint32_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
362 CHECK_NE(invoke_stub_size, 0U);
363 uint32_t thumb_offset = compiled_invoke_stub->CodeDelta();
364 invoke_stub_offset = offset + sizeof(invoke_stub_size) + thumb_offset;
Logan Chienccb7bf12012-03-28 12:52:32 +0800365
Logan Chien971bf3f2012-05-01 15:47:55 +0800366 // Deduplicate invoke stubs
367 SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter = code_offsets_.find(&invoke_stub);
368 if (stub_iter != code_offsets_.end()) {
369 invoke_stub_offset = stub_iter->second;
370 } else {
371 code_offsets_.Put(&invoke_stub, invoke_stub_offset);
372 offset += sizeof(invoke_stub_size); // invoke stub size is prepended before code
373 offset += invoke_stub_size;
374 oat_header_->UpdateChecksum(&invoke_stub[0], invoke_stub_size);
jeffhao55d78212011-11-02 11:41:50 -0700375 }
Brian Carlstrom265091e2013-01-30 14:08:26 -0800376#endif
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700377 }
378
Ian Rogersc928de92013-02-27 14:30:44 -0800379#if defined(ART_USE_PORTABLE_COMPILER)
Brian Carlstrom265091e2013-01-30 14:08:26 -0800380 if (invoke_type != kStatic) {
381 CompiledInvokeStub* compiled_proxy_stub = compiler_driver_->FindProxyStub(shorty);
Logan Chien7a2a23a2012-06-06 11:01:00 +0800382 if (compiled_proxy_stub != NULL) {
Brian Carlstrom265091e2013-01-30 14:08:26 -0800383 compiled_proxy_stub->AddOatdataOffsetToCompliledCodeOffset(
384 oat_method_offsets_offset + OFFSETOF_MEMBER(OatMethodOffsets, proxy_stub_offset_));
Logan Chien7a2a23a2012-06-06 11:01:00 +0800385 }
386 }
387#endif
388
Brian Carlstrom265091e2013-01-30 14:08:26 -0800389 oat_class->method_offsets_[class_def_method_index]
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700390 = OatMethodOffsets(code_offset,
391 frame_size_in_bytes,
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700392 core_spill_mask,
393 fp_spill_mask,
394 mapping_table_offset,
395 vmap_table_offset,
Brian Carlstrome7d856b2012-01-11 18:10:55 -0800396 gc_map_offset,
Logan Chienccb7bf12012-03-28 12:52:32 +0800397 invoke_stub_offset
Ian Rogersc928de92013-02-27 14:30:44 -0800398#if defined(ART_USE_PORTABLE_COMPILER)
Logan Chien971bf3f2012-05-01 15:47:55 +0800399 , proxy_stub_offset
Logan Chienccb7bf12012-03-28 12:52:32 +0800400#endif
401 );
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700402
Ian Rogers1212a022013-03-04 10:48:41 -0800403 if (compiler_driver_->IsImage()) {
Ian Rogers0571d352011-11-03 19:51:38 -0700404 ClassLinker* linker = Runtime::Current()->GetClassLinker();
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800405 mirror::DexCache* dex_cache = linker->FindDexCache(*dex_file);
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700406 // Unchecked as we hold mutator_lock_ on entry.
407 ScopedObjectAccessUnchecked soa(Thread::Current());
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800408 mirror::AbstractMethod* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache,
Brian Carlstrom265091e2013-01-30 14:08:26 -0800409 NULL, NULL, invoke_type);
Ian Rogers0571d352011-11-03 19:51:38 -0700410 CHECK(method != NULL);
411 method->SetFrameSizeInBytes(frame_size_in_bytes);
412 method->SetCoreSpillMask(core_spill_mask);
413 method->SetFpSpillMask(fp_spill_mask);
414 method->SetOatMappingTableOffset(mapping_table_offset);
Ian Rogers19846512012-02-24 11:42:47 -0800415 // Don't overwrite static method trampoline
416 if (!method->IsStatic() || method->IsConstructor() ||
417 method->GetDeclaringClass()->IsInitialized()) {
418 method->SetOatCodeOffset(code_offset);
419 } else {
420 method->SetCode(Runtime::Current()->GetResolutionStubArray(Runtime::kStaticMethod)->GetData());
421 }
Ian Rogers0571d352011-11-03 19:51:38 -0700422 method->SetOatVmapTableOffset(vmap_table_offset);
Ian Rogers0c7abda2012-09-19 13:33:42 -0700423 method->SetOatNativeGcMapOffset(gc_map_offset);
Ian Rogers0571d352011-11-03 19:51:38 -0700424 method->SetOatInvokeStubOffset(invoke_stub_offset);
425 }
Logan Chien8b977d32012-02-21 19:14:55 +0800426
Brian Carlstrome24fa612011-09-29 00:53:55 -0700427 return offset;
428}
429
Brian Carlstrom265091e2013-01-30 14:08:26 -0800430#define DCHECK_OFFSET() \
431 DCHECK_EQ(static_cast<off_t>(offset), out.Seek(0, kSeekCurrent))
432
433#define DCHECK_OFFSET_() \
434 DCHECK_EQ(static_cast<off_t>(offset_), out.Seek(0, kSeekCurrent))
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700435
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800436bool OatWriter::Write(OutputStream& out) {
437 if (!out.WriteFully(oat_header_, sizeof(*oat_header_))) {
438 PLOG(ERROR) << "Failed to write oat header to " << out.GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700439 return false;
440 }
441
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800442 if (!out.WriteFully(image_file_location_.data(), image_file_location_.size())) {
443 PLOG(ERROR) << "Failed to write oat header image file location to " << out.GetLocation();
Brian Carlstrom81f3ca12012-03-17 00:27:35 -0700444 return false;
445 }
446
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800447 if (!WriteTables(out)) {
448 LOG(ERROR) << "Failed to write oat tables to " << out.GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700449 return false;
450 }
451
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800452 size_t code_offset = WriteCode(out);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700453 if (code_offset == 0) {
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800454 LOG(ERROR) << "Failed to write oat code to " << out.GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700455 return false;
456 }
457
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800458 code_offset = WriteCodeDexFiles(out, code_offset);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700459 if (code_offset == 0) {
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800460 LOG(ERROR) << "Failed to write oat code for dex files to " << out.GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700461 return false;
462 }
463
464 return true;
465}
466
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800467bool OatWriter::WriteTables(OutputStream& out) {
Brian Carlstrome24fa612011-09-29 00:53:55 -0700468 for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800469 if (!oat_dex_files_[i]->Write(out)) {
470 PLOG(ERROR) << "Failed to write oat dex information to " << out.GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700471 return false;
472 }
473 }
Brian Carlstrom89521892011-12-07 22:05:07 -0800474 for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
475 uint32_t expected_offset = oat_dex_files_[i]->dex_file_offset_;
Brian Carlstrom49a0f152013-01-22 17:17:36 -0800476 off_t actual_offset = out.Seek(expected_offset, kSeekSet);
Brian Carlstrom89521892011-12-07 22:05:07 -0800477 if (static_cast<uint32_t>(actual_offset) != expected_offset) {
478 const DexFile* dex_file = (*dex_files_)[i];
479 PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
480 << " Expected: " << expected_offset << " File: " << dex_file->GetLocation();
481 return false;
482 }
483 const DexFile* dex_file = (*dex_files_)[i];
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800484 if (!out.WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) {
485 PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation() << " to " << out.GetLocation();
Brian Carlstrom89521892011-12-07 22:05:07 -0800486 return false;
487 }
488 }
Brian Carlstrom389efb02012-01-11 12:06:26 -0800489 for (size_t i = 0; i != oat_classes_.size(); ++i) {
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800490 if (!oat_classes_[i]->Write(out)) {
491 PLOG(ERROR) << "Failed to write oat methods information to " << out.GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700492 return false;
493 }
494 }
495 return true;
496}
497
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800498size_t OatWriter::WriteCode(OutputStream& out) {
Brian Carlstrom265091e2013-01-30 14:08:26 -0800499 uint32_t offset = oat_header_->GetExecutableOffset();
Brian Carlstrom49a0f152013-01-22 17:17:36 -0800500 off_t new_offset = out.Seek(executable_offset_padding_length_, kSeekCurrent);
Brian Carlstrom265091e2013-01-30 14:08:26 -0800501 if (static_cast<uint32_t>(new_offset) != offset) {
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700502 PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
Brian Carlstrom265091e2013-01-30 14:08:26 -0800503 << " Expected: " << offset << " File: " << out.GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700504 return 0;
505 }
Brian Carlstrom265091e2013-01-30 14:08:26 -0800506 DCHECK_OFFSET();
507 return offset;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700508}
509
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800510size_t OatWriter::WriteCodeDexFiles(OutputStream& out, size_t code_offset) {
Ian Rogers0571d352011-11-03 19:51:38 -0700511 size_t oat_class_index = 0;
Brian Carlstrom6e3b1d92012-01-11 01:36:32 -0800512 for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
Brian Carlstrome24fa612011-09-29 00:53:55 -0700513 const DexFile* dex_file = (*dex_files_)[i];
514 CHECK(dex_file != NULL);
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800515 code_offset = WriteCodeDexFile(out, code_offset, oat_class_index, *dex_file);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700516 if (code_offset == 0) {
517 return 0;
518 }
519 }
520 return code_offset;
521}
522
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800523size_t OatWriter::WriteCodeDexFile(OutputStream& out, size_t code_offset, size_t& oat_class_index,
Ian Rogers0571d352011-11-03 19:51:38 -0700524 const DexFile& dex_file) {
525 for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs();
526 class_def_index++, oat_class_index++) {
Brian Carlstrome24fa612011-09-29 00:53:55 -0700527 const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800528 code_offset = WriteCodeClassDef(out, code_offset, oat_class_index, dex_file, class_def);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700529 if (code_offset == 0) {
530 return 0;
531 }
532 }
533 return code_offset;
534}
535
Ian Rogers0571d352011-11-03 19:51:38 -0700536void OatWriter::ReportWriteFailure(const char* what, uint32_t method_idx,
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800537 const DexFile& dex_file, OutputStream& out) const {
Ian Rogers0571d352011-11-03 19:51:38 -0700538 PLOG(ERROR) << "Failed to write " << what << " for " << PrettyMethod(method_idx, dex_file)
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800539 << " to " << out.GetLocation();
Elliott Hughes234da572011-11-03 22:13:06 -0700540}
541
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800542size_t OatWriter::WriteCodeClassDef(OutputStream& out,
Ian Rogers0571d352011-11-03 19:51:38 -0700543 size_t code_offset, size_t oat_class_index,
Brian Carlstrome24fa612011-09-29 00:53:55 -0700544 const DexFile& dex_file,
545 const DexFile::ClassDef& class_def) {
Brian Carlstrome24fa612011-09-29 00:53:55 -0700546 const byte* class_data = dex_file.GetClassData(class_def);
Ian Rogers0571d352011-11-03 19:51:38 -0700547 if (class_data == NULL) {
548 // ie. an empty class such as a marker interface
Ian Rogers387b6992011-10-31 17:52:37 -0700549 return code_offset;
550 }
Ian Rogers0571d352011-11-03 19:51:38 -0700551 ClassDataItemIterator it(dex_file, class_data);
552 // Skip fields
553 while (it.HasNextStaticField()) {
554 it.Next();
555 }
556 while (it.HasNextInstanceField()) {
557 it.Next();
558 }
559 // Process methods
560 size_t class_def_method_index = 0;
561 while (it.HasNextDirectMethod()) {
562 bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0;
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800563 code_offset = WriteCodeMethod(out, code_offset, oat_class_index, class_def_method_index,
Ian Rogers0571d352011-11-03 19:51:38 -0700564 is_static, it.GetMemberIndex(), dex_file);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700565 if (code_offset == 0) {
566 return 0;
567 }
Ian Rogers0571d352011-11-03 19:51:38 -0700568 class_def_method_index++;
569 it.Next();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700570 }
Ian Rogers0571d352011-11-03 19:51:38 -0700571 while (it.HasNextVirtualMethod()) {
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800572 code_offset = WriteCodeMethod(out, code_offset, oat_class_index, class_def_method_index,
Ian Rogers0571d352011-11-03 19:51:38 -0700573 false, it.GetMemberIndex(), dex_file);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700574 if (code_offset == 0) {
575 return 0;
576 }
Ian Rogers0571d352011-11-03 19:51:38 -0700577 class_def_method_index++;
578 it.Next();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700579 }
580 return code_offset;
581}
582
Brian Carlstrom265091e2013-01-30 14:08:26 -0800583size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_class_index,
Ian Rogers0571d352011-11-03 19:51:38 -0700584 size_t class_def_method_index, bool is_static,
585 uint32_t method_idx, const DexFile& dex_file) {
586 const CompiledMethod* compiled_method =
Ian Rogers1212a022013-03-04 10:48:41 -0800587 compiler_driver_->GetCompiledMethod(CompilerDriver::MethodReference(&dex_file, method_idx));
Ian Rogers0571d352011-11-03 19:51:38 -0700588
Ian Rogers0571d352011-11-03 19:51:38 -0700589 OatMethodOffsets method_offsets =
Brian Carlstrom389efb02012-01-11 12:06:26 -0800590 oat_classes_[oat_class_index]->method_offsets_[class_def_method_index];
Ian Rogers0571d352011-11-03 19:51:38 -0700591
592
593 if (compiled_method != NULL) { // ie. not an abstract method
Brian Carlstrom265091e2013-01-30 14:08:26 -0800594#if !defined(ART_USE_PORTABLE_COMPILER)
595 uint32_t aligned_offset = compiled_method->AlignCode(offset);
596 uint32_t aligned_code_delta = aligned_offset - offset;
Logan Chien971bf3f2012-05-01 15:47:55 +0800597 if (aligned_code_delta != 0) {
Brian Carlstrom49a0f152013-01-22 17:17:36 -0800598 off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent);
Brian Carlstrom265091e2013-01-30 14:08:26 -0800599 if (static_cast<uint32_t>(new_offset) != aligned_offset) {
Logan Chien971bf3f2012-05-01 15:47:55 +0800600 PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
Brian Carlstrom265091e2013-01-30 14:08:26 -0800601 << " Expected: " << aligned_offset << " File: " << out.GetLocation();
Logan Chien971bf3f2012-05-01 15:47:55 +0800602 return 0;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700603 }
Brian Carlstrom265091e2013-01-30 14:08:26 -0800604 offset += aligned_code_delta;
605 DCHECK_OFFSET();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700606 }
Brian Carlstrom265091e2013-01-30 14:08:26 -0800607 DCHECK_ALIGNED(offset, kArmAlignment);
Logan Chien971bf3f2012-05-01 15:47:55 +0800608 const std::vector<uint8_t>& code = compiled_method->GetCode();
609 uint32_t code_size = code.size() * sizeof(code[0]);
610 CHECK_NE(code_size, 0U);
611
612 // Deduplicate code arrays
Brian Carlstrom265091e2013-01-30 14:08:26 -0800613 size_t code_offset = offset + sizeof(code_size) + compiled_method->CodeDelta();
Logan Chien971bf3f2012-05-01 15:47:55 +0800614 SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code);
Brian Carlstrom265091e2013-01-30 14:08:26 -0800615 if (code_iter != code_offsets_.end() && code_offset != method_offsets.code_offset_) {
616 DCHECK(code_iter->second == method_offsets.code_offset_)
617 << PrettyMethod(method_idx, dex_file);
Logan Chien971bf3f2012-05-01 15:47:55 +0800618 } else {
Brian Carlstrom265091e2013-01-30 14:08:26 -0800619 DCHECK(code_offset == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file);
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800620 if (!out.WriteFully(&code_size, sizeof(code_size))) {
621 ReportWriteFailure("method code size", method_idx, dex_file, out);
Logan Chien971bf3f2012-05-01 15:47:55 +0800622 return 0;
623 }
Brian Carlstrom265091e2013-01-30 14:08:26 -0800624 offset += sizeof(code_size);
625 DCHECK_OFFSET();
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800626 if (!out.WriteFully(&code[0], code_size)) {
627 ReportWriteFailure("method code", method_idx, dex_file, out);
Logan Chien971bf3f2012-05-01 15:47:55 +0800628 return 0;
629 }
Brian Carlstrom265091e2013-01-30 14:08:26 -0800630 offset += code_size;
Logan Chien971bf3f2012-05-01 15:47:55 +0800631 }
Brian Carlstrom265091e2013-01-30 14:08:26 -0800632 DCHECK_OFFSET();
633#endif
Logan Chien971bf3f2012-05-01 15:47:55 +0800634
635 const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
636 size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
637
638 // Deduplicate mapping tables
639 SafeMap<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter =
640 mapping_table_offsets_.find(&mapping_table);
641 if (mapping_iter != mapping_table_offsets_.end() &&
Brian Carlstrom265091e2013-01-30 14:08:26 -0800642 offset != method_offsets.mapping_table_offset_) {
Logan Chien971bf3f2012-05-01 15:47:55 +0800643 DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
644 || mapping_iter->second == method_offsets.mapping_table_offset_)
645 << PrettyMethod(method_idx, dex_file);
646 } else {
647 DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
Brian Carlstrom265091e2013-01-30 14:08:26 -0800648 || offset == method_offsets.mapping_table_offset_)
Logan Chien971bf3f2012-05-01 15:47:55 +0800649 << PrettyMethod(method_idx, dex_file);
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800650 if (!out.WriteFully(&mapping_table[0], mapping_table_size)) {
651 ReportWriteFailure("mapping table", method_idx, dex_file, out);
Logan Chien971bf3f2012-05-01 15:47:55 +0800652 return 0;
653 }
Brian Carlstrom265091e2013-01-30 14:08:26 -0800654 offset += mapping_table_size;
Logan Chien971bf3f2012-05-01 15:47:55 +0800655 }
Brian Carlstrom265091e2013-01-30 14:08:26 -0800656 DCHECK_OFFSET();
Logan Chien971bf3f2012-05-01 15:47:55 +0800657
658 const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
659 size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
660
661 // Deduplicate vmap tables
662 SafeMap<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter =
663 vmap_table_offsets_.find(&vmap_table);
664 if (vmap_iter != vmap_table_offsets_.end() &&
Brian Carlstrom265091e2013-01-30 14:08:26 -0800665 offset != method_offsets.vmap_table_offset_) {
Logan Chien971bf3f2012-05-01 15:47:55 +0800666 DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
667 || vmap_iter->second == method_offsets.vmap_table_offset_)
668 << PrettyMethod(method_idx, dex_file);
669 } else {
670 DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
Brian Carlstrom265091e2013-01-30 14:08:26 -0800671 || offset == method_offsets.vmap_table_offset_)
Logan Chien971bf3f2012-05-01 15:47:55 +0800672 << PrettyMethod(method_idx, dex_file);
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800673 if (!out.WriteFully(&vmap_table[0], vmap_table_size)) {
674 ReportWriteFailure("vmap table", method_idx, dex_file, out);
Logan Chien971bf3f2012-05-01 15:47:55 +0800675 return 0;
676 }
Brian Carlstrom265091e2013-01-30 14:08:26 -0800677 offset += vmap_table_size;
Logan Chien971bf3f2012-05-01 15:47:55 +0800678 }
Brian Carlstrom265091e2013-01-30 14:08:26 -0800679 DCHECK_OFFSET();
Logan Chien971bf3f2012-05-01 15:47:55 +0800680
Ian Rogers0c7abda2012-09-19 13:33:42 -0700681 const std::vector<uint8_t>& gc_map = compiled_method->GetNativeGcMap();
Logan Chien971bf3f2012-05-01 15:47:55 +0800682 size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]);
683
684 // Deduplicate GC maps
685 SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter =
686 gc_map_offsets_.find(&gc_map);
687 if (gc_map_iter != gc_map_offsets_.end() &&
Brian Carlstrom265091e2013-01-30 14:08:26 -0800688 offset != method_offsets.gc_map_offset_) {
Logan Chien971bf3f2012-05-01 15:47:55 +0800689 DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
690 || gc_map_iter->second == method_offsets.gc_map_offset_)
691 << PrettyMethod(method_idx, dex_file);
692 } else {
693 DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
Brian Carlstrom265091e2013-01-30 14:08:26 -0800694 || offset == method_offsets.gc_map_offset_)
Logan Chien971bf3f2012-05-01 15:47:55 +0800695 << PrettyMethod(method_idx, dex_file);
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800696 if (!out.WriteFully(&gc_map[0], gc_map_size)) {
697 ReportWriteFailure("GC map", method_idx, dex_file, out);
Logan Chien971bf3f2012-05-01 15:47:55 +0800698 return 0;
699 }
Brian Carlstrom265091e2013-01-30 14:08:26 -0800700 offset += gc_map_size;
Logan Chien971bf3f2012-05-01 15:47:55 +0800701 }
Brian Carlstrom265091e2013-01-30 14:08:26 -0800702 DCHECK_OFFSET();
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700703 }
Brian Carlstrom265091e2013-01-30 14:08:26 -0800704
705#if !defined(ART_USE_PORTABLE_COMPILER)
Ian Rogers0571d352011-11-03 19:51:38 -0700706 const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
Ian Rogers1212a022013-03-04 10:48:41 -0800707 const CompiledInvokeStub* compiled_invoke_stub = compiler_driver_->FindInvokeStub(is_static, shorty);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700708 if (compiled_invoke_stub != NULL) {
Brian Carlstrom265091e2013-01-30 14:08:26 -0800709 uint32_t aligned_offset = CompiledMethod::AlignCode(offset,
710 compiler_driver_->GetInstructionSet());
711 uint32_t aligned_code_delta = aligned_offset - offset;
Logan Chien971bf3f2012-05-01 15:47:55 +0800712 if (aligned_code_delta != 0) {
Brian Carlstrom49a0f152013-01-22 17:17:36 -0800713 off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent);
Brian Carlstrom265091e2013-01-30 14:08:26 -0800714 if (static_cast<uint32_t>(new_offset) != aligned_offset) {
Logan Chien971bf3f2012-05-01 15:47:55 +0800715 PLOG(ERROR) << "Failed to seek to align invoke stub code. Actual: " << new_offset
Brian Carlstrom265091e2013-01-30 14:08:26 -0800716 << " Expected: " << aligned_offset;
Logan Chien971bf3f2012-05-01 15:47:55 +0800717 return 0;
718 }
Brian Carlstrom265091e2013-01-30 14:08:26 -0800719 offset += aligned_code_delta;
720 DCHECK_OFFSET();
Logan Chien971bf3f2012-05-01 15:47:55 +0800721 }
Brian Carlstrom265091e2013-01-30 14:08:26 -0800722 DCHECK_ALIGNED(offset, kArmAlignment);
Logan Chien971bf3f2012-05-01 15:47:55 +0800723 const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
724 uint32_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
725 CHECK_NE(invoke_stub_size, 0U);
726
727 // Deduplicate invoke stubs
Brian Carlstrom265091e2013-01-30 14:08:26 -0800728 size_t invoke_stub_offset = offset + sizeof(invoke_stub_size) + compiled_invoke_stub->CodeDelta();
Logan Chien971bf3f2012-05-01 15:47:55 +0800729 SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter =
730 code_offsets_.find(&invoke_stub);
Brian Carlstrom265091e2013-01-30 14:08:26 -0800731 if (stub_iter != code_offsets_.end()
732 && invoke_stub_offset != method_offsets.invoke_stub_offset_) {
733 DCHECK(stub_iter->second == method_offsets.invoke_stub_offset_)
734 << PrettyMethod(method_idx, dex_file);
Logan Chien971bf3f2012-05-01 15:47:55 +0800735 } else {
Brian Carlstrom265091e2013-01-30 14:08:26 -0800736 DCHECK(invoke_stub_offset == method_offsets.invoke_stub_offset_) << PrettyMethod(method_idx, dex_file);
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800737 if (!out.WriteFully(&invoke_stub_size, sizeof(invoke_stub_size))) {
738 ReportWriteFailure("invoke stub code size", method_idx, dex_file, out);
Logan Chien971bf3f2012-05-01 15:47:55 +0800739 return 0;
740 }
Brian Carlstrom265091e2013-01-30 14:08:26 -0800741 offset += sizeof(invoke_stub_size);
742 DCHECK_OFFSET();
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800743 if (!out.WriteFully(&invoke_stub[0], invoke_stub_size)) {
744 ReportWriteFailure("invoke stub code", method_idx, dex_file, out);
Logan Chien971bf3f2012-05-01 15:47:55 +0800745 return 0;
746 }
Brian Carlstrom265091e2013-01-30 14:08:26 -0800747 offset += invoke_stub_size;
748 DCHECK_OFFSET();
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700749 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700750 }
Logan Chien971bf3f2012-05-01 15:47:55 +0800751#endif
Logan Chien8b977d32012-02-21 19:14:55 +0800752
Brian Carlstrom265091e2013-01-30 14:08:26 -0800753 return offset;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700754}
755
Brian Carlstrom265091e2013-01-30 14:08:26 -0800756OatWriter::OatDexFile::OatDexFile(size_t offset, const DexFile& dex_file) {
757 offset_ = offset;
Elliott Hughes95572412011-12-13 18:14:20 -0800758 const std::string& location(dex_file.GetLocation());
Brian Carlstrome24fa612011-09-29 00:53:55 -0700759 dex_file_location_size_ = location.size();
760 dex_file_location_data_ = reinterpret_cast<const uint8_t*>(location.data());
Brian Carlstrom5b332c82012-02-01 15:02:31 -0800761 dex_file_location_checksum_ = dex_file.GetLocationChecksum();
Brian Carlstrom89521892011-12-07 22:05:07 -0800762 dex_file_offset_ = 0;
Brian Carlstrom6e3b1d92012-01-11 01:36:32 -0800763 methods_offsets_.resize(dex_file.NumClassDefs());
Brian Carlstrome24fa612011-09-29 00:53:55 -0700764}
765
766size_t OatWriter::OatDexFile::SizeOf() const {
767 return sizeof(dex_file_location_size_)
768 + dex_file_location_size_
Brian Carlstrom5b332c82012-02-01 15:02:31 -0800769 + sizeof(dex_file_location_checksum_)
Brian Carlstrom89521892011-12-07 22:05:07 -0800770 + sizeof(dex_file_offset_)
Brian Carlstrom6e3b1d92012-01-11 01:36:32 -0800771 + (sizeof(methods_offsets_[0]) * methods_offsets_.size());
Brian Carlstrome24fa612011-09-29 00:53:55 -0700772}
773
774void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const {
775 oat_header.UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
776 oat_header.UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
Brian Carlstrom5b332c82012-02-01 15:02:31 -0800777 oat_header.UpdateChecksum(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_));
Brian Carlstrom89521892011-12-07 22:05:07 -0800778 oat_header.UpdateChecksum(&dex_file_offset_, sizeof(dex_file_offset_));
Brian Carlstrom6e3b1d92012-01-11 01:36:32 -0800779 oat_header.UpdateChecksum(&methods_offsets_[0],
780 sizeof(methods_offsets_[0]) * methods_offsets_.size());
Brian Carlstrome24fa612011-09-29 00:53:55 -0700781}
782
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800783bool OatWriter::OatDexFile::Write(OutputStream& out) const {
Brian Carlstrom265091e2013-01-30 14:08:26 -0800784 DCHECK_OFFSET_();
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800785 if (!out.WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
786 PLOG(ERROR) << "Failed to write dex file location length to " << out.GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700787 return false;
788 }
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800789 if (!out.WriteFully(dex_file_location_data_, dex_file_location_size_)) {
790 PLOG(ERROR) << "Failed to write dex file location data to " << out.GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700791 return false;
792 }
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800793 if (!out.WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
794 PLOG(ERROR) << "Failed to write dex file location checksum to " << out.GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700795 return false;
796 }
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800797 if (!out.WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
798 PLOG(ERROR) << "Failed to write dex file offset to " << out.GetLocation();
Brian Carlstrom89521892011-12-07 22:05:07 -0800799 return false;
800 }
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800801 if (!out.WriteFully(&methods_offsets_[0],
802 sizeof(methods_offsets_[0]) * methods_offsets_.size())) {
803 PLOG(ERROR) << "Failed to write methods offsets to " << out.GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700804 return false;
805 }
806 return true;
807}
808
Brian Carlstrom265091e2013-01-30 14:08:26 -0800809OatWriter::OatClass::OatClass(size_t offset, mirror::Class::Status status, uint32_t methods_count) {
810 offset_ = offset;
Brian Carlstrom0755ec52012-01-11 15:19:46 -0800811 status_ = status;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700812 method_offsets_.resize(methods_count);
813}
814
Brian Carlstrom265091e2013-01-30 14:08:26 -0800815size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatHeader(
816 size_t class_def_method_index_) const {
817 return offset_ + GetOatMethodOffsetsOffsetFromOatClass(class_def_method_index_);
818}
819
820size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatClass(
821 size_t class_def_method_index_) const {
Brian Carlstrom0755ec52012-01-11 15:19:46 -0800822 return sizeof(status_)
Brian Carlstrom265091e2013-01-30 14:08:26 -0800823 + (sizeof(method_offsets_[0]) * class_def_method_index_);
824}
825
826size_t OatWriter::OatClass::SizeOf() const {
827 return GetOatMethodOffsetsOffsetFromOatClass(method_offsets_.size());
Brian Carlstrome24fa612011-09-29 00:53:55 -0700828}
829
Brian Carlstrom389efb02012-01-11 12:06:26 -0800830void OatWriter::OatClass::UpdateChecksum(OatHeader& oat_header) const {
Brian Carlstrom0755ec52012-01-11 15:19:46 -0800831 oat_header.UpdateChecksum(&status_, sizeof(status_));
832 oat_header.UpdateChecksum(&method_offsets_[0],
833 sizeof(method_offsets_[0]) * method_offsets_.size());
Brian Carlstrome24fa612011-09-29 00:53:55 -0700834}
835
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800836bool OatWriter::OatClass::Write(OutputStream& out) const {
Brian Carlstrom265091e2013-01-30 14:08:26 -0800837 DCHECK_OFFSET_();
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800838 if (!out.WriteFully(&status_, sizeof(status_))) {
839 PLOG(ERROR) << "Failed to write class status to " << out.GetLocation();
Brian Carlstrom0755ec52012-01-11 15:19:46 -0800840 return false;
841 }
Brian Carlstrom265091e2013-01-30 14:08:26 -0800842 DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(0)),
843 out.Seek(0, kSeekCurrent));
Brian Carlstromcd60ac72013-01-20 17:09:51 -0800844 if (!out.WriteFully(&method_offsets_[0],
845 sizeof(method_offsets_[0]) * method_offsets_.size())) {
846 PLOG(ERROR) << "Failed to write method offsets to " << out.GetLocation();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700847 return false;
848 }
Brian Carlstrom265091e2013-01-30 14:08:26 -0800849 DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(method_offsets_.size())),
850 out.Seek(0, kSeekCurrent));
Brian Carlstrome24fa612011-09-29 00:53:55 -0700851 return true;
852}
853
Brian Carlstrome24fa612011-09-29 00:53:55 -0700854} // namespace art