Files
dmcallis 65a0592776 Initial source code drop
Source code drop for the Actionscript virtual machine in the Adobe
Flash Player for December 2013
2013-12-02 16:04:04 -08:00

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
}