| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 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 "image_writer.h" | 
 | 18 |  | 
 | 19 | #include <sys/stat.h> | 
 | 20 |  | 
| Ian Rogers | 700a402 | 2014-05-19 16:49:03 -0700 | [diff] [blame] | 21 | #include <memory> | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 22 | #include <vector> | 
 | 23 |  | 
 | 24 | #include "base/logging.h" | 
 | 25 | #include "base/unix_file/fd_file.h" | 
 | 26 | #include "class_linker.h" | 
 | 27 | #include "compiled_method.h" | 
 | 28 | #include "dex_file-inl.h" | 
 | 29 | #include "driver/compiler_driver.h" | 
| Alex Light | 53cb16b | 2014-06-12 11:26:29 -0700 | [diff] [blame] | 30 | #include "elf_file.h" | 
 | 31 | #include "elf_utils.h" | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 32 | #include "elf_writer.h" | 
 | 33 | #include "gc/accounting/card_table-inl.h" | 
 | 34 | #include "gc/accounting/heap_bitmap.h" | 
| Mathieu Chartier | 31e8925 | 2013-08-28 11:29:12 -0700 | [diff] [blame] | 35 | #include "gc/accounting/space_bitmap-inl.h" | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 36 | #include "gc/heap.h" | 
 | 37 | #include "gc/space/large_object_space.h" | 
 | 38 | #include "gc/space/space-inl.h" | 
 | 39 | #include "globals.h" | 
 | 40 | #include "image.h" | 
 | 41 | #include "intern_table.h" | 
| Mathieu Chartier | ad2541a | 2013-10-25 10:05:23 -0700 | [diff] [blame] | 42 | #include "lock_word.h" | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 43 | #include "mirror/art_field-inl.h" | 
 | 44 | #include "mirror/art_method-inl.h" | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 45 | #include "mirror/array-inl.h" | 
 | 46 | #include "mirror/class-inl.h" | 
 | 47 | #include "mirror/class_loader.h" | 
 | 48 | #include "mirror/dex_cache-inl.h" | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 49 | #include "mirror/object-inl.h" | 
 | 50 | #include "mirror/object_array-inl.h" | 
| Ian Rogers | b0fa5dc | 2014-04-28 16:47:08 -0700 | [diff] [blame] | 51 | #include "mirror/string-inl.h" | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 52 | #include "oat.h" | 
 | 53 | #include "oat_file.h" | 
 | 54 | #include "object_utils.h" | 
 | 55 | #include "runtime.h" | 
 | 56 | #include "scoped_thread_state_change.h" | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 57 | #include "handle_scope-inl.h" | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 58 | #include "utils.h" | 
 | 59 |  | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 60 | using ::art::mirror::ArtField; | 
 | 61 | using ::art::mirror::ArtMethod; | 
| Brian Carlstrom | 3e3d591 | 2013-07-18 00:19:45 -0700 | [diff] [blame] | 62 | using ::art::mirror::Class; | 
 | 63 | using ::art::mirror::DexCache; | 
 | 64 | using ::art::mirror::EntryPointFromInterpreter; | 
