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