blob: 2635bf8294576f5e31b52952b75244456e6ce02a [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
Brian Carlstrom3320cf42011-10-04 14:58:28 -070013bool OatWriter::Create(const std::string& filename,
14 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);
Brian Carlstrome24fa612011-09-29 00:53:55 -070018 return oat_writer.Write(filename);
19}
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;
27
28 size_t offset = InitOatHeader();
29 offset = InitOatDexFiles(offset);
30 offset = InitOatClasses(offset);
31 offset = InitOatMethods(offset);
32 offset = InitOatCode(offset);
33 offset = InitOatCodeDexFiles(offset);
34
35 CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
36 CHECK_EQ(dex_files_->size(), oat_classes_.size());
37}
38
39size_t OatWriter::InitOatHeader() {
40 // create the OatHeader
41 oat_header_ = new OatHeader(dex_files_);
42 size_t offset = sizeof(*oat_header_);
43 return offset;
44}
45
46size_t OatWriter::InitOatDexFiles(size_t offset) {
47 // create the OatDexFiles
48 for (size_t i = 0; i != dex_files_->size(); ++i) {
49 const DexFile* dex_file = (*dex_files_)[i];
50 CHECK(dex_file != NULL);
51 OatDexFile* oat_dex_file = new OatDexFile(*dex_file);
52 oat_dex_files_.push_back(oat_dex_file);
53 offset += oat_dex_file->SizeOf();
54 }
55 return offset;
56}
57
58size_t OatWriter::InitOatClasses(size_t offset) {
59 // create the OatClasses
60 // calculate the offsets within OatDexFiles to OatClasses
61 for (size_t i = 0; i != dex_files_->size(); ++i) {
62 // set offset in OatDexFile to OatClasses
63 oat_dex_files_[i]->classes_offset_ = offset;
64 oat_dex_files_[i]->UpdateChecksum(*oat_header_);
65
66 const DexFile* dex_file = (*dex_files_)[i];
67 OatClasses* oat_classes = new OatClasses(*dex_file);
68 oat_classes_.push_back(oat_classes);
69 offset += oat_classes->SizeOf();
70 }
71 return offset;
72}
73
74size_t OatWriter::InitOatMethods(size_t offset) {
75 // create the OatMethods
76 // calculate the offsets within OatClasses to OatMethods
77 size_t class_index = 0;
78 for (size_t i = 0; i != dex_files_->size(); ++i) {
79 const DexFile* dex_file = (*dex_files_)[i];
80 for (size_t class_def_index = 0;
81 class_def_index < dex_file->NumClassDefs();
82 class_def_index++, class_index++) {
83 oat_classes_[i]->methods_offsets_[class_def_index] = offset;
84 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
85 const byte* class_data = dex_file->GetClassData(class_def);
86 DexFile::ClassDataHeader header = dex_file->ReadClassDataHeader(&class_data);
87 size_t num_direct_methods = header.direct_methods_size_;
88 size_t num_virtual_methods = header.virtual_methods_size_;
89 uint32_t num_methods = num_direct_methods + num_virtual_methods;
90 OatMethods* oat_methods = new OatMethods(num_methods);
91 oat_methods_.push_back(oat_methods);
92 offset += oat_methods->SizeOf();
93 }
94 oat_classes_[i]->UpdateChecksum(*oat_header_);
95 }
96 return offset;
97}
98
99size_t OatWriter::InitOatCode(size_t offset) {
100 // calculate the offsets within OatHeader to executable code
101 size_t old_offset = offset;
102 // required to be on a new page boundary
103 offset = RoundUp(offset, kPageSize);
104 oat_header_->SetExecutableOffset(offset);
105 executable_offset_padding_length_ = offset - old_offset;
106 return offset;
107}
108
109size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
110 // calculate the offsets within OatMethods
111 size_t oat_class_index = 0;
112 for (size_t i = 0; i != dex_files_->size(); ++i) {
113 const DexFile* dex_file = (*dex_files_)[i];
114 CHECK(dex_file != NULL);
115 offset = InitOatCodeDexFile(offset, oat_class_index, *dex_file);
116 }
117 return offset;
118}
119
120size_t OatWriter::InitOatCodeDexFile(size_t offset,
121 size_t& oat_class_index,
122 const DexFile& dex_file) {
123 for (size_t class_def_index = 0;
124 class_def_index < dex_file.NumClassDefs();
125 class_def_index++, oat_class_index++) {
126 const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
127 offset = InitOatCodeClassDef(offset, oat_class_index, dex_file, class_def);
128 oat_methods_[oat_class_index]->UpdateChecksum(*oat_header_);
129 }
130 return offset;
131}
132
133size_t OatWriter::InitOatCodeClassDef(size_t offset,
134 size_t oat_class_index,
135 const DexFile& dex_file,
136 const DexFile::ClassDef& class_def) {
137 const byte* class_data = dex_file.GetClassData(class_def);
138 DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data);
139 size_t num_virtual_methods = header.virtual_methods_size_;
140 const char* descriptor = dex_file.GetClassDescriptor(class_def);
141
142 // TODO: remove code ByteArrays from Class/Method (and therefore ClassLoader)
143 // TODO: don't write code for shared stubs
144 Class* klass = Runtime::Current()->GetClassLinker()->FindClass(descriptor, class_loader_);
145 CHECK(klass != NULL) << descriptor;
146 CHECK_EQ(klass->GetClassLoader(), class_loader_);
147 CHECK_EQ(oat_methods_[oat_class_index]->method_offsets_.size(),
148 klass->NumDirectMethods() + num_virtual_methods);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700149 size_t class_def_method_index = 0;
150 for (size_t i = 0; i < klass->NumDirectMethods(); i++, class_def_method_index++) {
151 Method* method = klass->GetDirectMethod(i);
152 CHECK(method != NULL) << descriptor << " direct " << i;
153 offset = InitOatCodeMethod(offset, oat_class_index, class_def_method_index, method);
154 }
155 // note that num_virtual_methods != klass->NumVirtualMethods() because of miranda methods
156 for (size_t i = 0; i < num_virtual_methods; i++, class_def_method_index++) {
157 Method* method = klass->GetVirtualMethod(i);
158 CHECK(method != NULL) << descriptor << " virtual " << i;
159 offset = InitOatCodeMethod(offset, oat_class_index, class_def_method_index, method);
160 }
161 return offset;
162}
163
164size_t OatWriter::InitOatCodeMethod(size_t offset,
165 size_t oat_class_index,
166 size_t class_def_method_index,
167 Method* method) {
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700168 // derived from CompiledMethod if available
169 uint32_t code_offset = 0;
170 uint32_t frame_size_in_bytes = kStackAlignment;
171 uint32_t return_pc_offset_in_bytes = 0;
172 uint32_t core_spill_mask = 0;
173 uint32_t fp_spill_mask = 0;
174 uint32_t mapping_table_offset = 0;
175 uint32_t vmap_table_offset = 0;
176 // derived from CompiledInvokeStub if available
177 uint32_t invoke_stub_offset = 0;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700178
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700179 const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method);
180 if (compiled_method != NULL) {
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700181 offset = compiled_method->AlignCode(offset);
Elliott Hughes06b37d92011-10-16 11:51:29 -0700182 DCHECK_ALIGNED(offset, kArmAlignment);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700183 const std::vector<uint8_t>& code = compiled_method->GetCode();
184 size_t code_size = code.size() * sizeof(code[0]);
185 uint32_t thumb_offset = compiled_method->CodeDelta();
186 code_offset = (code_size == 0) ? 0 : offset + thumb_offset;
187 offset += code_size;
188 oat_header_->UpdateChecksum(&code[0], code_size);
189
190 frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
191 return_pc_offset_in_bytes = compiled_method->GetReturnPcOffsetInBytes();
192 core_spill_mask = compiled_method->GetCoreSpillMask();
193 fp_spill_mask = compiled_method->GetFpSpillMask();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700194 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700195
196 offset += sizeof(frame_size_in_bytes);
197 oat_header_->UpdateChecksum(&frame_size_in_bytes, sizeof(frame_size_in_bytes));
198
199 offset += sizeof(return_pc_offset_in_bytes);
200 oat_header_->UpdateChecksum(&return_pc_offset_in_bytes, sizeof(return_pc_offset_in_bytes));
201
202 offset += sizeof(core_spill_mask);
203 oat_header_->UpdateChecksum(&core_spill_mask, sizeof(core_spill_mask));
204
205 offset += sizeof(fp_spill_mask);
206 oat_header_->UpdateChecksum(&fp_spill_mask, sizeof(fp_spill_mask));
207
208 if (compiled_method != NULL) {
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700209 const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
210 size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
211 mapping_table_offset = (mapping_table_size == 0) ? 0 : offset;
212 offset += mapping_table_size;
213 oat_header_->UpdateChecksum(&mapping_table[0], mapping_table_size);
214
215 const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
216 size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
217 vmap_table_offset = (vmap_table_size == 0) ? 0 : offset;
218 offset += vmap_table_size;
219 oat_header_->UpdateChecksum(&vmap_table[0], vmap_table_size);
220 }
221
222 const CompiledInvokeStub* compiled_invoke_stub = compiler_->GetCompiledInvokeStub(method);
223 if (compiled_invoke_stub != NULL) {
224 offset = CompiledMethod::AlignCode(offset, compiler_->GetInstructionSet());
Elliott Hughes06b37d92011-10-16 11:51:29 -0700225 DCHECK_ALIGNED(offset, kArmAlignment);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700226 const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
227 size_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
228 invoke_stub_offset = (invoke_stub_size == 0) ? 0 : offset;
229 offset += invoke_stub_size;
230 oat_header_->UpdateChecksum(&invoke_stub[0], invoke_stub_size);
231 }
232
233 oat_methods_[oat_class_index]->method_offsets_[class_def_method_index]
234 = OatMethodOffsets(code_offset,
235 frame_size_in_bytes,
236 return_pc_offset_in_bytes,
237 core_spill_mask,
238 fp_spill_mask,
239 mapping_table_offset,
240 vmap_table_offset,
241 invoke_stub_offset);
242
243 // Note that we leave the offset and values back in the Method where ImageWriter will find them
244 method->SetOatCodeOffset(code_offset);
245 method->SetFrameSizeInBytes(frame_size_in_bytes);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700246 method->SetCoreSpillMask(core_spill_mask);
247 method->SetFpSpillMask(fp_spill_mask);
248 method->SetOatMappingTableOffset(mapping_table_offset);
249 method->SetOatVmapTableOffset(vmap_table_offset);
250 method->SetOatInvokeStubOffset(invoke_stub_offset);
251
Brian Carlstrome24fa612011-09-29 00:53:55 -0700252 return offset;
253}
254
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700255#define DCHECK_CODE_OFFSET() \
256 DCHECK_EQ(static_cast<off_t>(code_offset), lseek(file->Fd(), 0, SEEK_CUR))
257
Brian Carlstrome24fa612011-09-29 00:53:55 -0700258bool OatWriter::Write(const std::string& filename) {
Brian Carlstrome24fa612011-09-29 00:53:55 -0700259 UniquePtr<File> file(OS::OpenFile(filename.c_str(), true));
260 if (file.get() == NULL) {
261 return false;
262 }
263
264 if (!file->WriteFully(oat_header_, sizeof(*oat_header_))) {
265 PLOG(ERROR) << "Failed to write oat header to " << filename;
266 return false;
267 }
268
269 if (!WriteTables(file.get())) {
270 LOG(ERROR) << "Failed to write oat tables to " << filename;
271 return false;
272 }
273
274 size_t code_offset = WriteCode(file.get());
275 if (code_offset == 0) {
276 LOG(ERROR) << "Failed to write oat code to " << filename;
277 return false;
278 }
279
280 code_offset = WriteCodeDexFiles(file.get(), code_offset);
281 if (code_offset == 0) {
282 LOG(ERROR) << "Failed to write oat code for dex files to " << filename;
283 return false;
284 }
285
286 return true;
287}
288
289bool OatWriter::WriteTables(File* file) {
290 for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
291 if (!oat_dex_files_[i]->Write(file)) {
292 PLOG(ERROR) << "Failed to write oat dex information";
293 return false;
294 }
295 }
296 for (size_t i = 0; i != oat_classes_.size(); ++i) {
297 if (!oat_classes_[i]->Write(file)) {
298 PLOG(ERROR) << "Failed to write oat classes information";
299 return false;
300 }
301 }
302 for (size_t i = 0; i != oat_methods_.size(); ++i) {
303 if (!oat_methods_[i]->Write(file)) {
304 PLOG(ERROR) << "Failed to write oat methods information";
305 return false;
306 }
307 }
308 return true;
309}
310
311size_t OatWriter::WriteCode(File* file) {
312 uint32_t code_offset = oat_header_->GetExecutableOffset();
313 off_t new_offset = lseek(file->Fd(), executable_offset_padding_length_, SEEK_CUR);
314 if (static_cast<uint32_t>(new_offset) != code_offset) {
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700315 PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
316 << " Expected: " << code_offset;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700317 return 0;
318 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700319 DCHECK_CODE_OFFSET();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700320 return code_offset;
321}
322
323size_t OatWriter::WriteCodeDexFiles(File* file, size_t code_offset) {
324 for (size_t i = 0; i != oat_classes_.size(); ++i) {
325 const DexFile* dex_file = (*dex_files_)[i];
326 CHECK(dex_file != NULL);
327 code_offset = WriteCodeDexFile(file, code_offset, *dex_file);
328 if (code_offset == 0) {
329 return 0;
330 }
331 }
332 return code_offset;
333}
334
335size_t OatWriter::WriteCodeDexFile(File* file,
336 size_t code_offset,
337 const DexFile& dex_file) {
338 for (size_t class_def_index = 0;
339 class_def_index < dex_file.NumClassDefs();
340 class_def_index++) {
341 const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
342 code_offset = WriteCodeClassDef(file, code_offset, dex_file, class_def);
343 if (code_offset == 0) {
344 return 0;
345 }
346 }
347 return code_offset;
348}
349
350size_t OatWriter::WriteCodeClassDef(File* file,
351 size_t code_offset,
352 const DexFile& dex_file,
353 const DexFile::ClassDef& class_def) {
Brian Carlstrome24fa612011-09-29 00:53:55 -0700354 const byte* class_data = dex_file.GetClassData(class_def);
355 DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data);
356 size_t num_virtual_methods = header.virtual_methods_size_;
357 const char* descriptor = dex_file.GetClassDescriptor(class_def);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700358 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700359 Class* klass = class_linker->FindClass(descriptor, class_loader_);
360
361 // TODO: deduplicate code arrays
362 // Note that we clear the code array here, image_writer will use GetCodeOffset to find it
363 for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
364 Method* method = klass->GetDirectMethod(i);
365 code_offset = WriteCodeMethod(file, code_offset, method);
366 if (code_offset == 0) {
367 return 0;
368 }
369 }
370 // note that num_virtual_methods != klass->NumVirtualMethods() because of miranda methods
371 for (size_t i = 0; i < num_virtual_methods; i++) {
372 Method* method = klass->GetVirtualMethod(i);
373 code_offset = WriteCodeMethod(file, code_offset, method);
374 if (code_offset == 0) {
375 return 0;
376 }
377 }
378 for (size_t i = num_virtual_methods; i < klass->NumVirtualMethods(); i++) {
379 Method* method = klass->GetVirtualMethod(i);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700380 CHECK(compiler_->GetCompiledMethod(method) == NULL) << PrettyMethod(method);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700381 }
382 return code_offset;
383}
384
Elliott Hughesf09afe82011-10-16 14:24:21 -0700385size_t OatWriter::WriteCodeMethod(File* file, size_t code_offset, Method* method) {
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700386 const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method);
387 if (compiled_method != NULL) {
388 uint32_t aligned_code_offset = compiled_method->AlignCode(code_offset);
Brian Carlstrome24fa612011-09-29 00:53:55 -0700389 uint32_t aligned_code_delta = aligned_code_offset - code_offset;
390 if (aligned_code_delta != 0) {
391 off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
392 if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700393 PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
394 << " Expected: " << aligned_code_offset;
Brian Carlstrome24fa612011-09-29 00:53:55 -0700395 return false;
396 }
397 code_offset += aligned_code_delta;
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700398 DCHECK_CODE_OFFSET();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700399 }
Elliott Hughes06b37d92011-10-16 11:51:29 -0700400 DCHECK_ALIGNED(code_offset, kArmAlignment);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700401 const std::vector<uint8_t>& code = compiled_method->GetCode();
402 size_t code_size = code.size() * sizeof(code[0]);
403 DCHECK((code_size == 0 && method->GetOatCodeOffset() == 0)
404 || code_offset + compiled_method->CodeDelta() == method->GetOatCodeOffset());
405 if (!file->WriteFully(&code[0], code_size)) {
Brian Carlstrome24fa612011-09-29 00:53:55 -0700406 PLOG(ERROR) << "Failed to write method code for " << PrettyMethod(method);
407 return false;
408 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700409 code_offset += code_size;
410 DCHECK_CODE_OFFSET();
Brian Carlstrome24fa612011-09-29 00:53:55 -0700411 }
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700412
413 uint32_t frame_size_in_bytes = method->GetFrameSizeInBytes();
414 uint32_t return_pc_offset_in_bytes = method->GetReturnPcOffsetInBytes();
415 uint32_t core_spill_mask = method->GetCoreSpillMask();
416 uint32_t fp_spill_mask = method->GetFpSpillMask();
417 if (!file->WriteFully(&frame_size_in_bytes, sizeof(frame_size_in_bytes))) {
418 PLOG(ERROR) << "Failed to write method frame size for " << PrettyMethod(method);
419 return false;
420 }
421 code_offset += sizeof(frame_size_in_bytes);
422 if (!file->WriteFully(&return_pc_offset_in_bytes, sizeof(return_pc_offset_in_bytes))) {
423 PLOG(ERROR) << "Failed to write method return pc offset for " << PrettyMethod(method);
424 return false;
425 }
426 code_offset += sizeof(return_pc_offset_in_bytes);
427 if (!file->WriteFully(&core_spill_mask, sizeof(core_spill_mask))) {
428 PLOG(ERROR) << "Failed to write method core spill mask for " << PrettyMethod(method);
429 return false;
430 }
431 code_offset += sizeof(core_spill_mask);
432 if (!file->WriteFully(&fp_spill_mask, sizeof(fp_spill_mask))) {
433 PLOG(ERROR) << "Failed to write method fp spill mask for " << PrettyMethod(method);
434 return false;
435 }
436 code_offset += sizeof(fp_spill_mask);
437
438 if (compiled_method != NULL) {
439 const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
440 size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
441 DCHECK((mapping_table_size == 0 && method->GetOatMappingTableOffset() == 0)
442 || code_offset == method->GetOatMappingTableOffset());
443 if (!file->WriteFully(&mapping_table[0], mapping_table_size)) {
444 PLOG(ERROR) << "Failed to write mapping table for " << PrettyMethod(method);
445 return false;
446 }
447 code_offset += mapping_table_size;
448 DCHECK_CODE_OFFSET();
449
450 const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
451 size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
452 DCHECK((vmap_table_size == 0 && method->GetOatVmapTableOffset() == 0)
453 || code_offset == method->GetOatVmapTableOffset());
454 if (!file->WriteFully(&vmap_table[0], vmap_table_size)) {
455 PLOG(ERROR) << "Failed to write vmap table for " << PrettyMethod(method);
456 return false;
457 }
458 code_offset += vmap_table_size;
459 DCHECK_CODE_OFFSET();
460 }
461
462 const CompiledInvokeStub* compiled_invoke_stub = compiler_->GetCompiledInvokeStub(method);
463 if (compiled_invoke_stub != NULL) {
464 uint32_t aligned_code_offset = CompiledMethod::AlignCode(code_offset,
465 compiler_->GetInstructionSet());
466 uint32_t aligned_code_delta = aligned_code_offset - code_offset;
467 if (aligned_code_delta != 0) {
468 off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
469 if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
470 PLOG(ERROR) << "Failed to seek to align invoke stub code. Actual: " << new_offset
471 << " Expected: " << aligned_code_offset;
472 return false;
473 }
474 code_offset += aligned_code_delta;
475 DCHECK_CODE_OFFSET();
476 }
Elliott Hughes06b37d92011-10-16 11:51:29 -0700477 DCHECK_ALIGNED(code_offset, kArmAlignment);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700478 const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
479 size_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
480 DCHECK((invoke_stub_size == 0 && method->GetOatInvokeStubOffset() == 0)
Elliott Hughesf09afe82011-10-16 14:24:21 -0700481 || code_offset == method->GetOatInvokeStubOffset()) << PrettyMethod(method);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700482 if (!file->WriteFully(&invoke_stub[0], invoke_stub_size)) {
483 PLOG(ERROR) << "Failed to write invoke stub code for " << PrettyMethod(method);
484 return false;
485 }
486 code_offset += invoke_stub_size;
487 DCHECK_CODE_OFFSET();
488 }
489
Brian Carlstrome24fa612011-09-29 00:53:55 -0700490 return code_offset;
491}
492
493OatWriter::~OatWriter() {
494 delete oat_header_;
495 STLDeleteElements(&oat_dex_files_);
496 STLDeleteElements(&oat_classes_);
497 STLDeleteElements(&oat_methods_);
498}
499
500OatWriter::OatDexFile::OatDexFile(const DexFile& dex_file) {
501 const std::string& location = dex_file.GetLocation();
502 dex_file_location_size_ = location.size();
503 dex_file_location_data_ = reinterpret_cast<const uint8_t*>(location.data());
504 dex_file_checksum_ = dex_file.GetHeader().checksum_;
505}
506
507size_t OatWriter::OatDexFile::SizeOf() const {
508 return sizeof(dex_file_location_size_)
509 + dex_file_location_size_
510 + sizeof(dex_file_checksum_)
511 + sizeof(classes_offset_);
512}
513
514void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const {
515 oat_header.UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
516 oat_header.UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
517 oat_header.UpdateChecksum(&dex_file_checksum_, sizeof(dex_file_checksum_));
518 oat_header.UpdateChecksum(&classes_offset_, sizeof(classes_offset_));
519}
520
521bool OatWriter::OatDexFile::Write(File* file) const {
522 if (!file->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
523 PLOG(ERROR) << "Failed to write dex file location length";
524 return false;
525 }
526 if (!file->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
527 PLOG(ERROR) << "Failed to write dex file location data";
528 return false;
529 }
530 if (!file->WriteFully(&dex_file_checksum_, sizeof(dex_file_checksum_))) {
531 PLOG(ERROR) << "Failed to write dex file checksum";
532 return false;
533 }
534 if (!file->WriteFully(&classes_offset_, sizeof(classes_offset_))) {
535 PLOG(ERROR) << "Failed to write classes offset";
536 return false;
537 }
538 return true;
539}
540
541OatWriter::OatClasses::OatClasses(const DexFile& dex_file) {
542 methods_offsets_.resize(dex_file.NumClassDefs());
543}
544
545size_t OatWriter::OatClasses::SizeOf() const {
546 return (sizeof(methods_offsets_[0]) * methods_offsets_.size());
547}
548
549void OatWriter::OatClasses::UpdateChecksum(OatHeader& oat_header) const {
550 oat_header.UpdateChecksum(&methods_offsets_[0], SizeOf());
551}
552
553bool OatWriter::OatClasses::Write(File* file) const {
554 if (!file->WriteFully(&methods_offsets_[0], SizeOf())) {
555 PLOG(ERROR) << "Failed to methods offsets";
556 return false;
557 }
558 return true;
559}
560
561OatWriter::OatMethods::OatMethods(uint32_t methods_count) {
562 method_offsets_.resize(methods_count);
563}
564
565size_t OatWriter::OatMethods::SizeOf() const {
566 return (sizeof(method_offsets_[0]) * method_offsets_.size());
567}
568
569void OatWriter::OatMethods::UpdateChecksum(OatHeader& oat_header) const {
570 oat_header.UpdateChecksum(&method_offsets_[0], SizeOf());
571}
572
573bool OatWriter::OatMethods::Write(File* file) const {
574 if (!file->WriteFully(&method_offsets_[0], SizeOf())) {
575 PLOG(ERROR) << "Failed to method offsets";
576 return false;
577 }
578 return true;
579}
580
581} // namespace art