image_writer.cc revision e24fa61603a60ade3797e4a0c8b3fccb346cb048
1// Copyright 2011 Google Inc. All Rights Reserved. 2 3#include "image_writer.h" 4 5#include <sys/mman.h> 6 7#include <vector> 8 9#include "UniquePtr.h" 10#include "class_linker.h" 11#include "class_loader.h" 12#include "dex_cache.h" 13#include "file.h" 14#include "globals.h" 15#include "heap.h" 16#include "image.h" 17#include "intern_table.h" 18#include "logging.h" 19#include "object.h" 20#include "runtime.h" 21#include "space.h" 22#include "utils.h" 23 24namespace art { 25 26bool ImageWriter::Write(const char* image_filename, uintptr_t image_base, 27 const std::string& oat_filename, const std::string& strip_location_prefix) { 28 CHECK_NE(image_base, 0U); 29 image_base_ = reinterpret_cast<byte*>(image_base); 30 31 const std::vector<Space*>& spaces = Heap::GetSpaces(); 32 // currently just write the last space, assuming it is the space that was being used for allocation 33 CHECK_GE(spaces.size(), 1U); 34 source_space_ = spaces[spaces.size()-1]; 35 36 oat_file_.reset(OatFile::Open(oat_filename, strip_location_prefix, NULL)); 37 if (oat_file_.get() == NULL) { 38 LOG(ERROR) << "Failed to open oat file " << oat_filename; 39 return false; 40 } 41 42 if (!Init()) { 43 return false; 44 } 45 Heap::CollectGarbage(); 46 CalculateNewObjectOffsets(); 47 CopyAndFixupObjects(); 48 49 UniquePtr<File> file(OS::OpenFile(image_filename, true)); 50 if (file.get() == NULL) { 51 LOG(ERROR) << "Failed to open image file " << image_filename; 52 return false; 53 } 54 bool success = file->WriteFully(image_->GetAddress(), image_top_); 55 if (!success) { 56 PLOG(ERROR) << "Failed to write image file " << image_filename; 57 return false; 58 } 59 return true; 60} 61 62bool ImageWriter::Init() { 63 size_t size = source_space_->Size(); 64 int prot = PROT_READ | PROT_WRITE; 65 size_t length = RoundUp(size, kPageSize); 66 image_.reset(MemMap::Map(length, prot)); 67 if (image_.get() == NULL) { 68 LOG(ERROR) << "Failed to allocate memory for image file generation"; 69 return false; 70 } 71 return true; 72} 73 74void ImageWriter::CalculateNewObjectOffsetsCallback(Object* obj, void* arg) { 75 DCHECK(obj != NULL); 76 DCHECK(arg != NULL); 77 ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg); 78 if (!image_writer->InSourceSpace(obj)) { 79 return; 80 } 81 82 // if it is a string, we want to intern it if its not interned. 83 if (obj->IsString()) { 84 // we must be an interned string that was forward referenced and already assigned 85 if (IsImageOffsetAssigned(obj)) { 86 DCHECK_EQ(obj, obj->AsString()->Intern()); 87 return; 88 } 89 String* interned = obj->AsString()->Intern(); 90 if (obj != interned) { 91 if (!IsImageOffsetAssigned(interned)) { 92 // interned obj is after us, allocate its location early 93 image_writer->AssignImageOffset(interned); 94 } 95 // point those looking for this object to the interned version. 96 SetImageOffset(obj, GetImageOffset(interned)); 97 return; 98 } 99 // else (obj == interned), nothing to do but fall through to the normal case 100 } 101 102 image_writer->AssignImageOffset(obj); 103 104 // sniff out the DexCaches on this pass for use on the next pass 105 if (obj->IsClass()) { 106 Class* klass = obj->AsClass(); 107 DexCache* dex_cache = klass->GetDexCache(); 108 if (dex_cache != NULL) { 109 image_writer->dex_caches_.insert(dex_cache); 110 } else { 111 DCHECK(klass->IsArrayClass() || klass->IsPrimitive()) << PrettyClass(klass); 112 } 113 } 114} 115 116ObjectArray<Object>* ImageWriter::CreateImageRoots() const { 117 // build a Object[] of the roots needed to restore the runtime 118 Runtime* runtime = Runtime::Current(); 119 ClassLinker* class_linker = runtime->GetClassLinker(); 120 Class* object_array_class = class_linker->FindSystemClass("[Ljava/lang/Object;"); 121 ObjectArray<Object>* image_roots = ObjectArray<Object>::Alloc(object_array_class, 122 ImageHeader::kImageRootsMax); 123 image_roots->Set(ImageHeader::kJniStubArray, 124 runtime->GetJniStubArray()); 125 image_roots->Set(ImageHeader::kAbstractMethodErrorStubArray, 126 runtime->GetAbstractMethodErrorStubArray()); 127 image_roots->Set(ImageHeader::kCalleeSaveMethod, 128 runtime->GetCalleeSaveMethod()); 129 image_roots->Set(ImageHeader::kOatLocation, 130 String::AllocFromModifiedUtf8(oat_file_->GetLocation().c_str())); 131 for (int i = 0; i < ImageHeader::kImageRootsMax; i++) { 132 CHECK(image_roots->Get(i) != NULL); 133 } 134 return image_roots; 135} 136 137void ImageWriter::CalculateNewObjectOffsets() { 138 ObjectArray<Object>* image_roots = CreateImageRoots(); 139 140 HeapBitmap* heap_bitmap = Heap::GetLiveBits(); 141 DCHECK(heap_bitmap != NULL); 142 DCHECK_EQ(0U, image_top_); 143 144 // leave space for the header, but do not write it yet, we need to 145 // know where image_roots is going to end up 146 image_top_ += RoundUp(sizeof(ImageHeader), 8); // 64-bit-alignment 147 148 heap_bitmap->Walk(CalculateNewObjectOffsetsCallback, this); // TODO: add Space-limited Walk 149 DCHECK_LT(image_top_, image_->GetLength()); 150 151 // Note that image_top_ is left at end of used space 152 oat_base_ = image_base_ + RoundUp(image_top_, kPageSize); 153 byte* oat_limit = oat_base_ + oat_file_->GetSize(); 154 155 // return to write header at start of image with future location of image_roots 156 ImageHeader image_header(reinterpret_cast<uint32_t>(image_base_), 157 reinterpret_cast<uint32_t>(GetImageAddress(image_roots)), 158 oat_file_->GetOatHeader().GetChecksum(), 159 reinterpret_cast<uint32_t>(oat_base_), 160 reinterpret_cast<uint32_t>(oat_limit)); 161 memcpy(image_->GetAddress(), &image_header, sizeof(image_header)); 162} 163 164void ImageWriter::CopyAndFixupObjects() { 165 HeapBitmap* heap_bitmap = Heap::GetLiveBits(); 166 DCHECK(heap_bitmap != NULL); 167 // TODO: heap validation can't handle this fix up pass 168 Heap::DisableObjectValidation(); 169 heap_bitmap->Walk(CopyAndFixupObjectsCallback, this); // TODO: add Space-limited Walk 170 FixupDexCaches(); 171} 172 173void ImageWriter::CopyAndFixupObjectsCallback(Object* object, void* arg) { 174 DCHECK(object != NULL); 175 DCHECK(arg != NULL); 176 const Object* obj = object; 177 ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg); 178 if (!image_writer->InSourceSpace(object)) { 179 return; 180 } 181 182 // see GetLocalAddress for similar computation 183 size_t offset = image_writer->GetImageOffset(obj); 184 byte* dst = image_writer->image_->GetAddress() + offset; 185 const byte* src = reinterpret_cast<const byte*>(obj); 186 size_t n = obj->SizeOf(); 187 DCHECK_LT(offset + n, image_writer->image_->GetLength()); 188 memcpy(dst, src, n); 189 Object* copy = reinterpret_cast<Object*>(dst); 190 ResetImageOffset(copy); 191 image_writer->FixupObject(obj, copy); 192} 193 194void ImageWriter::FixupObject(const Object* orig, Object* copy) { 195 DCHECK(orig != NULL); 196 DCHECK(copy != NULL); 197 copy->SetClass(down_cast<Class*>(GetImageAddress(orig->GetClass()))); 198 // TODO: special case init of pointers to malloc data (or removal of these pointers) 199 if (orig->IsClass()) { 200 FixupClass(orig->AsClass(), down_cast<Class*>(copy)); 201 } else if (orig->IsObjectArray()) { 202 FixupObjectArray(orig->AsObjectArray<Object>(), down_cast<ObjectArray<Object>*>(copy)); 203 } else if (orig->IsMethod()) { 204 FixupMethod(orig->AsMethod(), down_cast<Method*>(copy)); 205 } else { 206 FixupInstanceFields(orig, copy); 207 } 208} 209 210void ImageWriter::FixupClass(const Class* orig, Class* copy) { 211 FixupInstanceFields(orig, copy); 212 FixupStaticFields(orig, copy); 213} 214 215const void* FixupCode(const ByteArray* copy_code_array, const void* orig_code) { 216 // TODO: change to DCHECK when all code compiling 217 if (copy_code_array == NULL) { 218 return NULL; 219 } 220 const void* copy_code = copy_code_array->GetData(); 221 // TODO: remember InstructionSet with each code array so we know if we need to do thumb fixup? 222 if ((reinterpret_cast<uintptr_t>(orig_code) % 2) == 1) { 223 return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(copy_code) + 1); 224 } 225 return copy_code; 226} 227 228void ImageWriter::FixupMethod(const Method* orig, Method* copy) { 229 FixupInstanceFields(orig, copy); 230 231 // OatWriter clears the code_array_ after writing the code. 232 // It replaces the code_ with an offset value we now adjust to be a pointer. 233 DCHECK(copy->code_array_ == NULL) 234 << PrettyMethod(orig) 235 << " orig_code_array_=" << orig->GetCodeArray() << " orig_code_=" << orig->GetCode() 236 << " copy_code_array_=" << copy->code_array_ << " orig_code_=" << copy->code_ 237 << " jni_stub=" << Runtime::Current()->GetJniStubArray() 238 << " ame_stub=" << Runtime::Current()->GetAbstractMethodErrorStubArray(); 239 copy->invoke_stub_ = reinterpret_cast<Method::InvokeStub*>(FixupCode(copy->invoke_stub_array_, reinterpret_cast<void*>(orig->invoke_stub_))); 240 if (orig->IsNative()) { 241 ByteArray* orig_jni_stub_array_ = Runtime::Current()->GetJniStubArray(); 242 ByteArray* copy_jni_stub_array_ = down_cast<ByteArray*>(GetImageAddress(orig_jni_stub_array_)); 243 copy->native_method_ = copy_jni_stub_array_->GetData(); 244 copy->code_ = oat_base_ + orig->GetOatCodeOffset(); 245 } else { 246 DCHECK(copy->native_method_ == NULL) << copy->native_method_; 247 if (orig->IsAbstract()) { 248 ByteArray* orig_ame_stub_array_ = Runtime::Current()->GetAbstractMethodErrorStubArray(); 249 ByteArray* copy_ame_stub_array_ = down_cast<ByteArray*>(GetImageAddress(orig_ame_stub_array_)); 250 copy->code_ = copy_ame_stub_array_->GetData(); 251 } else { 252 copy->code_ = oat_base_ + orig->GetOatCodeOffset(); 253 } 254 } 255} 256 257void ImageWriter::FixupObjectArray(const ObjectArray<Object>* orig, ObjectArray<Object>* copy) { 258 for (int32_t i = 0; i < orig->GetLength(); ++i) { 259 const Object* element = orig->Get(i); 260 copy->SetWithoutChecks(i, GetImageAddress(element)); 261 } 262} 263 264void ImageWriter::FixupInstanceFields(const Object* orig, Object* copy) { 265 DCHECK(orig != NULL); 266 DCHECK(copy != NULL); 267 Class* klass = orig->GetClass(); 268 DCHECK(klass != NULL); 269 FixupFields(orig, 270 copy, 271 klass->GetReferenceInstanceOffsets(), 272 false); 273} 274 275void ImageWriter::FixupStaticFields(const Class* orig, Class* copy) { 276 DCHECK(orig != NULL); 277 DCHECK(copy != NULL); 278 FixupFields(orig, 279 copy, 280 orig->GetReferenceStaticOffsets(), 281 true); 282} 283 284void ImageWriter::FixupFields(const Object* orig, 285 Object* copy, 286 uint32_t ref_offsets, 287 bool is_static) { 288 if (ref_offsets != CLASS_WALK_SUPER) { 289 // Found a reference offset bitmap. Fixup the specified offsets. 290 while (ref_offsets != 0) { 291 size_t right_shift = CLZ(ref_offsets); 292 MemberOffset byte_offset = CLASS_OFFSET_FROM_CLZ(right_shift); 293 const Object* ref = orig->GetFieldObject<const Object*>(byte_offset, false); 294 copy->SetFieldObject(byte_offset, GetImageAddress(ref), false); 295 ref_offsets &= ~(CLASS_HIGH_BIT >> right_shift); 296 } 297 } else { 298 // There is no reference offset bitmap. In the non-static case, 299 // walk up the class inheritance hierarchy and find reference 300 // offsets the hard way. In the static case, just consider this 301 // class. 302 for (const Class *klass = is_static ? orig->AsClass() : orig->GetClass(); 303 klass != NULL; 304 klass = is_static ? NULL : klass->GetSuperClass()) { 305 size_t num_reference_fields = (is_static 306 ? klass->NumReferenceStaticFields() 307 : klass->NumReferenceInstanceFields()); 308 for (size_t i = 0; i < num_reference_fields; ++i) { 309 Field* field = (is_static 310 ? klass->GetStaticField(i) 311 : klass->GetInstanceField(i)); 312 MemberOffset field_offset = field->GetOffset(); 313 const Object* ref = orig->GetFieldObject<const Object*>(field_offset, false); 314 copy->SetFieldObject(field_offset, GetImageAddress(ref), false); 315 } 316 } 317 } 318} 319 320void ImageWriter::FixupDexCaches() { 321 typedef Set::const_iterator It; // TODO: C++0x auto 322 for (It it = dex_caches_.begin(), end = dex_caches_.end(); it != end; ++it) { 323 DexCache* orig = *it; 324 DexCache* copy = down_cast<DexCache*>(GetLocalAddress(orig)); 325 FixupDexCache(orig, copy); 326 } 327} 328 329void ImageWriter::FixupDexCache(const DexCache* orig, DexCache* copy) { 330 CHECK(orig != NULL); 331 CHECK(copy != NULL); 332 333 CodeAndDirectMethods* orig_cadms = orig->GetCodeAndDirectMethods(); 334 CodeAndDirectMethods* copy_cadms = down_cast<CodeAndDirectMethods*>(GetLocalAddress(orig_cadms)); 335 for (size_t i = 0; i < orig->NumResolvedMethods(); i++) { 336 Method* orig_method = orig->GetResolvedMethod(i); 337 // if it was resolved in the original, resolve it in the copy 338 if (orig_method != NULL 339 && InSourceSpace(orig_method) 340 && orig_method == orig_cadms->GetResolvedMethod(i)) { 341 Method* copy_method = down_cast<Method*>(GetLocalAddress(orig_method)); 342 copy_cadms->Set(CodeAndDirectMethods::CodeIndex(i), 343 reinterpret_cast<int32_t>(copy_method->code_)); 344 copy_cadms->Set(CodeAndDirectMethods::MethodIndex(i), 345 reinterpret_cast<int32_t>(GetImageAddress(orig_method))); 346 } 347 } 348} 349 350} // namespace art 351