| Brian Carlstrom | 3e3d591 | 2013-07-18 00:19:45 -0700 | [diff] [blame] | 65 | using ::art::mirror::Object; | 
 | 66 | using ::art::mirror::ObjectArray; | 
 | 67 | using ::art::mirror::String; | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 68 |  | 
 | 69 | namespace art { | 
 | 70 |  | 
 | 71 | bool ImageWriter::Write(const std::string& image_filename, | 
 | 72 |                         uintptr_t image_begin, | 
 | 73 |                         const std::string& oat_filename, | 
 | 74 |                         const std::string& oat_location) { | 
 | 75 |   CHECK(!image_filename.empty()); | 
 | 76 |  | 
 | 77 |   CHECK_NE(image_begin, 0U); | 
 | 78 |   image_begin_ = reinterpret_cast<byte*>(image_begin); | 
 | 79 |  | 
 | 80 |   ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 81 |  | 
| Ian Rogers | 700a402 | 2014-05-19 16:49:03 -0700 | [diff] [blame] | 82 |   std::unique_ptr<File> oat_file(OS::OpenFileReadWrite(oat_filename.c_str())); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 83 |   if (oat_file.get() == NULL) { | 
 | 84 |     LOG(ERROR) << "Failed to open oat file " << oat_filename << " for " << oat_location; | 
 | 85 |     return false; | 
 | 86 |   } | 
| Ian Rogers | 8d31bbd | 2013-10-13 10:44:14 -0700 | [diff] [blame] | 87 |   std::string error_msg; | 
 | 88 |   oat_file_ = OatFile::OpenWritable(oat_file.get(), oat_location, &error_msg); | 
 | 89 |   if (oat_file_ == nullptr) { | 
 | 90 |     LOG(ERROR) << "Failed to open writable oat file " << oat_filename << " for " << oat_location | 
 | 91 |         << ": " << error_msg; | 
| Brian Carlstrom | c50d8e1 | 2013-07-23 22:35:16 -0700 | [diff] [blame] | 92 |     return false; | 
 | 93 |   } | 
| Ian Rogers | 8d31bbd | 2013-10-13 10:44:14 -0700 | [diff] [blame] | 94 |   CHECK_EQ(class_linker->RegisterOatFile(oat_file_), oat_file_); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 95 |  | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 96 |   interpreter_to_interpreter_bridge_offset_ = | 
 | 97 |       oat_file_->GetOatHeader().GetInterpreterToInterpreterBridgeOffset(); | 
 | 98 |   interpreter_to_compiled_code_bridge_offset_ = | 
 | 99 |       oat_file_->GetOatHeader().GetInterpreterToCompiledCodeBridgeOffset(); | 
 | 100 |  | 
 | 101 |   jni_dlsym_lookup_offset_ = oat_file_->GetOatHeader().GetJniDlsymLookupOffset(); | 
 | 102 |  | 
| Jeff Hao | 88474b4 | 2013-10-23 16:24:40 -0700 | [diff] [blame] | 103 |   portable_imt_conflict_trampoline_offset_ = | 
 | 104 |       oat_file_->GetOatHeader().GetPortableImtConflictTrampolineOffset(); | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 105 |   portable_resolution_trampoline_offset_ = | 
 | 106 |       oat_file_->GetOatHeader().GetPortableResolutionTrampolineOffset(); | 
 | 107 |   portable_to_interpreter_bridge_offset_ = | 
 | 108 |       oat_file_->GetOatHeader().GetPortableToInterpreterBridgeOffset(); | 
 | 109 |  | 
| Andreas Gampe | 2da8823 | 2014-02-27 12:26:20 -0800 | [diff] [blame] | 110 |   quick_generic_jni_trampoline_offset_ = | 
 | 111 |       oat_file_->GetOatHeader().GetQuickGenericJniTrampolineOffset(); | 
| Jeff Hao | 88474b4 | 2013-10-23 16:24:40 -0700 | [diff] [blame] | 112 |   quick_imt_conflict_trampoline_offset_ = | 
 | 113 |       oat_file_->GetOatHeader().GetQuickImtConflictTrampolineOffset(); | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 114 |   quick_resolution_trampoline_offset_ = | 
 | 115 |       oat_file_->GetOatHeader().GetQuickResolutionTrampolineOffset(); | 
 | 116 |   quick_to_interpreter_bridge_offset_ = | 
 | 117 |       oat_file_->GetOatHeader().GetQuickToInterpreterBridgeOffset(); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 118 |   { | 
 | 119 |     Thread::Current()->TransitionFromSuspendedToRunnable(); | 
 | 120 |     PruneNonImageClasses();  // Remove junk | 
 | 121 |     ComputeLazyFieldsForImageClasses();  // Add useful information | 
 | 122 |     ComputeEagerResolvedStrings(); | 
 | 123 |     Thread::Current()->TransitionFromRunnableToSuspended(kNative); | 
 | 124 |   } | 
 | 125 |   gc::Heap* heap = Runtime::Current()->GetHeap(); | 
 | 126 |   heap->CollectGarbage(false);  // Remove garbage. | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 127 |  | 
 | 128 |   if (!AllocMemory()) { | 
 | 129 |     return false; | 
 | 130 |   } | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 131 |  | 
 | 132 |   if (kIsDebugBuild) { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 133 |     ScopedObjectAccess soa(Thread::Current()); | 
 | 134 |     CheckNonImageClassesRemoved(); | 
 | 135 |   } | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 136 |  | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 137 |   Thread::Current()->TransitionFromSuspendedToRunnable(); | 
 | 138 |   size_t oat_loaded_size = 0; | 
 | 139 |   size_t oat_data_offset = 0; | 
 | 140 |   ElfWriter::GetOatElfInformation(oat_file.get(), oat_loaded_size, oat_data_offset); | 
 | 141 |   CalculateNewObjectOffsets(oat_loaded_size, oat_data_offset); | 
 | 142 |   CopyAndFixupObjects(); | 
| Alex Light | 53cb16b | 2014-06-12 11:26:29 -0700 | [diff] [blame] | 143 |  | 
 | 144 |   PatchOatCodeAndMethods(oat_file.get()); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 145 |   Thread::Current()->TransitionFromRunnableToSuspended(kNative); | 
 | 146 |  | 
| Ian Rogers | 700a402 | 2014-05-19 16:49:03 -0700 | [diff] [blame] | 147 |   std::unique_ptr<File> image_file(OS::CreateEmptyFile(image_filename.c_str())); | 
| Mathieu Chartier | 31e8925 | 2013-08-28 11:29:12 -0700 | [diff] [blame] | 148 |   ImageHeader* image_header = reinterpret_cast<ImageHeader*>(image_->Begin()); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 149 |   if (image_file.get() == NULL) { | 
 | 150 |     LOG(ERROR) << "Failed to open image file " << image_filename; | 
 | 151 |     return false; | 
 | 152 |   } | 
 | 153 |   if (fchmod(image_file->Fd(), 0644) != 0) { | 
 | 154 |     PLOG(ERROR) << "Failed to make image file world readable: " << image_filename; | 
 | 155 |     return EXIT_FAILURE; | 
 | 156 |   } | 
| Mathieu Chartier | 31e8925 | 2013-08-28 11:29:12 -0700 | [diff] [blame] | 157 |  | 
 | 158 |   // Write out the image. | 
 | 159 |   CHECK_EQ(image_end_, image_header->GetImageSize()); | 
 | 160 |   if (!image_file->WriteFully(image_->Begin(), image_end_)) { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 161 |     PLOG(ERROR) << "Failed to write image file " << image_filename; | 
 | 162 |     return false; | 
 | 163 |   } | 
| Mathieu Chartier | 31e8925 | 2013-08-28 11:29:12 -0700 | [diff] [blame] | 164 |  | 
 | 165 |   // Write out the image bitmap at the page aligned start of the image end. | 
 | 166 |   CHECK_ALIGNED(image_header->GetImageBitmapOffset(), kPageSize); | 
 | 167 |   if (!image_file->Write(reinterpret_cast<char*>(image_bitmap_->Begin()), | 
 | 168 |                          image_header->GetImageBitmapSize(), | 
 | 169 |                          image_header->GetImageBitmapOffset())) { | 
 | 170 |     PLOG(ERROR) << "Failed to write image file " << image_filename; | 
 | 171 |     return false; | 
 | 172 |   } | 
 | 173 |  | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 174 |   return true; | 
 | 175 | } | 
 | 176 |  | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 177 | void ImageWriter::SetImageOffset(mirror::Object* object, size_t offset) { | 
 | 178 |   DCHECK(object != nullptr); | 
 | 179 |   DCHECK_NE(offset, 0U); | 
 | 180 |   DCHECK(!IsImageOffsetAssigned(object)); | 
 | 181 |   mirror::Object* obj = reinterpret_cast<mirror::Object*>(image_->Begin() + offset); | 
 | 182 |   DCHECK_ALIGNED(obj, kObjectAlignment); | 
 | 183 |   image_bitmap_->Set(obj); | 
 | 184 |   // Before we stomp over the lock word, save the hash code for later. | 
 | 185 |   Monitor::Deflate(Thread::Current(), object);; | 
| Mathieu Chartier | 4d7f61d | 2014-04-17 14:43:39 -0700 | [diff] [blame] | 186 |   LockWord lw(object->GetLockWord(false)); | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 187 |   switch (lw.GetState()) { | 
 | 188 |     case LockWord::kFatLocked: { | 
 | 189 |       LOG(FATAL) << "Fat locked object " << obj << " found during object copy"; | 
 | 190 |       break; | 
 | 191 |     } | 
 | 192 |     case LockWord::kThinLocked: { | 
 | 193 |       LOG(FATAL) << "Thin locked object " << obj << " found during object copy"; | 
 | 194 |       break; | 
 | 195 |     } | 
 | 196 |     case LockWord::kUnlocked: | 
 | 197 |       // No hash, don't need to save it. | 
 | 198 |       break; | 
 | 199 |     case LockWord::kHashCode: | 
 | 200 |       saved_hashes_.push_back(std::make_pair(obj, lw.GetHashCode())); | 
 | 201 |       break; | 
 | 202 |     default: | 
 | 203 |       LOG(FATAL) << "Unreachable."; | 
 | 204 |       break; | 
| Mathieu Chartier | 31e8925 | 2013-08-28 11:29:12 -0700 | [diff] [blame] | 205 |   } | 
| Mathieu Chartier | 4d7f61d | 2014-04-17 14:43:39 -0700 | [diff] [blame] | 206 |   object->SetLockWord(LockWord::FromForwardingAddress(offset), false); | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 207 |   DCHECK(IsImageOffsetAssigned(object)); | 
 | 208 | } | 
 | 209 |  | 
 | 210 | void ImageWriter::AssignImageOffset(mirror::Object* object) { | 
 | 211 |   DCHECK(object != nullptr); | 
 | 212 |   SetImageOffset(object, image_end_); | 
 | 213 |   image_end_ += RoundUp(object->SizeOf(), 8);  // 64-bit alignment | 
 | 214 |   DCHECK_LT(image_end_, image_->Size()); | 
 | 215 | } | 
 | 216 |  | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 217 | bool ImageWriter::IsImageOffsetAssigned(mirror::Object* object) const { | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 218 |   DCHECK(object != nullptr); | 
| Mathieu Chartier | 4d7f61d | 2014-04-17 14:43:39 -0700 | [diff] [blame] | 219 |   return object->GetLockWord(false).GetState() == LockWord::kForwardingAddress; | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 220 | } | 
 | 221 |  | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 222 | size_t ImageWriter::GetImageOffset(mirror::Object* object) const { | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 223 |   DCHECK(object != nullptr); | 
 | 224 |   DCHECK(IsImageOffsetAssigned(object)); | 
| Mathieu Chartier | 4d7f61d | 2014-04-17 14:43:39 -0700 | [diff] [blame] | 225 |   LockWord lock_word = object->GetLockWord(false); | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 226 |   size_t offset = lock_word.ForwardingAddress(); | 
 | 227 |   DCHECK_LT(offset, image_end_); | 
 | 228 |   return offset; | 
| Mathieu Chartier | 31e8925 | 2013-08-28 11:29:12 -0700 | [diff] [blame] | 229 | } | 
 | 230 |  | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 231 | bool ImageWriter::AllocMemory() { | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 232 |   size_t length = RoundUp(Runtime::Current()->GetHeap()->GetTotalMemory(), kPageSize); | 
| Ian Rogers | 8d31bbd | 2013-10-13 10:44:14 -0700 | [diff] [blame] | 233 |   std::string error_msg; | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 234 |   image_.reset(MemMap::MapAnonymous("image writer image", NULL, length, PROT_READ | PROT_WRITE, | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 235 |                                     true, &error_msg)); | 
| Ian Rogers | 8d31bbd | 2013-10-13 10:44:14 -0700 | [diff] [blame] | 236 |   if (UNLIKELY(image_.get() == nullptr)) { | 
 | 237 |     LOG(ERROR) << "Failed to allocate memory for image file generation: " << error_msg; | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 238 |     return false; | 
 | 239 |   } | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 240 |  | 
 | 241 |   // Create the image bitmap. | 
| Mathieu Chartier | a8e8f9c | 2014-04-09 14:51:05 -0700 | [diff] [blame] | 242 |   image_bitmap_.reset(gc::accounting::ContinuousSpaceBitmap::Create("image bitmap", image_->Begin(), | 
 | 243 |                                                                     length)); | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 244 |   if (image_bitmap_.get() == nullptr) { | 
 | 245 |     LOG(ERROR) << "Failed to allocate memory for image bitmap"; | 
 | 246 |     return false; | 
 | 247 |   } | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 248 |   return true; | 
 | 249 | } | 
 | 250 |  | 
 | 251 | void ImageWriter::ComputeLazyFieldsForImageClasses() { | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 252 |   ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 253 |   class_linker->VisitClassesWithoutClassesLock(ComputeLazyFieldsForClassesVisitor, NULL); | 
 | 254 | } | 
 | 255 |  | 
 | 256 | bool ImageWriter::ComputeLazyFieldsForClassesVisitor(Class* c, void* /*arg*/) { | 
| Mathieu Chartier | f832284 | 2014-05-16 10:59:25 -0700 | [diff] [blame] | 257 |   Thread* self = Thread::Current(); | 
 | 258 |   StackHandleScope<1> hs(self); | 
 | 259 |   mirror::Class::ComputeName(hs.NewHandle(c)); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 260 |   return true; | 
 | 261 | } | 
 | 262 |  | 
 | 263 | void ImageWriter::ComputeEagerResolvedStringsCallback(Object* obj, void* arg) { | 
 | 264 |   if (!obj->GetClass()->IsStringClass()) { | 
 | 265 |     return; | 
 | 266 |   } | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 267 |   mirror::String* string = obj->AsString(); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 268 |   const uint16_t* utf16_string = string->GetCharArray()->GetData() + string->GetOffset(); | 
| Hiroshi Yamauchi | e9e3e69 | 2014-06-24 14:31:37 -0700 | [diff] [blame] | 269 |   ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); | 
 | 270 |   ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock()); | 
 | 271 |   size_t dex_cache_count = class_linker->GetDexCacheCount(); | 
 | 272 |   for (size_t i = 0; i < dex_cache_count; ++i) { | 
 | 273 |     DexCache* dex_cache = class_linker->GetDexCache(i); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 274 |     const DexFile& dex_file = *dex_cache->GetDexFile(); | 
| Ian Rogers | 24c534d | 2013-11-14 00:15:00 -0800 | [diff] [blame] | 275 |     const DexFile::StringId* string_id; | 
 | 276 |     if (UNLIKELY(string->GetLength() == 0)) { | 
 | 277 |       string_id = dex_file.FindStringId(""); | 
 | 278 |     } else { | 
 | 279 |       string_id = dex_file.FindStringId(utf16_string); | 
 | 280 |     } | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 281 |     if (string_id != nullptr) { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 282 |       // This string occurs in this dex file, assign the dex cache entry. | 
 | 283 |       uint32_t string_idx = dex_file.GetIndexForStringId(*string_id); | 
 | 284 |       if (dex_cache->GetResolvedString(string_idx) == NULL) { | 
 | 285 |         dex_cache->SetResolvedString(string_idx, string); | 
 | 286 |       } | 
 | 287 |     } | 
 | 288 |   } | 
 | 289 | } | 
 | 290 |  | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 291 | void ImageWriter::ComputeEagerResolvedStrings() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { | 
 | 292 |   ReaderMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_); | 
 | 293 |   Runtime::Current()->GetHeap()->VisitObjects(ComputeEagerResolvedStringsCallback, this); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 294 | } | 
 | 295 |  | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 296 | bool ImageWriter::IsImageClass(Class* klass) { | 
| Mathieu Chartier | f832284 | 2014-05-16 10:59:25 -0700 | [diff] [blame] | 297 |   return compiler_driver_.IsImageClass(klass->GetDescriptor().c_str()); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 298 | } | 
 | 299 |  | 
 | 300 | struct NonImageClasses { | 
 | 301 |   ImageWriter* image_writer; | 
 | 302 |   std::set<std::string>* non_image_classes; | 
 | 303 | }; | 
 | 304 |  | 
 | 305 | void ImageWriter::PruneNonImageClasses() { | 
 | 306 |   if (compiler_driver_.GetImageClasses() == NULL) { | 
 | 307 |     return; | 
 | 308 |   } | 
 | 309 |   Runtime* runtime = Runtime::Current(); | 
 | 310 |   ClassLinker* class_linker = runtime->GetClassLinker(); | 
 | 311 |  | 
 | 312 |   // Make a list of classes we would like to prune. | 
 | 313 |   std::set<std::string> non_image_classes; | 
 | 314 |   NonImageClasses context; | 
 | 315 |   context.image_writer = this; | 
 | 316 |   context.non_image_classes = &non_image_classes; | 
 | 317 |   class_linker->VisitClasses(NonImageClassesVisitor, &context); | 
 | 318 |  | 
 | 319 |   // Remove the undesired classes from the class roots. | 
| Mathieu Chartier | 02e2511 | 2013-08-14 16:14:24 -0700 | [diff] [blame] | 320 |   for (const std::string& it : non_image_classes) { | 
 | 321 |     class_linker->RemoveClass(it.c_str(), NULL); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 322 |   } | 
 | 323 |  | 
 | 324 |   // Clear references to removed classes from the DexCaches. | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 325 |   ArtMethod* resolution_method = runtime->GetResolutionMethod(); | 
| Hiroshi Yamauchi | e9e3e69 | 2014-06-24 14:31:37 -0700 | [diff] [blame] | 326 |   ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock()); | 
 | 327 |   size_t dex_cache_count = class_linker->GetDexCacheCount(); | 
 | 328 |   for (size_t idx = 0; idx < dex_cache_count; ++idx) { | 
 | 329 |     DexCache* dex_cache = class_linker->GetDexCache(idx); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 330 |     for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) { | 
 | 331 |       Class* klass = dex_cache->GetResolvedType(i); | 
 | 332 |       if (klass != NULL && !IsImageClass(klass)) { | 
 | 333 |         dex_cache->SetResolvedType(i, NULL); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 334 |       } | 
 | 335 |     } | 
 | 336 |     for (size_t i = 0; i < dex_cache->NumResolvedMethods(); i++) { | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 337 |       ArtMethod* method = dex_cache->GetResolvedMethod(i); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 338 |       if (method != NULL && !IsImageClass(method->GetDeclaringClass())) { | 
 | 339 |         dex_cache->SetResolvedMethod(i, resolution_method); | 
 | 340 |       } | 
 | 341 |     } | 
 | 342 |     for (size_t i = 0; i < dex_cache->NumResolvedFields(); i++) { | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 343 |       ArtField* field = dex_cache->GetResolvedField(i); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 344 |       if (field != NULL && !IsImageClass(field->GetDeclaringClass())) { | 
 | 345 |         dex_cache->SetResolvedField(i, NULL); | 
 | 346 |       } | 
 | 347 |     } | 
 | 348 |   } | 
 | 349 | } | 
 | 350 |  | 
 | 351 | bool ImageWriter::NonImageClassesVisitor(Class* klass, void* arg) { | 
 | 352 |   NonImageClasses* context = reinterpret_cast<NonImageClasses*>(arg); | 
 | 353 |   if (!context->image_writer->IsImageClass(klass)) { | 
| Mathieu Chartier | f832284 | 2014-05-16 10:59:25 -0700 | [diff] [blame] | 354 |     context->non_image_classes->insert(klass->GetDescriptor()); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 355 |   } | 
 | 356 |   return true; | 
 | 357 | } | 
 | 358 |  | 
 | 359 | void ImageWriter::CheckNonImageClassesRemoved() | 
 | 360 |     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 361 |   if (compiler_driver_.GetImageClasses() != nullptr) { | 
 | 362 |     gc::Heap* heap = Runtime::Current()->GetHeap(); | 
 | 363 |     ReaderMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_); | 
 | 364 |     heap->VisitObjects(CheckNonImageClassesRemovedCallback, this); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 365 |   } | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 366 | } | 
 | 367 |  | 
 | 368 | void ImageWriter::CheckNonImageClassesRemovedCallback(Object* obj, void* arg) { | 
 | 369 |   ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg); | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 370 |   if (obj->IsClass()) { | 
 | 371 |     Class* klass = obj->AsClass(); | 
 | 372 |     if (!image_writer->IsImageClass(klass)) { | 
 | 373 |       image_writer->DumpImageClasses(); | 
| Mathieu Chartier | f832284 | 2014-05-16 10:59:25 -0700 | [diff] [blame] | 374 |       CHECK(image_writer->IsImageClass(klass)) << klass->GetDescriptor() | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 375 |                                                << " " << PrettyDescriptor(klass); | 
 | 376 |     } | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 377 |   } | 
 | 378 | } | 
 | 379 |  | 
 | 380 | void ImageWriter::DumpImageClasses() { | 
 | 381 |   CompilerDriver::DescriptorSet* image_classes = compiler_driver_.GetImageClasses(); | 
 | 382 |   CHECK(image_classes != NULL); | 
| Mathieu Chartier | 02e2511 | 2013-08-14 16:14:24 -0700 | [diff] [blame] | 383 |   for (const std::string& image_class : *image_classes) { | 
 | 384 |     LOG(INFO) << " " << image_class; | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 385 |   } | 
 | 386 | } | 
 | 387 |  | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 388 | void ImageWriter::CalculateObjectOffsets(Object* obj) { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 389 |   DCHECK(obj != NULL); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 390 |   // if it is a string, we want to intern it if its not interned. | 
 | 391 |   if (obj->GetClass()->IsStringClass()) { | 
 | 392 |     // we must be an interned string that was forward referenced and already assigned | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 393 |     if (IsImageOffsetAssigned(obj)) { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 394 |       DCHECK_EQ(obj, obj->AsString()->Intern()); | 
 | 395 |       return; | 
 | 396 |     } | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 397 |     mirror::String* const interned = obj->AsString()->Intern(); | 
 | 398 |     if (obj != interned) { | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 399 |       if (!IsImageOffsetAssigned(interned)) { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 400 |         // interned obj is after us, allocate its location early | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 401 |         AssignImageOffset(interned); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 402 |       } | 
 | 403 |       // point those looking for this object to the interned version. | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 404 |       SetImageOffset(obj, GetImageOffset(interned)); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 405 |       return; | 
 | 406 |     } | 
 | 407 |     // else (obj == interned), nothing to do but fall through to the normal case | 
 | 408 |   } | 
 | 409 |  | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 410 |   AssignImageOffset(obj); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 411 | } | 
 | 412 |  | 
 | 413 | ObjectArray<Object>* ImageWriter::CreateImageRoots() const { | 
 | 414 |   Runtime* runtime = Runtime::Current(); | 
 | 415 |   ClassLinker* class_linker = runtime->GetClassLinker(); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 416 |   Thread* self = Thread::Current(); | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 417 |   StackHandleScope<3> hs(self); | 
 | 418 |   Handle<Class> object_array_class(hs.NewHandle( | 
 | 419 |       class_linker->FindSystemClass(self, "[Ljava/lang/Object;"))); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 420 |  | 
| Hiroshi Yamauchi | e9e3e69 | 2014-06-24 14:31:37 -0700 | [diff] [blame] | 421 |   // build an Object[] of all the DexCaches used in the source_space_. | 
 | 422 |   // Since we can't hold the dex lock when allocating the dex_caches | 
 | 423 |   // ObjectArray, we lock the dex lock twice, first to get the number | 
 | 424 |   // of dex caches first and then lock it again to copy the dex | 
 | 425 |   // caches. We check that the number of dex caches does not change. | 
 | 426 |   size_t dex_cache_count; | 
 | 427 |   { | 
 | 428 |     ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock()); | 
 | 429 |     dex_cache_count = class_linker->GetDexCacheCount(); | 
 | 430 |   } | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 431 |   Handle<ObjectArray<Object>> dex_caches( | 
 | 432 |       hs.NewHandle(ObjectArray<Object>::Alloc(self, object_array_class.Get(), | 
| Hiroshi Yamauchi | e9e3e69 | 2014-06-24 14:31:37 -0700 | [diff] [blame] | 433 |                                               dex_cache_count))); | 
 | 434 |   CHECK(dex_caches.Get() != nullptr) << "Failed to allocate a dex cache array."; | 
 | 435 |   { | 
 | 436 |     ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock()); | 
 | 437 |     CHECK_EQ(dex_cache_count, class_linker->GetDexCacheCount()) | 
 | 438 |         << "The number of dex caches changed."; | 
 | 439 |     for (size_t i = 0; i < dex_cache_count; ++i) { | 
 | 440 |       dex_caches->Set<false>(i, class_linker->GetDexCache(i)); | 
 | 441 |     } | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 442 |   } | 
 | 443 |  | 
 | 444 |   // build an Object[] of the roots needed to restore the runtime | 
