Home | History | Annotate | Download | only in codeflinger
      1 /* libs/pixelflinger/codeflinger/CodeCache.cpp
      2 **
      3 ** Copyright 2006, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 
     19 #include <assert.h>
     20 #include <stdio.h>
     21 #include <stdlib.h>
     22 #include <unistd.h>
     23 #include <sys/mman.h>
     24 
     25 #include <cutils/ashmem.h>
     26 #include <cutils/atomic.h>
     27 #define LOG_TAG "CodeCache"
     28 #include <cutils/log.h>
     29 
     30 
     31 #include "CodeCache.h"
     32 
     33 namespace android {
     34 
     35 // ----------------------------------------------------------------------------
     36 
     37 #if defined(__arm__) || defined(__aarch64__)
     38 #include <unistd.h>
     39 #include <errno.h>
     40 #endif
     41 
     42 #if defined(__mips__)
     43 #include <asm/cachectl.h>
     44 #include <errno.h>
     45 #endif
     46 
     47 // ----------------------------------------------------------------------------
     48 // ----------------------------------------------------------------------------
     49 
     50 // A dlmalloc mspace is used to manage the code cache over a mmaped region.
     51 #define HAVE_MMAP 0
     52 #define HAVE_MREMAP 0
     53 #define HAVE_MORECORE 0
     54 #define MALLOC_ALIGNMENT 16
     55 #define MSPACES 1
     56 #define NO_MALLINFO 1
     57 #define ONLY_MSPACES 1
     58 // Custom heap error handling.
     59 #define PROCEED_ON_ERROR 0
     60 static void heap_error(const char* msg, const char* function, void* p);
     61 #define CORRUPTION_ERROR_ACTION(m) \
     62     heap_error("HEAP MEMORY CORRUPTION", __FUNCTION__, NULL)
     63 #define USAGE_ERROR_ACTION(m,p) \
     64     heap_error("ARGUMENT IS INVALID HEAP ADDRESS", __FUNCTION__, p)
     65 
     66 #include "../../../../bionic/libc/upstream-dlmalloc/malloc.c"
     67 
     68 static void heap_error(const char* msg, const char* function, void* p) {
     69     ALOG(LOG_FATAL, LOG_TAG, "@@@ ABORTING: CODE FLINGER: %s IN %s addr=%p",
     70          msg, function, p);
     71     /* So that we can get a memory dump around p */
     72     *((int **) 0xdeadbaad) = (int *) p;
     73 }
     74 
     75 // ----------------------------------------------------------------------------
     76 
     77 static void* gExecutableStore = NULL;
     78 static mspace gMspace = NULL;
     79 const size_t kMaxCodeCacheCapacity = 1024 * 1024;
     80 
     81 static mspace getMspace()
     82 {
     83     if (gExecutableStore == NULL) {
     84         int fd = ashmem_create_region("CodeFlinger code cache",
     85                                       kMaxCodeCacheCapacity);
     86         LOG_ALWAYS_FATAL_IF(fd < 0,
     87                             "Creating code cache, ashmem_create_region "
     88                             "failed with error '%s'", strerror(errno));
     89         gExecutableStore = mmap(NULL, kMaxCodeCacheCapacity,
     90                                 PROT_READ | PROT_WRITE | PROT_EXEC,
     91                                 MAP_PRIVATE, fd, 0);
     92         LOG_ALWAYS_FATAL_IF(gExecutableStore == MAP_FAILED,
     93                             "Creating code cache, mmap failed with error "
     94                             "'%s'", strerror(errno));
     95         close(fd);
     96         gMspace = create_mspace_with_base(gExecutableStore, kMaxCodeCacheCapacity,
     97                                           /*locked=*/ false);
     98         mspace_set_footprint_limit(gMspace, kMaxCodeCacheCapacity);
     99     }
    100     return gMspace;
    101 }
    102 
    103 Assembly::Assembly(size_t size)
    104     : mCount(1), mSize(0)
    105 {
    106     mBase = (uint32_t*)mspace_malloc(getMspace(), size);
    107     LOG_ALWAYS_FATAL_IF(mBase == NULL,
    108                         "Failed to create Assembly of size %zd in executable "
    109                         "store of size %zd", size, kMaxCodeCacheCapacity);
    110     mSize = size;
    111 }
    112 
    113 Assembly::~Assembly()
    114 {
    115     mspace_free(getMspace(), mBase);
    116 }
    117 
    118 void Assembly::incStrong(const void*) const
    119 {
    120     android_atomic_inc(&mCount);
    121 }
    122 
    123 void Assembly::decStrong(const void*) const
    124 {
    125     if (android_atomic_dec(&mCount) == 1) {
    126         delete this;
    127     }
    128 }
    129 
    130 ssize_t Assembly::size() const
    131 {
    132     if (!mBase) return NO_MEMORY;
    133     return mSize;
    134 }
    135 
    136 uint32_t* Assembly::base() const
    137 {
    138     return mBase;
    139 }
    140 
    141 ssize_t Assembly::resize(size_t newSize)
    142 {
    143     mBase = (uint32_t*)mspace_realloc(getMspace(), mBase, newSize);
    144     LOG_ALWAYS_FATAL_IF(mBase == NULL,
    145                         "Failed to resize Assembly to %zd in code cache "
    146                         "of size %zd", newSize, kMaxCodeCacheCapacity);
    147     mSize = newSize;
    148     return size();
    149 }
    150 
    151 // ----------------------------------------------------------------------------
    152 
    153 CodeCache::CodeCache(size_t size)
    154     : mCacheSize(size), mCacheInUse(0)
    155 {
    156     pthread_mutex_init(&mLock, 0);
    157 }
    158 
    159 CodeCache::~CodeCache()
    160 {
    161     pthread_mutex_destroy(&mLock);
    162 }
    163 
    164 sp<Assembly> CodeCache::lookup(const AssemblyKeyBase& keyBase) const
    165 {
    166     pthread_mutex_lock(&mLock);
    167     sp<Assembly> r;
    168     ssize_t index = mCacheData.indexOfKey(key_t(keyBase));
    169     if (index >= 0) {
    170         const cache_entry_t& e = mCacheData.valueAt(index);
    171         e.when = mWhen++;
    172         r = e.entry;
    173     }
    174     pthread_mutex_unlock(&mLock);
    175     return r;
    176 }
    177 
    178 int CodeCache::cache(  const AssemblyKeyBase& keyBase,
    179                             const sp<Assembly>& assembly)
    180 {
    181     pthread_mutex_lock(&mLock);
    182 
    183     const ssize_t assemblySize = assembly->size();
    184     while (mCacheInUse + assemblySize > mCacheSize) {
    185         // evict the LRU
    186         size_t lru = 0;
    187         size_t count = mCacheData.size();
    188         for (size_t i=0 ; i<count ; i++) {
    189             const cache_entry_t& e = mCacheData.valueAt(i);
    190             if (e.when < mCacheData.valueAt(lru).when) {
    191                 lru = i;
    192             }
    193         }
    194         const cache_entry_t& e = mCacheData.valueAt(lru);
    195         mCacheInUse -= e.entry->size();
    196         mCacheData.removeItemsAt(lru);
    197     }
    198 
    199     ssize_t err = mCacheData.add(key_t(keyBase), cache_entry_t(assembly, mWhen));
    200     if (err >= 0) {
    201         mCacheInUse += assemblySize;
    202         mWhen++;
    203         // synchronize caches...
    204         char* base = reinterpret_cast<char*>(assembly->base());
    205         char* curr = reinterpret_cast<char*>(base + assembly->size());
    206         __builtin___clear_cache(base, curr);
    207     }
    208 
    209     pthread_mutex_unlock(&mLock);
    210     return err;
    211 }
    212 
    213 // ----------------------------------------------------------------------------
    214 
    215 }; // namespace android
    216