Mozilla/mozilla/js/tamarin/core/MultinameHashtable.cpp
gerv%gerv.net 0a3a70857a Bug 236613: fix formatting of MPL/LGPL/GPL tri-license.
git-svn-id: svn://10.0.0.236/trunk@220064 18797224-902f-48f8-a5cc-f745e15eee43
2007-02-13 18:05:02 +00:00

271 lines
7.1 KiB
C++

/* ***** 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-2006
* 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 "avmplus.h"
using namespace MMgc;
namespace avmplus
{
MultinameHashtable::MultinameHashtable(int capacity)
{
Init(capacity);
}
void MultinameHashtable::Init(int capacity)
{
if(capacity)
{
numTriplets = MathUtils::nextPowerOfTwo(capacity);
MMgc::GC* gc = MMgc::GC::GetGC(this);
AvmAssert(numTriplets > 0);
MMGC_MEM_TYPE(this);
triples = (Triple *) gc->Alloc (sizeof(Triple) * numTriplets, GC::kContainsPointers|GC::kZero);
}
}
MultinameHashtable::~MultinameHashtable()
{
GC *gc = GC::GetGC(this);
gc->Free (triples);
}
bool MultinameHashtable::isFull() const
{
// 0.80 load factor
return 5*(size+1) >= numTriplets*4;
}
int MultinameHashtable::find(Stringp name, Namespace* ns, Triple *t, unsigned m)
{
AvmAssert(name != NULL && ns != NULL);
// this is a quadratic probe but we only hit every third slot since those hold keys.
int n = 7;
int bitmask = (m - 1);
// Note: Mask off MSB to avoid negative indices. Mask off bottom
// 3 bits because it doesn't contribute to hash. Triple it
// because names, namespaces, and values are stored adjacently.
unsigned i = ((0x7FFFFFF8 & (uintptr)name) >> 3) & bitmask;
Stringp k;
while (((k=t[i].name) != name || t[i].ns != ns) && k != NULL)
{
i = (i + (n++)) & bitmask; // quadratic probe
}
return i;
}
void MultinameHashtable::put(Stringp name, Namespace* ns, Binding value)
{
AvmAssert(!isFull());
GC *gc = GC::GetGC(triples);
int i = find(name, ns, triples, numTriplets);
Triple &t = triples[i];
if (t.name == name)
{
// This <name,ns> pair is already in the table
AvmAssert(t.ns == ns);
}
else
{
// New table entry for this <name,ns> pair
size++;
//triples[i] = name;
WBRC(gc, triples, &t.name, name);
//triples[i+1] = ns;
WBRC(gc, triples, &t.ns, ns);
}
//triples[i+2] = value;
WB(gc, triples, &t.value, value);
}
Binding MultinameHashtable::get(Stringp name, Namespace* ns) const
{
Triple* t = triples;
int i = find(name, ns, t, numTriplets);
if (t[i].name == name)
{
AvmAssert(t[i].ns == ns);
return t[i].value;
}
return BIND_NONE;
}
Binding MultinameHashtable::getName(Stringp name) const
{
Triple* t = triples;
for (int i=0, n=numTriplets; i < n; i++)
{
if (t[i].name == name)
{
return t[i].value;
}
}
return BIND_NONE;
}
Binding MultinameHashtable::get(Stringp mnameName, NamespaceSet *nsset) const
{
Binding match = BIND_NONE;
int nsCount = nsset->size;
// this is a quadratic probe but we only hit every third slot since those hold keys.
int n = 7;
int bitMask = numTriplets - 1;
// Note: Mask off MSB to avoid negative indices. Mask off bottom
// 3 bits because it doesn't contribute to hash. Triple it
// because names, namespaces, and values are stored adjacently.
unsigned i = ((0x7FFFFFF8 & (uintptr)mnameName)>>3) & bitMask;
int j;
Stringp atomName;
Triple* t = triples;
while ((atomName = t[i].name) != EMPTY)
{
if (atomName == mnameName)
{
Namespace *ns = t[i].ns;
for (j=0; j < nsCount; j++)
{
if (ns == nsset->namespaces[j])
{
if (match == BIND_NONE)
{
match = t[i].value;
break;
}
else if (match != t[i].value)
{
return BIND_AMBIGUOUS;
}
}
}
}
i = (i + (n++)) & bitMask; // quadratic probe
}
return match;
}
Binding MultinameHashtable::getMulti(Multiname* mname) const
{
// multiname must not be an attr name, have wildcards, or have runtime parts.
AvmAssert(mname->isBinding() && !mname->isAnyName());
if (!mname->isNsset())
return get(mname->getName(), mname->getNamespace());
else
return get(mname->getName(), mname->getNsset());
}
void MultinameHashtable::add(Stringp name, Namespace* ns, Binding value)
{
if (isFull())
{
grow();
}
put(name, ns, value);
}
void MultinameHashtable::rehash(Triple *oldAtoms, int oldTriplet, Triple *newAtoms, int newTriplet)
{
for (int i=0, n=oldTriplet; i < n; i++)
{
Stringp oldName;
if ((oldName=oldAtoms[i].name) != EMPTY)
{
// inlined & simplified version of put()
int j = find(oldName, oldAtoms[i].ns, newAtoms, newTriplet);
newAtoms[j].name = oldName;
newAtoms[j].ns = oldAtoms[i].ns;
newAtoms[j].value = oldAtoms[i].value;
}
}
}
void MultinameHashtable::grow()
{
// double our table
int capacity = numTriplets*2;
MMgc::GC* gc = MMgc::GC::GetGC(this);
MMGC_MEM_TYPE(this);
Triple *newAtoms = (Triple *) gc->Calloc(capacity, sizeof(Triple), GC::kContainsPointers|GC::kZero);
rehash(triples, numTriplets, newAtoms, capacity);
gc->Free (triples);
triples = newAtoms;
numTriplets = capacity;
}
Stringp MultinameHashtable::keyAt(int index)
{
AvmAssert(NULL != triples[index-1].name);
return triples[index-1].name;
}
Namespace* MultinameHashtable::nsAt(int index)
{
return triples[index-1].ns;
}
Binding MultinameHashtable::valueAt(int index)
{
return triples[index-1].value;
}
// call this method using the previous value returned
// by this method starting with 0, until 0 is returned.
int MultinameHashtable::next(int index)
{
// Advance to first non-empty slot.
Triple* t = triples;
while (index < numTriplets) {
if (t[index++].name != NULL) {
return index;
}
}
return 0;
}
}