Source code drop for the Actionscript virtual machine in the Adobe Flash Player for December 2013
242 lines
7.7 KiB
C++
242 lines
7.7 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/. */
|
|
|
|
#ifndef __avmplus_BitSet__
|
|
#define __avmplus_BitSet__
|
|
|
|
|
|
namespace avmplus
|
|
{
|
|
/**
|
|
* Bit vectors are an efficent method of keeping True/False information
|
|
* on a set of items or conditions. Class BitSet provides functions
|
|
* to manipulate individual bits in the vector.
|
|
*
|
|
* Since most vectors are rather small an array of machine words is used by
|
|
* default to house the value of the bits. If more bits are needed
|
|
* then an array is allocated dynamically outside of this object.
|
|
*
|
|
* This object is not optimized for a fixed sized bit vector
|
|
* it instead allows for dynamically growing the bit vector.
|
|
*/
|
|
class BitSet
|
|
{
|
|
private:
|
|
uintptr_t *getbits() {
|
|
return capacity > kDefaultCapacity ? bits.ptr : bits.ar;
|
|
}
|
|
const uintptr_t *getbits() const {
|
|
return capacity > kDefaultCapacity ? bits.ptr : bits.ar;
|
|
}
|
|
static const uintptr_t kOne = 1;
|
|
|
|
public:
|
|
|
|
enum { kUnit = 8*sizeof(uintptr_t),
|
|
kDefaultCapacity = 4 };
|
|
|
|
BitSet(): capacity(kDefaultCapacity) {
|
|
reset();
|
|
}
|
|
|
|
BitSet(int bitcap) : capacity(kDefaultCapacity) {
|
|
reset();
|
|
int cap = ((bitcap+kUnit-1)/kUnit);
|
|
if (cap > kDefaultCapacity)
|
|
grow(cap);
|
|
}
|
|
|
|
virtual ~BitSet() {
|
|
if (capacity > kDefaultCapacity) {
|
|
mmfx_delete_array(bits.ptr);
|
|
bits.ptr = 0;
|
|
capacity = kDefaultCapacity;
|
|
}
|
|
}
|
|
|
|
void reset()
|
|
{
|
|
uintptr_t *bits = getbits();
|
|
for (int i=0, n = capacity; i < n; i++)
|
|
bits[i] = 0;
|
|
}
|
|
|
|
void set(int bitNbr)
|
|
{
|
|
int index = bitNbr / kUnit;
|
|
int bit = bitNbr % kUnit;
|
|
int cap = this->capacity;
|
|
if (index >= cap) {
|
|
cap *= 2;
|
|
while (index >= cap) {
|
|
cap *= 2;
|
|
}
|
|
grow(cap);
|
|
}
|
|
getbits()[index] |= kOne << bit;
|
|
}
|
|
|
|
void clear(int bitNbr)
|
|
{
|
|
int index = bitNbr / kUnit;
|
|
int bit = bitNbr % kUnit;
|
|
if (index < capacity)
|
|
getbits()[index] &= ~(kOne << bit);
|
|
}
|
|
|
|
bool get(int bitNbr) const
|
|
{
|
|
int index = bitNbr / kUnit;
|
|
int bit = bitNbr % kUnit;
|
|
return index < capacity && (getbits()[index] & kOne<<bit) != 0;
|
|
}
|
|
|
|
uintptr_t setFrom(BitSet &other) {
|
|
int c = other.capacity;
|
|
if (c > capacity)
|
|
grow(c);
|
|
uintptr_t *bits = getbits();
|
|
uintptr_t *otherbits = other.getbits();
|
|
uintptr_t newbits = 0;
|
|
for (int i=0; i < c; i++) {
|
|
uintptr_t b = bits[i];
|
|
uintptr_t b2 = otherbits[i];
|
|
newbits |= b2 & ~b; // bits in b2 that are not in b
|
|
bits[i] = b|b2;
|
|
}
|
|
return newbits;
|
|
}
|
|
|
|
private:
|
|
|
|
// Grow the array until at least newCapacity big
|
|
void grow(int newCapacity)
|
|
{
|
|
uintptr_t* newBits = mmfx_new_array( uintptr_t, newCapacity);
|
|
// copy the old one
|
|
uintptr_t *bits = getbits();
|
|
for (int i=0, n=capacity; i < n; i++)
|
|
newBits[i] = bits[i];
|
|
for (int i=capacity; i < newCapacity; i++)
|
|
newBits[i] = 0;
|
|
|
|
// in with the new out with the old
|
|
if (capacity > kDefaultCapacity)
|
|
mmfx_delete_array( bits );
|
|
|
|
this->bits.ptr = newBits;
|
|
capacity = newCapacity;
|
|
}
|
|
|
|
// by default we use the array, but if the vector
|
|
// size grows beyond kDefaultCapacity we allocate
|
|
// space dynamically.
|
|
int capacity;
|
|
union
|
|
{
|
|
uintptr_t ar[kDefaultCapacity];
|
|
uintptr_t* ptr;
|
|
}
|
|
bits;
|
|
};
|
|
|
|
// a simpler version of BitSet that doesn't dynamically grow,
|
|
// and doesn't require allocation for <=31 (or 63) size. This expects
|
|
// to be embedded as a member variable in a GCObject and will
|
|
// use WB if allocation is necessary.
|
|
class FixedBitSet : public MMgc::GCInlineObject
|
|
{
|
|
public:
|
|
inline explicit FixedBitSet() : m_bits(0)
|
|
#ifdef _DEBUG
|
|
, m_cap(0)
|
|
#endif
|
|
{
|
|
}
|
|
|
|
inline void gcTrace(MMgc::GC* gc)
|
|
{
|
|
if (!(m_bits & 1))
|
|
gc->TraceLocation(&m_bits);
|
|
}
|
|
|
|
// blows away existing content, sets all bits to 0
|
|
inline void resize(MMgc::GC* gc, uint32_t cap)
|
|
{
|
|
const uint32_t MAX_INLINE_BITS = BITS_PER_UINTPTR - 1;
|
|
if (cap > MAX_INLINE_BITS)
|
|
{
|
|
// always allocate one more bit than we need to simplify the logic elsewhere (bit 0 goes unused)
|
|
const uint32_t count = (cap + (BITS_PER_UINTPTR - 1) + 1) / BITS_PER_UINTPTR;
|
|
const uint32_t sz = count * sizeof(uintptr_t);
|
|
uintptr_t* v = (uintptr_t*)gc->Alloc(sz, MMgc::GC::kZero);
|
|
void* beginning = gc->FindBeginningFast(this);
|
|
if (beginning)
|
|
{
|
|
WB(gc, beginning, &m_bits, v);
|
|
}
|
|
else
|
|
{
|
|
m_bits = uintptr_t(v);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_bits = 0x1;
|
|
}
|
|
#ifdef _DEBUG
|
|
m_cap = cap;
|
|
#endif
|
|
}
|
|
|
|
inline void set(uint32_t bit)
|
|
{
|
|
AvmAssert(bit < m_cap);
|
|
uintptr_t* v = (m_bits & 1) ? &m_bits : (uintptr_t*)m_bits;
|
|
const uint32_t nbit = bit + 1;
|
|
v[nbit / BITS_PER_UINTPTR] |= (uintptr_t(1) << (nbit & (BITS_PER_UINTPTR-1)));
|
|
}
|
|
|
|
inline void clr(uint32_t bit)
|
|
{
|
|
AvmAssert(bit < m_cap);
|
|
uintptr_t* v = (m_bits & 1) ? &m_bits : (uintptr_t*)m_bits;
|
|
const uint32_t nbit = bit + 1;
|
|
v[nbit / BITS_PER_UINTPTR] &= ~(uintptr_t(1) << (nbit & (BITS_PER_UINTPTR-1)));
|
|
}
|
|
|
|
inline bool test(uint32_t bit) const
|
|
{
|
|
AvmAssert(bit < m_cap);
|
|
const uint32_t nbit = bit + 1;
|
|
uintptr_t w = m_bits;
|
|
if (!(w & 1))
|
|
w = ((const uintptr_t*)m_bits)[nbit / BITS_PER_UINTPTR];
|
|
return (w & (uintptr_t(1) << (nbit & (BITS_PER_UINTPTR-1)))) != 0;
|
|
}
|
|
|
|
inline size_t allocatedSize()
|
|
{
|
|
return ((m_bits & 1) || (m_bits == 0)) ? 0 : MMgc::GC::Size((void*)m_bits);
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
inline uint32_t cap() const { return uint32_t(m_cap); }
|
|
#endif
|
|
|
|
private:
|
|
enum { BITS_PER_UINTPTR = sizeof(uintptr_t)*8 };
|
|
private:
|
|
uintptr_t m_bits; // low bit 1 == inline, low bit 0 == dynamic alloc
|
|
#ifdef _DEBUG
|
|
uintptr_t m_cap;
|
|
#endif
|
|
};
|
|
|
|
}
|
|
|
|
#endif /* __avmplus_BitSet__ */
|