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