1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "Dalvik.h" 18 #include "alloc/HeapTable.h" 19 #include "alloc/HeapInternal.h" 20 21 #include <limits.h> // for INT_MAX 22 23 static const int kLargeHeapRefTableNElems = 1024; 24 static const int kFinalizableRefDefault = 128; 25 26 void dvmHeapHeapTableFree(void *ptr) 27 { 28 free(ptr); 29 } 30 31 #define heapRefTableIsFull(refs) \ 32 dvmIsReferenceTableFull(refs) 33 34 bool dvmHeapInitHeapRefTable(HeapRefTable *refs) 35 { 36 memset(refs, 0, sizeof(*refs)); 37 return dvmInitReferenceTable(refs, kFinalizableRefDefault, INT_MAX); 38 } 39 40 /* Frees the array inside the HeapRefTable, not the HeapRefTable itself. 41 */ 42 void dvmHeapFreeHeapRefTable(HeapRefTable *refs) 43 { 44 dvmClearReferenceTable(refs); 45 } 46 47 /* 48 * Large, non-contiguous reference tables 49 */ 50 51 bool dvmHeapAddRefToLargeTable(LargeHeapRefTable **tableP, Object *ref) 52 { 53 LargeHeapRefTable *table; 54 55 assert(tableP != NULL); 56 assert(ref != NULL); 57 58 /* Make sure that a table with a free slot is 59 * at the head of the list. 60 */ 61 if (*tableP != NULL) { 62 table = *tableP; 63 LargeHeapRefTable *prevTable; 64 65 /* Find an empty slot for this reference. 66 */ 67 prevTable = NULL; 68 while (table != NULL && heapRefTableIsFull(&table->refs)) { 69 prevTable = table; 70 table = table->next; 71 } 72 if (table != NULL) { 73 if (prevTable != NULL) { 74 /* Move the table to the head of the list. 75 */ 76 prevTable->next = table->next; 77 table->next = *tableP; 78 *tableP = table; 79 } 80 /* else it's already at the head. */ 81 82 goto insert; 83 } 84 /* else all tables are already full; 85 * fall through to the alloc case. 86 */ 87 } 88 89 /* Allocate a new table. 90 */ 91 table = calloc(1, sizeof(LargeHeapRefTable)); 92 if (table == NULL) { 93 LOGE_HEAP("Can't allocate a new large ref table\n"); 94 return false; 95 } 96 if (!dvmInitReferenceTable(&table->refs, 97 kLargeHeapRefTableNElems, 98 INT_MAX)) { 99 LOGE_HEAP("Can't initialize a new large ref table\n"); 100 dvmHeapHeapTableFree(table); 101 return false; 102 } 103 104 /* Stick it at the head. 105 */ 106 table->next = *tableP; 107 *tableP = table; 108 109 insert: 110 /* Insert the reference. 111 */ 112 assert(table == *tableP); 113 assert(table != NULL); 114 assert(!heapRefTableIsFull(&table->refs)); 115 *table->refs.nextEntry++ = ref; 116 117 return true; 118 } 119 120 bool dvmHeapAddTableToLargeTable(LargeHeapRefTable **tableP, HeapRefTable *refs) 121 { 122 LargeHeapRefTable *table; 123 124 /* Allocate a node. 125 */ 126 table = calloc(1, sizeof(LargeHeapRefTable)); 127 if (table == NULL) { 128 LOGE_HEAP("Can't allocate a new large ref table\n"); 129 return false; 130 } 131 table->refs = *refs; 132 133 /* Insert the table into the list. 134 */ 135 table->next = *tableP; 136 *tableP = table; 137 138 return true; 139 } 140 141 /* Frees everything associated with the LargeHeapRefTable. 142 */ 143 void dvmHeapFreeLargeTable(LargeHeapRefTable *table) 144 { 145 while (table != NULL) { 146 LargeHeapRefTable *next = table->next; 147 dvmHeapFreeHeapRefTable(&table->refs); 148 dvmHeapHeapTableFree(table); 149 table = next; 150 } 151 } 152 153 Object *dvmHeapGetNextObjectFromLargeTable(LargeHeapRefTable **pTable) 154 { 155 LargeHeapRefTable *table; 156 Object *obj; 157 158 assert(pTable != NULL); 159 160 obj = NULL; 161 table = *pTable; 162 if (table != NULL) { 163 HeapRefTable *refs = &table->refs; 164 165 /* We should never have an empty table node in the list. 166 */ 167 assert(dvmReferenceTableEntries(refs) != 0); 168 169 /* Remove and return the last entry in the list. 170 */ 171 obj = *--refs->nextEntry; 172 173 /* If this was the last entry in the table node, 174 * free it and patch up the list. 175 */ 176 if (refs->nextEntry == refs->table) { 177 *pTable = table->next; 178 dvmClearReferenceTable(refs); 179 dvmHeapHeapTableFree(table); 180 } 181 } 182 183 return obj; 184 } 185 186 void dvmHeapMarkLargeTableRefs(LargeHeapRefTable *table) 187 { 188 while (table != NULL) { 189 Object **ref, **lastRef; 190 191 ref = table->refs.table; 192 lastRef = table->refs.nextEntry; 193 while (ref < lastRef) { 194 dvmMarkObjectNonNull(*ref++); 195 } 196 table = table->next; 197 } 198 } 199