oat_writer.cc revision 0571d357843c53e042f370f5f2c2e9aa3fe803a9
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 = 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 41OatWriter::~OatWriter() { 42 delete oat_header_; 43 STLDeleteElements(&oat_dex_files_); 44 STLDeleteElements(&oat_classes_); 45 STLDeleteElements(&oat_methods_); 46} 47 48size_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); 95 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 } 102 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); 150 if (class_data == NULL) { 151 // empty class, such as a marker interface 152 return offset; 153 } 154 ClassDataItemIterator it(dex_file, class_data); 155 CHECK_EQ(oat_methods_[oat_class_index]->method_offsets_.size(), 156 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 165 size_t class_def_method_index = 0; 166 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(); 172 } 173 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(); 179 } 180 DCHECK(!it.HasNext()); 181 return offset; 182} 183 184size_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) { 187 // derived from CompiledMethod if available 188 uint32_t code_offset = 0; 189 uint32_t frame_size_in_bytes = kStackAlignment; 190 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; 196 197 CompiledMethod* compiled_method = 198 compiler_->GetCompiledMethod(art::Compiler::MethodReference(dex_file, method_idx)); 199 if (compiled_method != NULL) { 200 offset = compiled_method->AlignCode(offset); 201 DCHECK_ALIGNED(offset, kArmAlignment); 202 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; 206 207 // Deduplicate code arrays 208 std::map<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code); 209 if (code_iter != code_offsets_.end()) { 210 code_offset = code_iter->second; 211 } else { 212 code_offsets_.insert(std::pair<const std::vector<uint8_t>*, uint32_t>(&code, code_offset)); 213 offset += code_size; 214 oat_header_->UpdateChecksum(&code[0], code_size); 215 } 216 217 frame_size_in_bytes = compiled_method->GetFrameSizeInBytes(); 218 core_spill_mask = compiled_method->GetCoreSpillMask(); 219 fp_spill_mask = compiled_method->GetFpSpillMask(); 220 } 221 222 offset += sizeof(frame_size_in_bytes); 223 oat_header_->UpdateChecksum(&frame_size_in_bytes, sizeof(frame_size_in_bytes)); 224 225 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) { 232 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; 235 236 // Deduplicate mapping tables 237 std::map<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter = mapping_table_offsets_.find(&mapping_table); 238 if (mapping_iter != mapping_table_offsets_.end()) { 239 mapping_table_offset = mapping_iter->second; 240 } else { 241 mapping_table_offsets_.insert(std::pair<const std::vector<uint32_t>*, uint32_t>(&mapping_table, mapping_table_offset)); 242 offset += mapping_table_size; 243 oat_header_->UpdateChecksum(&mapping_table[0], mapping_table_size); 244 } 245 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; 249 250 // Deduplicate vmap tables 251 std::map<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter = vmap_table_offsets_.find(&vmap_table); 252 if (vmap_iter != vmap_table_offsets_.end()) { 253 vmap_table_offset = vmap_iter->second; 254 } else { 255 vmap_table_offsets_.insert(std::pair<const std::vector<uint16_t>*, uint32_t>(&vmap_table, vmap_table_offset)); 256 offset += vmap_table_size; 257 oat_header_->UpdateChecksum(&vmap_table[0], vmap_table_size); 258 } 259 } 260 261 const char* shorty = dex_file->GetMethodShorty(dex_file->GetMethodId(method_idx)); 262 const CompiledInvokeStub* compiled_invoke_stub = compiler_->FindInvokeStub(is_static, shorty); 263 if (compiled_invoke_stub != NULL) { 264 offset = CompiledMethod::AlignCode(offset, compiler_->GetInstructionSet()); 265 DCHECK_ALIGNED(offset, kArmAlignment); 266 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; 269 270 // Deduplicate invoke stubs 271 std::map<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter = code_offsets_.find(&invoke_stub); 272 if (stub_iter != code_offsets_.end()) { 273 invoke_stub_offset = stub_iter->second; 274 } else { 275 code_offsets_.insert(std::pair<const std::vector<uint8_t>*, uint32_t>(&invoke_stub, invoke_stub_offset)); 276 offset += invoke_stub_size; 277 oat_header_->UpdateChecksum(&invoke_stub[0], invoke_stub_size); 278 } 279 } 280 281 oat_methods_[oat_class_index]->method_offsets_[class_def_method_index] 282 = OatMethodOffsets(code_offset, 283 frame_size_in_bytes, 284 core_spill_mask, 285 fp_spill_mask, 286 mapping_table_offset, 287 vmap_table_offset, 288 invoke_stub_offset); 289 290 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 } 304 return offset; 305} 306 307#define DCHECK_CODE_OFFSET() \ 308 DCHECK_EQ(static_cast<off_t>(code_offset), lseek(file->Fd(), 0, SEEK_CUR)) 309 310bool OatWriter::Write(File* file) { 311 if (!file->WriteFully(oat_header_, sizeof(*oat_header_))) { 312 PLOG(ERROR) << "Failed to write oat header to " << file->name(); 313 return false; 314 } 315 316 if (!WriteTables(file)) { 317 LOG(ERROR) << "Failed to write oat tables to " << file->name(); 318 return false; 319 } 320 321 size_t code_offset = WriteCode(file); 322 if (code_offset == 0) { 323 LOG(ERROR) << "Failed to write oat code to " << file->name(); 324 return false; 325 } 326 327 code_offset = WriteCodeDexFiles(file, code_offset); 328 if (code_offset == 0) { 329 LOG(ERROR) << "Failed to write oat code for dex files to " << file->name(); 330 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)) { 339 PLOG(ERROR) << "Failed to write oat dex information to " << file->name(); 340 return false; 341 } 342 } 343 for (size_t i = 0; i != oat_classes_.size(); ++i) { 344 if (!oat_classes_[i]->Write(file)) { 345 PLOG(ERROR) << "Failed to write oat classes information to " << file->name(); 346 return false; 347 } 348 } 349 for (size_t i = 0; i != oat_methods_.size(); ++i) { 350 if (!oat_methods_[i]->Write(file)) { 351 PLOG(ERROR) << "Failed to write oat methods information to " << file->name(); 352 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) { 362 PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset 363 << " Expected: " << code_offset << " File: " << file->name(); 364 return 0; 365 } 366 DCHECK_CODE_OFFSET(); 367 return code_offset; 368} 369 370size_t OatWriter::WriteCodeDexFiles(File* file, size_t code_offset) { 371 size_t oat_class_index = 0; 372 for (size_t i = 0; i != oat_classes_.size(); ++i) { 373 const DexFile* dex_file = (*dex_files_)[i]; 374 CHECK(dex_file != NULL); 375 code_offset = WriteCodeDexFile(file, code_offset, oat_class_index, *dex_file); 376 if (code_offset == 0) { 377 return 0; 378 } 379 } 380 return code_offset; 381} 382 383size_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++) { 387 const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); 388 code_offset = WriteCodeClassDef(file, code_offset, oat_class_index, dex_file, class_def); 389 if (code_offset == 0) { 390 return 0; 391 } 392 } 393 return code_offset; 394} 395 396void 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(); 400} 401 402size_t OatWriter::WriteCodeClassDef(File* file, 403 size_t code_offset, size_t oat_class_index, 404 const DexFile& dex_file, 405 const DexFile::ClassDef& class_def) { 406 const byte* class_data = dex_file.GetClassData(class_def); 407 if (class_data == NULL) { 408 // ie. an empty class such as a marker interface 409 return code_offset; 410 } 411 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); 425 if (code_offset == 0) { 426 return 0; 427 } 428 class_def_method_index++; 429 it.Next(); 430 } 431 while (it.HasNextVirtualMethod()) { 432 code_offset = WriteCodeMethod(file, code_offset, oat_class_index, class_def_method_index, 433 false, it.GetMemberIndex(), dex_file); 434 if (code_offset == 0) { 435 return 0; 436 } 437 class_def_method_index++; 438 it.Next(); 439 } 440 return code_offset; 441} 442 443size_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 458 uint32_t aligned_code_offset = compiled_method->AlignCode(code_offset); 459 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) { 463 PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset 464 << " Expected: " << aligned_code_offset << " File: " << file->name(); 465 return false; 466 } 467 code_offset += aligned_code_delta; 468 DCHECK_CODE_OFFSET(); 469 } 470 DCHECK_ALIGNED(code_offset, kArmAlignment); 471 const std::vector<uint8_t>& code = compiled_method->GetCode(); 472 size_t code_size = code.size() * sizeof(code[0]); 473 474 // Deduplicate code arrays 475 size_t offset = code_offset + compiled_method->CodeDelta(); 476 std::map<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code); 477 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); 481 } else { 482 DCHECK((code_size == 0 && method_offsets.code_offset_ == 0) 483 || offset == method_offsets.code_offset_) 484 << PrettyMethod(method_idx, dex_file); 485 if (!file->WriteFully(&code[0], code_size)) { 486 ReportWriteFailure("method code", method_idx, dex_file, file); 487 return false; 488 } 489 code_offset += code_size; 490 } 491 DCHECK_CODE_OFFSET(); 492 frame_size_in_bytes = compiled_method->GetFrameSizeInBytes(); 493 core_spill_mask = compiled_method->GetCoreSpillMask(); 494 fp_spill_mask = compiled_method->GetFpSpillMask(); 495 } 496 497 if (!file->WriteFully(&frame_size_in_bytes, sizeof(frame_size_in_bytes))) { 498 ReportWriteFailure("method frame size", method_idx, dex_file, file); 499 return false; 500 } 501 code_offset += sizeof(frame_size_in_bytes); 502 if (!file->WriteFully(&core_spill_mask, sizeof(core_spill_mask))) { 503 ReportWriteFailure("method core spill mask", method_idx, dex_file, file); 504 return false; 505 } 506 code_offset += sizeof(core_spill_mask); 507 if (!file->WriteFully(&fp_spill_mask, sizeof(fp_spill_mask))) { 508 ReportWriteFailure("method fp spill mask", method_idx, dex_file, file); 509 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]); 516 517 // Deduplicate mapping tables 518 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); 525 } else { 526 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); 529 if (!file->WriteFully(&mapping_table[0], mapping_table_size)) { 530 ReportWriteFailure("mapping table", method_idx, dex_file, file); 531 return false; 532 } 533 code_offset += mapping_table_size; 534 } 535 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]); 539 540 // Deduplicate vmap tables 541 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); 548 } else { 549 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); 552 if (!file->WriteFully(&vmap_table[0], vmap_table_size)) { 553 ReportWriteFailure("vmap table", method_idx, dex_file, file); 554 return false; 555 } 556 code_offset += vmap_table_size; 557 } 558 DCHECK_CODE_OFFSET(); 559 } 560 const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx)); 561 const CompiledInvokeStub* compiled_invoke_stub = compiler_->FindInvokeStub(is_static, shorty); 562 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 } 576 DCHECK_ALIGNED(code_offset, kArmAlignment); 577 const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode(); 578 size_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]); 579 580 // Deduplicate invoke stubs 581 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); 588 } else { 589 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); 592 if (!file->WriteFully(&invoke_stub[0], invoke_stub_size)) { 593 ReportWriteFailure("invoke stub code", method_idx, dex_file, file); 594 return false; 595 } 596 code_offset += invoke_stub_size; 597 } 598 DCHECK_CODE_OFFSET(); 599 } 600 return code_offset; 601} 602 603OatWriter::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_; 608 classes_offset_ = 0; 609} 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_))) { 627 PLOG(ERROR) << "Failed to write dex file location length to " << file->name(); 628 return false; 629 } 630 if (!file->WriteFully(dex_file_location_data_, dex_file_location_size_)) { 631 PLOG(ERROR) << "Failed to write dex file location data to " << file->name(); 632 return false; 633 } 634 if (!file->WriteFully(&dex_file_checksum_, sizeof(dex_file_checksum_))) { 635 PLOG(ERROR) << "Failed to write dex file checksum to " << file->name(); 636 return false; 637 } 638 if (!file->WriteFully(&classes_offset_, sizeof(classes_offset_))) { 639 PLOG(ERROR) << "Failed to write classes offset to " << file->name(); 640 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())) { 659 PLOG(ERROR) << "Failed to write methods offsets to " << file->name(); 660 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())) { 679 PLOG(ERROR) << "Failed to write method offsets to " << file->name(); 680 return false; 681 } 682 return true; 683} 684 685} // namespace art 686