Source code: Allocator/SimpleAllocator.java
1 // SimpleAllocator.java, created Mon Feb 5 23:23:19 2001 by joewhaley
2 // Copyright (C) 2001-3 John Whaley <jwhaley@alum.mit.edu>
3 // Licensed under the terms of the GNU LGPL; see COPYING for details.
4 package Allocator;
5
6 import Bootstrap.PrimordialClassLoader;
7 import Clazz.jq_Class;
8 import Clazz.jq_InstanceMethod;
9 import GC.GCBits;
10 import Memory.Address;
11 import Memory.HeapAddress;
12 import Run_Time.SystemInterface;
13 import Util.Assert;
14
15 /**
16 * SimpleAllocator
17 *
18 * @author John Whaley <jwhaley@alum.mit.edu>
19 * @version $Id: SimpleAllocator.java,v 1.30 2003/05/12 10:04:52 joewhaley Exp $
20 */
21
22 public class SimpleAllocator extends HeapAllocator {
23
24 /**
25 * Size of blocks allocated from the OS.
26 */
27 public static final int BLOCK_SIZE = 2097152;
28
29 /**
30 * Maximum memory, in bytes, to be allocated from the OS.
31 */
32 public static /*final*/ int MAX_MEMORY = 67108864;
33
34 /**
35 * Threshold for direct OS allocation. When an array overflows the current block
36 * and is larger than this size, it is allocated directly from the OS.
37 */
38 public static final int LARGE_THRESHOLD = 262144;
39
40 /**
41 * Pointers to the start, current, and end of the heap.
42 */
43 private HeapAddress heapFirst, heapCurrent, heapEnd;
44
45 /**
46 * GC information for the current block.
47 */
48 private GCBits gcBits;
49
50 /**
51 * Perform initialization for this allocator. This will be called before any other methods.
52 * This allocates an initial block of memory from the OS and sets up relevant pointers.
53 *
54 * @throws OutOfMemoryError if there is not enough memory for initialization
55 */
56 public final void init() throws OutOfMemoryError {
57 heapCurrent = heapFirst = (HeapAddress) SystemInterface.syscalloc(BLOCK_SIZE);
58 if (heapCurrent.isNull())
59 HeapAllocator.outOfMemory();
60 heapEnd = (HeapAddress) heapFirst.offset(BLOCK_SIZE - 2 * HeapAddress.size());
61 installGCBits();
62 }
63
64 /**
65 * Allocates a new block of memory from the OS, sets the current block to
66 * point to it, makes the new block the current block, and allocates and
67 * installs the GC structures.
68 *
69 * @throws OutOfMemoryError if there is not enough memory for initialization
70 */
71 private void allocateNewBlock() {
72 if (totalMemory() >= MAX_MEMORY) HeapAllocator.outOfMemory();
73 heapCurrent = (HeapAddress) SystemInterface.syscalloc(BLOCK_SIZE);
74 if (heapCurrent.isNull())
75 HeapAllocator.outOfMemory();
76 // GCBits address of current block already filled
77 heapEnd.offset(HeapAddress.size()).poke(heapCurrent);
78 // address for per block GCBits plus address for next block
79 heapEnd = (HeapAddress) heapCurrent.offset(BLOCK_SIZE - 2 * HeapAddress.size());
80 installGCBits();
81 }
82
83 /**
84 * Allocates and installs the GC structures for the current block.
85 */
86 private void installGCBits() {
87 // install gc bits for next block.
88 gcBits = null;
89 // NOTE: allocations caused by the next line don't have gc bits set.
90 gcBits = new GCBits(heapCurrent, heapEnd);
91 heapEnd.poke(HeapAddress.addressOf(gcBits));
92 }
93
94 /**
95 * Returns an estimate of the amount of free memory available.
96 *
97 * @return bytes of free memory
98 */
99 public final int freeMemory() {
100 return heapEnd.difference(heapCurrent);
101 }
102
103 /**
104 * Returns an estimate of the total memory allocated (both used and unused).
105 *
106 * @return bytes of memory allocated
107 */
108 public final int totalMemory() {
109 int total = 0;
110 HeapAddress ptr = heapFirst;
111 while (!ptr.isNull()) {
112 total += BLOCK_SIZE;
113 ptr = (HeapAddress) ptr.offset(BLOCK_SIZE - HeapAddress.size()).peek();
114 }
115 return total;
116 }
117
118 /**
119 * Allocate an object with the default alignment.
120 * If the object cannot be allocated due to lack of memory, throws OutOfMemoryError.
121 *
122 * @param size size of object to allocate (including object header), in bytes
123 * @param vtable vtable pointer for new object
124 * @return new uninitialized object
125 * @throws OutOfMemoryError if there is insufficient memory to perform the operation
126 */
127 public final Object allocateObject(int size, Object vtable) throws OutOfMemoryError {
128 if (size < ObjectLayout.OBJ_HEADER_SIZE) // size overflow! become minus!
129 HeapAllocator.outOfMemory();
130 //jq.Assert((size & 0x3) == 0);
131 size = (size + 3) & ~3; // align size
132 HeapAddress addr = (HeapAddress) heapCurrent.offset(ObjectLayout.OBJ_HEADER_SIZE);
133 heapCurrent = (HeapAddress) heapCurrent.offset(size);
134 if (heapEnd.difference(heapCurrent) < 0) {
135 // not enough space (rare path)
136 Assert._assert(size < BLOCK_SIZE - 2 * HeapAddress.size());
137 heapCurrent = (HeapAddress) heapCurrent.offset(-size);
138 // consult FreeMemManager for free memory in previous blocks
139 addr = (HeapAddress)FreeMemManager.getFreeMem(size + ObjectLayout.OBJ_HEADER_SIZE);
140 if (addr != null) {
141 addr = (HeapAddress) addr.offset(ObjectLayout.OBJ_HEADER_SIZE);
142 } else {
143 allocateNewBlock();
144 addr = (HeapAddress) heapCurrent.offset(ObjectLayout.OBJ_HEADER_SIZE);
145 heapCurrent = (HeapAddress) heapCurrent.offset(size);
146 }
147 }
148 // fast path
149 addr.offset(ObjectLayout.VTABLE_OFFSET).poke(HeapAddress.addressOf(vtable));
150 if (gcBits != null) {
151 gcBits.set((HeapAddress) addr.offset(-ObjectLayout.OBJ_HEADER_SIZE));
152 }
153 return addr.asObject();
154 }
155
156 /**
157 * Allocate an object such that the first field is 8-byte aligned.
158 * If the object cannot be allocated due to lack of memory, throws OutOfMemoryError.
159 *
160 * @param size size of object to allocate (including object header), in bytes
161 * @param vtable vtable pointer for new object
162 * @return new uninitialized object
163 * @throws OutOfMemoryError if there is insufficient memory to perform the operation
164 */
165 public final Object allocateObjectAlign8(int size, Object vtable) throws OutOfMemoryError {
166 heapCurrent = (HeapAddress) heapCurrent.offset(ObjectLayout.OBJ_HEADER_SIZE).align(3).offset(-ObjectLayout.OBJ_HEADER_SIZE);
167 return allocateObject(size, vtable);
168 }
169
170 /**
171 * Allocate an array with the default alignment.
172 * If length is negative, throws NegativeArraySizeException.
173 * If the array cannot be allocated due to lack of memory, throws OutOfMemoryError.
174 *
175 * @param length length of new array
176 * @param size size of array to allocate (including array header), in bytes
177 * @param vtable vtable pointer for new array
178 * @return new array
179 * @throws NegativeArraySizeException if length is negative
180 * @throws OutOfMemoryError if there is insufficient memory to perform the operation
181 */
182 public final Object allocateArray(int length, int size, Object vtable) throws OutOfMemoryError, NegativeArraySizeException {
183 if (length < 0) throw new NegativeArraySizeException(length + " < 0");
184 if (size < ObjectLayout.ARRAY_HEADER_SIZE) // size overflow!
185 HeapAllocator.outOfMemory();
186 size = (size + 3) & ~3; // align size
187 HeapAddress addr = (HeapAddress) heapCurrent.offset(ObjectLayout.ARRAY_HEADER_SIZE);
188 heapCurrent = (HeapAddress) heapCurrent.offset(size);
189 if (heapEnd.difference(heapCurrent) < 0) {
190 // not enough space (rare path)
191 heapCurrent = (HeapAddress) heapCurrent.offset(-size);
192 if (size > LARGE_THRESHOLD) {
193 // special large-object allocation
194 addr = (HeapAddress) SystemInterface.syscalloc(size);
195 if (addr.isNull())
196 outOfMemory();
197 addr = (HeapAddress) addr.offset(ObjectLayout.ARRAY_HEADER_SIZE);
198 addr.offset(ObjectLayout.ARRAY_LENGTH_OFFSET).poke4(length);
199 addr.offset(ObjectLayout.VTABLE_OFFSET).poke(HeapAddress.addressOf(vtable));
200 // TODO: gc ?!?
201 return addr.asObject();
202 } else {
203 Assert._assert(size < BLOCK_SIZE - 2 * HeapAddress.size());
204 // consult FreeMemManager for free memory in previous blocks
205 addr = (HeapAddress)FreeMemManager.getFreeMem(size + ObjectLayout.OBJ_HEADER_SIZE);
206 if (addr != null) {
207 addr = (HeapAddress) addr.offset(ObjectLayout.ARRAY_HEADER_SIZE);
208 } else {
209 allocateNewBlock();
210 addr = (HeapAddress) heapCurrent.offset(ObjectLayout.ARRAY_HEADER_SIZE);
211 heapCurrent = (HeapAddress) heapCurrent.offset(size);
212 }
213 }
214 }
215 // fast path
216 addr.offset(ObjectLayout.ARRAY_LENGTH_OFFSET).poke4(length);
217 addr.offset(ObjectLayout.VTABLE_OFFSET).poke(HeapAddress.addressOf(vtable));
218 if (gcBits != null) {
219 gcBits.set((HeapAddress) addr.offset(-ObjectLayout.ARRAY_HEADER_SIZE));
220 }
221 return addr.asObject();
222 }
223
224 /**
225 * Allocate an array such that the elements are 8-byte aligned.
226 * If length is negative, throws NegativeArraySizeException.
227 * If the array cannot be allocated due to lack of memory, throws OutOfMemoryError.
228 *
229 * @param length length of new array
230 * @param size size of array to allocate (including array header), in bytes
231 * @param vtable vtable pointer for new array
232 * @return new array
233 * @throws NegativeArraySizeException if length is negative
234 * @throws OutOfMemoryError if there is insufficient memory to perform the operation
235 */
236 public final Object allocateArrayAlign8(int length, int size, Object vtable) throws OutOfMemoryError, NegativeArraySizeException {
237 heapCurrent = (HeapAddress) heapCurrent.offset(ObjectLayout.ARRAY_HEADER_SIZE).align(3).offset(-ObjectLayout.ARRAY_HEADER_SIZE);
238 return allocateArray(length, size, vtable);
239 }
240
241 public final void collect() {
242 // nothing for now.
243 }
244
245 public final void processPtrField(Address a) {
246 // nothing for now.
247 }
248
249 public static final jq_Class _class;
250 public static final jq_InstanceMethod _allocateObject;
251 public static final jq_InstanceMethod _allocateObjectAlign8;
252 public static final jq_InstanceMethod _allocateArray;
253 public static final jq_InstanceMethod _allocateArrayAlign8;
254
255 static {
256 _class = (jq_Class) PrimordialClassLoader.loader.getOrCreateBSType("LAllocator/SimpleAllocator;");
257 _allocateObject = _class.getOrCreateInstanceMethod("allocateObject", "(ILjava/lang/Object;)Ljava/lang/Object;");
258 _allocateObjectAlign8 = _class.getOrCreateInstanceMethod("allocateObjectAlign8", "(ILjava/lang/Object;)Ljava/lang/Object;");
259 _allocateArray = _class.getOrCreateInstanceMethod("allocateArray", "(IILjava/lang/Object;)Ljava/lang/Object;");
260 _allocateArrayAlign8 = _class.getOrCreateInstanceMethod("allocateArrayAlign8", "(IILjava/lang/Object;)Ljava/lang/Object;");
261 }
262 }