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