oat_writer.cc revision 51c2467e8771b56e25ae4f17f66522f979f57a7e
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "oat_writer.h" 18 19#include <zlib.h> 20 21#include "base/stl_util.h" 22#include "base/unix_file/fd_file.h" 23#include "class_linker.h" 24#include "dex_file-inl.h" 25#include "gc/space/space.h" 26#include "mirror/abstract_method-inl.h" 27#include "mirror/array.h" 28#include "mirror/class_loader.h" 29#include "mirror/object-inl.h" 30#include "os.h" 31#include "output_stream.h" 32#include "safe_map.h" 33#include "scoped_thread_state_change.h" 34#include "verifier/method_verifier.h" 35 36namespace art { 37 38bool OatWriter::Create(OutputStream& output_stream, 39 const std::vector<const DexFile*>& dex_files, 40 uint32_t image_file_location_oat_checksum, 41 uint32_t image_file_location_oat_begin, 42 const std::string& image_file_location, 43 const CompilerDriver& driver) { 44 OatWriter oat_writer(dex_files, 45 image_file_location_oat_checksum, 46 image_file_location_oat_begin, 47 image_file_location, 48 &driver); 49 return oat_writer.Write(output_stream); 50} 51 52OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files, 53 uint32_t image_file_location_oat_checksum, 54 uint32_t image_file_location_oat_begin, 55 const std::string& image_file_location, 56 const CompilerDriver* compiler) 57 : compiler_driver_(compiler), 58 dex_files_(&dex_files), 59 image_file_location_oat_checksum_(image_file_location_oat_checksum), 60 image_file_location_oat_begin_(image_file_location_oat_begin), 61 image_file_location_(image_file_location), 62 oat_header_(NULL), 63 size_dex_file_alignment_(0), 64 size_executable_offset_alignment_(0), 65 size_oat_header_(0), 66 size_oat_header_image_file_location_(0), 67 size_dex_file_(0), 68 size_interpreter_to_interpreter_entry_(0), 69 size_interpreter_to_quick_entry_(0), 70 size_portable_resolution_trampoline_(0), 71 size_quick_resolution_trampoline_(0), 72 size_stubs_alignment_(0), 73 size_code_size_(0), 74 size_code_(0), 75 size_code_alignment_(0), 76 size_mapping_table_(0), 77 size_vmap_table_(0), 78 size_gc_map_(0), 79 size_oat_dex_file_location_size_(0), 80 size_oat_dex_file_location_data_(0), 81 size_oat_dex_file_location_checksum_(0), 82 size_oat_dex_file_offset_(0), 83 size_oat_dex_file_methods_offsets_(0), 84 size_oat_class_status_(0), 85 size_oat_class_method_offsets_(0) { 86 87 size_t offset = InitOatHeader(); 88 offset = InitOatDexFiles(offset); 89 offset = InitDexFiles(offset); 90 offset = InitOatClasses(offset); 91 offset = InitOatCode(offset); 92 offset = InitOatCodeDexFiles(offset); 93 94 CHECK_EQ(dex_files_->size(), oat_dex_files_.size()); 95 CHECK(image_file_location.empty() == compiler->IsImage()); 96} 97 98OatWriter::~OatWriter() { 99 delete oat_header_; 100 STLDeleteElements(&oat_dex_files_); 101 STLDeleteElements(&oat_classes_); 102} 103 104size_t OatWriter::InitOatHeader() { 105 // create the OatHeader 106 oat_header_ = new OatHeader(compiler_driver_->GetInstructionSet(), 107 dex_files_, 108 image_file_location_oat_checksum_, 109 image_file_location_oat_begin_, 110 image_file_location_); 111 size_t offset = sizeof(*oat_header_); 112 offset += image_file_location_.size(); 113 return offset; 114} 115 116size_t OatWriter::InitOatDexFiles(size_t offset) { 117 // create the OatDexFiles 118 for (size_t i = 0; i != dex_files_->size(); ++i) { 119 const DexFile* dex_file = (*dex_files_)[i]; 120 CHECK(dex_file != NULL); 121 OatDexFile* oat_dex_file = new OatDexFile(offset, *dex_file); 122 oat_dex_files_.push_back(oat_dex_file); 123 offset += oat_dex_file->SizeOf(); 124 } 125 return offset; 126} 127 128size_t OatWriter::InitDexFiles(size_t offset) { 129 // calculate the offsets within OatDexFiles to the DexFiles 130 for (size_t i = 0; i != dex_files_->size(); ++i) { 131 // dex files are required to be 4 byte aligned 132 size_t original_offset = offset; 133 offset = RoundUp(offset, 4); 134 size_dex_file_alignment_ += offset - original_offset; 135 136 // set offset in OatDexFile to DexFile 137 oat_dex_files_[i]->dex_file_offset_ = offset; 138 139 const DexFile* dex_file = (*dex_files_)[i]; 140 offset += dex_file->GetHeader().file_size_; 141 } 142 return offset; 143} 144 145size_t OatWriter::InitOatClasses(size_t offset) { 146 // create the OatClasses 147 // calculate the offsets within OatDexFiles to OatClasses 148 for (size_t i = 0; i != dex_files_->size(); ++i) { 149 const DexFile* dex_file = (*dex_files_)[i]; 150 for (size_t class_def_index = 0; 151 class_def_index < dex_file->NumClassDefs(); 152 class_def_index++) { 153 oat_dex_files_[i]->methods_offsets_[class_def_index] = offset; 154 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); 155 const byte* class_data = dex_file->GetClassData(class_def); 156 uint32_t num_methods = 0; 157 if (class_data != NULL) { // ie not an empty class, such as a marker interface 158 ClassDataItemIterator it(*dex_file, class_data); 159 size_t num_direct_methods = it.NumDirectMethods(); 160 size_t num_virtual_methods = it.NumVirtualMethods(); 161 num_methods = num_direct_methods + num_virtual_methods; 162 } 163 164 ClassReference class_ref(dex_file, class_def_index); 165 CompiledClass* compiled_class = compiler_driver_->GetCompiledClass(class_ref); 166 mirror::Class::Status status; 167 if (compiled_class != NULL) { 168 status = compiled_class->GetStatus(); 169 } else if (verifier::MethodVerifier::IsClassRejected(class_ref)) { 170 status = mirror::Class::kStatusError; 171 } else { 172 status = mirror::Class::kStatusNotReady; 173 } 174 175 OatClass* oat_class = new OatClass(offset, status, num_methods); 176 oat_classes_.push_back(oat_class); 177 offset += oat_class->SizeOf(); 178 } 179 oat_dex_files_[i]->UpdateChecksum(*oat_header_); 180 } 181 return offset; 182} 183 184size_t OatWriter::InitOatCode(size_t offset) { 185 // calculate the offsets within OatHeader to executable code 186 size_t old_offset = offset; 187 // required to be on a new page boundary 188 offset = RoundUp(offset, kPageSize); 189 oat_header_->SetExecutableOffset(offset); 190 size_executable_offset_alignment_ = offset - old_offset; 191 if (compiler_driver_->IsImage()) { 192 InstructionSet instruction_set = compiler_driver_->GetInstructionSet(); 193 oat_header_->SetInterpreterToInterpreterEntryOffset(offset); 194 interpreter_to_interpreter_entry_.reset(compiler_driver_->CreateInterpreterToInterpreterEntry()); 195 offset += interpreter_to_interpreter_entry_->size(); 196 197 offset = CompiledCode::AlignCode(offset, instruction_set); 198 oat_header_->SetInterpreterToQuickEntryOffset(offset); 199 interpreter_to_quick_entry_.reset(compiler_driver_->CreateInterpreterToQuickEntry()); 200 offset += interpreter_to_quick_entry_->size(); 201 202 offset = CompiledCode::AlignCode(offset, instruction_set); 203 oat_header_->SetPortableResolutionTrampolineOffset(offset); 204 portable_resolution_trampoline_.reset(compiler_driver_->CreatePortableResolutionTrampoline()); 205 offset += portable_resolution_trampoline_->size(); 206 207 offset = CompiledCode::AlignCode(offset, instruction_set); 208 oat_header_->SetQuickResolutionTrampolineOffset(offset); 209 quick_resolution_trampoline_.reset(compiler_driver_->CreateQuickResolutionTrampoline()); 210 offset += quick_resolution_trampoline_->size(); 211 } else { 212 oat_header_->SetInterpreterToInterpreterEntryOffset(0); 213 oat_header_->SetInterpreterToQuickEntryOffset(0); 214 oat_header_->SetPortableResolutionTrampolineOffset(0); 215 oat_header_->SetQuickResolutionTrampolineOffset(0); 216 } 217 return offset; 218} 219 220size_t OatWriter::InitOatCodeDexFiles(size_t offset) { 221 size_t oat_class_index = 0; 222 for (size_t i = 0; i != dex_files_->size(); ++i) { 223 const DexFile* dex_file = (*dex_files_)[i]; 224 CHECK(dex_file != NULL); 225 offset = InitOatCodeDexFile(offset, oat_class_index, *dex_file); 226 } 227 return offset; 228} 229 230size_t OatWriter::InitOatCodeDexFile(size_t offset, 231 size_t& oat_class_index, 232 const DexFile& dex_file) { 233 for (size_t class_def_index = 0; 234 class_def_index < dex_file.NumClassDefs(); 235 class_def_index++, oat_class_index++) { 236 const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); 237 offset = InitOatCodeClassDef(offset, oat_class_index, class_def_index, dex_file, class_def); 238 oat_classes_[oat_class_index]->UpdateChecksum(*oat_header_); 239 } 240 return offset; 241} 242 243size_t OatWriter::InitOatCodeClassDef(size_t offset, 244 size_t oat_class_index, size_t class_def_index, 245 const DexFile& dex_file, 246 const DexFile::ClassDef& class_def) { 247 const byte* class_data = dex_file.GetClassData(class_def); 248 if (class_data == NULL) { 249 // empty class, such as a marker interface 250 return offset; 251 } 252 ClassDataItemIterator it(dex_file, class_data); 253 CHECK_EQ(oat_classes_[oat_class_index]->method_offsets_.size(), 254 it.NumDirectMethods() + it.NumVirtualMethods()); 255 // Skip fields 256 while (it.HasNextStaticField()) { 257 it.Next(); 258 } 259 while (it.HasNextInstanceField()) { 260 it.Next(); 261 } 262 // Process methods 263 size_t class_def_method_index = 0; 264 while (it.HasNextDirectMethod()) { 265 bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0; 266 offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index, 267 is_native, it.GetMethodInvokeType(class_def), it.GetMemberIndex(), 268 &dex_file); 269 class_def_method_index++; 270 it.Next(); 271 } 272 while (it.HasNextVirtualMethod()) { 273 bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0; 274 offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index, 275 is_native, it.GetMethodInvokeType(class_def), it.GetMemberIndex(), 276 &dex_file); 277 class_def_method_index++; 278 it.Next(); 279 } 280 DCHECK(!it.HasNext()); 281 return offset; 282} 283 284size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, 285 size_t __attribute__((unused)) class_def_index, 286 size_t class_def_method_index, 287 bool __attribute__((unused)) is_native, 288 InvokeType invoke_type, 289 uint32_t method_idx, const DexFile* dex_file) { 290 // derived from CompiledMethod if available 291 uint32_t code_offset = 0; 292 uint32_t frame_size_in_bytes = kStackAlignment; 293 uint32_t core_spill_mask = 0; 294 uint32_t fp_spill_mask = 0; 295 uint32_t mapping_table_offset = 0; 296 uint32_t vmap_table_offset = 0; 297 uint32_t gc_map_offset = 0; 298 299 OatClass* oat_class = oat_classes_[oat_class_index]; 300#if defined(ART_USE_PORTABLE_COMPILER) 301 size_t oat_method_offsets_offset = 302 oat_class->GetOatMethodOffsetsOffsetFromOatHeader(class_def_method_index); 303#endif 304 305 CompiledMethod* compiled_method = 306 compiler_driver_->GetCompiledMethod(MethodReference(dex_file, method_idx)); 307 if (compiled_method != NULL) { 308#if defined(ART_USE_PORTABLE_COMPILER) 309 compiled_method->AddOatdataOffsetToCompliledCodeOffset( 310 oat_method_offsets_offset + OFFSETOF_MEMBER(OatMethodOffsets, code_offset_)); 311#else 312 const std::vector<uint8_t>& code = compiled_method->GetCode(); 313 offset = compiled_method->AlignCode(offset); 314 DCHECK_ALIGNED(offset, kArmAlignment); 315 uint32_t code_size = code.size() * sizeof(code[0]); 316 CHECK_NE(code_size, 0U); 317 uint32_t thumb_offset = compiled_method->CodeDelta(); 318 code_offset = offset + sizeof(code_size) + thumb_offset; 319 320 // Deduplicate code arrays 321 SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code); 322 if (code_iter != code_offsets_.end()) { 323 code_offset = code_iter->second; 324 } else { 325 code_offsets_.Put(&code, code_offset); 326 offset += sizeof(code_size); // code size is prepended before code 327 offset += code_size; 328 oat_header_->UpdateChecksum(&code[0], code_size); 329 } 330#endif 331 frame_size_in_bytes = compiled_method->GetFrameSizeInBytes(); 332 core_spill_mask = compiled_method->GetCoreSpillMask(); 333 fp_spill_mask = compiled_method->GetFpSpillMask(); 334 335 const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable(); 336 size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]); 337 mapping_table_offset = (mapping_table_size == 0) ? 0 : offset; 338 339 // Deduplicate mapping tables 340 SafeMap<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter = mapping_table_offsets_.find(&mapping_table); 341 if (mapping_iter != mapping_table_offsets_.end()) { 342 mapping_table_offset = mapping_iter->second; 343 } else { 344 mapping_table_offsets_.Put(&mapping_table, mapping_table_offset); 345 offset += mapping_table_size; 346 oat_header_->UpdateChecksum(&mapping_table[0], mapping_table_size); 347 } 348 349 const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable(); 350 size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]); 351 vmap_table_offset = (vmap_table_size == 0) ? 0 : offset; 352 353 // Deduplicate vmap tables 354 SafeMap<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter = vmap_table_offsets_.find(&vmap_table); 355 if (vmap_iter != vmap_table_offsets_.end()) { 356 vmap_table_offset = vmap_iter->second; 357 } else { 358 vmap_table_offsets_.Put(&vmap_table, vmap_table_offset); 359 offset += vmap_table_size; 360 oat_header_->UpdateChecksum(&vmap_table[0], vmap_table_size); 361 } 362 363 const std::vector<uint8_t>& gc_map = compiled_method->GetGcMap(); 364 size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]); 365 gc_map_offset = (gc_map_size == 0) ? 0 : offset; 366 367#if !defined(NDEBUG) 368 // We expect GC maps except when the class hasn't been verified or the method is native 369 ClassReference class_ref(dex_file, class_def_index); 370 CompiledClass* compiled_class = compiler_driver_->GetCompiledClass(class_ref); 371 mirror::Class::Status status; 372 if (compiled_class != NULL) { 373 status = compiled_class->GetStatus(); 374 } else if (verifier::MethodVerifier::IsClassRejected(class_ref)) { 375 status = mirror::Class::kStatusError; 376 } else { 377 status = mirror::Class::kStatusNotReady; 378 } 379 CHECK(gc_map_size != 0 || is_native || status < mirror::Class::kStatusVerified) 380 << &gc_map << " " << gc_map_size << " " << (is_native ? "true" : "false") << " " 381 << (status < mirror::Class::kStatusVerified) << " " << status << " " 382 << PrettyMethod(method_idx, *dex_file); 383#endif 384 385 // Deduplicate GC maps 386 SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter = gc_map_offsets_.find(&gc_map); 387 if (gc_map_iter != gc_map_offsets_.end()) { 388 gc_map_offset = gc_map_iter->second; 389 } else { 390 gc_map_offsets_.Put(&gc_map, gc_map_offset); 391 offset += gc_map_size; 392 oat_header_->UpdateChecksum(&gc_map[0], gc_map_size); 393 } 394 } 395 396 oat_class->method_offsets_[class_def_method_index] 397 = OatMethodOffsets(code_offset, 398 frame_size_in_bytes, 399 core_spill_mask, 400 fp_spill_mask, 401 mapping_table_offset, 402 vmap_table_offset, 403 gc_map_offset 404 ); 405 406 if (compiler_driver_->IsImage()) { 407 ClassLinker* linker = Runtime::Current()->GetClassLinker(); 408 mirror::DexCache* dex_cache = linker->FindDexCache(*dex_file); 409 // Unchecked as we hold mutator_lock_ on entry. 410 ScopedObjectAccessUnchecked soa(Thread::Current()); 411 mirror::AbstractMethod* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache, 412 NULL, NULL, invoke_type); 413 CHECK(method != NULL); 414 method->SetFrameSizeInBytes(frame_size_in_bytes); 415 method->SetCoreSpillMask(core_spill_mask); 416 method->SetFpSpillMask(fp_spill_mask); 417 method->SetOatMappingTableOffset(mapping_table_offset); 418 // Don't overwrite static method trampoline 419 if (!method->IsStatic() || method->IsConstructor() || 420 method->GetDeclaringClass()->IsInitialized()) { 421 method->SetOatCodeOffset(code_offset); 422 } else { 423 method->SetEntryPointFromCompiledCode(NULL); 424 } 425 method->SetOatVmapTableOffset(vmap_table_offset); 426 method->SetOatNativeGcMapOffset(gc_map_offset); 427 } 428 429 return offset; 430} 431 432#define DCHECK_OFFSET() \ 433 DCHECK_EQ(static_cast<off_t>(offset), out.Seek(0, kSeekCurrent)) 434 435#define DCHECK_OFFSET_() \ 436 DCHECK_EQ(static_cast<off_t>(offset_), out.Seek(0, kSeekCurrent)) 437 438bool OatWriter::Write(OutputStream& out) { 439 if (!out.WriteFully(oat_header_, sizeof(*oat_header_))) { 440 PLOG(ERROR) << "Failed to write oat header to " << out.GetLocation(); 441 return false; 442 } 443 size_oat_header_ += sizeof(*oat_header_); 444 445 if (!out.WriteFully(image_file_location_.data(), image_file_location_.size())) { 446 PLOG(ERROR) << "Failed to write oat header image file location to " << out.GetLocation(); 447 return false; 448 } 449 size_oat_header_image_file_location_ += image_file_location_.size(); 450 451 if (!WriteTables(out)) { 452 LOG(ERROR) << "Failed to write oat tables to " << out.GetLocation(); 453 return false; 454 } 455 456 size_t code_offset = WriteCode(out); 457 if (code_offset == 0) { 458 LOG(ERROR) << "Failed to write oat code to " << out.GetLocation(); 459 return false; 460 } 461 462 code_offset = WriteCodeDexFiles(out, code_offset); 463 if (code_offset == 0) { 464 LOG(ERROR) << "Failed to write oat code for dex files to " << out.GetLocation(); 465 return false; 466 } 467 468 if (kIsDebugBuild) { 469 uint32_t size_total = 0; 470 #define DO_STAT(x) \ 471 LOG(INFO) << #x "=" << PrettySize(x) << " (" << x << "B)"; \ 472 size_total += x; 473 474 DO_STAT(size_dex_file_alignment_); 475 DO_STAT(size_executable_offset_alignment_); 476 DO_STAT(size_oat_header_); 477 DO_STAT(size_oat_header_image_file_location_); 478 DO_STAT(size_dex_file_); 479 DO_STAT(size_interpreter_to_interpreter_entry_); 480 DO_STAT(size_interpreter_to_quick_entry_); 481 DO_STAT(size_portable_resolution_trampoline_); 482 DO_STAT(size_quick_resolution_trampoline_); 483 DO_STAT(size_stubs_alignment_); 484 DO_STAT(size_code_size_); 485 DO_STAT(size_code_); 486 DO_STAT(size_code_alignment_); 487 DO_STAT(size_mapping_table_); 488 DO_STAT(size_vmap_table_); 489 DO_STAT(size_gc_map_); 490 DO_STAT(size_oat_dex_file_location_size_); 491 DO_STAT(size_oat_dex_file_location_data_); 492 DO_STAT(size_oat_dex_file_location_checksum_); 493 DO_STAT(size_oat_dex_file_offset_); 494 DO_STAT(size_oat_dex_file_methods_offsets_); 495 DO_STAT(size_oat_class_status_); 496 DO_STAT(size_oat_class_method_offsets_); 497 #undef DO_STAT 498 499 LOG(INFO) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)"; \ 500 CHECK_EQ(size_total, static_cast<uint32_t>(out.Seek(0, kSeekCurrent))); 501 } 502 503 return true; 504} 505 506bool OatWriter::WriteTables(OutputStream& out) { 507 for (size_t i = 0; i != oat_dex_files_.size(); ++i) { 508 if (!oat_dex_files_[i]->Write(this, out)) { 509 PLOG(ERROR) << "Failed to write oat dex information to " << out.GetLocation(); 510 return false; 511 } 512 } 513 for (size_t i = 0; i != oat_dex_files_.size(); ++i) { 514 uint32_t expected_offset = oat_dex_files_[i]->dex_file_offset_; 515 off_t actual_offset = out.Seek(expected_offset, kSeekSet); 516 if (static_cast<uint32_t>(actual_offset) != expected_offset) { 517 const DexFile* dex_file = (*dex_files_)[i]; 518 PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset 519 << " Expected: " << expected_offset << " File: " << dex_file->GetLocation(); 520 return false; 521 } 522 const DexFile* dex_file = (*dex_files_)[i]; 523 if (!out.WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) { 524 PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation() << " to " << out.GetLocation(); 525 return false; 526 } 527 size_dex_file_ += dex_file->GetHeader().file_size_; 528 } 529 for (size_t i = 0; i != oat_classes_.size(); ++i) { 530 if (!oat_classes_[i]->Write(this, out)) { 531 PLOG(ERROR) << "Failed to write oat methods information to " << out.GetLocation(); 532 return false; 533 } 534 } 535 return true; 536} 537 538size_t OatWriter::WriteCode(OutputStream& out) { 539 uint32_t offset = oat_header_->GetExecutableOffset(); 540 off_t new_offset = out.Seek(size_executable_offset_alignment_, kSeekCurrent); 541 if (static_cast<uint32_t>(new_offset) != offset) { 542 PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset 543 << " Expected: " << offset << " File: " << out.GetLocation(); 544 return 0; 545 } 546 DCHECK_OFFSET(); 547 if (compiler_driver_->IsImage()) { 548 InstructionSet instruction_set = compiler_driver_->GetInstructionSet(); 549 if (!out.WriteFully(&(*interpreter_to_interpreter_entry_)[0], interpreter_to_interpreter_entry_->size())) { 550 PLOG(ERROR) << "Failed to write interpreter to interpreter entry to " << out.GetLocation(); 551 return false; 552 } 553 size_interpreter_to_interpreter_entry_ += interpreter_to_interpreter_entry_->size(); 554 offset += interpreter_to_interpreter_entry_->size(); 555 DCHECK_OFFSET(); 556 557 uint32_t aligned_offset = CompiledCode::AlignCode(offset, instruction_set); 558 uint32_t alignment_padding = aligned_offset - offset; 559 out.Seek(alignment_padding, kSeekCurrent); 560 size_stubs_alignment_ += alignment_padding; 561 if (!out.WriteFully(&(*interpreter_to_quick_entry_)[0], interpreter_to_quick_entry_->size())) { 562 PLOG(ERROR) << "Failed to write interpreter to quick entry to " << out.GetLocation(); 563 return false; 564 } 565 size_interpreter_to_quick_entry_ += interpreter_to_quick_entry_->size(); 566 offset += alignment_padding + interpreter_to_quick_entry_->size(); 567 DCHECK_OFFSET(); 568 569 aligned_offset = CompiledCode::AlignCode(offset, instruction_set); 570 alignment_padding = aligned_offset - offset; 571 out.Seek(alignment_padding, kSeekCurrent); 572 size_stubs_alignment_ += alignment_padding; 573 if (!out.WriteFully(&(*portable_resolution_trampoline_)[0], portable_resolution_trampoline_->size())) { 574 PLOG(ERROR) << "Failed to write portable resolution trampoline to " << out.GetLocation(); 575 return false; 576 } 577 size_portable_resolution_trampoline_ += portable_resolution_trampoline_->size(); 578 offset += alignment_padding + portable_resolution_trampoline_->size(); 579 DCHECK_OFFSET(); 580 581 aligned_offset = CompiledCode::AlignCode(offset, instruction_set); 582 alignment_padding = aligned_offset - offset; 583 out.Seek(alignment_padding, kSeekCurrent); 584 size_stubs_alignment_ += alignment_padding; 585 if (!out.WriteFully(&(*quick_resolution_trampoline_)[0], quick_resolution_trampoline_->size())) { 586 PLOG(ERROR) << "Failed to write quick resolution trampoline to " << out.GetLocation(); 587 return false; 588 } 589 size_quick_resolution_trampoline_ += quick_resolution_trampoline_->size(); 590 offset += alignment_padding + quick_resolution_trampoline_->size(); 591 DCHECK_OFFSET(); 592 } 593 return offset; 594} 595 596size_t OatWriter::WriteCodeDexFiles(OutputStream& out, size_t code_offset) { 597 size_t oat_class_index = 0; 598 for (size_t i = 0; i != oat_dex_files_.size(); ++i) { 599 const DexFile* dex_file = (*dex_files_)[i]; 600 CHECK(dex_file != NULL); 601 code_offset = WriteCodeDexFile(out, code_offset, oat_class_index, *dex_file); 602 if (code_offset == 0) { 603 return 0; 604 } 605 } 606 return code_offset; 607} 608 609size_t OatWriter::WriteCodeDexFile(OutputStream& out, size_t code_offset, size_t& oat_class_index, 610 const DexFile& dex_file) { 611 for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs(); 612 class_def_index++, oat_class_index++) { 613 const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); 614 code_offset = WriteCodeClassDef(out, code_offset, oat_class_index, dex_file, class_def); 615 if (code_offset == 0) { 616 return 0; 617 } 618 } 619 return code_offset; 620} 621 622void OatWriter::ReportWriteFailure(const char* what, uint32_t method_idx, 623 const DexFile& dex_file, OutputStream& out) const { 624 PLOG(ERROR) << "Failed to write " << what << " for " << PrettyMethod(method_idx, dex_file) 625 << " to " << out.GetLocation(); 626} 627 628size_t OatWriter::WriteCodeClassDef(OutputStream& out, 629 size_t code_offset, size_t oat_class_index, 630 const DexFile& dex_file, 631 const DexFile::ClassDef& class_def) { 632 const byte* class_data = dex_file.GetClassData(class_def); 633 if (class_data == NULL) { 634 // ie. an empty class such as a marker interface 635 return code_offset; 636 } 637 ClassDataItemIterator it(dex_file, class_data); 638 // Skip fields 639 while (it.HasNextStaticField()) { 640 it.Next(); 641 } 642 while (it.HasNextInstanceField()) { 643 it.Next(); 644 } 645 // Process methods 646 size_t class_def_method_index = 0; 647 while (it.HasNextDirectMethod()) { 648 bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0; 649 code_offset = WriteCodeMethod(out, code_offset, oat_class_index, class_def_method_index, 650 is_static, it.GetMemberIndex(), dex_file); 651 if (code_offset == 0) { 652 return 0; 653 } 654 class_def_method_index++; 655 it.Next(); 656 } 657 while (it.HasNextVirtualMethod()) { 658 code_offset = WriteCodeMethod(out, code_offset, oat_class_index, class_def_method_index, 659 false, it.GetMemberIndex(), dex_file); 660 if (code_offset == 0) { 661 return 0; 662 } 663 class_def_method_index++; 664 it.Next(); 665 } 666 return code_offset; 667} 668 669size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_class_index, 670 size_t class_def_method_index, bool is_static, 671 uint32_t method_idx, const DexFile& dex_file) { 672 const CompiledMethod* compiled_method = 673 compiler_driver_->GetCompiledMethod(MethodReference(&dex_file, method_idx)); 674 675 OatMethodOffsets method_offsets = 676 oat_classes_[oat_class_index]->method_offsets_[class_def_method_index]; 677 678 679 if (compiled_method != NULL) { // ie. not an abstract method 680#if !defined(ART_USE_PORTABLE_COMPILER) 681 uint32_t aligned_offset = compiled_method->AlignCode(offset); 682 uint32_t aligned_code_delta = aligned_offset - offset; 683 if (aligned_code_delta != 0) { 684 off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent); 685 size_code_alignment_ += aligned_code_delta; 686 if (static_cast<uint32_t>(new_offset) != aligned_offset) { 687 PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset 688 << " Expected: " << aligned_offset << " File: " << out.GetLocation(); 689 return 0; 690 } 691 offset += aligned_code_delta; 692 DCHECK_OFFSET(); 693 } 694 DCHECK_ALIGNED(offset, kArmAlignment); 695 const std::vector<uint8_t>& code = compiled_method->GetCode(); 696 uint32_t code_size = code.size() * sizeof(code[0]); 697 CHECK_NE(code_size, 0U); 698 699 // Deduplicate code arrays 700 size_t code_offset = offset + sizeof(code_size) + compiled_method->CodeDelta(); 701 SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code); 702 if (code_iter != code_offsets_.end() && code_offset != method_offsets.code_offset_) { 703 DCHECK(code_iter->second == method_offsets.code_offset_) 704 << PrettyMethod(method_idx, dex_file); 705 } else { 706 DCHECK(code_offset == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file); 707 if (!out.WriteFully(&code_size, sizeof(code_size))) { 708 ReportWriteFailure("method code size", method_idx, dex_file, out); 709 return 0; 710 } 711 size_code_size_ += sizeof(code_size); 712 offset += sizeof(code_size); 713 DCHECK_OFFSET(); 714 if (!out.WriteFully(&code[0], code_size)) { 715 ReportWriteFailure("method code", method_idx, dex_file, out); 716 return 0; 717 } 718 size_code_ += code_size; 719 offset += code_size; 720 } 721 DCHECK_OFFSET(); 722#endif 723 724 const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable(); 725 size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]); 726 727 // Deduplicate mapping tables 728 SafeMap<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter = 729 mapping_table_offsets_.find(&mapping_table); 730 if (mapping_iter != mapping_table_offsets_.end() && 731 offset != method_offsets.mapping_table_offset_) { 732 DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0) 733 || mapping_iter->second == method_offsets.mapping_table_offset_) 734 << PrettyMethod(method_idx, dex_file); 735 } else { 736 DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0) 737 || offset == method_offsets.mapping_table_offset_) 738 << PrettyMethod(method_idx, dex_file); 739 if (!out.WriteFully(&mapping_table[0], mapping_table_size)) { 740 ReportWriteFailure("mapping table", method_idx, dex_file, out); 741 return 0; 742 } 743 size_mapping_table_ += mapping_table_size; 744 offset += mapping_table_size; 745 } 746 DCHECK_OFFSET(); 747 748 const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable(); 749 size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]); 750 751 // Deduplicate vmap tables 752 SafeMap<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter = 753 vmap_table_offsets_.find(&vmap_table); 754 if (vmap_iter != vmap_table_offsets_.end() && 755 offset != method_offsets.vmap_table_offset_) { 756 DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0) 757 || vmap_iter->second == method_offsets.vmap_table_offset_) 758 << PrettyMethod(method_idx, dex_file); 759 } else { 760 DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0) 761 || offset == method_offsets.vmap_table_offset_) 762 << PrettyMethod(method_idx, dex_file); 763 if (!out.WriteFully(&vmap_table[0], vmap_table_size)) { 764 ReportWriteFailure("vmap table", method_idx, dex_file, out); 765 return 0; 766 } 767 size_vmap_table_ += vmap_table_size; 768 offset += vmap_table_size; 769 } 770 DCHECK_OFFSET(); 771 772 const std::vector<uint8_t>& gc_map = compiled_method->GetGcMap(); 773 size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]); 774 775 // Deduplicate GC maps 776 SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter = 777 gc_map_offsets_.find(&gc_map); 778 if (gc_map_iter != gc_map_offsets_.end() && 779 offset != method_offsets.gc_map_offset_) { 780 DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0) 781 || gc_map_iter->second == method_offsets.gc_map_offset_) 782 << PrettyMethod(method_idx, dex_file); 783 } else { 784 DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0) 785 || offset == method_offsets.gc_map_offset_) 786 << PrettyMethod(method_idx, dex_file); 787 if (!out.WriteFully(&gc_map[0], gc_map_size)) { 788 ReportWriteFailure("GC map", method_idx, dex_file, out); 789 return 0; 790 } 791 size_gc_map_ += gc_map_size; 792 offset += gc_map_size; 793 } 794 DCHECK_OFFSET(); 795 } 796 797 return offset; 798} 799 800OatWriter::OatDexFile::OatDexFile(size_t offset, const DexFile& dex_file) { 801 offset_ = offset; 802 const std::string& location(dex_file.GetLocation()); 803 dex_file_location_size_ = location.size(); 804 dex_file_location_data_ = reinterpret_cast<const uint8_t*>(location.data()); 805 dex_file_location_checksum_ = dex_file.GetLocationChecksum(); 806 dex_file_offset_ = 0; 807 methods_offsets_.resize(dex_file.NumClassDefs()); 808} 809 810size_t OatWriter::OatDexFile::SizeOf() const { 811 return sizeof(dex_file_location_size_) 812 + dex_file_location_size_ 813 + sizeof(dex_file_location_checksum_) 814 + sizeof(dex_file_offset_) 815 + (sizeof(methods_offsets_[0]) * methods_offsets_.size()); 816} 817 818void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const { 819 oat_header.UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_)); 820 oat_header.UpdateChecksum(dex_file_location_data_, dex_file_location_size_); 821 oat_header.UpdateChecksum(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_)); 822 oat_header.UpdateChecksum(&dex_file_offset_, sizeof(dex_file_offset_)); 823 oat_header.UpdateChecksum(&methods_offsets_[0], 824 sizeof(methods_offsets_[0]) * methods_offsets_.size()); 825} 826 827bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream& out) const { 828 DCHECK_OFFSET_(); 829 if (!out.WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) { 830 PLOG(ERROR) << "Failed to write dex file location length to " << out.GetLocation(); 831 return false; 832 } 833 oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_); 834 if (!out.WriteFully(dex_file_location_data_, dex_file_location_size_)) { 835 PLOG(ERROR) << "Failed to write dex file location data to " << out.GetLocation(); 836 return false; 837 } 838 oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_; 839 if (!out.WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) { 840 PLOG(ERROR) << "Failed to write dex file location checksum to " << out.GetLocation(); 841 return false; 842 } 843 oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_); 844 if (!out.WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) { 845 PLOG(ERROR) << "Failed to write dex file offset to " << out.GetLocation(); 846 return false; 847 } 848 oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_); 849 if (!out.WriteFully(&methods_offsets_[0], 850 sizeof(methods_offsets_[0]) * methods_offsets_.size())) { 851 PLOG(ERROR) << "Failed to write methods offsets to " << out.GetLocation(); 852 return false; 853 } 854 oat_writer->size_oat_dex_file_methods_offsets_ += 855 sizeof(methods_offsets_[0]) * methods_offsets_.size(); 856 return true; 857} 858 859OatWriter::OatClass::OatClass(size_t offset, mirror::Class::Status status, uint32_t methods_count) { 860 offset_ = offset; 861 status_ = status; 862 method_offsets_.resize(methods_count); 863} 864 865size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatHeader( 866 size_t class_def_method_index_) const { 867 return offset_ + GetOatMethodOffsetsOffsetFromOatClass(class_def_method_index_); 868} 869 870size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatClass( 871 size_t class_def_method_index_) const { 872 return sizeof(status_) 873 + (sizeof(method_offsets_[0]) * class_def_method_index_); 874} 875 876size_t OatWriter::OatClass::SizeOf() const { 877 return GetOatMethodOffsetsOffsetFromOatClass(method_offsets_.size()); 878} 879 880void OatWriter::OatClass::UpdateChecksum(OatHeader& oat_header) const { 881 oat_header.UpdateChecksum(&status_, sizeof(status_)); 882 oat_header.UpdateChecksum(&method_offsets_[0], 883 sizeof(method_offsets_[0]) * method_offsets_.size()); 884} 885 886bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream& out) const { 887 DCHECK_OFFSET_(); 888 if (!out.WriteFully(&status_, sizeof(status_))) { 889 PLOG(ERROR) << "Failed to write class status to " << out.GetLocation(); 890 return false; 891 } 892 oat_writer->size_oat_class_status_ += sizeof(status_); 893 DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(0)), 894 out.Seek(0, kSeekCurrent)); 895 if (!out.WriteFully(&method_offsets_[0], 896 sizeof(method_offsets_[0]) * method_offsets_.size())) { 897 PLOG(ERROR) << "Failed to write method offsets to " << out.GetLocation(); 898 return false; 899 } 900 oat_writer->size_oat_class_method_offsets_ += sizeof(method_offsets_[0]) * method_offsets_.size(); 901 DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(method_offsets_.size())), 902 out.Seek(0, kSeekCurrent)); 903 return true; 904} 905 906} // namespace art 907