| Ian Rogers | 700a402 | 2014-05-19 16:49:03 -0700 | [diff] [blame] | 445 |   Handle<ObjectArray<Object>> image_roots(hs.NewHandle( | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 446 |       ObjectArray<Object>::Alloc(self, object_array_class.Get(), ImageHeader::kImageRootsMax))); | 
| Sebastien Hertz | d2fe10a | 2014-01-15 10:20:56 +0100 | [diff] [blame] | 447 |   image_roots->Set<false>(ImageHeader::kResolutionMethod, runtime->GetResolutionMethod()); | 
 | 448 |   image_roots->Set<false>(ImageHeader::kImtConflictMethod, runtime->GetImtConflictMethod()); | 
 | 449 |   image_roots->Set<false>(ImageHeader::kDefaultImt, runtime->GetDefaultImt()); | 
 | 450 |   image_roots->Set<false>(ImageHeader::kCalleeSaveMethod, | 
 | 451 |                           runtime->GetCalleeSaveMethod(Runtime::kSaveAll)); | 
 | 452 |   image_roots->Set<false>(ImageHeader::kRefsOnlySaveMethod, | 
 | 453 |                           runtime->GetCalleeSaveMethod(Runtime::kRefsOnly)); | 
 | 454 |   image_roots->Set<false>(ImageHeader::kRefsAndArgsSaveMethod, | 
 | 455 |                           runtime->GetCalleeSaveMethod(Runtime::kRefsAndArgs)); | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 456 |   image_roots->Set<false>(ImageHeader::kDexCaches, dex_caches.Get()); | 
