/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "Dalvik.h" #include "alloc/HeapTable.h" #include "alloc/HeapInternal.h" #include <limits.h> // for INT_MAX static void *heapTableRealloc(void *oldPtr, size_t newSize) { /* Don't just call realloc(), in case the native system * doesn't malloc() on realloc(NULL). */ if (oldPtr != NULL) { return realloc(oldPtr, newSize); } else { return malloc(newSize); } } void dvmHeapHeapTableFree(void *ptr) { free(ptr); } #define heapRefTableIsFull(refs) \ ({ \ const HeapRefTable *HRTIF_refs = (refs); \ dvmIsReferenceTableFull(refs); \ }) bool dvmHeapInitHeapRefTable(HeapRefTable *refs, size_t nelems) { memset(refs, 0, sizeof(*refs)); return dvmInitReferenceTable(refs, nelems, INT_MAX); } /* Frees the array inside the HeapRefTable, not the HeapRefTable itself. */ void dvmHeapFreeHeapRefTable(HeapRefTable *refs) { dvmClearReferenceTable(refs); } /* * Large, non-contiguous reference tables */ #define kLargeHeapRefTableNElems 1024 bool dvmHeapAddRefToLargeTable(LargeHeapRefTable **tableP, Object *ref) { LargeHeapRefTable *table; assert(tableP != NULL); assert(ref != NULL); /* Make sure that a table with a free slot is * at the head of the list. */ if (*tableP != NULL) { table = *tableP; LargeHeapRefTable *prevTable; /* Find an empty slot for this reference. */ prevTable = NULL; while (table != NULL && heapRefTableIsFull(&table->refs)) { prevTable = table; table = table->next; } if (table != NULL) { if (prevTable != NULL) { /* Move the table to the head of the list. */ prevTable->next = table->next; table->next = *tableP; *tableP = table; } /* else it's already at the head. */ goto insert; } /* else all tables are already full; * fall through to the alloc case. */ } /* Allocate a new table. */ table = (LargeHeapRefTable *)heapTableRealloc(NULL, sizeof(LargeHeapRefTable)); if (table == NULL) { LOGE_HEAP("Can't allocate a new large ref table\n"); return false; } if (!dvmHeapInitHeapRefTable(&table->refs, kLargeHeapRefTableNElems)) { LOGE_HEAP("Can't initialize a new large ref table\n"); dvmHeapHeapTableFree(table); return false; } /* Stick it at the head. */ table->next = *tableP; *tableP = table; insert: /* Insert the reference. */ assert(table == *tableP); assert(table != NULL); assert(!heapRefTableIsFull(&table->refs)); *table->refs.nextEntry++ = ref; return true; } bool dvmHeapAddTableToLargeTable(LargeHeapRefTable **tableP, HeapRefTable *refs) { LargeHeapRefTable *table; /* Allocate a node. */ table = (LargeHeapRefTable *)heapTableRealloc(NULL, sizeof(LargeHeapRefTable)); if (table == NULL) { LOGE_HEAP("Can't allocate a new large ref table\n"); return false; } table->refs = *refs; /* Insert the table into the list. */ table->next = *tableP; *tableP = table; return true; } /* Frees everything associated with the LargeHeapRefTable. */ void dvmHeapFreeLargeTable(LargeHeapRefTable *table) { while (table != NULL) { LargeHeapRefTable *next = table->next; dvmHeapFreeHeapRefTable(&table->refs); dvmHeapHeapTableFree(table); table = next; } } Object *dvmHeapGetNextObjectFromLargeTable(LargeHeapRefTable **pTable) { LargeHeapRefTable *table; Object *obj; assert(pTable != NULL); obj = NULL; table = *pTable; if (table != NULL) { GcHeap *gcHeap = gDvm.gcHeap; HeapRefTable *refs = &table->refs; /* We should never have an empty table node in the list. */ assert(dvmReferenceTableEntries(refs) != 0); /* Remove and return the last entry in the list. */ obj = *--refs->nextEntry; /* If this was the last entry in the table node, * free it and patch up the list. */ if (refs->nextEntry == refs->table) { *pTable = table->next; dvmClearReferenceTable(refs); dvmHeapHeapTableFree(table); } } return obj; } void dvmHeapMarkLargeTableRefs(LargeHeapRefTable *table, bool stripLowBits) { while (table != NULL) { Object **ref, **lastRef; ref = table->refs.table; lastRef = table->refs.nextEntry; if (stripLowBits) { /* This case is used for marking reference objects that * are still waiting for the heap worker thread to get to * them. The referents pointed to by the references are * marked when a SCHEDULED_REFERENCE_MAGIC is encountered * during scanning. */ while (ref < lastRef) { dvmMarkObjectNonNull((Object *)((uintptr_t)*ref++ & ~3)); } } else { while (ref < lastRef) { dvmMarkObjectNonNull(*ref++); } } table = table->next; } }