blob: 3ab2fb914210f866542a6705f58823606f3b4ff3 [file] [log] [blame]
Brian Carlstrome24fa612011-09-29 00:53:55 -07001// Copyright 2011 Google Inc. All Rights Reserved.
2
3#include "oat_writer.h"
4
5#include "class_linker.h"
6#include "class_loader.h"
7#include "file.h"
8#include "os.h"
9#include "stl_util.h"
10
11namespace art {
12
Elliott Hughes234da572011-11-03 22:13:06 -070013bool OatWriter::Create(File* file,
Brian Carlstrom3320cf42011-10-04 14:58:28 -070014 const ClassLoader* class_loader,
15 const Compiler& compiler) {
Brian Carlstromaded5f72011-10-07 17:15:04 -070016 const std::vector<const DexFile*>& dex_files = ClassLoader::GetCompileTimeClassPath(class_loader);
Brian Carlstrom3320cf42011-10-04 14:58:28 -070017 OatWriter oat_writer(dex_files, class_loader, compiler);
Elliott Hughes234da572011-11-03 22:13:06 -070018 return oat_writer.Write(file);
Brian Carlstrome24fa612011-09-29 00:53:55 -070019}
20
Brian Carlstrom3320cf42011-10-04 14:58:28 -070021OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
22 const ClassLoader* class_loader,
23 const Compiler& compiler) {
24 compiler_ = &compiler;
Brian Carlstrome24fa612011-09-29 00:53:55 -070025 class_loader_ = class_loader;
26 dex_files_ = &dex_files;
Ian Rogers0571d352011-11-03 19:51:38 -070027 oat_header_ = NULL;
28 executable_offset_padding_length_ = 0;
Brian Carlstrome24fa612011-09-29 00:53:55 -070029
30 size_t offset = InitOatHeader();
31 offset = InitOatDexFiles(offset);
Brian Carlstrom89521892011-12-07 22:05:07 -080032 offset = InitDexFiles(offset);
Brian Carlstrome24fa612011-09-29 00:53:55 -070033 offset = InitOatClasses(offset);
34 offset = InitOatMethods(offset);
35 offset = InitOatCode(offset);
36 offset = InitOatCodeDexFiles(offset);
37
38 CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
39 CHECK_EQ(dex_files_->size(), oat_classes_.size());
40}
41
Ian Rogers0571d352011-11-03 19:51:38 -070042OatWriter::~OatWriter() {
43 delete oat_header_;
44 STLDeleteElements(&oat_dex_files_);
45 STLDeleteElements(&oat_classes_);
46 STLDeleteElements(&oat_methods_);
47}
48
Brian Carlstrome24fa612011-09-29 00:53:55 -070049size_t OatWriter::InitOatHeader() {
50 // create the OatHeader
51 oat_header_ = new OatHeader(dex_files_);
52 size_t offset = sizeof(*oat_header_);
53 return offset;
54}
55
56size_t OatWriter::InitOatDexFiles(size_t offset) {
57 // create the OatDexFiles
58 for (size_t i = 0; i != dex_files_->size(); ++i) {
59 const DexFile* dex_file = (*dex_files_)[i];
60 CHECK(dex_file != NULL);
61 OatDexFile* oat_dex_file = new OatDexFile(*dex_file);
62 oat_dex_files_.push_back(oat_dex_file);
63 offset += oat_dex_file->SizeOf();
64 }
65 return offset;
66}
67
Brian Carlstrom89521892011-12-07 22:05:07 -080068size_t OatWriter::InitDexFiles(size_t offset) {
69 // calculate the offsets within OatDexFiles to the DexFiles
70 for (size_t i = 0; i != dex_files_->size(); ++i) {
71 // dex files are required to be 4 byte aligned
72 offset = RoundUp(offset, 4);
73
74 // set offset in OatDexFile to DexFile
75 oat_dex_files_[i]->dex_file_offset_ = offset;
76
77 const DexFile* dex_file = (*dex_files_)[i];
78 offset += dex_file->GetHeader().file_size_;
79 }
80 return offset;
81}
82
Brian Carlstrome24fa612011-09-29 00:53:55 -070083size_t OatWriter::InitOatClasses(size_t offset) {
84 // create the OatClasses
85 // calculate the offsets within OatDexFiles to OatClasses
86 for (size_t i = 0; i != dex_files_->size(); ++i) {
87 // set offset in OatDexFile to OatClasses
88 oat_dex_files_[i]->classes_offset_ = offset;
89 oat_dex_files_[i]->UpdateChecksum(*oat_header_);
90
91 const DexFile* dex_file = (*dex_files_)[i];
92 OatClasses* oat_classes = new OatClasses(*dex_file);
93 oat_classes_.push_back(oat_classes);
94 offset += oat_classes->SizeOf();
95 }
96 return offset;
97}
98
99size_t OatWriter::InitOatMethods(size_t offset) {
100 // create the OatMethods
101 // calculate the offsets within OatClasses to OatMethods
102 size_t class_index = 0;
103 for (size_t i = 0; i != dex_files_->size(); ++i) {
104 const DexFile* dex_file = (*dex_files_)[i];
105 for (size_t class_def_index = 0;
106 class_def_index < dex_file->NumClassDefs();
107 class_def_index++, class_index++) {
108 oat_classes_[i]->methods_offsets_[class_def_index] = offset;
109 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
110 const byte* class_data = dex_file->GetClassData(class_def);
Ian Rogers0571d352011-11-03 19:51:38 -0700111 uint32_t num_methods = 0;
112 if (class_data != NULL) { // ie not an empty class, such as a marker interface
113 ClassDataItemIterator it(*dex_file, class_data);
114 size_t num_direct_methods = it.NumDirectMethods();
115 size_t num_virtual_methods = it.NumVirtualMethods();
116 num_methods = num_direct_methods + num_virtual_methods;
117 }
Brian Carlstrome24fa612011-09-29 00:53:55 -0700118 OatMethods* oat_methods = new OatMethods(num_methods);
119 oat_methods_.push_back(oat_methods);
120 offset += oat_methods->SizeOf();
121 }
122 oat_classes_[i]->UpdateChecksum(*oat_header_);
123 }
124 return offset;
125}
126
127size_t OatWriter::InitOatCode(size_t offset) {
128 // calculate the offsets within OatHeader to executable code
129 size_t old_offset = offset;
130 // required to be on a new page boundary
131 offset = RoundUp(offset, kPageSize);
132 oat_header_->SetExecutableOffset(offset);
133 executable_offset_padding_length_ = offset - old_offset;
134 return offset;
135}
136
137size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
138 // calculate the offsets within OatMethods
139 size_t oat_class_index = 0;
140 for (size_t i = 0; i != dex_files_->size(); ++i) {
141 const DexFile* dex_file = (*dex_files_)[i];
142 CHECK(dex_file != NULL);
143 offset = InitOatCodeDexFile(offset, oat_class_index, *dex_file);
144 }
145 return offset;
146}
147
148size_t OatWriter::InitOatCodeDexFile(size_t offset,
149 size_t& oat_class_index,
150 const DexFile& dex_file) {
151 for (size_t class_def_index = 0;
152 class_def_index < dex_file.NumClassDefs();
153 class_def_index++, oat_class_index++) {
154 const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
155 offset = InitOatCodeClassDef(offset, oat_class_index, dex_file, class_def);
156 oat_methods_[oat_class_index]->UpdateChecksum(*oat_header_);
157 }
158 return offset;
159}
160
161size_t OatWriter::InitOatCodeClassDef(size_t offset,
162 size_t oat_class_index,
163 const DexFile& dex_file,
164 const DexFile::ClassDef& class_def) {
165 const byte* class_data = dex_file.GetClassData(class_def);
Ian Rogers0571d352011-11-03 19:51:38 -0700166 if (class_data == NULL) {
167 // empty class, such as a marker interface
Ian Rogers387b6992011-10-31 17:52:37 -0700168 return offset;
169 }
Ian Rogers0571d352011-11-03 19:51:38 -0700170 ClassDataItemIterator it(dex_file, class_data);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700171 CHECK_EQ(oat_methods_[oat_class_index]->method_offsets_.size(),
Ian Rogers0571d352011-11-03 19:51:38 -0700172 it.NumDirectMethods() + it.NumVirtualMethods());
173 // Skip fields
174 while (it.HasNextStaticField()) {
175 it.Next();
176 }
177 while (it.HasNextInstanceField()) {
178 it.Next();
179 }
180 // Process methods
Brian Carlstrome24fa612011-09-29 00:53:55 -0700181 size_t class_def_method_index = 0;
Ian Rogers0571d352011-11-03 19:51:38 -0700182 while (it.HasNextDirectMethod()) {
183 bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0;
184 offset = InitOatCodeMethod(offset, oat_class_index, class_def_method_index, is_static, true,
185 it.GetMemberIndex(), &dex_file);
186 class_def_method_index++;
187 it.Next();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700188 }
Ian Rogers0571d352011-11-03 19:51:38 -0700189 while (it.HasNextVirtualMethod()) {
190 CHECK_EQ(it.GetMemberAccessFlags() & kAccStatic, 0U);
191 offset = InitOatCodeMethod(offset, oat_class_index, class_def_method_index, false, false,
192 it.GetMemberIndex(), &dex_file);
193 class_def_method_index++;
194 it.Next();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700195 }
Ian Rogers0571d352011-11-03 19:51:38 -0700196 DCHECK(!it.HasNext());
Brian Carlstrome24fa612011-09-29 00:53:55 -0700197 return offset;
198}
199
Ian Rogers0571d352011-11-03 19:51:38 -0700200size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index,
201 size_t class_def_method_index, bool is_static, bool is_direct,
202 uint32_t method_idx, const DexFile* dex_file) {
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700203 // derived from CompiledMethod if available
204 uint32_t code_offset = 0;
205 uint32_t frame_size_in_bytes = kStackAlignment;
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700206 uint32_t core_spill_mask = 0;
207 uint32_t fp_spill_mask = 0;
208 uint32_t mapping_table_offset = 0;
209 uint32_t vmap_table_offset = 0;
210 // derived from CompiledInvokeStub if available
211 uint32_t invoke_stub_offset = 0;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700212
Ian Rogers0571d352011-11-03 19:51:38 -0700213 CompiledMethod* compiled_method =
214 compiler_->GetCompiledMethod(art::Compiler::MethodReference(dex_file, method_idx));
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700215 if (compiled_method != NULL) {
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700216 offset = compiled_method->AlignCode(offset);
Elliott Hughes06b37d92011-10-16 11:51:29 -0700217 DCHECK_ALIGNED(offset, kArmAlignment);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700218 const std::vector<uint8_t>& code = compiled_method->GetCode();
219 size_t code_size = code.size() * sizeof(code[0]);
220 uint32_t thumb_offset = compiled_method->CodeDelta();
221 code_offset = (code_size == 0) ? 0 : offset + thumb_offset;
jeffhao55d78212011-11-02 11:41:50 -0700222
223 // Deduplicate code arrays
jeffhaof479dcc2011-11-02 15:54:15 -0700224 std::map<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code);
jeffhao55d78212011-11-02 11:41:50 -0700225 if (code_iter != code_offsets_.end()) {
226 code_offset = code_iter->second;
227 } else {
jeffhaof479dcc2011-11-02 15:54:15 -0700228 code_offsets_.insert(std::pair<const std::vector<uint8_t>*, uint32_t>(&code, code_offset));
jeffhao55d78212011-11-02 11:41:50 -0700229 offset += code_size;
230 oat_header_->UpdateChecksum(&code[0], code_size);
231 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700232
233 frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700234 core_spill_mask = compiled_method->GetCoreSpillMask();
235 fp_spill_mask = compiled_method->GetFpSpillMask();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700236 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700237
238 offset += sizeof(frame_size_in_bytes);
239 oat_header_->UpdateChecksum(&frame_size_in_bytes, sizeof(frame_size_in_bytes));
240
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700241 offset += sizeof(core_spill_mask);
242 oat_header_->UpdateChecksum(&core_spill_mask, sizeof(core_spill_mask));
243
244 offset += sizeof(fp_spill_mask);
245 oat_header_->UpdateChecksum(&fp_spill_mask, sizeof(fp_spill_mask));
246
247 if (compiled_method != NULL) {
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700248 const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
249 size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
250 mapping_table_offset = (mapping_table_size == 0) ? 0 : offset;
jeffhao55d78212011-11-02 11:41:50 -0700251
252 // Deduplicate mapping tables
jeffhaof479dcc2011-11-02 15:54:15 -0700253 std::map<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter = mapping_table_offsets_.find(&mapping_table);
jeffhao55d78212011-11-02 11:41:50 -0700254 if (mapping_iter != mapping_table_offsets_.end()) {
255 mapping_table_offset = mapping_iter->second;
256 } else {
jeffhaof479dcc2011-11-02 15:54:15 -0700257 mapping_table_offsets_.insert(std::pair<const std::vector<uint32_t>*, uint32_t>(&mapping_table, mapping_table_offset));
jeffhao55d78212011-11-02 11:41:50 -0700258 offset += mapping_table_size;
259 oat_header_->UpdateChecksum(&mapping_table[0], mapping_table_size);
260 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700261
262 const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
263 size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
264 vmap_table_offset = (vmap_table_size == 0) ? 0 : offset;
jeffhao55d78212011-11-02 11:41:50 -0700265
266 // Deduplicate vmap tables
jeffhaof479dcc2011-11-02 15:54:15 -0700267 std::map<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter = vmap_table_offsets_.find(&vmap_table);
jeffhao55d78212011-11-02 11:41:50 -0700268 if (vmap_iter != vmap_table_offsets_.end()) {
269 vmap_table_offset = vmap_iter->second;
270 } else {
jeffhaof479dcc2011-11-02 15:54:15 -0700271 vmap_table_offsets_.insert(std::pair<const std::vector<uint16_t>*, uint32_t>(&vmap_table, vmap_table_offset));
jeffhao55d78212011-11-02 11:41:50 -0700272 offset += vmap_table_size;
273 oat_header_->UpdateChecksum(&vmap_table[0], vmap_table_size);
274 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700275 }
276
Ian Rogers0571d352011-11-03 19:51:38 -0700277 const char* shorty = dex_file->GetMethodShorty(dex_file->GetMethodId(method_idx));
278 const CompiledInvokeStub* compiled_invoke_stub = compiler_->FindInvokeStub(is_static, shorty);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700279 if (compiled_invoke_stub != NULL) {
280 offset = CompiledMethod::AlignCode(offset, compiler_->GetInstructionSet());
Elliott Hughes06b37d92011-10-16 11:51:29 -0700281 DCHECK_ALIGNED(offset, kArmAlignment);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700282 const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
283 size_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
284 invoke_stub_offset = (invoke_stub_size == 0) ? 0 : offset;
jeffhao55d78212011-11-02 11:41:50 -0700285
286 // Deduplicate invoke stubs
jeffhaof479dcc2011-11-02 15:54:15 -0700287 std::map<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter = code_offsets_.find(&invoke_stub);
jeffhao55d78212011-11-02 11:41:50 -0700288 if (stub_iter != code_offsets_.end()) {
289 invoke_stub_offset = stub_iter->second;
290 } else {
jeffhaof479dcc2011-11-02 15:54:15 -0700291 code_offsets_.insert(std::pair<const std::vector<uint8_t>*, uint32_t>(&invoke_stub, invoke_stub_offset));
jeffhao55d78212011-11-02 11:41:50 -0700292 offset += invoke_stub_size;
293 oat_header_->UpdateChecksum(&invoke_stub[0], invoke_stub_size);
294 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700295 }
296
297 oat_methods_[oat_class_index]->method_offsets_[class_def_method_index]
298 = OatMethodOffsets(code_offset,
299 frame_size_in_bytes,
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700300 core_spill_mask,
301 fp_spill_mask,
302 mapping_table_offset,
303 vmap_table_offset,
304 invoke_stub_offset);
305
Ian Rogers0571d352011-11-03 19:51:38 -0700306 if (compiler_->IsImage()) {
307 ClassLinker* linker = Runtime::Current()->GetClassLinker();
308 DexCache* dex_cache = linker->FindDexCache(*dex_file);
309 Method* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache, class_loader_,
310 is_direct);
311 CHECK(method != NULL);
312 method->SetFrameSizeInBytes(frame_size_in_bytes);
313 method->SetCoreSpillMask(core_spill_mask);
314 method->SetFpSpillMask(fp_spill_mask);
315 method->SetOatMappingTableOffset(mapping_table_offset);
316 method->SetOatCodeOffset(code_offset);
317 method->SetOatVmapTableOffset(vmap_table_offset);
318 method->SetOatInvokeStubOffset(invoke_stub_offset);
319 }
Brian Carlstrome24fa612011-09-29 00:53:55 -0700320 return offset;
321}
322
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700323#define DCHECK_CODE_OFFSET() \
Brian Carlstrom89521892011-12-07 22:05:07 -0800324 DCHECK_EQ(static_cast<off64_t>(code_offset), lseek64(file->Fd(), 0, SEEK_CUR))
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700325
Elliott Hughes234da572011-11-03 22:13:06 -0700326bool OatWriter::Write(File* file) {
Brian Carlstrome24fa612011-09-29 00:53:55 -0700327 if (!file->WriteFully(oat_header_, sizeof(*oat_header_))) {
Elliott Hughes234da572011-11-03 22:13:06 -0700328 PLOG(ERROR) << "Failed to write oat header to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700329 return false;
330 }
331
Elliott Hughes234da572011-11-03 22:13:06 -0700332 if (!WriteTables(file)) {
333 LOG(ERROR) << "Failed to write oat tables to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700334 return false;
335 }
336
Elliott Hughes234da572011-11-03 22:13:06 -0700337 size_t code_offset = WriteCode(file);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700338 if (code_offset == 0) {
Elliott Hughes234da572011-11-03 22:13:06 -0700339 LOG(ERROR) << "Failed to write oat code to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700340 return false;
341 }
342
Elliott Hughes234da572011-11-03 22:13:06 -0700343 code_offset = WriteCodeDexFiles(file, code_offset);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700344 if (code_offset == 0) {
Elliott Hughes234da572011-11-03 22:13:06 -0700345 LOG(ERROR) << "Failed to write oat code for dex files to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700346 return false;
347 }
348
349 return true;
350}
351
352bool OatWriter::WriteTables(File* file) {
353 for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
354 if (!oat_dex_files_[i]->Write(file)) {
Elliott Hughes234da572011-11-03 22:13:06 -0700355 PLOG(ERROR) << "Failed to write oat dex information to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700356 return false;
357 }
358 }
Brian Carlstrom89521892011-12-07 22:05:07 -0800359 for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
360 uint32_t expected_offset = oat_dex_files_[i]->dex_file_offset_;
361 off64_t actual_offset = lseek64(file->Fd(), expected_offset, SEEK_SET);
362 if (static_cast<uint32_t>(actual_offset) != expected_offset) {
363 const DexFile* dex_file = (*dex_files_)[i];
364 PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
365 << " Expected: " << expected_offset << " File: " << dex_file->GetLocation();
366 return false;
367 }
368 const DexFile* dex_file = (*dex_files_)[i];
369 if (!file->WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) {
370 PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation() << " to " << file->name();
371 return false;
372 }
373 }
Brian Carlstrome24fa612011-09-29 00:53:55 -0700374 for (size_t i = 0; i != oat_classes_.size(); ++i) {
375 if (!oat_classes_[i]->Write(file)) {
Elliott Hughes234da572011-11-03 22:13:06 -0700376 PLOG(ERROR) << "Failed to write oat classes information to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700377 return false;
378 }
379 }
380 for (size_t i = 0; i != oat_methods_.size(); ++i) {
381 if (!oat_methods_[i]->Write(file)) {
Elliott Hughes234da572011-11-03 22:13:06 -0700382 PLOG(ERROR) << "Failed to write oat methods information to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700383 return false;
384 }
385 }
386 return true;
387}
388
389size_t OatWriter::WriteCode(File* file) {
390 uint32_t code_offset = oat_header_->GetExecutableOffset();
Brian Carlstrom89521892011-12-07 22:05:07 -0800391 off64_t new_offset = lseek64(file->Fd(), executable_offset_padding_length_, SEEK_CUR);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700392 if (static_cast<uint32_t>(new_offset) != code_offset) {
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700393 PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
Elliott Hughes234da572011-11-03 22:13:06 -0700394 << " Expected: " << code_offset << " File: " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700395 return 0;
396 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700397 DCHECK_CODE_OFFSET();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700398 return code_offset;
399}
400
401size_t OatWriter::WriteCodeDexFiles(File* file, size_t code_offset) {
Ian Rogers0571d352011-11-03 19:51:38 -0700402 size_t oat_class_index = 0;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700403 for (size_t i = 0; i != oat_classes_.size(); ++i) {
404 const DexFile* dex_file = (*dex_files_)[i];
405 CHECK(dex_file != NULL);
Ian Rogers0571d352011-11-03 19:51:38 -0700406 code_offset = WriteCodeDexFile(file, code_offset, oat_class_index, *dex_file);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700407 if (code_offset == 0) {
408 return 0;
409 }
410 }
411 return code_offset;
412}
413
Ian Rogers0571d352011-11-03 19:51:38 -0700414size_t OatWriter::WriteCodeDexFile(File* file, size_t code_offset, size_t& oat_class_index,
415 const DexFile& dex_file) {
416 for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs();
417 class_def_index++, oat_class_index++) {
Brian Carlstrome24fa612011-09-29 00:53:55 -0700418 const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
Ian Rogers0571d352011-11-03 19:51:38 -0700419 code_offset = WriteCodeClassDef(file, code_offset, oat_class_index, dex_file, class_def);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700420 if (code_offset == 0) {
421 return 0;
422 }
423 }
424 return code_offset;
425}
426
Ian Rogers0571d352011-11-03 19:51:38 -0700427void OatWriter::ReportWriteFailure(const char* what, uint32_t method_idx,
428 const DexFile& dex_file, File* f) const {
429 PLOG(ERROR) << "Failed to write " << what << " for " << PrettyMethod(method_idx, dex_file)
430 << " to " << f->name();
Elliott Hughes234da572011-11-03 22:13:06 -0700431}
432
Brian Carlstrome24fa612011-09-29 00:53:55 -0700433size_t OatWriter::WriteCodeClassDef(File* file,
Ian Rogers0571d352011-11-03 19:51:38 -0700434 size_t code_offset, size_t oat_class_index,
Brian Carlstrome24fa612011-09-29 00:53:55 -0700435 const DexFile& dex_file,
436 const DexFile::ClassDef& class_def) {
Brian Carlstrome24fa612011-09-29 00:53:55 -0700437 const byte* class_data = dex_file.GetClassData(class_def);
Ian Rogers0571d352011-11-03 19:51:38 -0700438 if (class_data == NULL) {
439 // ie. an empty class such as a marker interface
Ian Rogers387b6992011-10-31 17:52:37 -0700440 return code_offset;
441 }
Ian Rogers0571d352011-11-03 19:51:38 -0700442 ClassDataItemIterator it(dex_file, class_data);
443 // Skip fields
444 while (it.HasNextStaticField()) {
445 it.Next();
446 }
447 while (it.HasNextInstanceField()) {
448 it.Next();
449 }
450 // Process methods
451 size_t class_def_method_index = 0;
452 while (it.HasNextDirectMethod()) {
453 bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0;
454 code_offset = WriteCodeMethod(file, code_offset, oat_class_index, class_def_method_index,
455 is_static, it.GetMemberIndex(), dex_file);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700456 if (code_offset == 0) {
457 return 0;
458 }
Ian Rogers0571d352011-11-03 19:51:38 -0700459 class_def_method_index++;
460 it.Next();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700461 }
Ian Rogers0571d352011-11-03 19:51:38 -0700462 while (it.HasNextVirtualMethod()) {
463 code_offset = WriteCodeMethod(file, code_offset, oat_class_index, class_def_method_index,
464 false, it.GetMemberIndex(), dex_file);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700465 if (code_offset == 0) {
466 return 0;
467 }
Ian Rogers0571d352011-11-03 19:51:38 -0700468 class_def_method_index++;
469 it.Next();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700470 }
471 return code_offset;
472}
473
Ian Rogers0571d352011-11-03 19:51:38 -0700474size_t OatWriter::WriteCodeMethod(File* file, size_t code_offset, size_t oat_class_index,
475 size_t class_def_method_index, bool is_static,
476 uint32_t method_idx, const DexFile& dex_file) {
477 const CompiledMethod* compiled_method =
478 compiler_->GetCompiledMethod(art::Compiler::MethodReference(&dex_file, method_idx));
479
480 uint32_t frame_size_in_bytes = 0;
481 uint32_t core_spill_mask = 0;
482 uint32_t fp_spill_mask = 0;
483
484 OatMethodOffsets method_offsets =
485 oat_methods_[oat_class_index]->method_offsets_[class_def_method_index];
486
487
488 if (compiled_method != NULL) { // ie. not an abstract method
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700489 uint32_t aligned_code_offset = compiled_method->AlignCode(code_offset);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700490 uint32_t aligned_code_delta = aligned_code_offset - code_offset;
491 if (aligned_code_delta != 0) {
Brian Carlstrom89521892011-12-07 22:05:07 -0800492 off64_t new_offset = lseek64(file->Fd(), aligned_code_delta, SEEK_CUR);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700493 if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700494 PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
Elliott Hughes234da572011-11-03 22:13:06 -0700495 << " Expected: " << aligned_code_offset << " File: " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700496 return false;
497 }
498 code_offset += aligned_code_delta;
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700499 DCHECK_CODE_OFFSET();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700500 }
Elliott Hughes06b37d92011-10-16 11:51:29 -0700501 DCHECK_ALIGNED(code_offset, kArmAlignment);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700502 const std::vector<uint8_t>& code = compiled_method->GetCode();
503 size_t code_size = code.size() * sizeof(code[0]);
jeffhao55d78212011-11-02 11:41:50 -0700504
505 // Deduplicate code arrays
506 size_t offset = code_offset + compiled_method->CodeDelta();
jeffhaof479dcc2011-11-02 15:54:15 -0700507 std::map<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code);
Ian Rogers0571d352011-11-03 19:51:38 -0700508 if (code_iter != code_offsets_.end() && offset != method_offsets.code_offset_) {
509 DCHECK((code_size == 0 && method_offsets.code_offset_ == 0)
510 || code_iter->second == method_offsets.code_offset_)
511 << PrettyMethod(method_idx, dex_file);
jeffhao55d78212011-11-02 11:41:50 -0700512 } else {
Ian Rogers0571d352011-11-03 19:51:38 -0700513 DCHECK((code_size == 0 && method_offsets.code_offset_ == 0)
514 || offset == method_offsets.code_offset_)
515 << PrettyMethod(method_idx, dex_file);
jeffhao55d78212011-11-02 11:41:50 -0700516 if (!file->WriteFully(&code[0], code_size)) {
Ian Rogers0571d352011-11-03 19:51:38 -0700517 ReportWriteFailure("method code", method_idx, dex_file, file);
jeffhao55d78212011-11-02 11:41:50 -0700518 return false;
519 }
520 code_offset += code_size;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700521 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700522 DCHECK_CODE_OFFSET();
Ian Rogers0571d352011-11-03 19:51:38 -0700523 frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
524 core_spill_mask = compiled_method->GetCoreSpillMask();
525 fp_spill_mask = compiled_method->GetFpSpillMask();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700526 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700527
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700528 if (!file->WriteFully(&frame_size_in_bytes, sizeof(frame_size_in_bytes))) {
Ian Rogers0571d352011-11-03 19:51:38 -0700529 ReportWriteFailure("method frame size", method_idx, dex_file, file);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700530 return false;
531 }
532 code_offset += sizeof(frame_size_in_bytes);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700533 if (!file->WriteFully(&core_spill_mask, sizeof(core_spill_mask))) {
Ian Rogers0571d352011-11-03 19:51:38 -0700534 ReportWriteFailure("method core spill mask", method_idx, dex_file, file);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700535 return false;
536 }
537 code_offset += sizeof(core_spill_mask);
538 if (!file->WriteFully(&fp_spill_mask, sizeof(fp_spill_mask))) {
Ian Rogers0571d352011-11-03 19:51:38 -0700539 ReportWriteFailure("method fp spill mask", method_idx, dex_file, file);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700540 return false;
541 }
542 code_offset += sizeof(fp_spill_mask);
543
544 if (compiled_method != NULL) {
545 const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
546 size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
jeffhao55d78212011-11-02 11:41:50 -0700547
548 // Deduplicate mapping tables
Ian Rogers0571d352011-11-03 19:51:38 -0700549 std::map<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter =
550 mapping_table_offsets_.find(&mapping_table);
551 if (mapping_iter != mapping_table_offsets_.end() &&
552 code_offset != method_offsets.mapping_table_offset_) {
553 DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
554 || mapping_iter->second == method_offsets.mapping_table_offset_)
555 << PrettyMethod(method_idx, dex_file);
jeffhao55d78212011-11-02 11:41:50 -0700556 } else {
Ian Rogers0571d352011-11-03 19:51:38 -0700557 DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
558 || code_offset == method_offsets.mapping_table_offset_)
559 << PrettyMethod(method_idx, dex_file);
jeffhao55d78212011-11-02 11:41:50 -0700560 if (!file->WriteFully(&mapping_table[0], mapping_table_size)) {
Ian Rogers0571d352011-11-03 19:51:38 -0700561 ReportWriteFailure("mapping table", method_idx, dex_file, file);
jeffhao55d78212011-11-02 11:41:50 -0700562 return false;
563 }
564 code_offset += mapping_table_size;
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700565 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700566 DCHECK_CODE_OFFSET();
567
568 const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
569 size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
jeffhao55d78212011-11-02 11:41:50 -0700570
571 // Deduplicate vmap tables
Ian Rogers0571d352011-11-03 19:51:38 -0700572 std::map<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter =
573 vmap_table_offsets_.find(&vmap_table);
574 if (vmap_iter != vmap_table_offsets_.end() &&
575 code_offset != method_offsets.vmap_table_offset_) {
576 DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
577 || vmap_iter->second == method_offsets.vmap_table_offset_)
578 << PrettyMethod(method_idx, dex_file);
jeffhao55d78212011-11-02 11:41:50 -0700579 } else {
Ian Rogers0571d352011-11-03 19:51:38 -0700580 DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
581 || code_offset == method_offsets.vmap_table_offset_)
582 << PrettyMethod(method_idx, dex_file);
jeffhao55d78212011-11-02 11:41:50 -0700583 if (!file->WriteFully(&vmap_table[0], vmap_table_size)) {
Ian Rogers0571d352011-11-03 19:51:38 -0700584 ReportWriteFailure("vmap table", method_idx, dex_file, file);
jeffhao55d78212011-11-02 11:41:50 -0700585 return false;
586 }
587 code_offset += vmap_table_size;
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700588 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700589 DCHECK_CODE_OFFSET();
590 }
Ian Rogers0571d352011-11-03 19:51:38 -0700591 const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
592 const CompiledInvokeStub* compiled_invoke_stub = compiler_->FindInvokeStub(is_static, shorty);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700593 if (compiled_invoke_stub != NULL) {
594 uint32_t aligned_code_offset = CompiledMethod::AlignCode(code_offset,
595 compiler_->GetInstructionSet());
596 uint32_t aligned_code_delta = aligned_code_offset - code_offset;
597 if (aligned_code_delta != 0) {
Brian Carlstrom89521892011-12-07 22:05:07 -0800598 off64_t new_offset = lseek64(file->Fd(), aligned_code_delta, SEEK_CUR);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700599 if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
600 PLOG(ERROR) << "Failed to seek to align invoke stub code. Actual: " << new_offset
601 << " Expected: " << aligned_code_offset;
602 return false;
603 }
604 code_offset += aligned_code_delta;
605 DCHECK_CODE_OFFSET();
606 }
Elliott Hughes06b37d92011-10-16 11:51:29 -0700607 DCHECK_ALIGNED(code_offset, kArmAlignment);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700608 const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
609 size_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
jeffhao55d78212011-11-02 11:41:50 -0700610
611 // Deduplicate invoke stubs
Ian Rogers0571d352011-11-03 19:51:38 -0700612 std::map<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter =
613 code_offsets_.find(&invoke_stub);
614 if (stub_iter != code_offsets_.end() &&
615 code_offset != method_offsets.invoke_stub_offset_) {
616 DCHECK((invoke_stub_size == 0 && method_offsets.invoke_stub_offset_ == 0)
617 || stub_iter->second == method_offsets.invoke_stub_offset_)
618 << PrettyMethod(method_idx, dex_file);
jeffhao55d78212011-11-02 11:41:50 -0700619 } else {
Ian Rogers0571d352011-11-03 19:51:38 -0700620 DCHECK((invoke_stub_size == 0 && method_offsets.invoke_stub_offset_ == 0)
621 || code_offset == method_offsets.invoke_stub_offset_)
622 << PrettyMethod(method_idx, dex_file);
jeffhao55d78212011-11-02 11:41:50 -0700623 if (!file->WriteFully(&invoke_stub[0], invoke_stub_size)) {
Ian Rogers0571d352011-11-03 19:51:38 -0700624 ReportWriteFailure("invoke stub code", method_idx, dex_file, file);
jeffhao55d78212011-11-02 11:41:50 -0700625 return false;
626 }
627 code_offset += invoke_stub_size;
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700628 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700629 DCHECK_CODE_OFFSET();
630 }
Brian Carlstrome24fa612011-09-29 00:53:55 -0700631 return code_offset;
632}
633
Brian Carlstrome24fa612011-09-29 00:53:55 -0700634OatWriter::OatDexFile::OatDexFile(const DexFile& dex_file) {
Elliott Hughes95572412011-12-13 18:14:20 -0800635 const std::string& location(dex_file.GetLocation());
Brian Carlstrome24fa612011-09-29 00:53:55 -0700636 dex_file_location_size_ = location.size();
637 dex_file_location_data_ = reinterpret_cast<const uint8_t*>(location.data());
638 dex_file_checksum_ = dex_file.GetHeader().checksum_;
Brian Carlstrom89521892011-12-07 22:05:07 -0800639 dex_file_offset_ = 0;
Ian Rogers0571d352011-11-03 19:51:38 -0700640 classes_offset_ = 0;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700641}
642
643size_t OatWriter::OatDexFile::SizeOf() const {
644 return sizeof(dex_file_location_size_)
645 + dex_file_location_size_
646 + sizeof(dex_file_checksum_)
Brian Carlstrom89521892011-12-07 22:05:07 -0800647 + sizeof(dex_file_offset_)
Brian Carlstrome24fa612011-09-29 00:53:55 -0700648 + sizeof(classes_offset_);
649}
650
651void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const {
652 oat_header.UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
653 oat_header.UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
654 oat_header.UpdateChecksum(&dex_file_checksum_, sizeof(dex_file_checksum_));
Brian Carlstrom89521892011-12-07 22:05:07 -0800655 oat_header.UpdateChecksum(&dex_file_offset_, sizeof(dex_file_offset_));
Brian Carlstrome24fa612011-09-29 00:53:55 -0700656 oat_header.UpdateChecksum(&classes_offset_, sizeof(classes_offset_));
657}
658
659bool OatWriter::OatDexFile::Write(File* file) const {
660 if (!file->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
Elliott Hughes234da572011-11-03 22:13:06 -0700661 PLOG(ERROR) << "Failed to write dex file location length to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700662 return false;
663 }
664 if (!file->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
Elliott Hughes234da572011-11-03 22:13:06 -0700665 PLOG(ERROR) << "Failed to write dex file location data to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700666 return false;
667 }
668 if (!file->WriteFully(&dex_file_checksum_, sizeof(dex_file_checksum_))) {
Elliott Hughes234da572011-11-03 22:13:06 -0700669 PLOG(ERROR) << "Failed to write dex file checksum to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700670 return false;
671 }
Brian Carlstrom89521892011-12-07 22:05:07 -0800672 if (!file->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
673 PLOG(ERROR) << "Failed to write dex file offset to " << file->name();
674 return false;
675 }
Brian Carlstrome24fa612011-09-29 00:53:55 -0700676 if (!file->WriteFully(&classes_offset_, sizeof(classes_offset_))) {
Elliott Hughes234da572011-11-03 22:13:06 -0700677 PLOG(ERROR) << "Failed to write classes offset to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700678 return false;
679 }
680 return true;
681}
682
683OatWriter::OatClasses::OatClasses(const DexFile& dex_file) {
684 methods_offsets_.resize(dex_file.NumClassDefs());
685}
686
687size_t OatWriter::OatClasses::SizeOf() const {
688 return (sizeof(methods_offsets_[0]) * methods_offsets_.size());
689}
690
691void OatWriter::OatClasses::UpdateChecksum(OatHeader& oat_header) const {
692 oat_header.UpdateChecksum(&methods_offsets_[0], SizeOf());
693}
694
695bool OatWriter::OatClasses::Write(File* file) const {
696 if (!file->WriteFully(&methods_offsets_[0], SizeOf())) {
Elliott Hughes234da572011-11-03 22:13:06 -0700697 PLOG(ERROR) << "Failed to write methods offsets to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700698 return false;
699 }
700 return true;
701}
702
703OatWriter::OatMethods::OatMethods(uint32_t methods_count) {
704 method_offsets_.resize(methods_count);
705}
706
707size_t OatWriter::OatMethods::SizeOf() const {
708 return (sizeof(method_offsets_[0]) * method_offsets_.size());
709}
710
711void OatWriter::OatMethods::UpdateChecksum(OatHeader& oat_header) const {
712 oat_header.UpdateChecksum(&method_offsets_[0], SizeOf());
713}
714
715bool OatWriter::OatMethods::Write(File* file) const {
716 if (!file->WriteFully(&method_offsets_[0], SizeOf())) {
Elliott Hughes234da572011-11-03 22:13:06 -0700717 PLOG(ERROR) << "Failed to write method offsets to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700718 return false;
719 }
720 return true;
721}
722
723} // namespace art