Files
Mozilla/mozilla/ef/gc/src/smalloc.c
dmose%mozilla.org 2ccab49e6d updating license boilerplate to xPL v1.1
git-svn-id: svn://10.0.0.236/trunk@52526 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-02 06:38:29 +00:00

305 lines
11 KiB
C

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* 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 mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
/*******************************************************************************
S P O R T M O D E L
_____
____/_____\____
/__o____o____o__\ __
\_______________/ (@@)/
/\_____|_____/\ x~[]~
~~~~~~~~~~~/~~~~~~~|~~~~~~~\~~~~~~~~/\~~~~~~~~~
Advanced Technology Garbage Collector
Copyright (c) 1997 Netscape Communications, Inc. All rights reserved.
Recovered by: Warren Harris
*******************************************************************************/
#include "smheap.h"
/******************************************************************************/
SMObjStruct*
sm_AddGCPage(SMGenNum genNum, SMBucket bucket)
{
SMObjStruct* obj = NULL;
SMPage* page = SM_NEW_PAGE(&sm_PageMgr);
if (page) {
SMSmallObjSize objSize = sm_ObjectSize[bucket];
SMSmallObjCount objTableSize = sm_ObjectsPerPage[bucket];
SMObjDesc* objTable;
if (bucket >= SM_FIRST_MIDSIZE_BUCKET) {
/* add an extra object descriptor for any extra space at the
end of the page due to a non-integral number of objects */
objTableSize++;
}
SM_ASSERT((objTableSize * objSize) >= SM_PAGE_SIZE);
objTable = (SMObjDesc*)SM_Malloc(sizeof(SMObjDesc) * objTableSize);
if (objTable == NULL) {
SM_DESTROY_PAGE(&sm_PageMgr, page);
return NULL;
}
obj = (SMObjStruct*)sm_PoolInitPage(&sm_Heap.gen[genNum].pool,
genNum, bucket, page, objTable, 0);
}
return obj;
}
/*******************************************************************************
* Allocator
******************************************************************************/
SMObjStruct*
sm_Alloc(PRUword instanceSize, SMBucket bucket)
{
SMObjStruct* obj;
SMGen* gen = &sm_Heap.gen[SMGenNum_Freshman];
SMGenNum collectGenNum = SMGenNum_Free;
PRUword objSize;
/* First force a collect if we've crossed our allocation threshold.
Collect the oldest generations that has crossed its threshold,
and all younger generations. */
if (gen->pool.allocAmount >= gen->allocThreshold) {
SMGenNum i;
for (collectGenNum = SMGenNum_Freshman; collectGenNum <= SMGenNum_Static; collectGenNum++) {
gen = &sm_Heap.gen[collectGenNum];
if (gen->pool.allocAmount < gen->allocThreshold)
break;
}
--collectGenNum;
sm_Collect0(collectGenNum, SM_IS_COPY_CYCLE(collectGenNum));
/* reset allocation cnnnounts */
for (i = SMGenNum_Freshman; i < collectGenNum; i++) {
sm_Heap.gen[i].pool.allocAmount = 0;
}
}
gen = &sm_Heap.gen[SMGenNum_Freshman];
if (instanceSize > SM_MAX_SMALLOBJECT_SIZE) {
do {
SM_GEN_ALLOC_LARGE_OBJ(obj, gen, SMGenNum_Freshman, instanceSize);
} while (obj == NULL &&
(sm_CompactHook ? sm_CompactHook(instanceSize) : PR_FALSE));
if (obj == NULL)
return NULL;
/* Don't add to the gen->pool.allocAmount for large objects --
they don't contribute to triggering a gc. */
objSize = SM_PAGE_WIDTH(SM_PAGE_COUNT(instanceSize));
/* XXX Should large objects factor into the allocAmount that
we use to cause a collection? */
}
else {
do {
SM_GEN_ALLOC_OBJ(obj, gen, bucket);
if (obj == NULL) {
/* no objects on the free list -- try allocating a new page */
obj = sm_AddGCPage(SMGenNum_Freshman, bucket);
}
} while (obj == NULL &&
(sm_CompactHook ? sm_CompactHook(sm_ObjectSize[bucket]) : PR_FALSE));
if (obj == NULL)
return NULL;
objSize = sm_ObjectSize[bucket];
gen->pool.allocAmount += objSize;
}
#ifdef DEBUG
{
SMPageDesc* pd = SM_OBJECT_PAGEDESC(obj);
SMObjDesc* od = SM_OBJECT_HEADER_FROM_PAGEDESC(obj, pd);
SM_ASSERT(SM_OBJDESC_IS_ALLOCATED(od));
}
#endif
SM_POOL_SET_ALLOC_STATS(&gen->pool, objSize, instanceSize);
DBG_MEMSET(obj, SM_UNUSED_PATTERN, instanceSize);
SM_SET_DEBUG_HEADER(obj, bucket, SMGenNum_Freshman);
return obj;
}
#define SM_INIT_OBJECT(obj, clazz) \
{ \
SMObject* _obj = (obj); \
SMClass* _clazz = (SMClass*)(clazz); \
/* Initialize reference fields */ \
SMFieldDesc* _fieldDesc = SM_CLASS_GET_INST_FIELD_DESCS(_clazz); \
PRUint16 i, _fdCount = SM_CLASS_GET_INST_FIELDS_COUNT(_clazz); \
for (i = 0; i < _fdCount; i++) { \
PRWord _offset = _fieldDesc[i].offset; \
PRUword _count = _fieldDesc[i].count; \
SMObject** _fieldRefs = &SM_OBJECT_FIELDS(_obj)[_offset]; \
SM_UNROLLED_WHILE(_count, { \
*_fieldRefs++ = NULL; \
}); \
} \
SM_OBJECT_CLASS(_obj) = _clazz; \
if (SM_CLASS_IS_FINALIZABLE(_clazz)) { \
SMObjStruct* _dobj = SM_DECRYPT_OBJECT(_obj); \
SMPageDesc* _pd = SM_OBJECT_PAGEDESC(_dobj); \
SMObjDesc* _od = SM_OBJECT_HEADER_FROM_PAGEDESC(_dobj, _pd); \
SM_OBJDESC_SET_FINALIZABLE(_od); \
} \
} \
SM_IMPLEMENT(SMObject*)
SM_AllocObject(SMObjectClass* clazz)
{
SMObjStruct* obj;
PRUword instanceSize = SM_CLASS_INSTANCE_SIZE(clazz);
SMBucket bucket = SM_CLASS_BUCKET(clazz);
PRMonitor* mon = sm_Heap.gen[SMGenNum_Freshman].pool.sweepList[bucket].monitor;
SM_ASSERT(SM_IS_OBJECT_CLASS(clazz));
PR_EnterMonitor(mon);
obj = sm_Alloc(instanceSize, bucket);
if (obj) {
SMObject* eobj = SM_ENCRYPT_OBJECT(obj);
SM_INIT_OBJECT(eobj, clazz);
}
SM_VERIFY_HEAP();
PR_ExitMonitor(mon);
return SM_ENCRYPT_OBJECT(obj);
}
/******************************************************************************/
SM_IMPLEMENT(SMArray*)
SM_AllocArray(SMArrayClass* clazz, PRUword size)
{
SMArrayStruct* arr;
PRUword instanceSize;
SMBucket bucket;
PRMonitor* mon;
int eltSize = SM_ELEMENT_SIZE(clazz);
SM_ASSERT(SM_IS_ARRAY_CLASS(clazz));
instanceSize = sizeof(SMArrayStruct) + (eltSize * size);
#ifdef DEBUG
/* In debug mode, we'll store a pointer back to the beginning
of the array in the last element of the array. This lets us
easily see where the array ends in memory. */
if (eltSize == sizeof(void*)) {
instanceSize += sizeof(void*);
}
#endif
SM_GET_ALLOC_BUCKET(bucket, instanceSize);
mon = sm_Heap.gen[SMGenNum_Freshman].pool.sweepList[bucket].monitor;
PR_EnterMonitor(mon);
arr = (SMArrayStruct*)sm_Alloc(instanceSize, bucket);
if (arr) {
SMArray* earr = SM_ENCRYPT_ARRAY(arr);
SM_ARRAY_CLASS(earr) = (SMClass*)clazz;
SM_ARRAY_SIZE(earr) = size;
if (SM_IS_OBJECT_ARRAY_CLASS(clazz)) {
SMObject** elements = SM_ARRAY_ELEMENTS(earr);
SM_UNROLLED_WHILE(size, {
SM_ASSERT(!SM_CHECK_DEBUG_HEADER(*elements));
*elements++ = NULL;
});
#ifdef DEBUG
if (eltSize == sizeof(void*)) {
*elements = (SMObject*)arr;
}
#endif
}
}
SM_VERIFY_HEAP();
PR_ExitMonitor(mon);
return SM_ENCRYPT_ARRAY(arr);
}
/******************************************************************************/
SM_IMPLEMENT(SMObject*)
SM_AllocObjectExtra(SMObjectClass* clazz, PRUword extraBytes)
{
SMObjStruct* obj;
PRUword instanceSize;
SMBucket bucket;
PRMonitor* mon;
SM_ASSERT(SM_IS_OBJECT_CLASS(clazz));
instanceSize = SM_CLASS_INSTANCE_SIZE(clazz) + extraBytes;
SM_GET_ALLOC_BUCKET(bucket, instanceSize);
mon = sm_Heap.gen[SMGenNum_Freshman].pool.sweepList[bucket].monitor;
PR_EnterMonitor(mon);
obj = sm_Alloc(instanceSize, bucket);
if (obj) {
SMObject* eobj = SM_ENCRYPT_OBJECT(obj);
SM_INIT_OBJECT(eobj, clazz);
memset(SM_OBJECT_EXTRA(eobj), 0, extraBytes);
}
SM_VERIFY_HEAP();
PR_ExitMonitor(mon);
return SM_ENCRYPT_OBJECT(obj);
}
/******************************************************************************/
SM_IMPLEMENT(PRUword)
SM_ObjectSize(SMObject* obj)
{
SMClass* clazz = SM_OBJECT_CLASS(obj);
PRUword size;
SM_ASSERT(clazz);
switch (SM_CLASS_KIND(clazz)) {
case SMClassKind_ObjectClass:
size = SM_CLASS_INSTANCE_SIZE(clazz);
break;
case SMClassKind_ArrayClass:
size = sizeof(SMArrayStruct) +
SM_ARRAY_SIZE((SMArray*)obj) * SM_ELEMENT_SIZE(clazz);
break;
default:
size = 0;
}
SM_ASSERT(size <= sm_ObjectSize[SM_PAGEDESC_BUCKET(SM_OBJECT_PAGEDESC(SM_DECRYPT_OBJECT(obj)))]);
return size;
}
SM_EXTERN(SMObject*)
SM_Clone(SMObject* obj)
{
SMObjStruct* dobj = SM_DECRYPT_OBJECT(obj);
SMPageDesc* pd = SM_OBJECT_PAGEDESC(dobj);
SMBucket bucket = SM_PAGEDESC_BUCKET(pd);
PRUword instanceSize;
SMObjStruct* result;
SM_OBJECT_GROSS_SIZE(&instanceSize, dobj);
result = sm_Alloc(instanceSize, bucket);
if (result) {
memcpy(result, obj, instanceSize);
}
return SM_ENCRYPT_OBJECT(result);
}
/******************************************************************************/