CodeCache.cpp revision 2bc2b792782b304b15d8c48b54916a9b3fa3a7ac
1dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/* libs/pixelflinger/codeflinger/CodeCache.cpp
2dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project**
3dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project** Copyright 2006, The Android Open Source Project
4dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project**
5dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");
6dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project** you may not use this file except in compliance with the License.
7dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project** You may obtain a copy of the License at
8dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project**
9dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project**     http://www.apache.org/licenses/LICENSE-2.0
10dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project**
11dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project** Unless required by applicable law or agreed to in writing, software
12dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project** distributed under the License is distributed on an "AS IS" BASIS,
13dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project** See the License for the specific language governing permissions and
15dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project** limitations under the License.
16dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project*/
17dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
18dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
19dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <assert.h>
20dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdio.h>
21dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdlib.h>
22beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich#include <unistd.h>
23beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich#include <sys/mman.h>
24dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
25dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <cutils/log.h>
26dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <cutils/atomic.h>
27dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
28dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include "codeflinger/CodeCache.h"
29dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
30dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectnamespace android {
31dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
32dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project// ----------------------------------------------------------------------------
33dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
34dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if defined(__arm__)
35dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <unistd.h>
36dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <errno.h>
37dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
38dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
392bc2b792782b304b15d8c48b54916a9b3fa3a7acPaul Lind#if defined(__mips__)
402bc2b792782b304b15d8c48b54916a9b3fa3a7acPaul Lind#include <asm/cachectl.h>
412bc2b792782b304b15d8c48b54916a9b3fa3a7acPaul Lind#include <errno.h>
422bc2b792782b304b15d8c48b54916a9b3fa3a7acPaul Lind#endif
432bc2b792782b304b15d8c48b54916a9b3fa3a7acPaul Lind
442bc2b792782b304b15d8c48b54916a9b3fa3a7acPaul Lind// ----------------------------------------------------------------------------
45dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project// ----------------------------------------------------------------------------
46dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
47dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source ProjectAssembly::Assembly(size_t size)
48dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    : mCount(1), mSize(0)
49dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
50beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich    mBase = (uint32_t*)mspace_malloc(getMspace(), size);
51beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich    mSize = size;
52beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich    ensureMbaseExecutable();
53dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
54dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
55dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source ProjectAssembly::~Assembly()
56dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
57beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich    mspace_free(getMspace(), mBase);
58dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
59dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
60dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid Assembly::incStrong(const void*) const
61dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
62dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    android_atomic_inc(&mCount);
63dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
64dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
65dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid Assembly::decStrong(const void*) const
66dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
67dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (android_atomic_dec(&mCount) == 1) {
68dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        delete this;
69dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
70dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
71dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
72dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectssize_t Assembly::size() const
73dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
74dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (!mBase) return NO_MEMORY;
75dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return mSize;
76dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
77dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
78dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectuint32_t* Assembly::base() const
79dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
80dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return mBase;
81dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
82dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
83dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectssize_t Assembly::resize(size_t newSize)
84dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
85beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich    mBase = (uint32_t*)mspace_realloc(getMspace(), mBase, newSize);
86dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    mSize = newSize;
87beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich    ensureMbaseExecutable();
88dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return size();
89dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
90dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
91beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevichmspace Assembly::getMspace()
92beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich{
93beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich    static mspace msp = create_contiguous_mspace(2 * 1024, 1024 * 1024, /*locked=*/ false);
94beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich    return msp;
95beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich}
96beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich
97beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevichvoid Assembly::ensureMbaseExecutable()
98beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich{
99beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich    long pagesize = sysconf(_SC_PAGESIZE);
100beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich    long pagemask = ~(pagesize - 1);  // assumes pagesize is a power of 2
101beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich
102beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich    uint32_t* pageStart = (uint32_t*) (((uintptr_t) mBase) & pagemask);
1038e0e372a388434a0553810e2b958e59a26a6bd96Jean-Baptiste Queru    size_t adjustedLength = (mBase - pageStart) * sizeof(uint32_t) + mSize;
104beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich
105beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich    if (mBase && mprotect(pageStart, adjustedLength, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
106beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich        mspace_free(getMspace(), mBase);
107beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich        mBase = NULL;
108beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich    }
109beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich}
110beeeee705bcf16d705748713ea40dca3486cc7b7Nick Kralevich
111dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project// ----------------------------------------------------------------------------
112dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
113dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source ProjectCodeCache::CodeCache(size_t size)
114dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    : mCacheSize(size), mCacheInUse(0)
115dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
116dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pthread_mutex_init(&mLock, 0);
117dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
118dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
119dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source ProjectCodeCache::~CodeCache()
120dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
121dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pthread_mutex_destroy(&mLock);
122dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
123dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
124dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectsp<Assembly> CodeCache::lookup(const AssemblyKeyBase& keyBase) const
125dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
126dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pthread_mutex_lock(&mLock);
127dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    sp<Assembly> r;
128dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ssize_t index = mCacheData.indexOfKey(key_t(keyBase));
129dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (index >= 0) {
130dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        const cache_entry_t& e = mCacheData.valueAt(index);
131dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        e.when = mWhen++;
132dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        r = e.entry;
133dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
134dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pthread_mutex_unlock(&mLock);
135dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return r;
136dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
137dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
138dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint CodeCache::cache(  const AssemblyKeyBase& keyBase,
139dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                            const sp<Assembly>& assembly)
140dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
141dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pthread_mutex_lock(&mLock);
142dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
143dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    const ssize_t assemblySize = assembly->size();
144dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    while (mCacheInUse + assemblySize > mCacheSize) {
145dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // evict the LRU
146dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        size_t lru = 0;
147dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        size_t count = mCacheData.size();
148dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        for (size_t i=0 ; i<count ; i++) {
149dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            const cache_entry_t& e = mCacheData.valueAt(i);
150dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (e.when < mCacheData.valueAt(lru).when) {
151dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                lru = i;
152dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
153dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
154dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        const cache_entry_t& e = mCacheData.valueAt(lru);
155dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        mCacheInUse -= e.entry->size();
156dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        mCacheData.removeItemsAt(lru);
157dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
158dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
159dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ssize_t err = mCacheData.add(key_t(keyBase), cache_entry_t(assembly, mWhen));
160dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (err >= 0) {
161dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        mCacheInUse += assemblySize;
162dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        mWhen++;
163dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // synchronize caches...
1642bc2b792782b304b15d8c48b54916a9b3fa3a7acPaul Lind#if defined(__arm__) || defined(__mips__)
165dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        const long base = long(assembly->base());
166dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        const long curr = base + long(assembly->size());
167dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        err = cacheflush(base, curr, 0);
1682bc2b792782b304b15d8c48b54916a9b3fa3a7acPaul Lind        ALOGE_IF(err, "cacheflush error %s\n",
1692bc2b792782b304b15d8c48b54916a9b3fa3a7acPaul Lind                 strerror(errno));
170dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
171dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
172dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
173dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pthread_mutex_unlock(&mLock);
174dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return err;
175dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
176dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
177dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project// ----------------------------------------------------------------------------
178dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
179dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}; // namespace android
180