blob: f3e78e6250e11ea37755b93760599d833f6d2753 [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);
32 offset = InitOatClasses(offset);
33 offset = InitOatMethods(offset);
34 offset = InitOatCode(offset);
35 offset = InitOatCodeDexFiles(offset);
36
37 CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
38 CHECK_EQ(dex_files_->size(), oat_classes_.size());
39}
40
Ian Rogers0571d352011-11-03 19:51:38 -070041OatWriter::~OatWriter() {
42 delete oat_header_;
43 STLDeleteElements(&oat_dex_files_);
44 STLDeleteElements(&oat_classes_);
45 STLDeleteElements(&oat_methods_);
46}
47
Brian Carlstrome24fa612011-09-29 00:53:55 -070048size_t OatWriter::InitOatHeader() {
49 // create the OatHeader
50 oat_header_ = new OatHeader(dex_files_);
51 size_t offset = sizeof(*oat_header_);
52 return offset;
53}
54
55size_t OatWriter::InitOatDexFiles(size_t offset) {
56 // create the OatDexFiles
57 for (size_t i = 0; i != dex_files_->size(); ++i) {
58 const DexFile* dex_file = (*dex_files_)[i];
59 CHECK(dex_file != NULL);
60 OatDexFile* oat_dex_file = new OatDexFile(*dex_file);
61 oat_dex_files_.push_back(oat_dex_file);
62 offset += oat_dex_file->SizeOf();
63 }
64 return offset;
65}
66
67size_t OatWriter::InitOatClasses(size_t offset) {
68 // create the OatClasses
69 // calculate the offsets within OatDexFiles to OatClasses
70 for (size_t i = 0; i != dex_files_->size(); ++i) {
71 // set offset in OatDexFile to OatClasses
72 oat_dex_files_[i]->classes_offset_ = offset;
73 oat_dex_files_[i]->UpdateChecksum(*oat_header_);
74
75 const DexFile* dex_file = (*dex_files_)[i];
76 OatClasses* oat_classes = new OatClasses(*dex_file);
77 oat_classes_.push_back(oat_classes);
78 offset += oat_classes->SizeOf();
79 }
80 return offset;
81}
82
83size_t OatWriter::InitOatMethods(size_t offset) {
84 // create the OatMethods
85 // calculate the offsets within OatClasses to OatMethods
86 size_t class_index = 0;
87 for (size_t i = 0; i != dex_files_->size(); ++i) {
88 const DexFile* dex_file = (*dex_files_)[i];
89 for (size_t class_def_index = 0;
90 class_def_index < dex_file->NumClassDefs();
91 class_def_index++, class_index++) {
92 oat_classes_[i]->methods_offsets_[class_def_index] = offset;
93 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
94 const byte* class_data = dex_file->GetClassData(class_def);
Ian Rogers0571d352011-11-03 19:51:38 -070095 uint32_t num_methods = 0;
96 if (class_data != NULL) { // ie not an empty class, such as a marker interface
97 ClassDataItemIterator it(*dex_file, class_data);
98 size_t num_direct_methods = it.NumDirectMethods();
99 size_t num_virtual_methods = it.NumVirtualMethods();
100 num_methods = num_direct_methods + num_virtual_methods;
101 }
Brian Carlstrome24fa612011-09-29 00:53:55 -0700102 OatMethods* oat_methods = new OatMethods(num_methods);
103 oat_methods_.push_back(oat_methods);
104 offset += oat_methods->SizeOf();
105 }
106 oat_classes_[i]->UpdateChecksum(*oat_header_);
107 }
108 return offset;
109}
110
111size_t OatWriter::InitOatCode(size_t offset) {
112 // calculate the offsets within OatHeader to executable code
113 size_t old_offset = offset;
114 // required to be on a new page boundary
115 offset = RoundUp(offset, kPageSize);
116 oat_header_->SetExecutableOffset(offset);
117 executable_offset_padding_length_ = offset - old_offset;
118 return offset;
119}
120
121size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
122 // calculate the offsets within OatMethods
123 size_t oat_class_index = 0;
124 for (size_t i = 0; i != dex_files_->size(); ++i) {
125 const DexFile* dex_file = (*dex_files_)[i];
126 CHECK(dex_file != NULL);
127 offset = InitOatCodeDexFile(offset, oat_class_index, *dex_file);
128 }
129 return offset;
130}
131
132size_t OatWriter::InitOatCodeDexFile(size_t offset,
133 size_t& oat_class_index,
134 const DexFile& dex_file) {
135 for (size_t class_def_index = 0;
136 class_def_index < dex_file.NumClassDefs();
137 class_def_index++, oat_class_index++) {
138 const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
139 offset = InitOatCodeClassDef(offset, oat_class_index, dex_file, class_def);
140 oat_methods_[oat_class_index]->UpdateChecksum(*oat_header_);
141 }
142 return offset;
143}
144
145size_t OatWriter::InitOatCodeClassDef(size_t offset,
146 size_t oat_class_index,
147 const DexFile& dex_file,
148 const DexFile::ClassDef& class_def) {
149 const byte* class_data = dex_file.GetClassData(class_def);
Ian Rogers0571d352011-11-03 19:51:38 -0700150 if (class_data == NULL) {
151 // empty class, such as a marker interface
Ian Rogers387b6992011-10-31 17:52:37 -0700152 return offset;
153 }
Ian Rogers0571d352011-11-03 19:51:38 -0700154 ClassDataItemIterator it(dex_file, class_data);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700155 CHECK_EQ(oat_methods_[oat_class_index]->method_offsets_.size(),
Ian Rogers0571d352011-11-03 19:51:38 -0700156 it.NumDirectMethods() + it.NumVirtualMethods());
157 // Skip fields
158 while (it.HasNextStaticField()) {
159 it.Next();
160 }
161 while (it.HasNextInstanceField()) {
162 it.Next();
163 }
164 // Process methods
Brian Carlstrome24fa612011-09-29 00:53:55 -0700165 size_t class_def_method_index = 0;
Ian Rogers0571d352011-11-03 19:51:38 -0700166 while (it.HasNextDirectMethod()) {
167 bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0;
168 offset = InitOatCodeMethod(offset, oat_class_index, class_def_method_index, is_static, true,
169 it.GetMemberIndex(), &dex_file);
170 class_def_method_index++;
171 it.Next();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700172 }
Ian Rogers0571d352011-11-03 19:51:38 -0700173 while (it.HasNextVirtualMethod()) {
174 CHECK_EQ(it.GetMemberAccessFlags() & kAccStatic, 0U);
175 offset = InitOatCodeMethod(offset, oat_class_index, class_def_method_index, false, false,
176 it.GetMemberIndex(), &dex_file);
177 class_def_method_index++;
178 it.Next();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700179 }
Ian Rogers0571d352011-11-03 19:51:38 -0700180 DCHECK(!it.HasNext());
Brian Carlstrome24fa612011-09-29 00:53:55 -0700181 return offset;
182}
183
Ian Rogers0571d352011-11-03 19:51:38 -0700184size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index,
185 size_t class_def_method_index, bool is_static, bool is_direct,
186 uint32_t method_idx, const DexFile* dex_file) {
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700187 // derived from CompiledMethod if available
188 uint32_t code_offset = 0;
189 uint32_t frame_size_in_bytes = kStackAlignment;
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700190 uint32_t core_spill_mask = 0;
191 uint32_t fp_spill_mask = 0;
192 uint32_t mapping_table_offset = 0;
193 uint32_t vmap_table_offset = 0;
194 // derived from CompiledInvokeStub if available
195 uint32_t invoke_stub_offset = 0;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700196
Ian Rogers0571d352011-11-03 19:51:38 -0700197 CompiledMethod* compiled_method =
198 compiler_->GetCompiledMethod(art::Compiler::MethodReference(dex_file, method_idx));
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700199 if (compiled_method != NULL) {
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700200 offset = compiled_method->AlignCode(offset);
Elliott Hughes06b37d92011-10-16 11:51:29 -0700201 DCHECK_ALIGNED(offset, kArmAlignment);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700202 const std::vector<uint8_t>& code = compiled_method->GetCode();
203 size_t code_size = code.size() * sizeof(code[0]);
204 uint32_t thumb_offset = compiled_method->CodeDelta();
205 code_offset = (code_size == 0) ? 0 : offset + thumb_offset;
jeffhao55d78212011-11-02 11:41:50 -0700206
207 // Deduplicate code arrays
jeffhaof479dcc2011-11-02 15:54:15 -0700208 std::map<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code);
jeffhao55d78212011-11-02 11:41:50 -0700209 if (code_iter != code_offsets_.end()) {
210 code_offset = code_iter->second;
211 } else {
jeffhaof479dcc2011-11-02 15:54:15 -0700212 code_offsets_.insert(std::pair<const std::vector<uint8_t>*, uint32_t>(&code, code_offset));
jeffhao55d78212011-11-02 11:41:50 -0700213 offset += code_size;
214 oat_header_->UpdateChecksum(&code[0], code_size);
215 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700216
217 frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700218 core_spill_mask = compiled_method->GetCoreSpillMask();
219 fp_spill_mask = compiled_method->GetFpSpillMask();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700220 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700221
222 offset += sizeof(frame_size_in_bytes);
223 oat_header_->UpdateChecksum(&frame_size_in_bytes, sizeof(frame_size_in_bytes));
224
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700225 offset += sizeof(core_spill_mask);
226 oat_header_->UpdateChecksum(&core_spill_mask, sizeof(core_spill_mask));
227
228 offset += sizeof(fp_spill_mask);
229 oat_header_->UpdateChecksum(&fp_spill_mask, sizeof(fp_spill_mask));
230
231 if (compiled_method != NULL) {
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700232 const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
233 size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
234 mapping_table_offset = (mapping_table_size == 0) ? 0 : offset;
jeffhao55d78212011-11-02 11:41:50 -0700235
236 // Deduplicate mapping tables
jeffhaof479dcc2011-11-02 15:54:15 -0700237 std::map<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter = mapping_table_offsets_.find(&mapping_table);
jeffhao55d78212011-11-02 11:41:50 -0700238 if (mapping_iter != mapping_table_offsets_.end()) {
239 mapping_table_offset = mapping_iter->second;
240 } else {
jeffhaof479dcc2011-11-02 15:54:15 -0700241 mapping_table_offsets_.insert(std::pair<const std::vector<uint32_t>*, uint32_t>(&mapping_table, mapping_table_offset));
jeffhao55d78212011-11-02 11:41:50 -0700242 offset += mapping_table_size;
243 oat_header_->UpdateChecksum(&mapping_table[0], mapping_table_size);
244 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700245
246 const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
247 size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
248 vmap_table_offset = (vmap_table_size == 0) ? 0 : offset;
jeffhao55d78212011-11-02 11:41:50 -0700249
250 // Deduplicate vmap tables
jeffhaof479dcc2011-11-02 15:54:15 -0700251 std::map<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter = vmap_table_offsets_.find(&vmap_table);
jeffhao55d78212011-11-02 11:41:50 -0700252 if (vmap_iter != vmap_table_offsets_.end()) {
253 vmap_table_offset = vmap_iter->second;
254 } else {
jeffhaof479dcc2011-11-02 15:54:15 -0700255 vmap_table_offsets_.insert(std::pair<const std::vector<uint16_t>*, uint32_t>(&vmap_table, vmap_table_offset));
jeffhao55d78212011-11-02 11:41:50 -0700256 offset += vmap_table_size;
257 oat_header_->UpdateChecksum(&vmap_table[0], vmap_table_size);
258 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700259 }
260
Ian Rogers0571d352011-11-03 19:51:38 -0700261 const char* shorty = dex_file->GetMethodShorty(dex_file->GetMethodId(method_idx));
262 const CompiledInvokeStub* compiled_invoke_stub = compiler_->FindInvokeStub(is_static, shorty);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700263 if (compiled_invoke_stub != NULL) {
264 offset = CompiledMethod::AlignCode(offset, compiler_->GetInstructionSet());
Elliott Hughes06b37d92011-10-16 11:51:29 -0700265 DCHECK_ALIGNED(offset, kArmAlignment);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700266 const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
267 size_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
268 invoke_stub_offset = (invoke_stub_size == 0) ? 0 : offset;
jeffhao55d78212011-11-02 11:41:50 -0700269
270 // Deduplicate invoke stubs
jeffhaof479dcc2011-11-02 15:54:15 -0700271 std::map<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter = code_offsets_.find(&invoke_stub);
jeffhao55d78212011-11-02 11:41:50 -0700272 if (stub_iter != code_offsets_.end()) {
273 invoke_stub_offset = stub_iter->second;
274 } else {
jeffhaof479dcc2011-11-02 15:54:15 -0700275 code_offsets_.insert(std::pair<const std::vector<uint8_t>*, uint32_t>(&invoke_stub, invoke_stub_offset));
jeffhao55d78212011-11-02 11:41:50 -0700276 offset += invoke_stub_size;
277 oat_header_->UpdateChecksum(&invoke_stub[0], invoke_stub_size);
278 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700279 }
280
281 oat_methods_[oat_class_index]->method_offsets_[class_def_method_index]
282 = OatMethodOffsets(code_offset,
283 frame_size_in_bytes,
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700284 core_spill_mask,
285 fp_spill_mask,
286 mapping_table_offset,
287 vmap_table_offset,
288 invoke_stub_offset);
289
Ian Rogers0571d352011-11-03 19:51:38 -0700290 if (compiler_->IsImage()) {
291 ClassLinker* linker = Runtime::Current()->GetClassLinker();
292 DexCache* dex_cache = linker->FindDexCache(*dex_file);
293 Method* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache, class_loader_,
294 is_direct);
295 CHECK(method != NULL);
296 method->SetFrameSizeInBytes(frame_size_in_bytes);
297 method->SetCoreSpillMask(core_spill_mask);
298 method->SetFpSpillMask(fp_spill_mask);
299 method->SetOatMappingTableOffset(mapping_table_offset);
300 method->SetOatCodeOffset(code_offset);
301 method->SetOatVmapTableOffset(vmap_table_offset);
302 method->SetOatInvokeStubOffset(invoke_stub_offset);
303 }
Brian Carlstrome24fa612011-09-29 00:53:55 -0700304 return offset;
305}
306
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700307#define DCHECK_CODE_OFFSET() \
308 DCHECK_EQ(static_cast<off_t>(code_offset), lseek(file->Fd(), 0, SEEK_CUR))
309
Elliott Hughes234da572011-11-03 22:13:06 -0700310bool OatWriter::Write(File* file) {
Brian Carlstrome24fa612011-09-29 00:53:55 -0700311 if (!file->WriteFully(oat_header_, sizeof(*oat_header_))) {
Elliott Hughes234da572011-11-03 22:13:06 -0700312 PLOG(ERROR) << "Failed to write oat header to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700313 return false;
314 }
315
Elliott Hughes234da572011-11-03 22:13:06 -0700316 if (!WriteTables(file)) {
317 LOG(ERROR) << "Failed to write oat tables to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700318 return false;
319 }
320
Elliott Hughes234da572011-11-03 22:13:06 -0700321 size_t code_offset = WriteCode(file);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700322 if (code_offset == 0) {
Elliott Hughes234da572011-11-03 22:13:06 -0700323 LOG(ERROR) << "Failed to write oat code to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700324 return false;
325 }
326
Elliott Hughes234da572011-11-03 22:13:06 -0700327 code_offset = WriteCodeDexFiles(file, code_offset);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700328 if (code_offset == 0) {
Elliott Hughes234da572011-11-03 22:13:06 -0700329 LOG(ERROR) << "Failed to write oat code for dex files to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700330 return false;
331 }
332
333 return true;
334}
335
336bool OatWriter::WriteTables(File* file) {
337 for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
338 if (!oat_dex_files_[i]->Write(file)) {
Elliott Hughes234da572011-11-03 22:13:06 -0700339 PLOG(ERROR) << "Failed to write oat dex information to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700340 return false;
341 }
342 }
343 for (size_t i = 0; i != oat_classes_.size(); ++i) {
344 if (!oat_classes_[i]->Write(file)) {
Elliott Hughes234da572011-11-03 22:13:06 -0700345 PLOG(ERROR) << "Failed to write oat classes information to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700346 return false;
347 }
348 }
349 for (size_t i = 0; i != oat_methods_.size(); ++i) {
350 if (!oat_methods_[i]->Write(file)) {
Elliott Hughes234da572011-11-03 22:13:06 -0700351 PLOG(ERROR) << "Failed to write oat methods information to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700352 return false;
353 }
354 }
355 return true;
356}
357
358size_t OatWriter::WriteCode(File* file) {
359 uint32_t code_offset = oat_header_->GetExecutableOffset();
360 off_t new_offset = lseek(file->Fd(), executable_offset_padding_length_, SEEK_CUR);
361 if (static_cast<uint32_t>(new_offset) != code_offset) {
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700362 PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
Elliott Hughes234da572011-11-03 22:13:06 -0700363 << " Expected: " << code_offset << " File: " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700364 return 0;
365 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700366 DCHECK_CODE_OFFSET();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700367 return code_offset;
368}
369
370size_t OatWriter::WriteCodeDexFiles(File* file, size_t code_offset) {
Ian Rogers0571d352011-11-03 19:51:38 -0700371 size_t oat_class_index = 0;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700372 for (size_t i = 0; i != oat_classes_.size(); ++i) {
373 const DexFile* dex_file = (*dex_files_)[i];
374 CHECK(dex_file != NULL);
Ian Rogers0571d352011-11-03 19:51:38 -0700375 code_offset = WriteCodeDexFile(file, code_offset, oat_class_index, *dex_file);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700376 if (code_offset == 0) {
377 return 0;
378 }
379 }
380 return code_offset;
381}
382
Ian Rogers0571d352011-11-03 19:51:38 -0700383size_t OatWriter::WriteCodeDexFile(File* file, size_t code_offset, size_t& oat_class_index,
384 const DexFile& dex_file) {
385 for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs();
386 class_def_index++, oat_class_index++) {
Brian Carlstrome24fa612011-09-29 00:53:55 -0700387 const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
Ian Rogers0571d352011-11-03 19:51:38 -0700388 code_offset = WriteCodeClassDef(file, code_offset, oat_class_index, dex_file, class_def);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700389 if (code_offset == 0) {
390 return 0;
391 }
392 }
393 return code_offset;
394}
395
Ian Rogers0571d352011-11-03 19:51:38 -0700396void OatWriter::ReportWriteFailure(const char* what, uint32_t method_idx,
397 const DexFile& dex_file, File* f) const {
398 PLOG(ERROR) << "Failed to write " << what << " for " << PrettyMethod(method_idx, dex_file)
399 << " to " << f->name();
Elliott Hughes234da572011-11-03 22:13:06 -0700400}
401
Brian Carlstrome24fa612011-09-29 00:53:55 -0700402size_t OatWriter::WriteCodeClassDef(File* file,
Ian Rogers0571d352011-11-03 19:51:38 -0700403 size_t code_offset, size_t oat_class_index,
Brian Carlstrome24fa612011-09-29 00:53:55 -0700404 const DexFile& dex_file,
405 const DexFile::ClassDef& class_def) {
Brian Carlstrome24fa612011-09-29 00:53:55 -0700406 const byte* class_data = dex_file.GetClassData(class_def);
Ian Rogers0571d352011-11-03 19:51:38 -0700407 if (class_data == NULL) {
408 // ie. an empty class such as a marker interface
Ian Rogers387b6992011-10-31 17:52:37 -0700409 return code_offset;
410 }
Ian Rogers0571d352011-11-03 19:51:38 -0700411 ClassDataItemIterator it(dex_file, class_data);
412 // Skip fields
413 while (it.HasNextStaticField()) {
414 it.Next();
415 }
416 while (it.HasNextInstanceField()) {
417 it.Next();
418 }
419 // Process methods
420 size_t class_def_method_index = 0;
421 while (it.HasNextDirectMethod()) {
422 bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0;
423 code_offset = WriteCodeMethod(file, code_offset, oat_class_index, class_def_method_index,
424 is_static, it.GetMemberIndex(), dex_file);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700425 if (code_offset == 0) {
426 return 0;
427 }
Ian Rogers0571d352011-11-03 19:51:38 -0700428 class_def_method_index++;
429 it.Next();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700430 }
Ian Rogers0571d352011-11-03 19:51:38 -0700431 while (it.HasNextVirtualMethod()) {
432 code_offset = WriteCodeMethod(file, code_offset, oat_class_index, class_def_method_index,
433 false, it.GetMemberIndex(), dex_file);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700434 if (code_offset == 0) {
435 return 0;
436 }
Ian Rogers0571d352011-11-03 19:51:38 -0700437 class_def_method_index++;
438 it.Next();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700439 }
440 return code_offset;
441}
442
Ian Rogers0571d352011-11-03 19:51:38 -0700443size_t OatWriter::WriteCodeMethod(File* file, size_t code_offset, size_t oat_class_index,
444 size_t class_def_method_index, bool is_static,
445 uint32_t method_idx, const DexFile& dex_file) {
446 const CompiledMethod* compiled_method =
447 compiler_->GetCompiledMethod(art::Compiler::MethodReference(&dex_file, method_idx));
448
449 uint32_t frame_size_in_bytes = 0;
450 uint32_t core_spill_mask = 0;
451 uint32_t fp_spill_mask = 0;
452
453 OatMethodOffsets method_offsets =
454 oat_methods_[oat_class_index]->method_offsets_[class_def_method_index];
455
456
457 if (compiled_method != NULL) { // ie. not an abstract method
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700458 uint32_t aligned_code_offset = compiled_method->AlignCode(code_offset);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700459 uint32_t aligned_code_delta = aligned_code_offset - code_offset;
460 if (aligned_code_delta != 0) {
461 off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
462 if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700463 PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
Elliott Hughes234da572011-11-03 22:13:06 -0700464 << " Expected: " << aligned_code_offset << " File: " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700465 return false;
466 }
467 code_offset += aligned_code_delta;
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700468 DCHECK_CODE_OFFSET();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700469 }
Elliott Hughes06b37d92011-10-16 11:51:29 -0700470 DCHECK_ALIGNED(code_offset, kArmAlignment);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700471 const std::vector<uint8_t>& code = compiled_method->GetCode();
472 size_t code_size = code.size() * sizeof(code[0]);
jeffhao55d78212011-11-02 11:41:50 -0700473
474 // Deduplicate code arrays
475 size_t offset = code_offset + compiled_method->CodeDelta();
jeffhaof479dcc2011-11-02 15:54:15 -0700476 std::map<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code);
Ian Rogers0571d352011-11-03 19:51:38 -0700477 if (code_iter != code_offsets_.end() && offset != method_offsets.code_offset_) {
478 DCHECK((code_size == 0 && method_offsets.code_offset_ == 0)
479 || code_iter->second == method_offsets.code_offset_)
480 << PrettyMethod(method_idx, dex_file);
jeffhao55d78212011-11-02 11:41:50 -0700481 } else {
Ian Rogers0571d352011-11-03 19:51:38 -0700482 DCHECK((code_size == 0 && method_offsets.code_offset_ == 0)
483 || offset == method_offsets.code_offset_)
484 << PrettyMethod(method_idx, dex_file);
jeffhao55d78212011-11-02 11:41:50 -0700485 if (!file->WriteFully(&code[0], code_size)) {
Ian Rogers0571d352011-11-03 19:51:38 -0700486 ReportWriteFailure("method code", method_idx, dex_file, file);
jeffhao55d78212011-11-02 11:41:50 -0700487 return false;
488 }
489 code_offset += code_size;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700490 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700491 DCHECK_CODE_OFFSET();
Ian Rogers0571d352011-11-03 19:51:38 -0700492 frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
493 core_spill_mask = compiled_method->GetCoreSpillMask();
494 fp_spill_mask = compiled_method->GetFpSpillMask();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700495 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700496
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700497 if (!file->WriteFully(&frame_size_in_bytes, sizeof(frame_size_in_bytes))) {
Ian Rogers0571d352011-11-03 19:51:38 -0700498 ReportWriteFailure("method frame size", method_idx, dex_file, file);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700499 return false;
500 }
501 code_offset += sizeof(frame_size_in_bytes);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700502 if (!file->WriteFully(&core_spill_mask, sizeof(core_spill_mask))) {
Ian Rogers0571d352011-11-03 19:51:38 -0700503 ReportWriteFailure("method core spill mask", method_idx, dex_file, file);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700504 return false;
505 }
506 code_offset += sizeof(core_spill_mask);
507 if (!file->WriteFully(&fp_spill_mask, sizeof(fp_spill_mask))) {
Ian Rogers0571d352011-11-03 19:51:38 -0700508 ReportWriteFailure("method fp spill mask", method_idx, dex_file, file);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700509 return false;
510 }
511 code_offset += sizeof(fp_spill_mask);
512
513 if (compiled_method != NULL) {
514 const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
515 size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
jeffhao55d78212011-11-02 11:41:50 -0700516
517 // Deduplicate mapping tables
Ian Rogers0571d352011-11-03 19:51:38 -0700518 std::map<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter =
519 mapping_table_offsets_.find(&mapping_table);
520 if (mapping_iter != mapping_table_offsets_.end() &&
521 code_offset != method_offsets.mapping_table_offset_) {
522 DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
523 || mapping_iter->second == method_offsets.mapping_table_offset_)
524 << PrettyMethod(method_idx, dex_file);
jeffhao55d78212011-11-02 11:41:50 -0700525 } else {
Ian Rogers0571d352011-11-03 19:51:38 -0700526 DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
527 || code_offset == method_offsets.mapping_table_offset_)
528 << PrettyMethod(method_idx, dex_file);
jeffhao55d78212011-11-02 11:41:50 -0700529 if (!file->WriteFully(&mapping_table[0], mapping_table_size)) {
Ian Rogers0571d352011-11-03 19:51:38 -0700530 ReportWriteFailure("mapping table", method_idx, dex_file, file);
jeffhao55d78212011-11-02 11:41:50 -0700531 return false;
532 }
533 code_offset += mapping_table_size;
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700534 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700535 DCHECK_CODE_OFFSET();
536
537 const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
538 size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
jeffhao55d78212011-11-02 11:41:50 -0700539
540 // Deduplicate vmap tables
Ian Rogers0571d352011-11-03 19:51:38 -0700541 std::map<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter =
542 vmap_table_offsets_.find(&vmap_table);
543 if (vmap_iter != vmap_table_offsets_.end() &&
544 code_offset != method_offsets.vmap_table_offset_) {
545 DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
546 || vmap_iter->second == method_offsets.vmap_table_offset_)
547 << PrettyMethod(method_idx, dex_file);
jeffhao55d78212011-11-02 11:41:50 -0700548 } else {
Ian Rogers0571d352011-11-03 19:51:38 -0700549 DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
550 || code_offset == method_offsets.vmap_table_offset_)
551 << PrettyMethod(method_idx, dex_file);
jeffhao55d78212011-11-02 11:41:50 -0700552 if (!file->WriteFully(&vmap_table[0], vmap_table_size)) {
Ian Rogers0571d352011-11-03 19:51:38 -0700553 ReportWriteFailure("vmap table", method_idx, dex_file, file);
jeffhao55d78212011-11-02 11:41:50 -0700554 return false;
555 }
556 code_offset += vmap_table_size;
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700557 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700558 DCHECK_CODE_OFFSET();
559 }
Ian Rogers0571d352011-11-03 19:51:38 -0700560 const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
561 const CompiledInvokeStub* compiled_invoke_stub = compiler_->FindInvokeStub(is_static, shorty);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700562 if (compiled_invoke_stub != NULL) {
563 uint32_t aligned_code_offset = CompiledMethod::AlignCode(code_offset,
564 compiler_->GetInstructionSet());
565 uint32_t aligned_code_delta = aligned_code_offset - code_offset;
566 if (aligned_code_delta != 0) {
567 off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
568 if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
569 PLOG(ERROR) << "Failed to seek to align invoke stub code. Actual: " << new_offset
570 << " Expected: " << aligned_code_offset;
571 return false;
572 }
573 code_offset += aligned_code_delta;
574 DCHECK_CODE_OFFSET();
575 }
Elliott Hughes06b37d92011-10-16 11:51:29 -0700576 DCHECK_ALIGNED(code_offset, kArmAlignment);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700577 const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
578 size_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
jeffhao55d78212011-11-02 11:41:50 -0700579
580 // Deduplicate invoke stubs
Ian Rogers0571d352011-11-03 19:51:38 -0700581 std::map<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter =
582 code_offsets_.find(&invoke_stub);
583 if (stub_iter != code_offsets_.end() &&
584 code_offset != method_offsets.invoke_stub_offset_) {
585 DCHECK((invoke_stub_size == 0 && method_offsets.invoke_stub_offset_ == 0)
586 || stub_iter->second == method_offsets.invoke_stub_offset_)
587 << PrettyMethod(method_idx, dex_file);
jeffhao55d78212011-11-02 11:41:50 -0700588 } else {
Ian Rogers0571d352011-11-03 19:51:38 -0700589 DCHECK((invoke_stub_size == 0 && method_offsets.invoke_stub_offset_ == 0)
590 || code_offset == method_offsets.invoke_stub_offset_)
591 << PrettyMethod(method_idx, dex_file);
jeffhao55d78212011-11-02 11:41:50 -0700592 if (!file->WriteFully(&invoke_stub[0], invoke_stub_size)) {
Ian Rogers0571d352011-11-03 19:51:38 -0700593 ReportWriteFailure("invoke stub code", method_idx, dex_file, file);
jeffhao55d78212011-11-02 11:41:50 -0700594 return false;
595 }
596 code_offset += invoke_stub_size;
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700597 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700598 DCHECK_CODE_OFFSET();
599 }
Brian Carlstrome24fa612011-09-29 00:53:55 -0700600 return code_offset;
601}
602
Brian Carlstrome24fa612011-09-29 00:53:55 -0700603OatWriter::OatDexFile::OatDexFile(const DexFile& dex_file) {
604 const std::string& location = dex_file.GetLocation();
605 dex_file_location_size_ = location.size();
606 dex_file_location_data_ = reinterpret_cast<const uint8_t*>(location.data());
607 dex_file_checksum_ = dex_file.GetHeader().checksum_;
Ian Rogers0571d352011-11-03 19:51:38 -0700608 classes_offset_ = 0;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700609}
610
611size_t OatWriter::OatDexFile::SizeOf() const {
612 return sizeof(dex_file_location_size_)
613 + dex_file_location_size_
614 + sizeof(dex_file_checksum_)
615 + sizeof(classes_offset_);
616}
617
618void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const {
619 oat_header.UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
620 oat_header.UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
621 oat_header.UpdateChecksum(&dex_file_checksum_, sizeof(dex_file_checksum_));
622 oat_header.UpdateChecksum(&classes_offset_, sizeof(classes_offset_));
623}
624
625bool OatWriter::OatDexFile::Write(File* file) const {
626 if (!file->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
Elliott Hughes234da572011-11-03 22:13:06 -0700627 PLOG(ERROR) << "Failed to write dex file location length to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700628 return false;
629 }
630 if (!file->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
Elliott Hughes234da572011-11-03 22:13:06 -0700631 PLOG(ERROR) << "Failed to write dex file location data to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700632 return false;
633 }
634 if (!file->WriteFully(&dex_file_checksum_, sizeof(dex_file_checksum_))) {
Elliott Hughes234da572011-11-03 22:13:06 -0700635 PLOG(ERROR) << "Failed to write dex file checksum to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700636 return false;
637 }
638 if (!file->WriteFully(&classes_offset_, sizeof(classes_offset_))) {
Elliott Hughes234da572011-11-03 22:13:06 -0700639 PLOG(ERROR) << "Failed to write classes offset to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700640 return false;
641 }
642 return true;
643}
644
645OatWriter::OatClasses::OatClasses(const DexFile& dex_file) {
646 methods_offsets_.resize(dex_file.NumClassDefs());
647}
648
649size_t OatWriter::OatClasses::SizeOf() const {
650 return (sizeof(methods_offsets_[0]) * methods_offsets_.size());
651}
652
653void OatWriter::OatClasses::UpdateChecksum(OatHeader& oat_header) const {
654 oat_header.UpdateChecksum(&methods_offsets_[0], SizeOf());
655}
656
657bool OatWriter::OatClasses::Write(File* file) const {
658 if (!file->WriteFully(&methods_offsets_[0], SizeOf())) {
Elliott Hughes234da572011-11-03 22:13:06 -0700659 PLOG(ERROR) << "Failed to write methods offsets to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700660 return false;
661 }
662 return true;
663}
664
665OatWriter::OatMethods::OatMethods(uint32_t methods_count) {
666 method_offsets_.resize(methods_count);
667}
668
669size_t OatWriter::OatMethods::SizeOf() const {
670 return (sizeof(method_offsets_[0]) * method_offsets_.size());
671}
672
673void OatWriter::OatMethods::UpdateChecksum(OatHeader& oat_header) const {
674 oat_header.UpdateChecksum(&method_offsets_[0], SizeOf());
675}
676
677bool OatWriter::OatMethods::Write(File* file) const {
678 if (!file->WriteFully(&method_offsets_[0], SizeOf())) {
Elliott Hughes234da572011-11-03 22:13:06 -0700679 PLOG(ERROR) << "Failed to write method offsets to " << file->name();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700680 return false;
681 }
682 return true;
683}
684
685} // namespace art