Source code drop for the Actionscript virtual machine in the Adobe Flash Player for December 2013
124 lines
3.0 KiB
C++
124 lines
3.0 KiB
C++
/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
|
|
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "avmplus.h"
|
|
|
|
namespace avmplus
|
|
{
|
|
using namespace MMgc;
|
|
|
|
QCache::QCache(uint32_t _max, MMgc::GC* _gc) :
|
|
m_gc(_gc),
|
|
m_head(NULL),
|
|
m_count(0),
|
|
m_max(0)
|
|
{
|
|
MathUtils::RandomFastInit(&m_rand);
|
|
resize(_max);
|
|
}
|
|
|
|
QCache::~QCache()
|
|
{
|
|
flush();
|
|
}
|
|
|
|
void QCache::flush()
|
|
{
|
|
QCachedItem* gen = first();
|
|
while (gen)
|
|
{
|
|
QCachedItem* n = next(gen);
|
|
gen->next = NULL;
|
|
gen = n;
|
|
}
|
|
m_head = NULL;
|
|
m_count = 0;
|
|
}
|
|
|
|
void QCache::resize(uint32_t _max)
|
|
{
|
|
flush();
|
|
// 0 -> unlimited
|
|
m_max = !_max ? 0xffffffff : _max;
|
|
}
|
|
|
|
QCachedItem* QCache::add(QCachedItem* gen)
|
|
{
|
|
AvmAssert(gen && !next(gen));
|
|
|
|
QCachedItem* evicted = NULL;
|
|
|
|
// if no space, evict oldest
|
|
if (m_count >= m_max)
|
|
{
|
|
AvmAssert(m_count == m_max);
|
|
uint32_t which = MathUtils::Random(count(), &m_rand);
|
|
QCachedItem* evicted_prev = NULL;
|
|
for (QCachedItem* td = first(); td; td = next(td))
|
|
{
|
|
if (!which--)
|
|
break;
|
|
evicted_prev = td;
|
|
}
|
|
if (evicted_prev)
|
|
{
|
|
evicted = evicted_prev->next;
|
|
AvmAssert(evicted != NULL && evicted != gen);
|
|
WB(m_gc, evicted_prev, &evicted_prev->next, evicted->next);
|
|
}
|
|
else
|
|
{
|
|
evicted = m_head;
|
|
AvmAssert(evicted != NULL && evicted != gen);
|
|
WB(m_gc, this, &m_head, evicted->next);
|
|
}
|
|
evicted->next = NULL; // never need a WB to write NULL
|
|
--m_count;
|
|
#ifdef QCACHE_DEBUG
|
|
validate();
|
|
#endif
|
|
}
|
|
|
|
// add at head
|
|
WB(m_gc, gen, &gen->next, m_head);
|
|
WB(m_gc, this, &m_head, gen);
|
|
++m_count;
|
|
|
|
#ifdef QCACHE_DEBUG
|
|
validate();
|
|
#endif
|
|
|
|
AvmAssert(evicted ? evicted->next == NULL : true);
|
|
return evicted;
|
|
}
|
|
|
|
#ifdef QCACHE_DEBUG
|
|
void QCache::validate() const
|
|
{
|
|
if (!m_head)
|
|
{
|
|
AvmAssert(m_count == 0);
|
|
return;
|
|
}
|
|
uint32_t c = 0;
|
|
QCachedItem* prev = NULL;
|
|
for (QCachedItem* td = first(); td; td = next(td))
|
|
{
|
|
AvmAssert(prev ? prev->next == td : true);
|
|
++c;
|
|
prev = td;
|
|
if (c > m_max)
|
|
{
|
|
// oops, probably a cycle, busted code
|
|
AvmAssert(0);
|
|
}
|
|
}
|
|
AvmAssert(c == m_count);
|
|
}
|
|
#endif
|
|
}
|
|
|