| Sebastien Hertz | d2fe10a | 2014-01-15 10:20:56 +0100 | [diff] [blame] | 457 |   image_roots->Set<false>(ImageHeader::kClassRoots, class_linker->GetClassRoots()); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 458 |   for (int i = 0; i < ImageHeader::kImageRootsMax; i++) { | 
 | 459 |     CHECK(image_roots->Get(i) != NULL); | 
 | 460 |   } | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 461 |   return image_roots.Get(); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 462 | } | 
 | 463 |  | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 464 | // Walk instance fields of the given Class. Separate function to allow recursion on the super | 
 | 465 | // class. | 
 | 466 | void ImageWriter::WalkInstanceFields(mirror::Object* obj, mirror::Class* klass) { | 
 | 467 |   // Visit fields of parent classes first. | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 468 |   StackHandleScope<1> hs(Thread::Current()); | 
 | 469 |   Handle<mirror::Class> h_class(hs.NewHandle(klass)); | 
 | 470 |   mirror::Class* super = h_class->GetSuperClass(); | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 471 |   if (super != nullptr) { | 
 | 472 |     WalkInstanceFields(obj, super); | 
 | 473 |   } | 
 | 474 |   // | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 475 |   size_t num_reference_fields = h_class->NumReferenceInstanceFields(); | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 476 |   for (size_t i = 0; i < num_reference_fields; ++i) { | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 477 |     mirror::ArtField* field = h_class->GetInstanceField(i); | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 478 |     MemberOffset field_offset = field->GetOffset(); | 
| Ian Rogers | b0fa5dc | 2014-04-28 16:47:08 -0700 | [diff] [blame] | 479 |     mirror::Object* value = obj->GetFieldObject<mirror::Object>(field_offset); | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 480 |     if (value != nullptr) { | 
 | 481 |       WalkFieldsInOrder(value); | 
 | 482 |     } | 
 | 483 |   } | 
 | 484 | } | 
 | 485 |  | 
 | 486 | // For an unvisited object, visit it then all its children found via fields. | 
 | 487 | void ImageWriter::WalkFieldsInOrder(mirror::Object* obj) { | 
 | 488 |   if (!IsImageOffsetAssigned(obj)) { | 
 | 489 |     // Walk instance fields of all objects | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 490 |     StackHandleScope<2> hs(Thread::Current()); | 
 | 491 |     Handle<mirror::Object> h_obj(hs.NewHandle(obj)); | 
 | 492 |     Handle<mirror::Class> klass(hs.NewHandle(obj->GetClass())); | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 493 |     // visit the object itself. | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 494 |     CalculateObjectOffsets(h_obj.Get()); | 
 | 495 |     WalkInstanceFields(h_obj.Get(), klass.Get()); | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 496 |     // Walk static fields of a Class. | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 497 |     if (h_obj->IsClass()) { | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 498 |       size_t num_static_fields = klass->NumReferenceStaticFields(); | 
 | 499 |       for (size_t i = 0; i < num_static_fields; ++i) { | 
 | 500 |         mirror::ArtField* field = klass->GetStaticField(i); | 
 | 501 |         MemberOffset field_offset = field->GetOffset(); | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 502 |         mirror::Object* value = h_obj->GetFieldObject<mirror::Object>(field_offset); | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 503 |         if (value != nullptr) { | 
 | 504 |           WalkFieldsInOrder(value); | 
 | 505 |         } | 
 | 506 |       } | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 507 |     } else if (h_obj->IsObjectArray()) { | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 508 |       // Walk elements of an object array. | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 509 |       int32_t length = h_obj->AsObjectArray<mirror::Object>()->GetLength(); | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 510 |       for (int32_t i = 0; i < length; i++) { | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 511 |         mirror::ObjectArray<mirror::Object>* obj_array = h_obj->AsObjectArray<mirror::Object>(); | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 512 |         mirror::Object* value = obj_array->Get(i); | 
 | 513 |         if (value != nullptr) { | 
 | 514 |           WalkFieldsInOrder(value); | 
 | 515 |         } | 
 | 516 |       } | 
 | 517 |     } | 
 | 518 |   } | 
 | 519 | } | 
 | 520 |  | 
 | 521 | void ImageWriter::WalkFieldsCallback(mirror::Object* obj, void* arg) { | 
 | 522 |   ImageWriter* writer = reinterpret_cast<ImageWriter*>(arg); | 
 | 523 |   DCHECK(writer != nullptr); | 
 | 524 |   writer->WalkFieldsInOrder(obj); | 
 | 525 | } | 
 | 526 |  | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 527 | void ImageWriter::CalculateNewObjectOffsets(size_t oat_loaded_size, size_t oat_data_offset) { | 
 | 528 |   CHECK_NE(0U, oat_loaded_size); | 
 | 529 |   Thread* self = Thread::Current(); | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 530 |   StackHandleScope<1> hs(self); | 
 | 531 |   Handle<ObjectArray<Object>> image_roots(hs.NewHandle(CreateImageRoots())); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 532 |  | 
 | 533 |   gc::Heap* heap = Runtime::Current()->GetHeap(); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 534 |   DCHECK_EQ(0U, image_end_); | 
 | 535 |  | 
| Mathieu Chartier | 31e8925 | 2013-08-28 11:29:12 -0700 | [diff] [blame] | 536 |   // Leave space for the header, but do not write it yet, we need to | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 537 |   // know where image_roots is going to end up | 
| Brian Carlstrom | 7934ac2 | 2013-07-26 10:54:15 -0700 | [diff] [blame] | 538 |   image_end_ += RoundUp(sizeof(ImageHeader), 8);  // 64-bit-alignment | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 539 |  | 
 | 540 |   { | 
 | 541 |     WriterMutexLock mu(self, *Locks::heap_bitmap_lock_); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 542 |     // TODO: Image spaces only? | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 543 |     const char* old = self->StartAssertNoThreadSuspension("ImageWriter"); | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 544 |     DCHECK_LT(image_end_, image_->Size()); | 
 | 545 |     // Clear any pre-existing monitors which may have been in the monitor words. | 
 | 546 |     heap->VisitObjects(WalkFieldsCallback, this); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 547 |     self->EndAssertNoThreadSuspension(old); | 
 | 548 |   } | 
 | 549 |  | 
 | 550 |   const byte* oat_file_begin = image_begin_ + RoundUp(image_end_, kPageSize); | 
 | 551 |   const byte* oat_file_end = oat_file_begin + oat_loaded_size; | 
 | 552 |   oat_data_begin_ = oat_file_begin + oat_data_offset; | 
 | 553 |   const byte* oat_data_end = oat_data_begin_ + oat_file_->Size(); | 
 | 554 |  | 
| Mathieu Chartier | 31e8925 | 2013-08-28 11:29:12 -0700 | [diff] [blame] | 555 |   // Return to write header at start of image with future location of image_roots. At this point, | 
 | 556 |   // image_end_ is the size of the image (excluding bitmaps). | 
| Mathieu Chartier | a8e8f9c | 2014-04-09 14:51:05 -0700 | [diff] [blame] | 557 |   const size_t heap_bytes_per_bitmap_byte = kBitsPerByte * kObjectAlignment; | 
| Mathieu Chartier | 12aeccd | 2013-11-13 15:52:06 -0800 | [diff] [blame] | 558 |   const size_t bitmap_bytes = RoundUp(image_end_, heap_bytes_per_bitmap_byte) / | 
 | 559 |       heap_bytes_per_bitmap_byte; | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 560 |   ImageHeader image_header(PointerToLowMemUInt32(image_begin_), | 
| Mathieu Chartier | 31e8925 | 2013-08-28 11:29:12 -0700 | [diff] [blame] | 561 |                            static_cast<uint32_t>(image_end_), | 
 | 562 |                            RoundUp(image_end_, kPageSize), | 
| Mathieu Chartier | 12aeccd | 2013-11-13 15:52:06 -0800 | [diff] [blame] | 563 |                            RoundUp(bitmap_bytes, kPageSize), | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 564 |                            PointerToLowMemUInt32(GetImageAddress(image_roots.Get())), | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 565 |                            oat_file_->GetOatHeader().GetChecksum(), | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 566 |                            PointerToLowMemUInt32(oat_file_begin), | 
 | 567 |                            PointerToLowMemUInt32(oat_data_begin_), | 
 | 568 |                            PointerToLowMemUInt32(oat_data_end), | 
 | 569 |                            PointerToLowMemUInt32(oat_file_end)); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 570 |   memcpy(image_->Begin(), &image_header, sizeof(image_header)); | 
 | 571 |  | 
 | 572 |   // Note that image_end_ is left at end of used space | 
 | 573 | } | 
 | 574 |  | 
 | 575 | void ImageWriter::CopyAndFixupObjects() | 
 | 576 |     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { | 
 | 577 |   Thread* self = Thread::Current(); | 
 | 578 |   const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter"); | 
 | 579 |   gc::Heap* heap = Runtime::Current()->GetHeap(); | 
 | 580 |   // TODO: heap validation can't handle this fix up pass | 
 | 581 |   heap->DisableObjectValidation(); | 
 | 582 |   // TODO: Image spaces only? | 
 | 583 |   WriterMutexLock mu(self, *Locks::heap_bitmap_lock_); | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 584 |   heap->VisitObjects(CopyAndFixupObjectsCallback, this); | 
 | 585 |   // Fix up the object previously had hash codes. | 
 | 586 |   for (const std::pair<mirror::Object*, uint32_t>& hash_pair : saved_hashes_) { | 
| Mathieu Chartier | 4d7f61d | 2014-04-17 14:43:39 -0700 | [diff] [blame] | 587 |     hash_pair.first->SetLockWord(LockWord::FromHashCode(hash_pair.second), false); | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 588 |   } | 
 | 589 |   saved_hashes_.clear(); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 590 |   self->EndAssertNoThreadSuspension(old_cause); | 
 | 591 | } | 
 | 592 |  | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 593 | void ImageWriter::CopyAndFixupObjectsCallback(Object* obj, void* arg) { | 
| Mathieu Chartier | 4d7f61d | 2014-04-17 14:43:39 -0700 | [diff] [blame] | 594 |   DCHECK(obj != nullptr); | 
 | 595 |   DCHECK(arg != nullptr); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 596 |   ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 597 |   // see GetLocalAddress for similar computation | 
 | 598 |   size_t offset = image_writer->GetImageOffset(obj); | 
 | 599 |   byte* dst = image_writer->image_->Begin() + offset; | 
 | 600 |   const byte* src = reinterpret_cast<const byte*>(obj); | 
 | 601 |   size_t n = obj->SizeOf(); | 
 | 602 |   DCHECK_LT(offset + n, image_writer->image_->Size()); | 
 | 603 |   memcpy(dst, src, n); | 
 | 604 |   Object* copy = reinterpret_cast<Object*>(dst); | 
| Mathieu Chartier | ad2541a | 2013-10-25 10:05:23 -0700 | [diff] [blame] | 605 |   // Write in a hash code of objects which have inflated monitors or a hash code in their monitor | 
 | 606 |   // word. | 
| Mathieu Chartier | 4d7f61d | 2014-04-17 14:43:39 -0700 | [diff] [blame] | 607 |   copy->SetLockWord(LockWord(), false); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 608 |   image_writer->FixupObject(obj, copy); | 
 | 609 | } | 
 | 610 |  | 
