mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-31 22:25:30 +00:00
Bug 509634 - Add new Allocator-friendly containers, r=dvander.
--HG-- extra : rebase_source : 9d85c87d2c12729873ad5af330edd2495d590d79
This commit is contained in:
parent
be6e1fd282
commit
63c66f15ac
@ -218,6 +218,7 @@ INSTALLED_HEADERS += \
|
||||
Assembler.h \
|
||||
Allocator.h \
|
||||
CodeAlloc.h \
|
||||
Containers.h \
|
||||
LIR.h \
|
||||
avmplus.h \
|
||||
Fragmento.h \
|
||||
@ -232,6 +233,7 @@ CPPSRCS += \
|
||||
Assembler.cpp \
|
||||
Allocator.cpp \
|
||||
CodeAlloc.cpp \
|
||||
Containers.cpp \
|
||||
Fragmento.cpp \
|
||||
LIR.cpp \
|
||||
RegAlloc.cpp \
|
||||
|
91
js/src/nanojit/Containers.cpp
Normal file
91
js/src/nanojit/Containers.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
/* -*- 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) */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine].
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Adobe System Incorporated.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2004-2007
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nanojit.h"
|
||||
|
||||
namespace nanojit
|
||||
{
|
||||
BitSet::BitSet(Allocator& allocator, int nbits)
|
||||
: allocator(allocator)
|
||||
, cap((nbits+63)>>6)
|
||||
, bits((int64_t*)allocator.alloc(cap * sizeof(int64_t)))
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void BitSet::reset()
|
||||
{
|
||||
for (int i=0, n=cap; i < n; i++)
|
||||
bits[i] = 0;
|
||||
}
|
||||
|
||||
bool BitSet::setFrom(BitSet& other)
|
||||
{
|
||||
int c = other.cap;
|
||||
if (c > cap)
|
||||
grow(c);
|
||||
int64_t *bits = this->bits;
|
||||
int64_t *otherbits = other.bits;
|
||||
int64_t newbits = 0;
|
||||
for (int i=0; i < c; i++) {
|
||||
int64_t b = bits[i];
|
||||
int64_t b2 = otherbits[i];
|
||||
newbits |= b2 & ~b; // bits in b2 that are not in b
|
||||
bits[i] = b|b2;
|
||||
}
|
||||
return newbits != 0;
|
||||
}
|
||||
|
||||
/** keep doubling the bitset length until w fits */
|
||||
void BitSet::grow(int w)
|
||||
{
|
||||
int cap2 = cap;
|
||||
do {
|
||||
cap2 <<= 1;
|
||||
} while (w > cap2);
|
||||
int64_t *bits2 = (int64_t*) allocator.alloc(cap2 * sizeof(int64_t));
|
||||
int j=0;
|
||||
for (; j < cap; j++)
|
||||
bits2[j] = bits[j];
|
||||
for (; j < cap2; j++)
|
||||
bits2[j] = 0;
|
||||
cap = cap2;
|
||||
bits = bits2;
|
||||
}
|
||||
}
|
382
js/src/nanojit/Containers.h
Normal file
382
js/src/nanojit/Containers.h
Normal file
@ -0,0 +1,382 @@
|
||||
/* -*- 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) */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine].
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Adobe System Incorporated.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2004-2007
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef __nanojit_Containers__
|
||||
#define __nanojit_Containers__
|
||||
|
||||
namespace nanojit
|
||||
{
|
||||
/** simple linear bit array, memory taken from Allocator
|
||||
* warning: when bit array grows, old memory is wasted since it
|
||||
* was allocated from Allocator. pre-size the bitmap when possible
|
||||
* by passing nbits to the constructor. */
|
||||
class BitSet {
|
||||
Allocator &allocator;
|
||||
int cap;
|
||||
int64_t *bits;
|
||||
static const int64_t ONE = 1;
|
||||
static const int SHIFT = 6;
|
||||
|
||||
inline int bitnum2word(int i) {
|
||||
return i >> 6;
|
||||
}
|
||||
inline int64_t bitnum2mask(int i) {
|
||||
return ONE << (i & 63);
|
||||
}
|
||||
|
||||
/** keep doubling array to fit at least w words */
|
||||
void grow(int w);
|
||||
|
||||
public:
|
||||
BitSet(Allocator& allocator, int nbits=128);
|
||||
|
||||
/** clear all bits */
|
||||
void reset();
|
||||
|
||||
/** perform a bitwise or with BitSet other, return true if
|
||||
* this bitset was modified */
|
||||
bool setFrom(BitSet& other);
|
||||
|
||||
/** return bit i as a bool */
|
||||
bool get(int i) {
|
||||
NanoAssert(i >= 0);
|
||||
int w = bitnum2word(i);
|
||||
if (w < cap)
|
||||
return (bits[w] & bitnum2mask(i)) != 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/** set bit i */
|
||||
void set(int i) {
|
||||
NanoAssert(i >= 0);
|
||||
int w = bitnum2word(i);
|
||||
if (w >= cap)
|
||||
grow(w);
|
||||
bits[w] |= bitnum2mask(i);
|
||||
}
|
||||
|
||||
/** clear bit i */
|
||||
void clear(int i) {
|
||||
NanoAssert(i >= 0);
|
||||
int w = bitnum2word(i);
|
||||
if (w < cap)
|
||||
bits[w] &= ~bitnum2mask(i);
|
||||
}
|
||||
};
|
||||
|
||||
/** Seq is a single node in a linked list */
|
||||
template<class T> class Seq {
|
||||
public:
|
||||
Seq(T head, Seq<T>* tail=NULL) : head(head), tail(tail) {}
|
||||
T head;
|
||||
Seq<T>* tail;
|
||||
};
|
||||
|
||||
/** SeqBuilder is used to create a linked list of Seq<T> by inserting
|
||||
* nodes either at the beginning, with insert(), or at the end, with
|
||||
* add(). Once built, the actual list can be retained while this
|
||||
* SeqBuilder can be discarded. */
|
||||
template<class T> class SeqBuilder {
|
||||
public:
|
||||
SeqBuilder(Allocator& allocator)
|
||||
: allocator(allocator)
|
||||
, items(NULL)
|
||||
, last(NULL)
|
||||
{ }
|
||||
|
||||
/** add item to beginning of list */
|
||||
void insert(T item) {
|
||||
Seq<T>* e = new (allocator) Seq<T>(item, items);
|
||||
if (last == NULL)
|
||||
last = e;
|
||||
items = e;
|
||||
}
|
||||
|
||||
/** add item to end of list */
|
||||
void add(T item) {
|
||||
Seq<T>* e = new (allocator) Seq<T>(item);
|
||||
if (last == NULL)
|
||||
items = e;
|
||||
else
|
||||
last->tail = e;
|
||||
last = e;
|
||||
}
|
||||
|
||||
/** return first item in sequence */
|
||||
Seq<T>* get() const {
|
||||
return items;
|
||||
}
|
||||
|
||||
/** self explanitory */
|
||||
bool isEmpty() const {
|
||||
return items == NULL;
|
||||
}
|
||||
|
||||
/** de-reference all items */
|
||||
void clear() {
|
||||
items = last = NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
Allocator& allocator;
|
||||
Seq<T>* items;
|
||||
Seq<T>* last;
|
||||
};
|
||||
|
||||
/** Bucket hashtable with a fixed # of buckets (never rehash)
|
||||
* Intended for use when a reasonable # of buckets can be estimated ahead of time.
|
||||
*
|
||||
* K is hashed by casting to intptr_t then to int. All users of this
|
||||
* class currently hash pointers and pointer-identity is okay. When this
|
||||
* changes we can parameterize the hash function and equality function,
|
||||
* or the caller can create a K type with custom cast(intptr_t) and == operators. */
|
||||
template<class K, class T> class HashMap {
|
||||
Allocator& allocator;
|
||||
uint32_t nbuckets;
|
||||
class Node {
|
||||
public:
|
||||
K key;
|
||||
T value;
|
||||
Node(K k, T v) : key(k), value(v) { }
|
||||
};
|
||||
Seq<Node>** buckets;
|
||||
|
||||
/** optimized for the assumption that k is a 4-byte aligned pointer. */
|
||||
uint32_t hash(K k) {
|
||||
uintptr_t h = (uintptr_t) k;
|
||||
h = (h>>3) ^ (h<<29); // move the low 3 bits higher up since they're often 0
|
||||
return uint32_t(h) % nbuckets;
|
||||
}
|
||||
|
||||
/** return the node containing K, and the bucket index, or NULL if not found */
|
||||
Node* find(K k, uint32_t &i) {
|
||||
i = hash(k);
|
||||
for (Seq<Node>* p = buckets[i]; p != NULL; p = p->tail) {
|
||||
if (p->head.key == k)
|
||||
return &p->head;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
public:
|
||||
HashMap(Allocator& a, uint32_t nbuckets = 16)
|
||||
: allocator(a)
|
||||
, nbuckets(nbuckets)
|
||||
, buckets(new (a) Seq<Node>*[nbuckets])
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
/** clear all buckets. Since we allocate all memory from Allocator,
|
||||
* nothing needs to be freed. */
|
||||
void clear() {
|
||||
VMPI_memset(buckets, 0, sizeof(Seq<Node>*) * nbuckets);
|
||||
}
|
||||
|
||||
/** add (k,v) to the map. If k is already in the map, replace the value */
|
||||
void put(K k, T v) {
|
||||
uint32_t i;
|
||||
Node* n = find(k, i);
|
||||
if (n) {
|
||||
n->value = v;
|
||||
return;
|
||||
}
|
||||
buckets[i] = new (allocator) Seq<Node>(Node(k,v), buckets[i]);
|
||||
}
|
||||
|
||||
/** return v for element k, or T(0) if k is not present */
|
||||
T get(K k) {
|
||||
uint32_t i;
|
||||
Node* n = find(k, i);
|
||||
return n ? n->value : 0;
|
||||
}
|
||||
|
||||
/** returns true if k is in the map. */
|
||||
bool containsKey(K k) {
|
||||
uint32_t i;
|
||||
return find(k, i) != 0;
|
||||
}
|
||||
|
||||
/** remove k from the map, if it is present. if not, remove()
|
||||
* silently returns */
|
||||
void remove(K k) {
|
||||
uint32_t i = hash(k);
|
||||
Seq<Node>** prev = &buckets[i];
|
||||
for (Seq<Node>* p = buckets[i]; p != NULL; p = p->tail) {
|
||||
if (p->head.key == k) {
|
||||
(*prev) = p->tail;
|
||||
return;
|
||||
}
|
||||
prev = &p->tail;
|
||||
}
|
||||
}
|
||||
|
||||
/** Iter is an iterator for HashMap, intended to be instantiated on
|
||||
* the stack. Iteration order is undefined. Mutating the hashmap
|
||||
* while iteration is in progress gives undefined results. All iteration
|
||||
* state is in class Iter, so multiple iterations can be in progress
|
||||
* at the same time. for example:
|
||||
*
|
||||
* HashMap<K,T>::Iter iter(map);
|
||||
* while (iter.next()) {
|
||||
* K *k = iter.key();
|
||||
* T *t = iter.value();
|
||||
* }
|
||||
*/
|
||||
class Iter {
|
||||
friend class HashMap;
|
||||
const HashMap<K,T> ↦
|
||||
int bucket;
|
||||
const Seq<Node>* current;
|
||||
|
||||
public:
|
||||
Iter(HashMap<K,T>& map) : map(map), bucket(map.nbuckets-1), current(NULL)
|
||||
{ }
|
||||
|
||||
/** return true if more (k,v) remain to be visited */
|
||||
bool next() {
|
||||
if (current)
|
||||
current = current->tail;
|
||||
while (bucket >= 0 && !current)
|
||||
current = map.buckets[bucket--];
|
||||
return current != NULL;
|
||||
}
|
||||
|
||||
/** return the current key */
|
||||
K key() const {
|
||||
NanoAssert(current != NULL);
|
||||
return current->head.key;
|
||||
}
|
||||
|
||||
/** return the current value */
|
||||
T value() const {
|
||||
NanoAssert(current != NULL);
|
||||
return current->head.value;
|
||||
}
|
||||
};
|
||||
|
||||
/** return true if the hashmap has no elements */
|
||||
bool isEmpty() {
|
||||
Iter iter(*this);
|
||||
return !iter.next();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Simple binary tree. No balancing is performed under the assumption
|
||||
* that the only users of this structure are not performance critical.
|
||||
*/
|
||||
template<class K, class T> class TreeMap {
|
||||
Allocator& alloc;
|
||||
class Node {
|
||||
public:
|
||||
Node* left;
|
||||
Node* right;
|
||||
K key;
|
||||
T value;
|
||||
Node(K k, T v) : left(NULL), right(NULL), key(k), value(v)
|
||||
{ }
|
||||
};
|
||||
Node* root;
|
||||
|
||||
/**
|
||||
* helper method to recursively insert (k,v) below Node n or a child
|
||||
* of n so that the binary search tree remains well formed.
|
||||
*/
|
||||
void insert(Node* &n, K k, T v) {
|
||||
if (!n)
|
||||
n = new (alloc) Node(k, v);
|
||||
else if (k == n->key)
|
||||
n->value = v;
|
||||
else if (k < n->key)
|
||||
insert(n->left, k, v);
|
||||
else
|
||||
insert(n->right, k, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* search for key k below Node n and return n if found, or the
|
||||
* closest parent n where k should be inserted.
|
||||
*/
|
||||
Node* find(Node* n, K k) {
|
||||
if (!n)
|
||||
return NULL;
|
||||
if (k == n->key)
|
||||
return n;
|
||||
if (k < n->key)
|
||||
return find(n->left, k);
|
||||
if (n->right)
|
||||
return find(n->right, k);
|
||||
return n;
|
||||
}
|
||||
|
||||
public:
|
||||
TreeMap(Allocator& alloc) : alloc(alloc), root(NULL)
|
||||
{ }
|
||||
|
||||
/** set k = v in the map. if k already exists, replace its value */
|
||||
void put(K k, T v) {
|
||||
insert(root, k, v);
|
||||
}
|
||||
|
||||
/** return the closest key that is <= k, or NULL if k
|
||||
is smaller than every key in the Map. */
|
||||
K findNear(K k) {
|
||||
Node* n = find(root, k);
|
||||
return n ? n->key : 0;
|
||||
}
|
||||
|
||||
/** returns the value for k or NULL */
|
||||
T get(K k) {
|
||||
Node* n = find(root, k);
|
||||
return (n && n->key == k) ? n->value : 0;
|
||||
}
|
||||
|
||||
/** returns true iff k is in the Map. */
|
||||
bool containsKey(K k) {
|
||||
Node* n = find(root, k);
|
||||
return n && n->key == k;
|
||||
}
|
||||
|
||||
/** make the tree empty. trivial since we dont manage elements */
|
||||
void clear() {
|
||||
root = NULL;
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif // __nanojit_Containers__
|
@ -294,6 +294,7 @@ namespace nanojit {
|
||||
|
||||
|
||||
#include "Allocator.h"
|
||||
#include "Containers.h"
|
||||
#include "Native.h"
|
||||
#include "CodeAlloc.h"
|
||||
#include "LIR.h"
|
||||
|
Loading…
Reference in New Issue
Block a user