ScriptObject::ScriptObject(VTable* _vtable, ScriptObject* _delegate, int capacity) : #ifdef DEBUGGER AvmPlusScriptableObject(sotObject(_vtable)), #endif // DEBUGGER vtable(_vtable), // note that it's substantially more efficient to initialize this in the ctor // list vs. a later explicit call to setDelegate, as we don't have to check for marking // nor decrement an existing value... delegate(_delegate) { AvmAssert(vtable->traits->isResolved()); // Ensure that our object is large enough to hold its extra traits data. AvmAssert(MMgc::GC::Size(this) >= vtable->traits->getTotalSize()); //if capacity not specified then initialize the hashtable lazily if (vtable->traits->needsHashtable() && capacity) { initHashtable(capacity); } }
Hashtable createHashtable( void* self, char* name, long maxItemsNum, HashtableSettings set, int setFlags) { IHashtableManager _ = (IHashtableManager)self; IErrorLogger elog = (IErrorLogger)_->errorLogger; ISpinLockManager slog = (ISpinLockManager)_->spinLockHelper; Hashtable tbl; int nHashLists; int nSegs; int segLLSize; uint elemSize; HashSegment* segP; ulong tblSegSize; /* Initialize the hash header, plus a copy of the table name. * First sizeof(Hashtable) bytes are allocated for a hash table. * The next strlen(Name) are allocated for the name. * In this way we unate one malloc call for struct SHashtable with another * malloc for char* name. */ tbl = (Hashtable)_->memManager->alloc(sizeof(SHashtable) + strlen(name) + 1); memset(tbl, 0, sizeof(SHashtable)); /* Adding one to a pointer means "produce a pointer to the object * that comes in memory right after this one," * which means that the compiler automatically scales up * whatever you're incrementing the pointer with * by the size of the object being pointed at. */ tbl->name = (char*)(tbl + 1); strcpy(tbl->name, name); setDefaults(tbl); if (setFlags & HASH_FUNC) tbl->hashFunc = set->hashFunc; if (tbl->hashFunc == hashFuncStr) tbl->hashCmp = hashCmpFuncStr; if (setFlags & HASH_CMP) tbl->hashCmp = set->hashCmp; if (tbl->hashFunc == hashFuncStr) tbl->hashCpy = (hashCpyFunc)strcpy; if (setFlags & HASH_KEYCPY) tbl->hashCpy = set->hashCpy; if (setFlags & HASH_ITEM) { tbl->keyLen = set->keyLen; tbl->valLen = set->valLen; } if (setFlags & HASH_SEG) { tbl->segmSize = set->segmSize; tbl->segmShift = set->segmShift; } if (setFlags & HASH_LIST_SIZE) { tbl->segmsAmount = set->segmsAmount; tbl->maxSegmsAmount = set->maxSegmsAmount; tbl->hashListSize = set->hashListSize; } if (setFlags & HASH_WITHOUT_EXTENTION) { tbl->isWithoutExtention = set->isWithoutExtention; } if (setFlags & HASH_PARTITION) { Bool isNumPowerOf2 = tbl->partNum == _->commonHelper->nextPowerOf2(tbl->partNum); /* First of all we need to check if the hashtable is located * in the shared memory. Applying partitions to a hashtable * which is located in the local memory is pointless because * no contention is applied. */ ASSERT(elog, setFlags & HASH_SHARED_MEMORY, NULL); /* We should check if the number of partiotions is really power of 2 */ ASSERT(elog, isNumPowerOf2, NULL); tbl->partNum = set->partNum; } if (IS_TABLE_PARTITIONED(tbl)) slog->spinLockInit(slog, &(tbl->mutex)); nHashLists = (maxItemsNum - 1) / tbl->hashListSize + 1; nHashLists = _->commonHelper->nextPowerOf2(nHashLists); tbl->lowMask = _->hashtableHelper->calcLowMask(nHashLists); tbl->highMask = _->hashtableHelper->calcHighMask(nHashLists); nSegs = _->hashtableHelper->calcSegmsNum(nHashLists, tbl->segmSize); tbl->numHashLists = nHashLists; tbl->segments = (AHashSegment)_->memManager->alloc(tbl->segmsAmount * sizeof(HashSegment)); tblSegSize = tbl->segmSize; /* Allocate initial segments */ for (segP = tbl->segments; tbl->nSegs < nSegs; tbl->nSegs++, segP++) { segLLSize = tblSegSize * sizeof(HashList); *segP = (HashSegment)(AHashList)_->memManager->alloc(segLLSize); memset(*segP, 0, segLLSize); } /* Our element consists of a header and data sp that the size * is sum of the header's size and data's size. * Header also includes aligned key. */ elemSize = HASH_ELEM_SIZE(tbl); tbl->numItemsToAlloc = itemsNumToAlloc(elemSize); if (!initHashtable(_, tbl)) { elog->log(LOG_ERROR, ERROR_CODE_FAILED_TO_INIT_HASHTABLE, "Spinlock exceeded max allowed sleep counts: %d"); return NULL; } if (setFlags & HASH_SEG || maxItemsNum < tbl->numItemsToAlloc) { if (!allocNewItems(_, tbl)) { elog->log(LOG_ERROR, ERROR_CODE_OUT_OF_MEMORY, "Out of memory"); return NULL; } return NULL; } return tbl; }