| Mathieu Chartier | b7ea3ac | 2014-03-24 16:54:46 -0700 | [diff] [blame] | 611 | class FixupVisitor { | 
 | 612 |  public: | 
 | 613 |   FixupVisitor(ImageWriter* image_writer, Object* copy) : image_writer_(image_writer), copy_(copy) { | 
 | 614 |   } | 
 | 615 |  | 
 | 616 |   void operator()(Object* obj, MemberOffset offset, bool /*is_static*/) const | 
 | 617 |       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) { | 
| Hiroshi Yamauchi | 6e83c17 | 2014-05-01 21:25:41 -0700 | [diff] [blame] | 618 |     Object* ref = obj->GetFieldObject<Object, kVerifyNone>(offset); | 
| Mathieu Chartier | b7ea3ac | 2014-03-24 16:54:46 -0700 | [diff] [blame] | 619 |     // Use SetFieldObjectWithoutWriteBarrier to avoid card marking since we are writing to the | 
 | 620 |     // image. | 
 | 621 |     copy_->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>( | 
| Ian Rogers | b0fa5dc | 2014-04-28 16:47:08 -0700 | [diff] [blame] | 622 |         offset, image_writer_->GetImageAddress(ref)); | 
| Mathieu Chartier | b7ea3ac | 2014-03-24 16:54:46 -0700 | [diff] [blame] | 623 |   } | 
 | 624 |  | 
 | 625 |   // java.lang.ref.Reference visitor. | 
 | 626 |   void operator()(mirror::Class* /*klass*/, mirror::Reference* ref) const | 
 | 627 |       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) | 
 | 628 |       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) { | 
 | 629 |     copy_->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>( | 
| Ian Rogers | b0fa5dc | 2014-04-28 16:47:08 -0700 | [diff] [blame] | 630 |         mirror::Reference::ReferentOffset(), image_writer_->GetImageAddress(ref->GetReferent())); | 
| Mathieu Chartier | b7ea3ac | 2014-03-24 16:54:46 -0700 | [diff] [blame] | 631 |   } | 
 | 632 |  | 
| Mingyao Yang | 98d1cc8 | 2014-05-15 17:02:16 -0700 | [diff] [blame] | 633 |  protected: | 
| Mathieu Chartier | b7ea3ac | 2014-03-24 16:54:46 -0700 | [diff] [blame] | 634 |   ImageWriter* const image_writer_; | 
 | 635 |   mirror::Object* const copy_; | 
 | 636 | }; | 
 | 637 |  | 
| Mingyao Yang | 98d1cc8 | 2014-05-15 17:02:16 -0700 | [diff] [blame] | 638 | class FixupClassVisitor FINAL : public FixupVisitor { | 
 | 639 |  public: | 
 | 640 |   FixupClassVisitor(ImageWriter* image_writer, Object* copy) : FixupVisitor(image_writer, copy) { | 
 | 641 |   } | 
 | 642 |  | 
 | 643 |   void operator()(Object* obj, MemberOffset offset, bool /*is_static*/) const | 
 | 644 |       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) { | 
 | 645 |     DCHECK(obj->IsClass()); | 
 | 646 |     FixupVisitor::operator()(obj, offset, false); | 
 | 647 |  | 
 | 648 |     if (offset.Uint32Value() < mirror::Class::EmbeddedVTableOffset().Uint32Value()) { | 
 | 649 |       return; | 
 | 650 |     } | 
 | 651 |   } | 
 | 652 |  | 
 | 653 |   void operator()(mirror::Class* /*klass*/, mirror::Reference* ref) const | 
 | 654 |       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) | 
 | 655 |       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) { | 
 | 656 |     LOG(FATAL) << "Reference not expected here."; | 
 | 657 |   } | 
 | 658 | }; | 
 | 659 |  | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 660 | void ImageWriter::FixupObject(Object* orig, Object* copy) { | 
| Mathieu Chartier | b7ea3ac | 2014-03-24 16:54:46 -0700 | [diff] [blame] | 661 |   DCHECK(orig != nullptr); | 
 | 662 |   DCHECK(copy != nullptr); | 
| Hiroshi Yamauchi | 624468c | 2014-03-31 15:14:47 -0700 | [diff] [blame] | 663 |   if (kUseBakerOrBrooksReadBarrier) { | 
 | 664 |     orig->AssertReadBarrierPointer(); | 
 | 665 |     if (kUseBrooksReadBarrier) { | 
 | 666 |       // Note the address 'copy' isn't the same as the image address of 'orig'. | 
 | 667 |       copy->SetReadBarrierPointer(GetImageAddress(orig)); | 
 | 668 |       DCHECK_EQ(copy->GetReadBarrierPointer(), GetImageAddress(orig)); | 
 | 669 |     } | 
| Hiroshi Yamauchi | 9d04a20 | 2014-01-31 13:35:49 -0800 | [diff] [blame] | 670 |   } | 
| Mingyao Yang | 98d1cc8 | 2014-05-15 17:02:16 -0700 | [diff] [blame] | 671 |   if (orig->IsClass() && orig->AsClass()->ShouldHaveEmbeddedImtAndVTable()) { | 
 | 672 |     FixupClassVisitor visitor(this, copy); | 
 | 673 |     orig->VisitReferences<true /*visit class*/>(visitor, visitor); | 
 | 674 |   } else { | 
 | 675 |     FixupVisitor visitor(this, copy); | 
 | 676 |     orig->VisitReferences<true /*visit class*/>(visitor, visitor); | 
 | 677 |   } | 
| Mathieu Chartier | b7ea3ac | 2014-03-24 16:54:46 -0700 | [diff] [blame] | 678 |   if (orig->IsArtMethod<kVerifyNone>()) { | 
| Mathieu Chartier | 4e30541 | 2014-02-19 10:54:44 -0800 | [diff] [blame] | 679 |     FixupMethod(orig->AsArtMethod<kVerifyNone>(), down_cast<ArtMethod*>(copy)); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 680 |   } | 
 | 681 | } | 
 | 682 |  | 
