Commit | Line | Data |
---|---|---|
7f918cf1 CE |
1 | /* Copyright (C) 2016 Matthew Fluet. |
2 | * Copyright (C) 1999-2007 Henry Cejtin, Matthew Fluet, Suresh | |
3 | * Jagannathan, and Stephen Weeks. | |
4 | * Copyright (C) 1997-2000 NEC Research Institute. | |
5 | * | |
6 | * MLton is released under a BSD-style license. | |
7 | * See the file MLton-LICENSE for details. | |
8 | */ | |
9 | ||
10 | pointer GC_arrayAllocate (GC_state s, | |
11 | size_t ensureBytesFree, | |
12 | GC_arrayLength numElements, | |
13 | GC_header header) { | |
14 | size_t arraySize, arraySizeAligned; | |
15 | size_t bytesPerElement; | |
16 | uint16_t bytesNonObjptrs; | |
17 | uint16_t numObjptrs; | |
18 | pointer frontier; | |
19 | pointer last; | |
20 | pointer result; | |
21 | ||
22 | splitHeader(s, header, NULL, NULL, &bytesNonObjptrs, &numObjptrs); | |
23 | if (DEBUG) | |
24 | fprintf (stderr, "GC_arrayAllocate (%"PRIuMAX", "FMTARRLEN", "FMTHDR")\n", | |
25 | (uintmax_t)ensureBytesFree, numElements, header); | |
26 | bytesPerElement = bytesNonObjptrs + (numObjptrs * OBJPTR_SIZE); | |
27 | /* Check for overflow when computing arraySize. | |
28 | */ | |
29 | if (bytesPerElement > 0 and numElements > (SIZE_MAX / bytesPerElement)) { | |
30 | goto doOverflow; | |
31 | } | |
32 | arraySize = bytesPerElement * numElements; | |
33 | if (arraySize > SIZE_MAX - GC_ARRAY_METADATA_SIZE) { | |
34 | goto doOverflow; | |
35 | } | |
36 | arraySize += GC_ARRAY_METADATA_SIZE; | |
37 | arraySizeAligned = align (arraySize, s->alignment); | |
38 | if (arraySizeAligned < arraySize) { | |
39 | goto doOverflow; | |
40 | } | |
41 | if (DEBUG_ARRAY) | |
42 | fprintf (stderr, | |
43 | "Array with "FMTARRLEN" elts of size %"PRIuMAX" and total size %s and total aligned size %s. " | |
44 | "Ensure %s bytes free.\n", | |
45 | numElements, (uintmax_t)bytesPerElement, | |
46 | uintmaxToCommaString(arraySize), | |
47 | uintmaxToCommaString(arraySizeAligned), | |
48 | uintmaxToCommaString(ensureBytesFree)); | |
49 | if (arraySizeAligned >= s->controls.oldGenArraySize) { | |
50 | if (not hasHeapBytesFree (s, arraySizeAligned, ensureBytesFree)) { | |
51 | enter (s); | |
52 | performGC (s, arraySizeAligned, ensureBytesFree, FALSE, TRUE); | |
53 | leave (s); | |
54 | } | |
55 | frontier = s->heap.start + s->heap.oldGenSize; | |
56 | s->heap.oldGenSize += arraySizeAligned; | |
57 | s->cumulativeStatistics.bytesAllocated += arraySizeAligned; | |
58 | } else { | |
59 | size_t bytesRequested; | |
60 | pointer newFrontier; | |
61 | ||
62 | bytesRequested = arraySizeAligned + ensureBytesFree; | |
63 | if (not hasHeapBytesFree (s, 0, bytesRequested)) { | |
64 | enter (s); | |
65 | performGC (s, 0, bytesRequested, FALSE, TRUE); | |
66 | leave (s); | |
67 | } | |
68 | frontier = s->frontier; | |
69 | newFrontier = frontier + arraySizeAligned; | |
70 | assert (isFrontierAligned (s, newFrontier)); | |
71 | s->frontier = newFrontier; | |
72 | } | |
73 | last = frontier + arraySize; | |
74 | *((GC_arrayCounter*)(frontier)) = 0; | |
75 | frontier = frontier + GC_ARRAY_COUNTER_SIZE; | |
76 | *((GC_arrayLength*)(frontier)) = numElements; | |
77 | frontier = frontier + GC_ARRAY_LENGTH_SIZE; | |
78 | *((GC_header*)(frontier)) = header; | |
79 | frontier = frontier + GC_HEADER_SIZE; | |
80 | result = frontier; | |
81 | assert (isAligned ((size_t)result, s->alignment)); | |
82 | /* Initialize all pointers with BOGUS_OBJPTR. */ | |
83 | if (1 <= numObjptrs and 0 < numElements) { | |
84 | pointer p; | |
85 | ||
86 | if (0 == bytesNonObjptrs) | |
87 | for (p = frontier; p < last; p += OBJPTR_SIZE) | |
88 | *((objptr*)p) = BOGUS_OBJPTR; | |
89 | else { | |
90 | /* Array with a mix of pointers and non-pointers. */ | |
91 | size_t bytesObjptrs; | |
92 | ||
93 | bytesObjptrs = numObjptrs * OBJPTR_SIZE; | |
94 | ||
95 | for (p = frontier; p < last; ) { | |
96 | pointer next; | |
97 | ||
98 | p += bytesNonObjptrs; | |
99 | next = p + bytesObjptrs; | |
100 | assert (next <= last); | |
101 | for ( ; p < next; p += OBJPTR_SIZE) | |
102 | *((objptr*)p) = BOGUS_OBJPTR; | |
103 | } | |
104 | } | |
105 | } | |
106 | GC_profileAllocInc (s, arraySizeAligned); | |
107 | if (DEBUG_ARRAY) { | |
108 | fprintf (stderr, "GC_arrayAllocate done. result = "FMTPTR" frontier = "FMTPTR"\n", | |
109 | (uintptr_t)result, (uintptr_t)s->frontier); | |
110 | displayGCState (s, stderr); | |
111 | } | |
112 | assert (ensureBytesFree <= (size_t)(s->limitPlusSlop - s->frontier)); | |
113 | /* Unfortunately, the invariant isn't quite true here, because | |
114 | * unless we did the GC, we never set s->currentThread->stack->used | |
115 | * to reflect what the mutator did with stackTop. | |
116 | */ | |
117 | return result; | |
118 | ||
119 | doOverflow: | |
120 | die ("Out of memory. Unable to allocate array with "FMTARRLEN" elements and elements of size %"PRIuMAX" bytes.", | |
121 | numElements, (uintmax_t)bytesPerElement); | |
122 | } |