• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 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 "jit_code_cache.h"
18 
19 #include <sstream>
20 
21 #include "art_method-inl.h"
22 #include "base/stl_util.h"
23 #include "base/systrace.h"
24 #include "base/time_utils.h"
25 #include "debugger_interface.h"
26 #include "entrypoints/runtime_asm_entrypoints.h"
27 #include "gc/accounting/bitmap-inl.h"
28 #include "gc/scoped_gc_critical_section.h"
29 #include "jit/jit.h"
30 #include "jit/profiling_info.h"
31 #include "linear_alloc.h"
32 #include "mem_map.h"
33 #include "oat_file-inl.h"
34 #include "scoped_thread_state_change.h"
35 #include "thread_list.h"
36 
37 namespace art {
38 namespace jit {
39 
40 static constexpr int kProtAll = PROT_READ | PROT_WRITE | PROT_EXEC;
41 static constexpr int kProtData = PROT_READ | PROT_WRITE;
42 static constexpr int kProtCode = PROT_READ | PROT_EXEC;
43 
44 static constexpr size_t kCodeSizeLogThreshold = 50 * KB;
45 static constexpr size_t kStackMapSizeLogThreshold = 50 * KB;
46 
47 #define CHECKED_MPROTECT(memory, size, prot)                \
48   do {                                                      \
49     int rc = mprotect(memory, size, prot);                  \
50     if (UNLIKELY(rc != 0)) {                                \
51       errno = rc;                                           \
52       PLOG(FATAL) << "Failed to mprotect jit code cache";   \
53     }                                                       \
54   } while (false)                                           \
55 
Create(size_t initial_capacity,size_t max_capacity,bool generate_debug_info,std::string * error_msg)56 JitCodeCache* JitCodeCache::Create(size_t initial_capacity,
57                                    size_t max_capacity,
58                                    bool generate_debug_info,
59                                    std::string* error_msg) {
60   ScopedTrace trace(__PRETTY_FUNCTION__);
61   CHECK_GE(max_capacity, initial_capacity);
62 
63   // Generating debug information is mostly for using the 'perf' tool, which does
64   // not work with ashmem.
65   bool use_ashmem = !generate_debug_info;
66   // With 'perf', we want a 1-1 mapping between an address and a method.
67   bool garbage_collect_code = !generate_debug_info;
68 
69   // We need to have 32 bit offsets from method headers in code cache which point to things
70   // in the data cache. If the maps are more than 4G apart, having multiple maps wouldn't work.
71   // Ensure we're below 1 GB to be safe.
72   if (max_capacity > 1 * GB) {
73     std::ostringstream oss;
74     oss << "Maxium code cache capacity is limited to 1 GB, "
75         << PrettySize(max_capacity) << " is too big";
76     *error_msg = oss.str();
77     return nullptr;
78   }
79 
80   std::string error_str;
81   // Map name specific for android_os_Debug.cpp accounting.
82   MemMap* data_map = MemMap::MapAnonymous(
83       "data-code-cache", nullptr, max_capacity, kProtAll, false, false, &error_str, use_ashmem);
84   if (data_map == nullptr) {
85     std::ostringstream oss;
86     oss << "Failed to create read write execute cache: " << error_str << " size=" << max_capacity;
87     *error_msg = oss.str();
88     return nullptr;
89   }
90 
91   // Align both capacities to page size, as that's the unit mspaces use.
92   initial_capacity = RoundDown(initial_capacity, 2 * kPageSize);
93   max_capacity = RoundDown(max_capacity, 2 * kPageSize);
94 
95   // Data cache is 1 / 2 of the map.
96   // TODO: Make this variable?
97   size_t data_size = max_capacity / 2;
98   size_t code_size = max_capacity - data_size;
99   DCHECK_EQ(code_size + data_size, max_capacity);
100   uint8_t* divider = data_map->Begin() + data_size;
101 
102   MemMap* code_map =
103       data_map->RemapAtEnd(divider, "jit-code-cache", kProtAll, &error_str, use_ashmem);
104   if (code_map == nullptr) {
105     std::ostringstream oss;
106     oss << "Failed to create read write execute cache: " << error_str << " size=" << max_capacity;
107     *error_msg = oss.str();
108     return nullptr;
109   }
110   DCHECK_EQ(code_map->Begin(), divider);
111   data_size = initial_capacity / 2;
112   code_size = initial_capacity - data_size;
113   DCHECK_EQ(code_size + data_size, initial_capacity);
114   return new JitCodeCache(
115       code_map, data_map, code_size, data_size, max_capacity, garbage_collect_code);
116 }
117 
JitCodeCache(MemMap * code_map,MemMap * data_map,size_t initial_code_capacity,size_t initial_data_capacity,size_t max_capacity,bool garbage_collect_code)118 JitCodeCache::JitCodeCache(MemMap* code_map,
119                            MemMap* data_map,
120                            size_t initial_code_capacity,
121                            size_t initial_data_capacity,
122                            size_t max_capacity,
123                            bool garbage_collect_code)
124     : lock_("Jit code cache", kJitCodeCacheLock),
125       lock_cond_("Jit code cache variable", lock_),
126       collection_in_progress_(false),
127       code_map_(code_map),
128       data_map_(data_map),
129       max_capacity_(max_capacity),
130       current_capacity_(initial_code_capacity + initial_data_capacity),
131       code_end_(initial_code_capacity),
132       data_end_(initial_data_capacity),
133       last_collection_increased_code_cache_(false),
134       last_update_time_ns_(0),
135       garbage_collect_code_(garbage_collect_code),
136       used_memory_for_data_(0),
137       used_memory_for_code_(0),
138       number_of_compilations_(0),
139       number_of_osr_compilations_(0),
140       number_of_deoptimizations_(0),
141       number_of_collections_(0),
142       histogram_stack_map_memory_use_("Memory used for stack maps", 16),
143       histogram_code_memory_use_("Memory used for compiled code", 16),
144       histogram_profiling_info_memory_use_("Memory used for profiling info", 16) {
145 
146   DCHECK_GE(max_capacity, initial_code_capacity + initial_data_capacity);
147   code_mspace_ = create_mspace_with_base(code_map_->Begin(), code_end_, false /*locked*/);
148   data_mspace_ = create_mspace_with_base(data_map_->Begin(), data_end_, false /*locked*/);
149 
150   if (code_mspace_ == nullptr || data_mspace_ == nullptr) {
151     PLOG(FATAL) << "create_mspace_with_base failed";
152   }
153 
154   SetFootprintLimit(current_capacity_);
155 
156   CHECKED_MPROTECT(code_map_->Begin(), code_map_->Size(), kProtCode);
157   CHECKED_MPROTECT(data_map_->Begin(), data_map_->Size(), kProtData);
158 
159   VLOG(jit) << "Created jit code cache: initial data size="
160             << PrettySize(initial_data_capacity)
161             << ", initial code size="
162             << PrettySize(initial_code_capacity);
163 }
164 
ContainsPc(const void * ptr) const165 bool JitCodeCache::ContainsPc(const void* ptr) const {
166   return code_map_->Begin() <= ptr && ptr < code_map_->End();
167 }
168 
ContainsMethod(ArtMethod * method)169 bool JitCodeCache::ContainsMethod(ArtMethod* method) {
170   MutexLock mu(Thread::Current(), lock_);
171   for (auto& it : method_code_map_) {
172     if (it.second == method) {
173       return true;
174     }
175   }
176   return false;
177 }
178 
179 class ScopedCodeCacheWrite : ScopedTrace {
180  public:
ScopedCodeCacheWrite(MemMap * code_map)181   explicit ScopedCodeCacheWrite(MemMap* code_map)
182       : ScopedTrace("ScopedCodeCacheWrite"),
183         code_map_(code_map) {
184     ScopedTrace trace("mprotect all");
185     CHECKED_MPROTECT(code_map_->Begin(), code_map_->Size(), kProtAll);
186   }
~ScopedCodeCacheWrite()187   ~ScopedCodeCacheWrite() {
188     ScopedTrace trace("mprotect code");
189     CHECKED_MPROTECT(code_map_->Begin(), code_map_->Size(), kProtCode);
190   }
191  private:
192   MemMap* const code_map_;
193 
194   DISALLOW_COPY_AND_ASSIGN(ScopedCodeCacheWrite);
195 };
196 
CommitCode(Thread * self,ArtMethod * method,const uint8_t * vmap_table,size_t frame_size_in_bytes,size_t core_spill_mask,size_t fp_spill_mask,const uint8_t * code,size_t code_size,bool osr)197 uint8_t* JitCodeCache::CommitCode(Thread* self,
198                                   ArtMethod* method,
199                                   const uint8_t* vmap_table,
200                                   size_t frame_size_in_bytes,
201                                   size_t core_spill_mask,
202                                   size_t fp_spill_mask,
203                                   const uint8_t* code,
204                                   size_t code_size,
205                                   bool osr) {
206   uint8_t* result = CommitCodeInternal(self,
207                                        method,
208                                        vmap_table,
209                                        frame_size_in_bytes,
210                                        core_spill_mask,
211                                        fp_spill_mask,
212                                        code,
213                                        code_size,
214                                        osr);
215   if (result == nullptr) {
216     // Retry.
217     GarbageCollectCache(self);
218     result = CommitCodeInternal(self,
219                                 method,
220                                 vmap_table,
221                                 frame_size_in_bytes,
222                                 core_spill_mask,
223                                 fp_spill_mask,
224                                 code,
225                                 code_size,
226                                 osr);
227   }
228   return result;
229 }
230 
WaitForPotentialCollectionToComplete(Thread * self)231 bool JitCodeCache::WaitForPotentialCollectionToComplete(Thread* self) {
232   bool in_collection = false;
233   while (collection_in_progress_) {
234     in_collection = true;
235     lock_cond_.Wait(self);
236   }
237   return in_collection;
238 }
239 
FromCodeToAllocation(const void * code)240 static uintptr_t FromCodeToAllocation(const void* code) {
241   size_t alignment = GetInstructionSetAlignment(kRuntimeISA);
242   return reinterpret_cast<uintptr_t>(code) - RoundUp(sizeof(OatQuickMethodHeader), alignment);
243 }
244 
FreeCode(const void * code_ptr,ArtMethod * method ATTRIBUTE_UNUSED)245 void JitCodeCache::FreeCode(const void* code_ptr, ArtMethod* method ATTRIBUTE_UNUSED) {
246   uintptr_t allocation = FromCodeToAllocation(code_ptr);
247   const OatQuickMethodHeader* method_header = OatQuickMethodHeader::FromCodePointer(code_ptr);
248   // Notify native debugger that we are about to remove the code.
249   // It does nothing if we are not using native debugger.
250   DeleteJITCodeEntryForAddress(reinterpret_cast<uintptr_t>(code_ptr));
251 
252   // Use the offset directly to prevent sanity check that the method is
253   // compiled with optimizing.
254   // TODO(ngeoffray): Clean up.
255   if (method_header->vmap_table_offset_ != 0) {
256     const uint8_t* data = method_header->code_ - method_header->vmap_table_offset_;
257     FreeData(const_cast<uint8_t*>(data));
258   }
259   FreeCode(reinterpret_cast<uint8_t*>(allocation));
260 }
261 
RemoveMethodsIn(Thread * self,const LinearAlloc & alloc)262 void JitCodeCache::RemoveMethodsIn(Thread* self, const LinearAlloc& alloc) {
263   ScopedTrace trace(__PRETTY_FUNCTION__);
264   MutexLock mu(self, lock_);
265   // We do not check if a code cache GC is in progress, as this method comes
266   // with the classlinker_classes_lock_ held, and suspending ourselves could
267   // lead to a deadlock.
268   {
269     ScopedCodeCacheWrite scc(code_map_.get());
270     for (auto it = method_code_map_.begin(); it != method_code_map_.end();) {
271       if (alloc.ContainsUnsafe(it->second)) {
272         FreeCode(it->first, it->second);
273         it = method_code_map_.erase(it);
274       } else {
275         ++it;
276       }
277     }
278   }
279   for (auto it = osr_code_map_.begin(); it != osr_code_map_.end();) {
280     if (alloc.ContainsUnsafe(it->first)) {
281       // Note that the code has already been removed in the loop above.
282       it = osr_code_map_.erase(it);
283     } else {
284       ++it;
285     }
286   }
287   for (auto it = profiling_infos_.begin(); it != profiling_infos_.end();) {
288     ProfilingInfo* info = *it;
289     if (alloc.ContainsUnsafe(info->GetMethod())) {
290       info->GetMethod()->SetProfilingInfo(nullptr);
291       FreeData(reinterpret_cast<uint8_t*>(info));
292       it = profiling_infos_.erase(it);
293     } else {
294       ++it;
295     }
296   }
297 }
298 
ClearGcRootsInInlineCaches(Thread * self)299 void JitCodeCache::ClearGcRootsInInlineCaches(Thread* self) {
300   MutexLock mu(self, lock_);
301   for (ProfilingInfo* info : profiling_infos_) {
302     if (!info->IsInUseByCompiler()) {
303       info->ClearGcRootsInInlineCaches();
304     }
305   }
306 }
307 
CommitCodeInternal(Thread * self,ArtMethod * method,const uint8_t * vmap_table,size_t frame_size_in_bytes,size_t core_spill_mask,size_t fp_spill_mask,const uint8_t * code,size_t code_size,bool osr)308 uint8_t* JitCodeCache::CommitCodeInternal(Thread* self,
309                                           ArtMethod* method,
310                                           const uint8_t* vmap_table,
311                                           size_t frame_size_in_bytes,
312                                           size_t core_spill_mask,
313                                           size_t fp_spill_mask,
314                                           const uint8_t* code,
315                                           size_t code_size,
316                                           bool osr) {
317   size_t alignment = GetInstructionSetAlignment(kRuntimeISA);
318   // Ensure the header ends up at expected instruction alignment.
319   size_t header_size = RoundUp(sizeof(OatQuickMethodHeader), alignment);
320   size_t total_size = header_size + code_size;
321 
322   OatQuickMethodHeader* method_header = nullptr;
323   uint8_t* code_ptr = nullptr;
324   uint8_t* memory = nullptr;
325   {
326     ScopedThreadSuspension sts(self, kSuspended);
327     MutexLock mu(self, lock_);
328     WaitForPotentialCollectionToComplete(self);
329     {
330       ScopedCodeCacheWrite scc(code_map_.get());
331       memory = AllocateCode(total_size);
332       if (memory == nullptr) {
333         return nullptr;
334       }
335       code_ptr = memory + header_size;
336 
337       std::copy(code, code + code_size, code_ptr);
338       method_header = OatQuickMethodHeader::FromCodePointer(code_ptr);
339       new (method_header) OatQuickMethodHeader(
340           (vmap_table == nullptr) ? 0 : code_ptr - vmap_table,
341           frame_size_in_bytes,
342           core_spill_mask,
343           fp_spill_mask,
344           code_size);
345       // Flush caches before we remove write permission because on some ARMv8 hardware,
346       // flushing caches require write permissions.
347       //
348       // For reference, here are kernel patches discussing about this issue:
349       // https://android.googlesource.com/kernel/msm/%2B/0e7f7bcc3fc87489cda5aa6aff8ce40eed912279
350       // https://patchwork.kernel.org/patch/9047921/
351       FlushInstructionCache(reinterpret_cast<char*>(code_ptr),
352                             reinterpret_cast<char*>(code_ptr + code_size));
353     }
354 
355     number_of_compilations_++;
356   }
357   // We need to update the entry point in the runnable state for the instrumentation.
358   {
359     MutexLock mu(self, lock_);
360     method_code_map_.Put(code_ptr, method);
361     if (osr) {
362       number_of_osr_compilations_++;
363       osr_code_map_.Put(method, code_ptr);
364     } else {
365       Runtime::Current()->GetInstrumentation()->UpdateMethodsCode(
366           method, method_header->GetEntryPoint());
367     }
368     if (collection_in_progress_) {
369       // We need to update the live bitmap if there is a GC to ensure it sees this new
370       // code.
371       GetLiveBitmap()->AtomicTestAndSet(FromCodeToAllocation(code_ptr));
372     }
373     last_update_time_ns_.StoreRelease(NanoTime());
374     VLOG(jit)
375         << "JIT added (osr=" << std::boolalpha << osr << std::noboolalpha << ") "
376         << PrettyMethod(method) << "@" << method
377         << " ccache_size=" << PrettySize(CodeCacheSizeLocked()) << ": "
378         << " dcache_size=" << PrettySize(DataCacheSizeLocked()) << ": "
379         << reinterpret_cast<const void*>(method_header->GetEntryPoint()) << ","
380         << reinterpret_cast<const void*>(method_header->GetEntryPoint() + method_header->code_size_);
381     histogram_code_memory_use_.AddValue(code_size);
382     if (code_size > kCodeSizeLogThreshold) {
383       LOG(INFO) << "JIT allocated "
384                 << PrettySize(code_size)
385                 << " for compiled code of "
386                 << PrettyMethod(method);
387     }
388   }
389 
390   return reinterpret_cast<uint8_t*>(method_header);
391 }
392 
CodeCacheSize()393 size_t JitCodeCache::CodeCacheSize() {
394   MutexLock mu(Thread::Current(), lock_);
395   return CodeCacheSizeLocked();
396 }
397 
CodeCacheSizeLocked()398 size_t JitCodeCache::CodeCacheSizeLocked() {
399   return used_memory_for_code_;
400 }
401 
DataCacheSize()402 size_t JitCodeCache::DataCacheSize() {
403   MutexLock mu(Thread::Current(), lock_);
404   return DataCacheSizeLocked();
405 }
406 
DataCacheSizeLocked()407 size_t JitCodeCache::DataCacheSizeLocked() {
408   return used_memory_for_data_;
409 }
410 
ClearData(Thread * self,void * data)411 void JitCodeCache::ClearData(Thread* self, void* data) {
412   MutexLock mu(self, lock_);
413   FreeData(reinterpret_cast<uint8_t*>(data));
414 }
415 
ReserveData(Thread * self,size_t size,ArtMethod * method)416 uint8_t* JitCodeCache::ReserveData(Thread* self, size_t size, ArtMethod* method) {
417   size = RoundUp(size, sizeof(void*));
418   uint8_t* result = nullptr;
419 
420   {
421     ScopedThreadSuspension sts(self, kSuspended);
422     MutexLock mu(self, lock_);
423     WaitForPotentialCollectionToComplete(self);
424     result = AllocateData(size);
425   }
426 
427   if (result == nullptr) {
428     // Retry.
429     GarbageCollectCache(self);
430     ScopedThreadSuspension sts(self, kSuspended);
431     MutexLock mu(self, lock_);
432     WaitForPotentialCollectionToComplete(self);
433     result = AllocateData(size);
434   }
435 
436   MutexLock mu(self, lock_);
437   histogram_stack_map_memory_use_.AddValue(size);
438   if (size > kStackMapSizeLogThreshold) {
439     LOG(INFO) << "JIT allocated "
440               << PrettySize(size)
441               << " for stack maps of "
442               << PrettyMethod(method);
443   }
444   return result;
445 }
446 
447 class MarkCodeVisitor FINAL : public StackVisitor {
448  public:
MarkCodeVisitor(Thread * thread_in,JitCodeCache * code_cache_in)449   MarkCodeVisitor(Thread* thread_in, JitCodeCache* code_cache_in)
450       : StackVisitor(thread_in, nullptr, StackVisitor::StackWalkKind::kSkipInlinedFrames),
451         code_cache_(code_cache_in),
452         bitmap_(code_cache_->GetLiveBitmap()) {}
453 
VisitFrame()454   bool VisitFrame() OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) {
455     const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
456     if (method_header == nullptr) {
457       return true;
458     }
459     const void* code = method_header->GetCode();
460     if (code_cache_->ContainsPc(code)) {
461       // Use the atomic set version, as multiple threads are executing this code.
462       bitmap_->AtomicTestAndSet(FromCodeToAllocation(code));
463     }
464     return true;
465   }
466 
467  private:
468   JitCodeCache* const code_cache_;
469   CodeCacheBitmap* const bitmap_;
470 };
471 
472 class MarkCodeClosure FINAL : public Closure {
473  public:
MarkCodeClosure(JitCodeCache * code_cache,Barrier * barrier)474   MarkCodeClosure(JitCodeCache* code_cache, Barrier* barrier)
475       : code_cache_(code_cache), barrier_(barrier) {}
476 
Run(Thread * thread)477   void Run(Thread* thread) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) {
478     ScopedTrace trace(__PRETTY_FUNCTION__);
479     DCHECK(thread == Thread::Current() || thread->IsSuspended());
480     MarkCodeVisitor visitor(thread, code_cache_);
481     visitor.WalkStack();
482     if (kIsDebugBuild) {
483       // The stack walking code queries the side instrumentation stack if it
484       // sees an instrumentation exit pc, so the JIT code of methods in that stack
485       // must have been seen. We sanity check this below.
486       for (const instrumentation::InstrumentationStackFrame& frame
487               : *thread->GetInstrumentationStack()) {
488         // The 'method_' in InstrumentationStackFrame is the one that has return_pc_ in
489         // its stack frame, it is not the method owning return_pc_. We just pass null to
490         // LookupMethodHeader: the method is only checked against in debug builds.
491         OatQuickMethodHeader* method_header =
492             code_cache_->LookupMethodHeader(frame.return_pc_, nullptr);
493         if (method_header != nullptr) {
494           const void* code = method_header->GetCode();
495           CHECK(code_cache_->GetLiveBitmap()->Test(FromCodeToAllocation(code)));
496         }
497       }
498     }
499     barrier_->Pass(Thread::Current());
500   }
501 
502  private:
503   JitCodeCache* const code_cache_;
504   Barrier* const barrier_;
505 };
506 
NotifyCollectionDone(Thread * self)507 void JitCodeCache::NotifyCollectionDone(Thread* self) {
508   collection_in_progress_ = false;
509   lock_cond_.Broadcast(self);
510 }
511 
SetFootprintLimit(size_t new_footprint)512 void JitCodeCache::SetFootprintLimit(size_t new_footprint) {
513   size_t per_space_footprint = new_footprint / 2;
514   DCHECK(IsAlignedParam(per_space_footprint, kPageSize));
515   DCHECK_EQ(per_space_footprint * 2, new_footprint);
516   mspace_set_footprint_limit(data_mspace_, per_space_footprint);
517   {
518     ScopedCodeCacheWrite scc(code_map_.get());
519     mspace_set_footprint_limit(code_mspace_, per_space_footprint);
520   }
521 }
522 
IncreaseCodeCacheCapacity()523 bool JitCodeCache::IncreaseCodeCacheCapacity() {
524   if (current_capacity_ == max_capacity_) {
525     return false;
526   }
527 
528   // Double the capacity if we're below 1MB, or increase it by 1MB if
529   // we're above.
530   if (current_capacity_ < 1 * MB) {
531     current_capacity_ *= 2;
532   } else {
533     current_capacity_ += 1 * MB;
534   }
535   if (current_capacity_ > max_capacity_) {
536     current_capacity_ = max_capacity_;
537   }
538 
539   if (!kIsDebugBuild || VLOG_IS_ON(jit)) {
540     LOG(INFO) << "Increasing code cache capacity to " << PrettySize(current_capacity_);
541   }
542 
543   SetFootprintLimit(current_capacity_);
544 
545   return true;
546 }
547 
MarkCompiledCodeOnThreadStacks(Thread * self)548 void JitCodeCache::MarkCompiledCodeOnThreadStacks(Thread* self) {
549   Barrier barrier(0);
550   size_t threads_running_checkpoint = 0;
551   MarkCodeClosure closure(this, &barrier);
552   threads_running_checkpoint = Runtime::Current()->GetThreadList()->RunCheckpoint(&closure);
553   // Now that we have run our checkpoint, move to a suspended state and wait
554   // for other threads to run the checkpoint.
555   ScopedThreadSuspension sts(self, kSuspended);
556   if (threads_running_checkpoint != 0) {
557     barrier.Increment(self, threads_running_checkpoint);
558   }
559 }
560 
ShouldDoFullCollection()561 bool JitCodeCache::ShouldDoFullCollection() {
562   if (current_capacity_ == max_capacity_) {
563     // Always do a full collection when the code cache is full.
564     return true;
565   } else if (current_capacity_ < kReservedCapacity) {
566     // Always do partial collection when the code cache size is below the reserved
567     // capacity.
568     return false;
569   } else if (last_collection_increased_code_cache_) {
570     // This time do a full collection.
571     return true;
572   } else {
573     // This time do a partial collection.
574     return false;
575   }
576 }
577 
GarbageCollectCache(Thread * self)578 void JitCodeCache::GarbageCollectCache(Thread* self) {
579   ScopedTrace trace(__FUNCTION__);
580   if (!garbage_collect_code_) {
581     MutexLock mu(self, lock_);
582     IncreaseCodeCacheCapacity();
583     return;
584   }
585 
586   // Wait for an existing collection, or let everyone know we are starting one.
587   {
588     ScopedThreadSuspension sts(self, kSuspended);
589     MutexLock mu(self, lock_);
590     if (WaitForPotentialCollectionToComplete(self)) {
591       return;
592     } else {
593       number_of_collections_++;
594       live_bitmap_.reset(CodeCacheBitmap::Create(
595           "code-cache-bitmap",
596           reinterpret_cast<uintptr_t>(code_map_->Begin()),
597           reinterpret_cast<uintptr_t>(code_map_->Begin() + current_capacity_ / 2)));
598       collection_in_progress_ = true;
599     }
600   }
601 
602   TimingLogger logger("JIT code cache timing logger", true, VLOG_IS_ON(jit));
603   {
604     TimingLogger::ScopedTiming st("Code cache collection", &logger);
605 
606     bool do_full_collection = false;
607     {
608       MutexLock mu(self, lock_);
609       do_full_collection = ShouldDoFullCollection();
610     }
611 
612     if (!kIsDebugBuild || VLOG_IS_ON(jit)) {
613       LOG(INFO) << "Do "
614                 << (do_full_collection ? "full" : "partial")
615                 << " code cache collection, code="
616                 << PrettySize(CodeCacheSize())
617                 << ", data=" << PrettySize(DataCacheSize());
618     }
619 
620     DoCollection(self, /* collect_profiling_info */ do_full_collection);
621 
622     if (!kIsDebugBuild || VLOG_IS_ON(jit)) {
623       LOG(INFO) << "After code cache collection, code="
624                 << PrettySize(CodeCacheSize())
625                 << ", data=" << PrettySize(DataCacheSize());
626     }
627 
628     {
629       MutexLock mu(self, lock_);
630 
631       // Increase the code cache only when we do partial collections.
632       // TODO: base this strategy on how full the code cache is?
633       if (do_full_collection) {
634         last_collection_increased_code_cache_ = false;
635       } else {
636         last_collection_increased_code_cache_ = true;
637         IncreaseCodeCacheCapacity();
638       }
639 
640       bool next_collection_will_be_full = ShouldDoFullCollection();
641 
642       // Start polling the liveness of compiled code to prepare for the next full collection.
643       if (next_collection_will_be_full) {
644         // Save the entry point of methods we have compiled, and update the entry
645         // point of those methods to the interpreter. If the method is invoked, the
646         // interpreter will update its entry point to the compiled code and call it.
647         for (ProfilingInfo* info : profiling_infos_) {
648           const void* entry_point = info->GetMethod()->GetEntryPointFromQuickCompiledCode();
649           if (ContainsPc(entry_point)) {
650             info->SetSavedEntryPoint(entry_point);
651             Runtime::Current()->GetInstrumentation()->UpdateMethodsCode(
652                 info->GetMethod(), GetQuickToInterpreterBridge());
653           }
654         }
655 
656         DCHECK(CheckLiveCompiledCodeHasProfilingInfo());
657       }
658       live_bitmap_.reset(nullptr);
659       NotifyCollectionDone(self);
660     }
661   }
662   Runtime::Current()->GetJit()->AddTimingLogger(logger);
663 }
664 
RemoveUnmarkedCode(Thread * self)665 void JitCodeCache::RemoveUnmarkedCode(Thread* self) {
666   ScopedTrace trace(__FUNCTION__);
667   MutexLock mu(self, lock_);
668   ScopedCodeCacheWrite scc(code_map_.get());
669   // Iterate over all compiled code and remove entries that are not marked.
670   for (auto it = method_code_map_.begin(); it != method_code_map_.end();) {
671     const void* code_ptr = it->first;
672     ArtMethod* method = it->second;
673     uintptr_t allocation = FromCodeToAllocation(code_ptr);
674     if (GetLiveBitmap()->Test(allocation)) {
675       ++it;
676     } else {
677       FreeCode(code_ptr, method);
678       it = method_code_map_.erase(it);
679     }
680   }
681 }
682 
DoCollection(Thread * self,bool collect_profiling_info)683 void JitCodeCache::DoCollection(Thread* self, bool collect_profiling_info) {
684   ScopedTrace trace(__FUNCTION__);
685   {
686     MutexLock mu(self, lock_);
687     if (collect_profiling_info) {
688       // Clear the profiling info of methods that do not have compiled code as entrypoint.
689       // Also remove the saved entry point from the ProfilingInfo objects.
690       for (ProfilingInfo* info : profiling_infos_) {
691         const void* ptr = info->GetMethod()->GetEntryPointFromQuickCompiledCode();
692         if (!ContainsPc(ptr) && !info->IsInUseByCompiler()) {
693           info->GetMethod()->SetProfilingInfo(nullptr);
694         }
695 
696         if (info->GetSavedEntryPoint() != nullptr) {
697           info->SetSavedEntryPoint(nullptr);
698           // We are going to move this method back to interpreter. Clear the counter now to
699           // give it a chance to be hot again.
700           info->GetMethod()->ClearCounter();
701         }
702       }
703     } else if (kIsDebugBuild) {
704       // Sanity check that the profiling infos do not have a dangling entry point.
705       for (ProfilingInfo* info : profiling_infos_) {
706         DCHECK(info->GetSavedEntryPoint() == nullptr);
707       }
708     }
709 
710     // Mark compiled code that are entrypoints of ArtMethods. Compiled code that is not
711     // an entry point is either:
712     // - an osr compiled code, that will be removed if not in a thread call stack.
713     // - discarded compiled code, that will be removed if not in a thread call stack.
714     for (const auto& it : method_code_map_) {
715       ArtMethod* method = it.second;
716       const void* code_ptr = it.first;
717       const OatQuickMethodHeader* method_header = OatQuickMethodHeader::FromCodePointer(code_ptr);
718       if (method_header->GetEntryPoint() == method->GetEntryPointFromQuickCompiledCode()) {
719         GetLiveBitmap()->AtomicTestAndSet(FromCodeToAllocation(code_ptr));
720       }
721     }
722 
723     // Empty osr method map, as osr compiled code will be deleted (except the ones
724     // on thread stacks).
725     osr_code_map_.clear();
726   }
727 
728   // Run a checkpoint on all threads to mark the JIT compiled code they are running.
729   MarkCompiledCodeOnThreadStacks(self);
730 
731   // At this point, mutator threads are still running, and entrypoints of methods can
732   // change. We do know they cannot change to a code cache entry that is not marked,
733   // therefore we can safely remove those entries.
734   RemoveUnmarkedCode(self);
735 
736   if (collect_profiling_info) {
737     ScopedThreadSuspension sts(self, kSuspended);
738     gc::ScopedGCCriticalSection gcs(
739         self, gc::kGcCauseJitCodeCache, gc::kCollectorTypeJitCodeCache);
740     MutexLock mu(self, lock_);
741     // Free all profiling infos of methods not compiled nor being compiled.
742     auto profiling_kept_end = std::remove_if(profiling_infos_.begin(), profiling_infos_.end(),
743       [this] (ProfilingInfo* info) NO_THREAD_SAFETY_ANALYSIS {
744         const void* ptr = info->GetMethod()->GetEntryPointFromQuickCompiledCode();
745         // We have previously cleared the ProfilingInfo pointer in the ArtMethod in the hope
746         // that the compiled code would not get revived. As mutator threads run concurrently,
747         // they may have revived the compiled code, and now we are in the situation where
748         // a method has compiled code but no ProfilingInfo.
749         // We make sure compiled methods have a ProfilingInfo object. It is needed for
750         // code cache collection.
751         if (ContainsPc(ptr) && info->GetMethod()->GetProfilingInfo(sizeof(void*)) == nullptr) {
752           // We clear the inline caches as classes in it might be stalled.
753           info->ClearGcRootsInInlineCaches();
754           // Do a fence to make sure the clearing is seen before attaching to the method.
755           QuasiAtomic::ThreadFenceRelease();
756           info->GetMethod()->SetProfilingInfo(info);
757         } else if (info->GetMethod()->GetProfilingInfo(sizeof(void*)) != info) {
758           // No need for this ProfilingInfo object anymore.
759           FreeData(reinterpret_cast<uint8_t*>(info));
760           return true;
761         }
762         return false;
763       });
764     profiling_infos_.erase(profiling_kept_end, profiling_infos_.end());
765     DCHECK(CheckLiveCompiledCodeHasProfilingInfo());
766   }
767 }
768 
CheckLiveCompiledCodeHasProfilingInfo()769 bool JitCodeCache::CheckLiveCompiledCodeHasProfilingInfo() {
770   ScopedTrace trace(__FUNCTION__);
771   // Check that methods we have compiled do have a ProfilingInfo object. We would
772   // have memory leaks of compiled code otherwise.
773   for (const auto& it : method_code_map_) {
774     ArtMethod* method = it.second;
775     if (method->GetProfilingInfo(sizeof(void*)) == nullptr) {
776       const void* code_ptr = it.first;
777       const OatQuickMethodHeader* method_header = OatQuickMethodHeader::FromCodePointer(code_ptr);
778       if (method_header->GetEntryPoint() == method->GetEntryPointFromQuickCompiledCode()) {
779         // If the code is not dead, then we have a problem. Note that this can even
780         // happen just after a collection, as mutator threads are running in parallel
781         // and could deoptimize an existing compiled code.
782         return false;
783       }
784     }
785   }
786   return true;
787 }
788 
LookupMethodHeader(uintptr_t pc,ArtMethod * method)789 OatQuickMethodHeader* JitCodeCache::LookupMethodHeader(uintptr_t pc, ArtMethod* method) {
790   static_assert(kRuntimeISA != kThumb2, "kThumb2 cannot be a runtime ISA");
791   if (kRuntimeISA == kArm) {
792     // On Thumb-2, the pc is offset by one.
793     --pc;
794   }
795   if (!ContainsPc(reinterpret_cast<const void*>(pc))) {
796     return nullptr;
797   }
798 
799   MutexLock mu(Thread::Current(), lock_);
800   if (method_code_map_.empty()) {
801     return nullptr;
802   }
803   auto it = method_code_map_.lower_bound(reinterpret_cast<const void*>(pc));
804   --it;
805 
806   const void* code_ptr = it->first;
807   OatQuickMethodHeader* method_header = OatQuickMethodHeader::FromCodePointer(code_ptr);
808   if (!method_header->Contains(pc)) {
809     return nullptr;
810   }
811   if (kIsDebugBuild && method != nullptr) {
812     DCHECK_EQ(it->second, method)
813         << PrettyMethod(method) << " " << PrettyMethod(it->second) << " " << std::hex << pc;
814   }
815   return method_header;
816 }
817 
LookupOsrMethodHeader(ArtMethod * method)818 OatQuickMethodHeader* JitCodeCache::LookupOsrMethodHeader(ArtMethod* method) {
819   MutexLock mu(Thread::Current(), lock_);
820   auto it = osr_code_map_.find(method);
821   if (it == osr_code_map_.end()) {
822     return nullptr;
823   }
824   return OatQuickMethodHeader::FromCodePointer(it->second);
825 }
826 
AddProfilingInfo(Thread * self,ArtMethod * method,const std::vector<uint32_t> & entries,bool retry_allocation)827 ProfilingInfo* JitCodeCache::AddProfilingInfo(Thread* self,
828                                               ArtMethod* method,
829                                               const std::vector<uint32_t>& entries,
830                                               bool retry_allocation)
831     // No thread safety analysis as we are using TryLock/Unlock explicitly.
832     NO_THREAD_SAFETY_ANALYSIS {
833   ProfilingInfo* info = nullptr;
834   if (!retry_allocation) {
835     // If we are allocating for the interpreter, just try to lock, to avoid
836     // lock contention with the JIT.
837     if (lock_.ExclusiveTryLock(self)) {
838       info = AddProfilingInfoInternal(self, method, entries);
839       lock_.ExclusiveUnlock(self);
840     }
841   } else {
842     {
843       MutexLock mu(self, lock_);
844       info = AddProfilingInfoInternal(self, method, entries);
845     }
846 
847     if (info == nullptr) {
848       GarbageCollectCache(self);
849       MutexLock mu(self, lock_);
850       info = AddProfilingInfoInternal(self, method, entries);
851     }
852   }
853   return info;
854 }
855 
AddProfilingInfoInternal(Thread * self ATTRIBUTE_UNUSED,ArtMethod * method,const std::vector<uint32_t> & entries)856 ProfilingInfo* JitCodeCache::AddProfilingInfoInternal(Thread* self ATTRIBUTE_UNUSED,
857                                                       ArtMethod* method,
858                                                       const std::vector<uint32_t>& entries) {
859   size_t profile_info_size = RoundUp(
860       sizeof(ProfilingInfo) + sizeof(InlineCache) * entries.size(),
861       sizeof(void*));
862 
863   // Check whether some other thread has concurrently created it.
864   ProfilingInfo* info = method->GetProfilingInfo(sizeof(void*));
865   if (info != nullptr) {
866     return info;
867   }
868 
869   uint8_t* data = AllocateData(profile_info_size);
870   if (data == nullptr) {
871     return nullptr;
872   }
873   info = new (data) ProfilingInfo(method, entries);
874 
875   // Make sure other threads see the data in the profiling info object before the
876   // store in the ArtMethod's ProfilingInfo pointer.
877   QuasiAtomic::ThreadFenceRelease();
878 
879   method->SetProfilingInfo(info);
880   profiling_infos_.push_back(info);
881   histogram_profiling_info_memory_use_.AddValue(profile_info_size);
882   return info;
883 }
884 
885 // NO_THREAD_SAFETY_ANALYSIS as this is called from mspace code, at which point the lock
886 // is already held.
MoreCore(const void * mspace,intptr_t increment)887 void* JitCodeCache::MoreCore(const void* mspace, intptr_t increment) NO_THREAD_SAFETY_ANALYSIS {
888   if (code_mspace_ == mspace) {
889     size_t result = code_end_;
890     code_end_ += increment;
891     return reinterpret_cast<void*>(result + code_map_->Begin());
892   } else {
893     DCHECK_EQ(data_mspace_, mspace);
894     size_t result = data_end_;
895     data_end_ += increment;
896     return reinterpret_cast<void*>(result + data_map_->Begin());
897   }
898 }
899 
GetProfiledMethods(const std::set<std::string> & dex_base_locations,std::vector<MethodReference> & methods)900 void JitCodeCache::GetProfiledMethods(const std::set<std::string>& dex_base_locations,
901                                       std::vector<MethodReference>& methods) {
902   ScopedTrace trace(__FUNCTION__);
903   MutexLock mu(Thread::Current(), lock_);
904   for (const ProfilingInfo* info : profiling_infos_) {
905     ArtMethod* method = info->GetMethod();
906     const DexFile* dex_file = method->GetDexFile();
907     if (ContainsElement(dex_base_locations, dex_file->GetBaseLocation())) {
908       methods.emplace_back(dex_file,  method->GetDexMethodIndex());
909     }
910   }
911 }
912 
GetLastUpdateTimeNs() const913 uint64_t JitCodeCache::GetLastUpdateTimeNs() const {
914   return last_update_time_ns_.LoadAcquire();
915 }
916 
IsOsrCompiled(ArtMethod * method)917 bool JitCodeCache::IsOsrCompiled(ArtMethod* method) {
918   MutexLock mu(Thread::Current(), lock_);
919   return osr_code_map_.find(method) != osr_code_map_.end();
920 }
921 
NotifyCompilationOf(ArtMethod * method,Thread * self,bool osr)922 bool JitCodeCache::NotifyCompilationOf(ArtMethod* method, Thread* self, bool osr) {
923   if (!osr && ContainsPc(method->GetEntryPointFromQuickCompiledCode())) {
924     return false;
925   }
926 
927   MutexLock mu(self, lock_);
928   if (osr && (osr_code_map_.find(method) != osr_code_map_.end())) {
929     return false;
930   }
931 
932   ProfilingInfo* info = method->GetProfilingInfo(sizeof(void*));
933   if (info == nullptr) {
934     VLOG(jit) << PrettyMethod(method) << " needs a ProfilingInfo to be compiled";
935     // Because the counter is not atomic, there are some rare cases where we may not
936     // hit the threshold for creating the ProfilingInfo. Reset the counter now to
937     // "correct" this.
938     method->ClearCounter();
939     return false;
940   }
941 
942   if (info->IsMethodBeingCompiled(osr)) {
943     return false;
944   }
945 
946   info->SetIsMethodBeingCompiled(true, osr);
947   return true;
948 }
949 
NotifyCompilerUse(ArtMethod * method,Thread * self)950 ProfilingInfo* JitCodeCache::NotifyCompilerUse(ArtMethod* method, Thread* self) {
951   MutexLock mu(self, lock_);
952   ProfilingInfo* info = method->GetProfilingInfo(sizeof(void*));
953   if (info != nullptr) {
954     info->IncrementInlineUse();
955   }
956   return info;
957 }
958 
DoneCompilerUse(ArtMethod * method,Thread * self)959 void JitCodeCache::DoneCompilerUse(ArtMethod* method, Thread* self) {
960   MutexLock mu(self, lock_);
961   ProfilingInfo* info = method->GetProfilingInfo(sizeof(void*));
962   DCHECK(info != nullptr);
963   info->DecrementInlineUse();
964 }
965 
DoneCompiling(ArtMethod * method,Thread * self ATTRIBUTE_UNUSED,bool osr)966 void JitCodeCache::DoneCompiling(ArtMethod* method, Thread* self ATTRIBUTE_UNUSED, bool osr) {
967   ProfilingInfo* info = method->GetProfilingInfo(sizeof(void*));
968   DCHECK(info->IsMethodBeingCompiled(osr));
969   info->SetIsMethodBeingCompiled(false, osr);
970 }
971 
GetMemorySizeOfCodePointer(const void * ptr)972 size_t JitCodeCache::GetMemorySizeOfCodePointer(const void* ptr) {
973   MutexLock mu(Thread::Current(), lock_);
974   return mspace_usable_size(reinterpret_cast<const void*>(FromCodeToAllocation(ptr)));
975 }
976 
InvalidateCompiledCodeFor(ArtMethod * method,const OatQuickMethodHeader * header)977 void JitCodeCache::InvalidateCompiledCodeFor(ArtMethod* method,
978                                              const OatQuickMethodHeader* header) {
979   ProfilingInfo* profiling_info = method->GetProfilingInfo(sizeof(void*));
980   if ((profiling_info != nullptr) &&
981       (profiling_info->GetSavedEntryPoint() == header->GetEntryPoint())) {
982     // Prevent future uses of the compiled code.
983     profiling_info->SetSavedEntryPoint(nullptr);
984   }
985 
986   if (method->GetEntryPointFromQuickCompiledCode() == header->GetEntryPoint()) {
987     // The entrypoint is the one to invalidate, so we just update
988     // it to the interpreter entry point and clear the counter to get the method
989     // Jitted again.
990     Runtime::Current()->GetInstrumentation()->UpdateMethodsCode(
991         method, GetQuickToInterpreterBridge());
992     method->ClearCounter();
993   } else {
994     MutexLock mu(Thread::Current(), lock_);
995     auto it = osr_code_map_.find(method);
996     if (it != osr_code_map_.end() && OatQuickMethodHeader::FromCodePointer(it->second) == header) {
997       // Remove the OSR method, to avoid using it again.
998       osr_code_map_.erase(it);
999     }
1000   }
1001   MutexLock mu(Thread::Current(), lock_);
1002   number_of_deoptimizations_++;
1003 }
1004 
AllocateCode(size_t code_size)1005 uint8_t* JitCodeCache::AllocateCode(size_t code_size) {
1006   size_t alignment = GetInstructionSetAlignment(kRuntimeISA);
1007   uint8_t* result = reinterpret_cast<uint8_t*>(
1008       mspace_memalign(code_mspace_, alignment, code_size));
1009   size_t header_size = RoundUp(sizeof(OatQuickMethodHeader), alignment);
1010   // Ensure the header ends up at expected instruction alignment.
1011   DCHECK_ALIGNED_PARAM(reinterpret_cast<uintptr_t>(result + header_size), alignment);
1012   used_memory_for_code_ += mspace_usable_size(result);
1013   return result;
1014 }
1015 
FreeCode(uint8_t * code)1016 void JitCodeCache::FreeCode(uint8_t* code) {
1017   used_memory_for_code_ -= mspace_usable_size(code);
1018   mspace_free(code_mspace_, code);
1019 }
1020 
AllocateData(size_t data_size)1021 uint8_t* JitCodeCache::AllocateData(size_t data_size) {
1022   void* result = mspace_malloc(data_mspace_, data_size);
1023   used_memory_for_data_ += mspace_usable_size(result);
1024   return reinterpret_cast<uint8_t*>(result);
1025 }
1026 
FreeData(uint8_t * data)1027 void JitCodeCache::FreeData(uint8_t* data) {
1028   used_memory_for_data_ -= mspace_usable_size(data);
1029   mspace_free(data_mspace_, data);
1030 }
1031 
Dump(std::ostream & os)1032 void JitCodeCache::Dump(std::ostream& os) {
1033   MutexLock mu(Thread::Current(), lock_);
1034   os << "Current JIT code cache size: " << PrettySize(used_memory_for_code_) << "\n"
1035      << "Current JIT data cache size: " << PrettySize(used_memory_for_data_) << "\n"
1036      << "Current JIT capacity: " << PrettySize(current_capacity_) << "\n"
1037      << "Current number of JIT code cache entries: " << method_code_map_.size() << "\n"
1038      << "Total number of JIT compilations: " << number_of_compilations_ << "\n"
1039      << "Total number of JIT compilations for on stack replacement: "
1040         << number_of_osr_compilations_ << "\n"
1041      << "Total number of deoptimizations: " << number_of_deoptimizations_ << "\n"
1042      << "Total number of JIT code cache collections: " << number_of_collections_ << std::endl;
1043   histogram_stack_map_memory_use_.PrintMemoryUse(os);
1044   histogram_code_memory_use_.PrintMemoryUse(os);
1045   histogram_profiling_info_memory_use_.PrintMemoryUse(os);
1046 }
1047 
1048 }  // namespace jit
1049 }  // namespace art
1050