| Mingyao Yang | 98d1cc8 | 2014-05-15 17:02:16 -0700 | [diff] [blame] | 683 | const byte* ImageWriter::GetQuickCode(mirror::ArtMethod* method, bool* quick_is_interpreted) { | 
 | 684 |   DCHECK(!method->IsResolutionMethod() && !method->IsImtConflictMethod() && | 
 | 685 |          !method->IsAbstract()) << PrettyMethod(method); | 
 | 686 |  | 
 | 687 |   // Use original code if it exists. Otherwise, set the code pointer to the resolution | 
 | 688 |   // trampoline. | 
 | 689 |  | 
 | 690 |   // Quick entrypoint: | 
 | 691 |   const byte* quick_code = GetOatAddress(method->GetQuickOatCodeOffset()); | 
 | 692 |   *quick_is_interpreted = false; | 
 | 693 |   if (quick_code != nullptr && | 
 | 694 |       (!method->IsStatic() || method->IsConstructor() || method->GetDeclaringClass()->IsInitialized())) { | 
 | 695 |     // We have code for a non-static or initialized method, just use the code. | 
 | 696 |   } else if (quick_code == nullptr && method->IsNative() && | 
 | 697 |       (!method->IsStatic() || method->GetDeclaringClass()->IsInitialized())) { | 
 | 698 |     // Non-static or initialized native method missing compiled code, use generic JNI version. | 
 | 699 |     quick_code = GetOatAddress(quick_generic_jni_trampoline_offset_); | 
 | 700 |   } else if (quick_code == nullptr && !method->IsNative()) { | 
 | 701 |     // We don't have code at all for a non-native method, use the interpreter. | 
 | 702 |     quick_code = GetOatAddress(quick_to_interpreter_bridge_offset_); | 
 | 703 |     *quick_is_interpreted = true; | 
 | 704 |   } else { | 
 | 705 |     CHECK(!method->GetDeclaringClass()->IsInitialized()); | 
 | 706 |     // We have code for a static method, but need to go through the resolution stub for class | 
 | 707 |     // initialization. | 
 | 708 |     quick_code = GetOatAddress(quick_resolution_trampoline_offset_); | 
 | 709 |   } | 
 | 710 |   return quick_code; | 
 | 711 | } | 
 | 712 |  | 
 | 713 | const byte* ImageWriter::GetQuickEntryPoint(mirror::ArtMethod* method) { | 
 | 714 |   // Calculate the quick entry point following the same logic as FixupMethod() below. | 
 | 715 |   // The resolution method has a special trampoline to call. | 
 | 716 |   if (UNLIKELY(method == Runtime::Current()->GetResolutionMethod())) { | 
 | 717 |     return GetOatAddress(quick_resolution_trampoline_offset_); | 
 | 718 |   } else if (UNLIKELY(method == Runtime::Current()->GetImtConflictMethod())) { | 
 | 719 |     return GetOatAddress(quick_imt_conflict_trampoline_offset_); | 
 | 720 |   } else { | 
 | 721 |     // We assume all methods have code. If they don't currently then we set them to the use the | 
 | 722 |     // resolution trampoline. Abstract methods never have code and so we need to make sure their | 
 | 723 |     // use results in an AbstractMethodError. We use the interpreter to achieve this. | 
 | 724 |     if (UNLIKELY(method->IsAbstract())) { | 
 | 725 |       return GetOatAddress(quick_to_interpreter_bridge_offset_); | 
 | 726 |     } else { | 
 | 727 |       bool quick_is_interpreted; | 
 | 728 |       return GetQuickCode(method, &quick_is_interpreted); | 
 | 729 |     } | 
 | 730 |   } | 
 | 731 | } | 
 | 732 |  | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 733 | void ImageWriter::FixupMethod(ArtMethod* orig, ArtMethod* copy) { | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 734 |   // OatWriter replaces the code_ with an offset value. Here we re-adjust to a pointer relative to | 
 | 735 |   // oat_begin_ | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 736 |  | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 737 |   // The resolution method has a special trampoline to call. | 
 | 738 |   if (UNLIKELY(orig == Runtime::Current()->GetResolutionMethod())) { | 
| Mathieu Chartier | 4e30541 | 2014-02-19 10:54:44 -0800 | [diff] [blame] | 739 |     copy->SetEntryPointFromPortableCompiledCode<kVerifyNone>(GetOatAddress(portable_resolution_trampoline_offset_)); | 
 | 740 |     copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(GetOatAddress(quick_resolution_trampoline_offset_)); | 
| Jeff Hao | 88474b4 | 2013-10-23 16:24:40 -0700 | [diff] [blame] | 741 |   } else if (UNLIKELY(orig == Runtime::Current()->GetImtConflictMethod())) { | 
| Mathieu Chartier | 4e30541 | 2014-02-19 10:54:44 -0800 | [diff] [blame] | 742 |     copy->SetEntryPointFromPortableCompiledCode<kVerifyNone>(GetOatAddress(portable_imt_conflict_trampoline_offset_)); | 
 | 743 |     copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(GetOatAddress(quick_imt_conflict_trampoline_offset_)); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 744 |   } else { | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 745 |     // We assume all methods have code. If they don't currently then we set them to the use the | 
 | 746 |     // resolution trampoline. Abstract methods never have code and so we need to make sure their | 
 | 747 |     // use results in an AbstractMethodError. We use the interpreter to achieve this. | 
 | 748 |     if (UNLIKELY(orig->IsAbstract())) { | 
| Mathieu Chartier | 4e30541 | 2014-02-19 10:54:44 -0800 | [diff] [blame] | 749 |       copy->SetEntryPointFromPortableCompiledCode<kVerifyNone>(GetOatAddress(portable_to_interpreter_bridge_offset_)); | 
 | 750 |       copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(GetOatAddress(quick_to_interpreter_bridge_offset_)); | 
 | 751 |       copy->SetEntryPointFromInterpreter<kVerifyNone>(reinterpret_cast<EntryPointFromInterpreter*> | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 752 |           (const_cast<byte*>(GetOatAddress(interpreter_to_interpreter_bridge_offset_)))); | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 753 |     } else { | 
| Mingyao Yang | 98d1cc8 | 2014-05-15 17:02:16 -0700 | [diff] [blame] | 754 |       bool quick_is_interpreted; | 
 | 755 |       const byte* quick_code = GetQuickCode(orig, &quick_is_interpreted); | 
| Sebastien Hertz | e1d0781 | 2014-05-21 15:44:09 +0200 | [diff] [blame] | 756 |       copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(quick_code); | 
 | 757 |  | 
 | 758 |       // Portable entrypoint: | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 759 |       const byte* portable_code = GetOatAddress(orig->GetPortableOatCodeOffset()); | 
| Sebastien Hertz | e1d0781 | 2014-05-21 15:44:09 +0200 | [diff] [blame] | 760 |       bool portable_is_interpreted = false; | 
 | 761 |       if (portable_code != nullptr && | 
 | 762 |           (!orig->IsStatic() || orig->IsConstructor() || orig->GetDeclaringClass()->IsInitialized())) { | 
 | 763 |         // We have code for a non-static or initialized method, just use the code. | 
 | 764 |       } else if (portable_code == nullptr && orig->IsNative() && | 
 | 765 |           (!orig->IsStatic() || orig->GetDeclaringClass()->IsInitialized())) { | 
 | 766 |         // Non-static or initialized native method missing compiled code, use generic JNI version. | 
 | 767 |         // TODO: generic JNI support for LLVM. | 
 | 768 |         portable_code = GetOatAddress(portable_resolution_trampoline_offset_); | 
 | 769 |       } else if (portable_code == nullptr && !orig->IsNative()) { | 
 | 770 |         // We don't have code at all for a non-native method, use the interpreter. | 
 | 771 |         portable_code = GetOatAddress(portable_to_interpreter_bridge_offset_); | 
 | 772 |         portable_is_interpreted = true; | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 773 |       } else { | 
| Sebastien Hertz | e1d0781 | 2014-05-21 15:44:09 +0200 | [diff] [blame] | 774 |         CHECK(!orig->GetDeclaringClass()->IsInitialized()); | 
 | 775 |         // We have code for a static method, but need to go through the resolution stub for class | 
 | 776 |         // initialization. | 
 | 777 |         portable_code = GetOatAddress(portable_resolution_trampoline_offset_); | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 778 |       } | 
| Sebastien Hertz | e1d0781 | 2014-05-21 15:44:09 +0200 | [diff] [blame] | 779 |       copy->SetEntryPointFromPortableCompiledCode<kVerifyNone>(portable_code); | 
 | 780 |  | 
 | 781 |       // JNI entrypoint: | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 782 |       if (orig->IsNative()) { | 
 | 783 |         // The native method's pointer is set to a stub to lookup via dlsym. | 
 | 784 |         // Note this is not the code_ pointer, that is handled above. | 
| Mathieu Chartier | 4e30541 | 2014-02-19 10:54:44 -0800 | [diff] [blame] | 785 |         copy->SetNativeMethod<kVerifyNone>(GetOatAddress(jni_dlsym_lookup_offset_)); | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 786 |       } else { | 
 | 787 |         // Normal (non-abstract non-native) methods have various tables to relocate. | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 788 |         uint32_t native_gc_map_offset = orig->GetOatNativeGcMapOffset(); | 
 | 789 |         const byte* native_gc_map = GetOatAddress(native_gc_map_offset); | 
| Mathieu Chartier | 4e30541 | 2014-02-19 10:54:44 -0800 | [diff] [blame] | 790 |         copy->SetNativeGcMap<kVerifyNone>(reinterpret_cast<const uint8_t*>(native_gc_map)); | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 791 |       } | 
| Sebastien Hertz | e1d0781 | 2014-05-21 15:44:09 +0200 | [diff] [blame] | 792 |  | 
 | 793 |       // Interpreter entrypoint: | 
 | 794 |       // Set the interpreter entrypoint depending on whether there is compiled code or not. | 
 | 795 |       uint32_t interpreter_code = (quick_is_interpreted && portable_is_interpreted) | 
 | 796 |           ? interpreter_to_interpreter_bridge_offset_ | 
 | 797 |           : interpreter_to_compiled_code_bridge_offset_; | 
 | 798 |       copy->SetEntryPointFromInterpreter<kVerifyNone>( | 
 | 799 |           reinterpret_cast<EntryPointFromInterpreter*>( | 
 | 800 |               const_cast<byte*>(GetOatAddress(interpreter_code)))); | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 801 |     } | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 802 |   } | 
 | 803 | } | 
 | 804 |  | 
| Hiroshi Yamauchi | be1ca55 | 2014-01-15 11:46:48 -0800 | [diff] [blame] | 805 | static ArtMethod* GetTargetMethod(const CompilerDriver::CallPatchInformation* patch) | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 806 |     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { | 
 | 807 |   ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); | 
| Mathieu Chartier | 0cd8135 | 2014-05-22 16:48:55 -0700 | [diff] [blame] | 808 |   StackHandleScope<1> hs(Thread::Current()); | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 809 |   Handle<mirror::DexCache> dex_cache( | 
 | 810 |       hs.NewHandle(class_linker->FindDexCache(*patch->GetTargetDexFile()))); | 
