oat_writer.cc revision 0755ec5ea1dce0b549fc1adefeb52d89f119ebec
1// 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 13bool OatWriter::Create(File* file, 14 const ClassLoader* class_loader, 15 const Compiler& compiler) { 16 const std::vector<const DexFile*>& dex_files = ClassLoader::GetCompileTimeClassPath(class_loader); 17 OatWriter oat_writer(dex_files, class_loader, compiler); 18 return oat_writer.Write(file); 19} 20 21OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files, 22 const ClassLoader* class_loader, 23 const Compiler& compiler) { 24 compiler_ = &compiler; 25 class_loader_ = class_loader; 26 dex_files_ = &dex_files; 27 oat_header_ = NULL; 28 executable_offset_padding_length_ = 0; 29 30 size_t offset = InitOatHeader(); 31 offset = InitOatDexFiles(offset); 32 offset = InitDexFiles(offset); 33 offset = InitOatClasses(offset); 34 offset = InitOatCode(offset); 35 offset = InitOatCodeDexFiles(offset); 36 37 CHECK_EQ(dex_files_->size(), oat_dex_files_.size()); 38} 39 40OatWriter::~OatWriter() { 41 delete oat_header_; 42 STLDeleteElements(&oat_dex_files_); 43 STLDeleteElements(&oat_classes_); 44} 45 46size_t OatWriter::InitOatHeader() { 47 // create the OatHeader 48 oat_header_ = new OatHeader(dex_files_); 49 size_t offset = sizeof(*oat_header_); 50 return offset; 51} 52 53size_t OatWriter::InitOatDexFiles(size_t offset) { 54 // create the OatDexFiles 55 for (size_t i = 0; i != dex_files_->size(); ++i) { 56 const DexFile* dex_file = (*dex_files_)[i]; 57 CHECK(dex_file != NULL); 58 OatDexFile* oat_dex_file = new OatDexFile(*dex_file); 59 oat_dex_files_.push_back(oat_dex_file); 60 offset += oat_dex_file->SizeOf(); 61 } 62 return offset; 63} 64 65size_t OatWriter::InitDexFiles(size_t offset) { 66 // calculate the offsets within OatDexFiles to the DexFiles 67 for (size_t i = 0; i != dex_files_->size(); ++i) { 68 // dex files are required to be 4 byte aligned 69 offset = RoundUp(offset, 4); 70 71 // set offset in OatDexFile to DexFile 72 oat_dex_files_[i]->dex_file_offset_ = offset; 73 74 const DexFile* dex_file = (*dex_files_)[i]; 75 offset += dex_file->GetHeader().file_size_; 76 } 77 return offset; 78} 79 80size_t OatWriter::InitOatClasses(size_t offset) { 81 // create the OatClasses 82 // calculate the offsets within OatDexFiles to OatClasses 83 size_t class_index = 0; 84 for (size_t i = 0; i != dex_files_->size(); ++i) { 85 const DexFile* dex_file = (*dex_files_)[i]; 86 for (size_t class_def_index = 0; 87 class_def_index < dex_file->NumClassDefs(); 88 class_def_index++, class_index++) { 89 oat_dex_files_[i]->methods_offsets_[class_def_index] = offset; 90 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); 91 const byte* class_data = dex_file->GetClassData(class_def); 92 uint32_t num_methods = 0; 93 if (class_data != NULL) { // ie not an empty class, such as a marker interface 94 ClassDataItemIterator it(*dex_file, class_data); 95 size_t num_direct_methods = it.NumDirectMethods(); 96 size_t num_virtual_methods = it.NumVirtualMethods(); 97 num_methods = num_direct_methods + num_virtual_methods; 98 } 99 100 CompiledClass* compiled_class = 101 compiler_->GetCompiledClass(art::Compiler::MethodReference(dex_file, class_def_index)); 102 Class::Status status = 103 (compiled_class != NULL) ? compiled_class->GetStatus() : Class::kStatusNotReady; 104 105 OatClass* oat_class = new OatClass(status, num_methods); 106 oat_classes_.push_back(oat_class); 107 offset += oat_class->SizeOf(); 108 } 109 oat_dex_files_[i]->UpdateChecksum(*oat_header_); 110 } 111 return offset; 112} 113 114size_t OatWriter::InitOatCode(size_t offset) { 115 // calculate the offsets within OatHeader to executable code 116 size_t old_offset = offset; 117 // required to be on a new page boundary 118 offset = RoundUp(offset, kPageSize); 119 oat_header_->SetExecutableOffset(offset); 120 executable_offset_padding_length_ = offset - old_offset; 121 return offset; 122} 123 124size_t OatWriter::InitOatCodeDexFiles(size_t offset) { 125 size_t oat_class_index = 0; 126 for (size_t i = 0; i != dex_files_->size(); ++i) { 127 const DexFile* dex_file = (*dex_files_)[i]; 128 CHECK(dex_file != NULL); 129 offset = InitOatCodeDexFile(offset, oat_class_index, *dex_file); 130 } 131 return offset; 132} 133 134size_t OatWriter::InitOatCodeDexFile(size_t offset, 135 size_t& oat_class_index, 136 const DexFile& dex_file) { 137 for (size_t class_def_index = 0; 138 class_def_index < dex_file.NumClassDefs(); 139 class_def_index++, oat_class_index++) { 140 const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); 141 offset = InitOatCodeClassDef(offset, oat_class_index, dex_file, class_def); 142 oat_classes_[oat_class_index]->UpdateChecksum(*oat_header_); 143 } 144 return offset; 145} 146 147size_t OatWriter::InitOatCodeClassDef(size_t offset, 148 size_t oat_class_index, 149 const DexFile& dex_file, 150 const DexFile::ClassDef& class_def) { 151 const byte* class_data = dex_file.GetClassData(class_def); 152 if (class_data == NULL) { 153 // empty class, such as a marker interface 154 return offset; 155 } 156 ClassDataItemIterator it(dex_file, class_data); 157 CHECK_EQ(oat_classes_[oat_class_index]->method_offsets_.size(), 158 it.NumDirectMethods() + it.NumVirtualMethods()); 159 // Skip fields 160 while (it.HasNextStaticField()) { 161 it.Next(); 162 } 163 while (it.HasNextInstanceField()) { 164 it.Next(); 165 } 166 // Process methods 167 size_t class_def_method_index = 0; 168 while (it.HasNextDirectMethod()) { 169 bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0; 170 offset = InitOatCodeMethod(offset, oat_class_index, class_def_method_index, is_static, true, 171 it.GetMemberIndex(), &dex_file); 172 class_def_method_index++; 173 it.Next(); 174 } 175 while (it.HasNextVirtualMethod()) { 176 CHECK_EQ(it.GetMemberAccessFlags() & kAccStatic, 0U); 177 offset = InitOatCodeMethod(offset, oat_class_index, class_def_method_index, false, false, 178 it.GetMemberIndex(), &dex_file); 179 class_def_method_index++; 180 it.Next(); 181 } 182 DCHECK(!it.HasNext()); 183 return offset; 184} 185 186size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, 187 size_t class_def_method_index, bool is_static, bool is_direct, 188 uint32_t method_idx, const DexFile* dex_file) { 189 // derived from CompiledMethod if available 190 uint32_t code_offset = 0; 191 uint32_t frame_size_in_bytes = kStackAlignment; 192 uint32_t core_spill_mask = 0; 193 uint32_t fp_spill_mask = 0; 194 uint32_t mapping_table_offset = 0; 195 uint32_t vmap_table_offset = 0; 196 // derived from CompiledInvokeStub if available 197 uint32_t invoke_stub_offset = 0; 198 199 CompiledMethod* compiled_method = 200 compiler_->GetCompiledMethod(art::Compiler::MethodReference(dex_file, method_idx)); 201 if (compiled_method != NULL) { 202 offset = compiled_method->AlignCode(offset); 203 DCHECK_ALIGNED(offset, kArmAlignment); 204 const std::vector<uint8_t>& code = compiled_method->GetCode(); 205 size_t code_size = code.size() * sizeof(code[0]); 206 uint32_t thumb_offset = compiled_method->CodeDelta(); 207 code_offset = (code_size == 0) ? 0 : offset + thumb_offset; 208 209 // Deduplicate code arrays 210 std::map<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code); 211 if (code_iter != code_offsets_.end()) { 212 code_offset = code_iter->second; 213 } else { 214 code_offsets_.insert(std::pair<const std::vector<uint8_t>*, uint32_t>(&code, code_offset)); 215 offset += code_size; 216 oat_header_->UpdateChecksum(&code[0], code_size); 217 } 218 219 frame_size_in_bytes = compiled_method->GetFrameSizeInBytes(); 220 core_spill_mask = compiled_method->GetCoreSpillMask(); 221 fp_spill_mask = compiled_method->GetFpSpillMask(); 222 } 223 224 offset += sizeof(frame_size_in_bytes); 225 oat_header_->UpdateChecksum(&frame_size_in_bytes, sizeof(frame_size_in_bytes)); 226 227 offset += sizeof(core_spill_mask); 228 oat_header_->UpdateChecksum(&core_spill_mask, sizeof(core_spill_mask)); 229 230 offset += sizeof(fp_spill_mask); 231 oat_header_->UpdateChecksum(&fp_spill_mask, sizeof(fp_spill_mask)); 232 233 if (compiled_method != NULL) { 234 const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable(); 235 size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]); 236 mapping_table_offset = (mapping_table_size == 0) ? 0 : offset; 237 238 // Deduplicate mapping tables 239 std::map<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter = mapping_table_offsets_.find(&mapping_table); 240 if (mapping_iter != mapping_table_offsets_.end()) { 241 mapping_table_offset = mapping_iter->second; 242 } else { 243 mapping_table_offsets_.insert(std::pair<const std::vector<uint32_t>*, uint32_t>(&mapping_table, mapping_table_offset)); 244 offset += mapping_table_size; 245 oat_header_->UpdateChecksum(&mapping_table[0], mapping_table_size); 246 } 247 248 const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable(); 249 size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]); 250 vmap_table_offset = (vmap_table_size == 0) ? 0 : offset; 251 252 // Deduplicate vmap tables 253 std::map<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter = vmap_table_offsets_.find(&vmap_table); 254 if (vmap_iter != vmap_table_offsets_.end()) { 255 vmap_table_offset = vmap_iter->second; 256 } else { 257 vmap_table_offsets_.insert(std::pair<const std::vector<uint16_t>*, uint32_t>(&vmap_table, vmap_table_offset)); 258 offset += vmap_table_size; 259 oat_header_->UpdateChecksum(&vmap_table[0], vmap_table_size); 260 } 261 } 262 263 const char* shorty = dex_file->GetMethodShorty(dex_file->GetMethodId(method_idx)); 264 const CompiledInvokeStub* compiled_invoke_stub = compiler_->FindInvokeStub(is_static, shorty); 265 if (compiled_invoke_stub != NULL) { 266 offset = CompiledMethod::AlignCode(offset, compiler_->GetInstructionSet()); 267 DCHECK_ALIGNED(offset, kArmAlignment); 268 const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode(); 269 size_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]); 270 invoke_stub_offset = (invoke_stub_size == 0) ? 0 : offset; 271 272 // Deduplicate invoke stubs 273 std::map<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter = code_offsets_.find(&invoke_stub); 274 if (stub_iter != code_offsets_.end()) { 275 invoke_stub_offset = stub_iter->second; 276 } else { 277 code_offsets_.insert(std::pair<const std::vector<uint8_t>*, uint32_t>(&invoke_stub, invoke_stub_offset)); 278 offset += invoke_stub_size; 279 oat_header_->UpdateChecksum(&invoke_stub[0], invoke_stub_size); 280 } 281 } 282 283 oat_classes_[oat_class_index]->method_offsets_[class_def_method_index] 284 = OatMethodOffsets(code_offset, 285 frame_size_in_bytes, 286 core_spill_mask, 287 fp_spill_mask, 288 mapping_table_offset, 289 vmap_table_offset, 290 invoke_stub_offset); 291 292 if (compiler_->IsImage()) { 293 ClassLinker* linker = Runtime::Current()->GetClassLinker(); 294 DexCache* dex_cache = linker->FindDexCache(*dex_file); 295 Method* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache, class_loader_, 296 is_direct); 297 CHECK(method != NULL); 298 method->SetFrameSizeInBytes(frame_size_in_bytes); 299 method->SetCoreSpillMask(core_spill_mask); 300 method->SetFpSpillMask(fp_spill_mask); 301 method->SetOatMappingTableOffset(mapping_table_offset); 302 method->SetOatCodeOffset(code_offset); 303 method->SetOatVmapTableOffset(vmap_table_offset); 304 method->SetOatInvokeStubOffset(invoke_stub_offset); 305 } 306 return offset; 307} 308 309#define DCHECK_CODE_OFFSET() \ 310 DCHECK_EQ(static_cast<off_t>(code_offset), lseek(file->Fd(), 0, SEEK_CUR)) 311 312bool OatWriter::Write(File* file) { 313 if (!file->WriteFully(oat_header_, sizeof(*oat_header_))) { 314 PLOG(ERROR) << "Failed to write oat header to " << file->name(); 315 return false; 316 } 317 318 if (!WriteTables(file)) { 319 LOG(ERROR) << "Failed to write oat tables to " << file->name(); 320 return false; 321 } 322 323 size_t code_offset = WriteCode(file); 324 if (code_offset == 0) { 325 LOG(ERROR) << "Failed to write oat code to " << file->name(); 326 return false; 327 } 328 329 code_offset = WriteCodeDexFiles(file, code_offset); 330 if (code_offset == 0) { 331 LOG(ERROR) << "Failed to write oat code for dex files to " << file->name(); 332 return false; 333 } 334 335 return true; 336} 337 338bool OatWriter::WriteTables(File* file) { 339 for (size_t i = 0; i != oat_dex_files_.size(); ++i) { 340 if (!oat_dex_files_[i]->Write(file)) { 341 PLOG(ERROR) << "Failed to write oat dex information to " << file->name(); 342 return false; 343 } 344 } 345 for (size_t i = 0; i != oat_dex_files_.size(); ++i) { 346 uint32_t expected_offset = oat_dex_files_[i]->dex_file_offset_; 347 off_t actual_offset = lseek(file->Fd(), expected_offset, SEEK_SET); 348 if (static_cast<uint32_t>(actual_offset) != expected_offset) { 349 const DexFile* dex_file = (*dex_files_)[i]; 350 PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset 351 << " Expected: " << expected_offset << " File: " << dex_file->GetLocation(); 352 return false; 353 } 354 const DexFile* dex_file = (*dex_files_)[i]; 355 if (!file->WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) { 356 PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation() << " to " << file->name(); 357 return false; 358 } 359 } 360 for (size_t i = 0; i != oat_classes_.size(); ++i) { 361 if (!oat_classes_[i]->Write(file)) { 362 PLOG(ERROR) << "Failed to write oat methods information to " << file->name(); 363 return false; 364 } 365 } 366 return true; 367} 368 369size_t OatWriter::WriteCode(File* file) { 370 uint32_t code_offset = oat_header_->GetExecutableOffset(); 371 off_t new_offset = lseek(file->Fd(), executable_offset_padding_length_, SEEK_CUR); 372 if (static_cast<uint32_t>(new_offset) != code_offset) { 373 PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset 374 << " Expected: " << code_offset << " File: " << file->name(); 375 return 0; 376 } 377 DCHECK_CODE_OFFSET(); 378 return code_offset; 379} 380 381size_t OatWriter::WriteCodeDexFiles(File* file, size_t code_offset) { 382 size_t oat_class_index = 0; 383 for (size_t i = 0; i != oat_dex_files_.size(); ++i) { 384 const DexFile* dex_file = (*dex_files_)[i]; 385 CHECK(dex_file != NULL); 386 code_offset = WriteCodeDexFile(file, code_offset, oat_class_index, *dex_file); 387 if (code_offset == 0) { 388 return 0; 389 } 390 } 391 return code_offset; 392} 393 394size_t OatWriter::WriteCodeDexFile(File* file, size_t code_offset, size_t& oat_class_index, 395 const DexFile& dex_file) { 396 for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs(); 397 class_def_index++, oat_class_index++) { 398 const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); 399 code_offset = WriteCodeClassDef(file, code_offset, oat_class_index, dex_file, class_def); 400 if (code_offset == 0) { 401 return 0; 402 } 403 } 404 return code_offset; 405} 406 407void OatWriter::ReportWriteFailure(const char* what, uint32_t method_idx, 408 const DexFile& dex_file, File* f) const { 409 PLOG(ERROR) << "Failed to write " << what << " for " << PrettyMethod(method_idx, dex_file) 410 << " to " << f->name(); 411} 412 413size_t OatWriter::WriteCodeClassDef(File* file, 414 size_t code_offset, size_t oat_class_index, 415 const DexFile& dex_file, 416 const DexFile::ClassDef& class_def) { 417 const byte* class_data = dex_file.GetClassData(class_def); 418 if (class_data == NULL) { 419 // ie. an empty class such as a marker interface 420 return code_offset; 421 } 422 ClassDataItemIterator it(dex_file, class_data); 423 // Skip fields 424 while (it.HasNextStaticField()) { 425 it.Next(); 426 } 427 while (it.HasNextInstanceField()) { 428 it.Next(); 429 } 430 // Process methods 431 size_t class_def_method_index = 0; 432 while (it.HasNextDirectMethod()) { 433 bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0; 434 code_offset = WriteCodeMethod(file, code_offset, oat_class_index, class_def_method_index, 435 is_static, it.GetMemberIndex(), dex_file); 436 if (code_offset == 0) { 437 return 0; 438 } 439 class_def_method_index++; 440 it.Next(); 441 } 442 while (it.HasNextVirtualMethod()) { 443 code_offset = WriteCodeMethod(file, code_offset, oat_class_index, class_def_method_index, 444 false, it.GetMemberIndex(), dex_file); 445 if (code_offset == 0) { 446 return 0; 447 } 448 class_def_method_index++; 449 it.Next(); 450 } 451 return code_offset; 452} 453 454size_t OatWriter::WriteCodeMethod(File* file, size_t code_offset, size_t oat_class_index, 455 size_t class_def_method_index, bool is_static, 456 uint32_t method_idx, const DexFile& dex_file) { 457 const CompiledMethod* compiled_method = 458 compiler_->GetCompiledMethod(art::Compiler::MethodReference(&dex_file, method_idx)); 459 460 uint32_t frame_size_in_bytes = 0; 461 uint32_t core_spill_mask = 0; 462 uint32_t fp_spill_mask = 0; 463 464 OatMethodOffsets method_offsets = 465 oat_classes_[oat_class_index]->method_offsets_[class_def_method_index]; 466 467 468 if (compiled_method != NULL) { // ie. not an abstract method 469 uint32_t aligned_code_offset = compiled_method->AlignCode(code_offset); 470 uint32_t aligned_code_delta = aligned_code_offset - code_offset; 471 if (aligned_code_delta != 0) { 472 off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR); 473 if (static_cast<uint32_t>(new_offset) != aligned_code_offset) { 474 PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset 475 << " Expected: " << aligned_code_offset << " File: " << file->name(); 476 return false; 477 } 478 code_offset += aligned_code_delta; 479 DCHECK_CODE_OFFSET(); 480 } 481 DCHECK_ALIGNED(code_offset, kArmAlignment); 482 const std::vector<uint8_t>& code = compiled_method->GetCode(); 483 size_t code_size = code.size() * sizeof(code[0]); 484 485 // Deduplicate code arrays 486 size_t offset = code_offset + compiled_method->CodeDelta(); 487 std::map<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code); 488 if (code_iter != code_offsets_.end() && offset != method_offsets.code_offset_) { 489 DCHECK((code_size == 0 && method_offsets.code_offset_ == 0) 490 || code_iter->second == method_offsets.code_offset_) 491 << PrettyMethod(method_idx, dex_file); 492 } else { 493 DCHECK((code_size == 0 && method_offsets.code_offset_ == 0) 494 || offset == method_offsets.code_offset_) 495 << PrettyMethod(method_idx, dex_file); 496 if (!file->WriteFully(&code[0], code_size)) { 497 ReportWriteFailure("method code", method_idx, dex_file, file); 498 return false; 499 } 500 code_offset += code_size; 501 } 502 DCHECK_CODE_OFFSET(); 503 frame_size_in_bytes = compiled_method->GetFrameSizeInBytes(); 504 core_spill_mask = compiled_method->GetCoreSpillMask(); 505 fp_spill_mask = compiled_method->GetFpSpillMask(); 506 } 507 508 if (!file->WriteFully(&frame_size_in_bytes, sizeof(frame_size_in_bytes))) { 509 ReportWriteFailure("method frame size", method_idx, dex_file, file); 510 return false; 511 } 512 code_offset += sizeof(frame_size_in_bytes); 513 if (!file->WriteFully(&core_spill_mask, sizeof(core_spill_mask))) { 514 ReportWriteFailure("method core spill mask", method_idx, dex_file, file); 515 return false; 516 } 517 code_offset += sizeof(core_spill_mask); 518 if (!file->WriteFully(&fp_spill_mask, sizeof(fp_spill_mask))) { 519 ReportWriteFailure("method fp spill mask", method_idx, dex_file, file); 520 return false; 521 } 522 code_offset += sizeof(fp_spill_mask); 523 524 if (compiled_method != NULL) { 525 const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable(); 526 size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]); 527 528 // Deduplicate mapping tables 529 std::map<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter = 530 mapping_table_offsets_.find(&mapping_table); 531 if (mapping_iter != mapping_table_offsets_.end() && 532 code_offset != method_offsets.mapping_table_offset_) { 533 DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0) 534 || mapping_iter->second == method_offsets.mapping_table_offset_) 535 << PrettyMethod(method_idx, dex_file); 536 } else { 537 DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0) 538 || code_offset == method_offsets.mapping_table_offset_) 539 << PrettyMethod(method_idx, dex_file); 540 if (!file->WriteFully(&mapping_table[0], mapping_table_size)) { 541 ReportWriteFailure("mapping table", method_idx, dex_file, file); 542 return false; 543 } 544 code_offset += mapping_table_size; 545 } 546 DCHECK_CODE_OFFSET(); 547 548 const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable(); 549 size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]); 550 551 // Deduplicate vmap tables 552 std::map<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter = 553 vmap_table_offsets_.find(&vmap_table); 554 if (vmap_iter != vmap_table_offsets_.end() && 555 code_offset != method_offsets.vmap_table_offset_) { 556 DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0) 557 || vmap_iter->second == method_offsets.vmap_table_offset_) 558 << PrettyMethod(method_idx, dex_file); 559 } else { 560 DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0) 561 || code_offset == method_offsets.vmap_table_offset_) 562 << PrettyMethod(method_idx, dex_file); 563 if (!file->WriteFully(&vmap_table[0], vmap_table_size)) { 564 ReportWriteFailure("vmap table", method_idx, dex_file, file); 565 return false; 566 } 567 code_offset += vmap_table_size; 568 } 569 DCHECK_CODE_OFFSET(); 570 } 571 const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx)); 572 const CompiledInvokeStub* compiled_invoke_stub = compiler_->FindInvokeStub(is_static, shorty); 573 if (compiled_invoke_stub != NULL) { 574 uint32_t aligned_code_offset = CompiledMethod::AlignCode(code_offset, 575 compiler_->GetInstructionSet()); 576 uint32_t aligned_code_delta = aligned_code_offset - code_offset; 577 if (aligned_code_delta != 0) { 578 off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR); 579 if (static_cast<uint32_t>(new_offset) != aligned_code_offset) { 580 PLOG(ERROR) << "Failed to seek to align invoke stub code. Actual: " << new_offset 581 << " Expected: " << aligned_code_offset; 582 return false; 583 } 584 code_offset += aligned_code_delta; 585 DCHECK_CODE_OFFSET(); 586 } 587 DCHECK_ALIGNED(code_offset, kArmAlignment); 588 const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode(); 589 size_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]); 590 591 // Deduplicate invoke stubs 592 std::map<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter = 593 code_offsets_.find(&invoke_stub); 594 if (stub_iter != code_offsets_.end() && 595 code_offset != method_offsets.invoke_stub_offset_) { 596 DCHECK((invoke_stub_size == 0 && method_offsets.invoke_stub_offset_ == 0) 597 || stub_iter->second == method_offsets.invoke_stub_offset_) 598 << PrettyMethod(method_idx, dex_file); 599 } else { 600 DCHECK((invoke_stub_size == 0 && method_offsets.invoke_stub_offset_ == 0) 601 || code_offset == method_offsets.invoke_stub_offset_) 602 << PrettyMethod(method_idx, dex_file); 603 if (!file->WriteFully(&invoke_stub[0], invoke_stub_size)) { 604 ReportWriteFailure("invoke stub code", method_idx, dex_file, file); 605 return false; 606 } 607 code_offset += invoke_stub_size; 608 } 609 DCHECK_CODE_OFFSET(); 610 } 611 return code_offset; 612} 613 614OatWriter::OatDexFile::OatDexFile(const DexFile& dex_file) { 615 const std::string& location(dex_file.GetLocation()); 616 dex_file_location_size_ = location.size(); 617 dex_file_location_data_ = reinterpret_cast<const uint8_t*>(location.data()); 618 dex_file_checksum_ = dex_file.GetHeader().checksum_; 619 dex_file_offset_ = 0; 620 methods_offsets_.resize(dex_file.NumClassDefs()); 621} 622 623size_t OatWriter::OatDexFile::SizeOf() const { 624 return sizeof(dex_file_location_size_) 625 + dex_file_location_size_ 626 + sizeof(dex_file_checksum_) 627 + sizeof(dex_file_offset_) 628 + (sizeof(methods_offsets_[0]) * methods_offsets_.size()); 629} 630 631void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const { 632 oat_header.UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_)); 633 oat_header.UpdateChecksum(dex_file_location_data_, dex_file_location_size_); 634 oat_header.UpdateChecksum(&dex_file_checksum_, sizeof(dex_file_checksum_)); 635 oat_header.UpdateChecksum(&dex_file_offset_, sizeof(dex_file_offset_)); 636 oat_header.UpdateChecksum(&methods_offsets_[0], 637 sizeof(methods_offsets_[0]) * methods_offsets_.size()); 638} 639 640bool OatWriter::OatDexFile::Write(File* file) const { 641 if (!file->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) { 642 PLOG(ERROR) << "Failed to write dex file location length to " << file->name(); 643 return false; 644 } 645 if (!file->WriteFully(dex_file_location_data_, dex_file_location_size_)) { 646 PLOG(ERROR) << "Failed to write dex file location data to " << file->name(); 647 return false; 648 } 649 if (!file->WriteFully(&dex_file_checksum_, sizeof(dex_file_checksum_))) { 650 PLOG(ERROR) << "Failed to write dex file checksum to " << file->name(); 651 return false; 652 } 653 if (!file->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) { 654 PLOG(ERROR) << "Failed to write dex file offset to " << file->name(); 655 return false; 656 } 657 if (!file->WriteFully(&methods_offsets_[0], 658 sizeof(methods_offsets_[0]) * methods_offsets_.size())) { 659 PLOG(ERROR) << "Failed to write methods offsets to " << file->name(); 660 return false; 661 } 662 return true; 663} 664 665OatWriter::OatClass::OatClass(Class::Status status, uint32_t methods_count) { 666 status_ = status; 667 method_offsets_.resize(methods_count); 668} 669 670size_t OatWriter::OatClass::SizeOf() const { 671 return sizeof(status_) 672 + (sizeof(method_offsets_[0]) * method_offsets_.size()); 673} 674 675void OatWriter::OatClass::UpdateChecksum(OatHeader& oat_header) const { 676 oat_header.UpdateChecksum(&status_, sizeof(status_)); 677 oat_header.UpdateChecksum(&method_offsets_[0], 678 sizeof(method_offsets_[0]) * method_offsets_.size()); 679} 680 681bool OatWriter::OatClass::Write(File* file) const { 682 if (!file->WriteFully(&status_, sizeof(status_))) { 683 PLOG(ERROR) << "Failed to write class status to " << file->name(); 684 return false; 685 } 686 if (!file->WriteFully(&method_offsets_[0], 687 sizeof(method_offsets_[0]) * method_offsets_.size())) { 688 PLOG(ERROR) << "Failed to write method offsets to " << file->name(); 689 return false; 690 } 691 return true; 692} 693 694} // namespace art 695