| Jeff Hao | 49161ce | 2014-03-12 11:05:25 -0700 | [diff] [blame] | 811 |   ArtMethod* method = class_linker->ResolveMethod(*patch->GetTargetDexFile(), | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 812 |                                                   patch->GetTargetMethodIdx(), | 
 | 813 |                                                   dex_cache, | 
| Mathieu Chartier | 0cd8135 | 2014-05-22 16:48:55 -0700 | [diff] [blame] | 814 |                                                   NullHandle<mirror::ClassLoader>(), | 
 | 815 |                                                   NullHandle<mirror::ArtMethod>(), | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 816 |                                                   patch->GetTargetInvokeType()); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 817 |   CHECK(method != NULL) | 
| Jeff Hao | 49161ce | 2014-03-12 11:05:25 -0700 | [diff] [blame] | 818 |     << patch->GetTargetDexFile()->GetLocation() << " " << patch->GetTargetMethodIdx(); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 819 |   CHECK(!method->IsRuntimeMethod()) | 
| Jeff Hao | 49161ce | 2014-03-12 11:05:25 -0700 | [diff] [blame] | 820 |     << patch->GetTargetDexFile()->GetLocation() << " " << patch->GetTargetMethodIdx(); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 821 |   CHECK(dex_cache->GetResolvedMethods()->Get(patch->GetTargetMethodIdx()) == method) | 
| Jeff Hao | 49161ce | 2014-03-12 11:05:25 -0700 | [diff] [blame] | 822 |     << patch->GetTargetDexFile()->GetLocation() << " " << patch->GetReferrerMethodIdx() << " " | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 823 |     << PrettyMethod(dex_cache->GetResolvedMethods()->Get(patch->GetTargetMethodIdx())) << " " | 
 | 824 |     << PrettyMethod(method); | 
 | 825 |   return method; | 
 | 826 | } | 
 | 827 |  | 
| Hiroshi Yamauchi | be1ca55 | 2014-01-15 11:46:48 -0800 | [diff] [blame] | 828 | static Class* GetTargetType(const CompilerDriver::TypePatchInformation* patch) | 
 | 829 |     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { | 
 | 830 |   ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 831 |   StackHandleScope<2> hs(Thread::Current()); | 
 | 832 |   Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(patch->GetDexFile()))); | 
| Mathieu Chartier | 0cd8135 | 2014-05-22 16:48:55 -0700 | [diff] [blame] | 833 |   Class* klass = class_linker->ResolveType(patch->GetDexFile(), patch->GetTargetTypeIdx(), | 
 | 834 |                                            dex_cache, NullHandle<mirror::ClassLoader>()); | 
| Hiroshi Yamauchi | be1ca55 | 2014-01-15 11:46:48 -0800 | [diff] [blame] | 835 |   CHECK(klass != NULL) | 
 | 836 |     << patch->GetDexFile().GetLocation() << " " << patch->GetTargetTypeIdx(); | 
 | 837 |   CHECK(dex_cache->GetResolvedTypes()->Get(patch->GetTargetTypeIdx()) == klass) | 
 | 838 |     << patch->GetDexFile().GetLocation() << " " << patch->GetReferrerMethodIdx() << " " | 
 | 839 |     << PrettyClass(dex_cache->GetResolvedTypes()->Get(patch->GetTargetTypeIdx())) << " " | 
 | 840 |     << PrettyClass(klass); | 
 | 841 |   return klass; | 
 | 842 | } | 
 | 843 |  | 
| Alex Light | 53cb16b | 2014-06-12 11:26:29 -0700 | [diff] [blame] | 844 | void ImageWriter::PatchOatCodeAndMethods(File* elf_file) { | 
 | 845 |   std::vector<uintptr_t> patches; | 
 | 846 |   std::set<uintptr_t> patches_set; | 
 | 847 |   auto maybe_push = [&patches, &patches_set] (uintptr_t p) { | 
 | 848 |     if (patches_set.find(p) == patches_set.end()) { | 
 | 849 |       patches.push_back(p); | 
 | 850 |       patches_set.insert(p); | 
 | 851 |     } | 
 | 852 |   }; | 
 | 853 |   const bool add_patches = compiler_driver_.GetCompilerOptions().GetIncludePatchInformation(); | 
 | 854 |   if (add_patches) { | 
| Alex Light | eefbe39 | 2014-07-08 09:53:18 -0700 | [diff] [blame] | 855 |     // TODO if we are adding patches the resulting ELF file might have a potentially rather large | 
 | 856 |     // amount of free space where patches might have been placed. We should adjust the ELF file to | 
 | 857 |     // get rid of this excess space. | 
| Alex Light | 53cb16b | 2014-06-12 11:26:29 -0700 | [diff] [blame] | 858 |     patches.reserve(compiler_driver_.GetCodeToPatch().size() + | 
 | 859 |                     compiler_driver_.GetMethodsToPatch().size() + | 
 | 860 |                     compiler_driver_.GetClassesToPatch().size()); | 
 | 861 |   } | 
 | 862 |   uintptr_t loc = 0; | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 863 |   Thread* self = Thread::Current(); | 
 | 864 |   ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); | 
 | 865 |   const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter"); | 
 | 866 |  | 
| Hiroshi Yamauchi | be1ca55 | 2014-01-15 11:46:48 -0800 | [diff] [blame] | 867 |   typedef std::vector<const CompilerDriver::CallPatchInformation*> CallPatches; | 
 | 868 |   const CallPatches& code_to_patch = compiler_driver_.GetCodeToPatch(); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 869 |   for (size_t i = 0; i < code_to_patch.size(); i++) { | 
| Hiroshi Yamauchi | be1ca55 | 2014-01-15 11:46:48 -0800 | [diff] [blame] | 870 |     const CompilerDriver::CallPatchInformation* patch = code_to_patch[i]; | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 871 |     ArtMethod* target = GetTargetMethod(patch); | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 872 |     uintptr_t quick_code = reinterpret_cast<uintptr_t>(class_linker->GetQuickOatCodeFor(target)); | 
| Mathieu Chartier | 57d2733 | 2014-05-29 10:19:19 -0700 | [diff] [blame] | 873 |     DCHECK_NE(quick_code, 0U) << PrettyMethod(target); | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 874 |     uintptr_t code_base = reinterpret_cast<uintptr_t>(&oat_file_->GetOatHeader()); | 
 | 875 |     uintptr_t code_offset = quick_code - code_base; | 
| Mathieu Chartier | 57d2733 | 2014-05-29 10:19:19 -0700 | [diff] [blame] | 876 |     bool is_quick_offset = false; | 
 | 877 |     if (quick_code == reinterpret_cast<uintptr_t>(GetQuickToInterpreterBridge())) { | 
 | 878 |       is_quick_offset = true; | 
| Mathieu Chartier | d8a737a | 2014-05-30 16:44:47 +0000 | [diff] [blame] | 879 |       code_offset = quick_to_interpreter_bridge_offset_; | 
| Mathieu Chartier | 57d2733 | 2014-05-29 10:19:19 -0700 | [diff] [blame] | 880 |     } else if (quick_code == | 
 | 881 |         reinterpret_cast<uintptr_t>(class_linker->GetQuickGenericJniTrampoline())) { | 
 | 882 |       CHECK(target->IsNative()); | 
 | 883 |       is_quick_offset = true; | 
| Mathieu Chartier | d8a737a | 2014-05-30 16:44:47 +0000 | [diff] [blame] | 884 |       code_offset = quick_generic_jni_trampoline_offset_; | 
| Mathieu Chartier | 57d2733 | 2014-05-29 10:19:19 -0700 | [diff] [blame] | 885 |     } | 
 | 886 |     uintptr_t value; | 
| Mark Mendell | 55d0eac | 2014-02-06 11:02:52 -0800 | [diff] [blame] | 887 |     if (patch->IsRelative()) { | 
 | 888 |       // value to patch is relative to the location being patched | 
 | 889 |       const void* quick_oat_code = | 
 | 890 |         class_linker->GetQuickOatCodeFor(patch->GetDexFile(), | 
 | 891 |                                          patch->GetReferrerClassDefIdx(), | 
 | 892 |                                          patch->GetReferrerMethodIdx()); | 
| Mathieu Chartier | 57d2733 | 2014-05-29 10:19:19 -0700 | [diff] [blame] | 893 |       if (is_quick_offset) { | 
| Mathieu Chartier | 57d2733 | 2014-05-29 10:19:19 -0700 | [diff] [blame] | 894 |         // If its a quick offset it means that we are doing a relative patch from the class linker | 
 | 895 |         // oat_file to the image writer oat_file so we need to adjust the quick oat code to be the | 
 | 896 |         // one in the image writer oat_file. | 
| Mathieu Chartier | d8a737a | 2014-05-30 16:44:47 +0000 | [diff] [blame] | 897 |         quick_code = PointerToLowMemUInt32(GetOatAddress(code_offset)); | 
| Mathieu Chartier | 57d2733 | 2014-05-29 10:19:19 -0700 | [diff] [blame] | 898 |         quick_oat_code = | 
 | 899 |             reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(quick_oat_code) + | 
 | 900 |                 reinterpret_cast<uintptr_t>(oat_data_begin_) - code_base); | 
 | 901 |       } | 
| Mark Mendell | 55d0eac | 2014-02-06 11:02:52 -0800 | [diff] [blame] | 902 |       uintptr_t base = reinterpret_cast<uintptr_t>(quick_oat_code); | 
 | 903 |       uintptr_t patch_location = base + patch->GetLiteralOffset(); | 
| Mathieu Chartier | 57d2733 | 2014-05-29 10:19:19 -0700 | [diff] [blame] | 904 |       value = quick_code - patch_location + patch->RelativeOffset(); | 
| Mark Mendell | 55d0eac | 2014-02-06 11:02:52 -0800 | [diff] [blame] | 905 |     } else { | 
| Mathieu Chartier | d8a737a | 2014-05-30 16:44:47 +0000 | [diff] [blame] | 906 |       value = PointerToLowMemUInt32(GetOatAddress(code_offset)); | 
| Mark Mendell | 55d0eac | 2014-02-06 11:02:52 -0800 | [diff] [blame] | 907 |     } | 
| Alex Light | 53cb16b | 2014-06-12 11:26:29 -0700 | [diff] [blame] | 908 |     SetPatchLocation(patch, value, &loc); | 
 | 909 |     if (add_patches && !patch->AsCall()->IsRelative()) { | 
 | 910 |       maybe_push(loc); | 
 | 911 |     } | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 912 |   } | 
 | 913 |  | 
| Hiroshi Yamauchi | be1ca55 | 2014-01-15 11:46:48 -0800 | [diff] [blame] | 914 |   const CallPatches& methods_to_patch = compiler_driver_.GetMethodsToPatch(); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 915 |   for (size_t i = 0; i < methods_to_patch.size(); i++) { | 
| Hiroshi Yamauchi | be1ca55 | 2014-01-15 11:46:48 -0800 | [diff] [blame] | 916 |     const CompilerDriver::CallPatchInformation* patch = methods_to_patch[i]; | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 917 |     ArtMethod* target = GetTargetMethod(patch); | 
| Alex Light | 53cb16b | 2014-06-12 11:26:29 -0700 | [diff] [blame] | 918 |     SetPatchLocation(patch, PointerToLowMemUInt32(GetImageAddress(target)), &loc); | 
 | 919 |     if (add_patches && !patch->AsCall()->IsRelative()) { | 
 | 920 |       maybe_push(loc); | 
 | 921 |     } | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 922 |   } | 
 | 923 |  | 
| Hiroshi Yamauchi | be1ca55 | 2014-01-15 11:46:48 -0800 | [diff] [blame] | 924 |   const std::vector<const CompilerDriver::TypePatchInformation*>& classes_to_patch = | 
 | 925 |       compiler_driver_.GetClassesToPatch(); | 
 | 926 |   for (size_t i = 0; i < classes_to_patch.size(); i++) { | 
 | 927 |     const CompilerDriver::TypePatchInformation* patch = classes_to_patch[i]; | 
 | 928 |     Class* target = GetTargetType(patch); | 
| Alex Light | 53cb16b | 2014-06-12 11:26:29 -0700 | [diff] [blame] | 929 |     SetPatchLocation(patch, PointerToLowMemUInt32(GetImageAddress(target)), &loc); | 
 | 930 |     if (add_patches) { | 
 | 931 |       maybe_push(loc); | 
 | 932 |     } | 
| Hiroshi Yamauchi | be1ca55 | 2014-01-15 11:46:48 -0800 | [diff] [blame] | 933 |   } | 
 | 934 |  | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 935 |   // Update the image header with the new checksum after patching | 
 | 936 |   ImageHeader* image_header = reinterpret_cast<ImageHeader*>(image_->Begin()); | 
 | 937 |   image_header->SetOatChecksum(oat_file_->GetOatHeader().GetChecksum()); | 
 | 938 |   self->EndAssertNoThreadSuspension(old_cause); | 
| Alex Light | 53cb16b | 2014-06-12 11:26:29 -0700 | [diff] [blame] | 939 |  | 
 | 940 |   // Update the ElfFiles SHT_OAT_PATCH section to include the patches. | 
 | 941 |   if (add_patches) { | 
 | 942 |     std::string err; | 
 | 943 |     // TODO we are mapping in the contents of this file twice. We should be able | 
 | 944 |     // to do it only once, which would be better. | 
 | 945 |     std::unique_ptr<ElfFile> file(ElfFile::Open(elf_file, true, false, &err)); | 
 | 946 |     if (file == nullptr) { | 
 | 947 |       LOG(ERROR) << err; | 
 | 948 |     } | 
 | 949 |     Elf32_Shdr* shdr = file->FindSectionByName(".oat_patches"); | 
 | 950 |     if (shdr != nullptr) { | 
| Alex Light | eefbe39 | 2014-07-08 09:53:18 -0700 | [diff] [blame] | 951 |       CHECK_EQ(shdr, file->FindSectionByType(SHT_OAT_PATCH)) | 
| Alex Light | 53cb16b | 2014-06-12 11:26:29 -0700 | [diff] [blame] | 952 |           << "Incorrect type for .oat_patches section"; | 
 | 953 |       CHECK_LE(patches.size() * sizeof(uintptr_t), shdr->sh_size) | 
 | 954 |           << "We got more patches than anticipated"; | 
 | 955 |       CHECK_LE(reinterpret_cast<uintptr_t>(file->Begin()) + shdr->sh_offset + shdr->sh_size, | 
 | 956 |                reinterpret_cast<uintptr_t>(file->End())) << "section is too large"; | 
 | 957 |       CHECK(shdr == &file->GetSectionHeader(file->GetSectionHeaderNum() - 1) || | 
 | 958 |             shdr->sh_offset + shdr->sh_size <= (shdr + 1)->sh_offset) | 
 | 959 |           << "Section overlaps onto next section"; | 
 | 960 |       // It's mmap'd so we can just memcpy. | 
 | 961 |       memcpy(file->Begin() + shdr->sh_offset, patches.data(), patches.size()*sizeof(uintptr_t)); | 
| Alex Light | eefbe39 | 2014-07-08 09:53:18 -0700 | [diff] [blame] | 962 |       // TODO We should fill in the newly empty space between the last patch and the start of the | 
 | 963 |       // next section by moving the following sections down if possible. | 
| Alex Light | 53cb16b | 2014-06-12 11:26:29 -0700 | [diff] [blame] | 964 |       shdr->sh_size = patches.size() * sizeof(uintptr_t); | 
 | 965 |     } else { | 
 | 966 |       LOG(ERROR) << "Unable to find section header for SHT_OAT_PATCH"; | 
 | 967 |     } | 
 | 968 |   } | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 969 | } | 
 | 970 |  | 
| Alex Light | 53cb16b | 2014-06-12 11:26:29 -0700 | [diff] [blame] | 971 | void ImageWriter::SetPatchLocation(const CompilerDriver::PatchInformation* patch, uint32_t value, | 
 | 972 |                                    uintptr_t* patched_ptr) { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 973 |   ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 974 |   const void* quick_oat_code = class_linker->GetQuickOatCodeFor(patch->GetDexFile(), | 
 | 975 |                                                                 patch->GetReferrerClassDefIdx(), | 
 | 976 |                                                                 patch->GetReferrerMethodIdx()); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 977 |   OatHeader& oat_header = const_cast<OatHeader&>(oat_file_->GetOatHeader()); | 
 | 978 |   // TODO: make this Thumb2 specific | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 979 |   uint8_t* base = reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(quick_oat_code) & ~0x1); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 980 |   uint32_t* patch_location = reinterpret_cast<uint32_t*>(base + patch->GetLiteralOffset()); | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 981 |   if (kIsDebugBuild) { | 
| Hiroshi Yamauchi | be1ca55 | 2014-01-15 11:46:48 -0800 | [diff] [blame] | 982 |     if (patch->IsCall()) { | 
 | 983 |       const CompilerDriver::CallPatchInformation* cpatch = patch->AsCall(); | 
| Jeff Hao | 49161ce | 2014-03-12 11:05:25 -0700 | [diff] [blame] | 984 |       const DexFile::MethodId& id = cpatch->GetTargetDexFile()->GetMethodId(cpatch->GetTargetMethodIdx()); | 
| Andreas Gampe | 2da8823 | 2014-02-27 12:26:20 -0800 | [diff] [blame] | 985 |       uint32_t expected = reinterpret_cast<uintptr_t>(&id) & 0xFFFFFFFF; | 
| Hiroshi Yamauchi | be1ca55 | 2014-01-15 11:46:48 -0800 | [diff] [blame] | 986 |       uint32_t actual = *patch_location; | 
 | 987 |       CHECK(actual == expected || actual == value) << std::hex | 
 | 988 |           << "actual=" << actual | 
 | 989 |           << "expected=" << expected | 
 | 990 |           << "value=" << value; | 
 | 991 |     } | 
 | 992 |     if (patch->IsType()) { | 
 | 993 |       const CompilerDriver::TypePatchInformation* tpatch = patch->AsType(); | 
 | 994 |       const DexFile::TypeId& id = tpatch->GetDexFile().GetTypeId(tpatch->GetTargetTypeIdx()); | 
| Andreas Gampe | 2da8823 | 2014-02-27 12:26:20 -0800 | [diff] [blame] | 995 |       uint32_t expected = reinterpret_cast<uintptr_t>(&id) & 0xFFFFFFFF; | 
| Hiroshi Yamauchi | be1ca55 | 2014-01-15 11:46:48 -0800 | [diff] [blame] | 996 |       uint32_t actual = *patch_location; | 
 | 997 |       CHECK(actual == expected || actual == value) << std::hex | 
 | 998 |           << "actual=" << actual | 
 | 999 |           << "expected=" << expected | 
 | 1000 |           << "value=" << value; | 
 | 1001 |     } | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 1002 |   } | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 1003 |   *patch_location = value; | 
 | 1004 |   oat_header.UpdateChecksum(patch_location, sizeof(value)); | 
| Alex Light | 53cb16b | 2014-06-12 11:26:29 -0700 | [diff] [blame] | 1005 |  | 
 | 1006 |   uintptr_t loc = reinterpret_cast<uintptr_t>(patch_location) - | 
 | 1007 |       (reinterpret_cast<uintptr_t>(oat_file_->Begin()) + oat_header.GetExecutableOffset()); | 
 | 1008 |   CHECK_GT(reinterpret_cast<uintptr_t>(patch_location), | 
 | 1009 |             reinterpret_cast<uintptr_t>(oat_file_->Begin()) + oat_header.GetExecutableOffset()); | 
 | 1010 |   CHECK_LT(loc, oat_file_->Size() - oat_header.GetExecutableOffset()); | 
 | 1011 |  | 
 | 1012 |   *patched_ptr = loc; | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 1013 | } | 
 | 1014 |  | 
 | 1015 | }  // namespace art |