Skip to content

Commit 4fc826e

Browse files
committed
Initial support static heaps in MaPLe
MLton/mlton#357 (revising MLton/mlton#328) introduced a number of "static heaps" into the compilation. Essentially, many "global" objects can be fully evaluated at compile time and represented in the compiled program as statics. The "static" objects look like regular ML objects (with proper headers, etc.), but exist outside the MLton heap. This is a "path of least resistance" commit for MaPLe. The `collectStatics.Globals` and `collectStatics.RealConsts` passes are disabled, but the `collectStatics.WordXVectorConsts` pass is enabled. In the `backend` pass (translation of RSSA to Machine), all RSSA statics are forced to the `Dynamic` static heap (and assigned a corresponding global objptr slot); similarly, any remaining `WordXVector` constants are forced to the `Dynamic` static heap. At program startup, the `Dynamic` static heap is copied into the root hierarchical heap. (This is slightly more complicated than the copy of the `Dynamic` static heap into the initial heap in MLton, because in MaPLe the `Dynamic` static heap may need to be split across multiple chunks.) See #127 for more discussion.
1 parent 87ada31 commit 4fc826e

File tree

3 files changed

+107
-123
lines changed

3 files changed

+107
-123
lines changed

mlton/backend/backend.fun

+10-7
Original file line numberDiff line numberDiff line change
@@ -373,14 +373,14 @@ fun toMachine (rssa: Rssa.Program.t) =
373373
({offset = offset, src = src},
374374
hasDynamic' orelse hasDynamic)
375375
end)
376-
fun translateObject obj =
376+
fun translateObject (obj, {forceDynamic}) =
377377
case obj of
378378
R.Object.Normal {init, tycon} =>
379379
let
380380
val {components, ...} = ObjectType.deNormal (tyconTy tycon)
381381
val (init, hasDynamic) = translateInit init
382382
val kind =
383-
if hasDynamic
383+
if forceDynamic orelse hasDynamic
384384
then Kind.Dynamic
385385
else if Prod.someIsMutable components
386386
then if Vector.exists (Prod.dest components,
@@ -414,7 +414,7 @@ fun toMachine (rssa: Rssa.Program.t) =
414414
(init, hasDynamic' orelse hasDynamic)
415415
end)
416416
val kind =
417-
if hasDynamic
417+
if forceDynamic orelse hasDynamic
418418
then Kind.Dynamic
419419
else if hasIdentity
420420
then if Vector.isEmpty init
@@ -448,10 +448,10 @@ fun toMachine (rssa: Rssa.Program.t) =
448448
nextIndex = Counter.generator 0,
449449
nextOffset = ref Bytes.zero})
450450

451-
fun add obj =
451+
fun add (obj, forceDynamic) =
452452
let
453453
val {kind, obj, offset, size, tycon} =
454-
translateObject obj
454+
translateObject (obj, forceDynamic)
455455
val {objs, nextIndex, nextOffset} = kindAcc kind
456456
val r = Ref.T {index = nextIndex (),
457457
kind = kind,
@@ -481,7 +481,7 @@ fun toMachine (rssa: Rssa.Program.t) =
481481

482482
val () = Vector.foreach (statics, fn {dst = (dstVar, dstTy), obj} =>
483483
let
484-
val oper = addToStaticHeaps obj
484+
val oper = addToStaticHeaps (obj, {forceDynamic = true})
485485
in
486486
setVarInfo (dstVar, {operand = VarOperand.Const oper, ty = dstTy})
487487
end)
@@ -519,7 +519,10 @@ fun toMachine (rssa: Rssa.Program.t) =
519519
val globalWordVector =
520520
make {equals = WordXVector.equals,
521521
hash = WordXVector.hash,
522-
oper = addToStaticHeaps o R.Object.fromWordXVector}
522+
oper = (fn wxv =>
523+
addToStaticHeaps
524+
(R.Object.fromWordXVector wxv,
525+
{forceDynamic = true}))}
523526
end
524527
fun constOperand (c: Const.t): M.Operand.t =
525528
let

mlton/backend/rssa-simplify.fun

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ val rssaPasses =
2323
execute = true} ::
2424
{name = "collectStatics.Globals",
2525
doit = CollectStatics.Globals.transform,
26-
execute = true} ::
26+
execute = false} ::
2727
{name = "collectStatics.RealConsts",
2828
doit = CollectStatics.RealConsts.transform,
29-
execute = true} ::
29+
execute = false} ::
3030
{name = "insertLimitChecks", doit = LimitCheck.transform, execute = true} ::
3131
{name = "insertSignalChecks", doit = SignalCheck.transform, execute = true} ::
3232
(* must be before implementHandlers *)

runtime/gc/init-world.c

+95-114
Original file line numberDiff line numberDiff line change
@@ -22,123 +22,104 @@ size_t sizeofInitialBytesLive (GC_state s) {
2222
}
2323

2424
void initDynHeap(GC_state s, GC_thread thread) {
25+
assert(0 == thread->currentDepth);
26+
27+
HM_chunk currentChunk;
28+
pointer frontier, limit;
29+
pointer start = s->staticHeaps.dynamic.start;
30+
pointer end = start + s->staticHeaps.dynamic.size;
31+
pointer p = start;
32+
size_t metaDataSize = 0, objectSize = 0;
33+
34+
// While there are segments of the initial dynamic heap to be copied
35+
// into the root hierarchical heap.
36+
while (1) {
37+
currentChunk = thread->currentChunk;
38+
frontier = HM_getChunkFrontier(currentChunk);
39+
assert(isFrontierAligned(s, frontier));
40+
limit = HM_getChunkLimit(currentChunk);
41+
assert(frontier <= limit);
42+
43+
// Find the end of this segement of the initial dynamic heap to
44+
// copy into the current chunk of the root hierarchical heap.
45+
// `start` is the start of the segment.
46+
// `p` is the candidate end of segment.
47+
while (1) {
48+
if (p >= end) {
49+
// This segment is the last to be copied.
50+
break;
51+
}
52+
pointer q = advanceToObjectData (s, p);
53+
#if ASSERT
54+
GC_header header = getHeader (q);
55+
assert (header == GC_REAL32_VECTOR_HEADER
56+
|| header == GC_REAL64_VECTOR_HEADER
57+
|| header == GC_WORD8_VECTOR_HEADER
58+
|| header == GC_WORD16_VECTOR_HEADER
59+
|| header == GC_WORD32_VECTOR_HEADER
60+
|| header == GC_WORD64_VECTOR_HEADER);
61+
#endif
62+
sizeofObjectAux (s, q, &metaDataSize, &objectSize);
63+
pointer r = q + objectSize;
64+
if (!inFirstBlockOfChunk(currentChunk, frontier + (q - start))
65+
|| frontier + (r - start) > limit) {
66+
// Next object does not fit into current chunk.
67+
break;
68+
}
69+
// Next object fits into current chunk; advance `p`.
70+
p = r;
71+
}
72+
73+
// Copy segment `[start,p)` into current segment.
74+
memcpy (frontier, start, p - start);
75+
// Adjust global objptrs that referenced an object in the segment.
76+
for (uint32_t i = 0; i < s->globalsLength; i++) {
77+
pointer g = objptrToPointer(s->globals[i], NULL);
78+
if (start <= g && g < p) {
79+
g = (g - start) + frontier;
80+
s->globals[i] = pointerToObjptr(g, NULL);
81+
}
82+
}
83+
// Advance frontier.
84+
frontier += p - start;
85+
HM_updateChunkValues(currentChunk, frontier);
86+
87+
if (p >= end) {
88+
// This segment was the last to be copied.
89+
break;
90+
}
91+
92+
// Initialize search for next segment.
93+
start = p;
94+
// `p` points to the beginning of an object that did not fit in
95+
// the last chunk; extend hierarchical heap with a chunk
96+
// sufficient to hold the next object.
97+
if (!HM_HH_extend(s, thread, metaDataSize + objectSize)) {
98+
DIE("Ran out of space for Hierarchical Heap!");
99+
}
100+
}
101+
102+
/* If the last allocation passed a block boundary, we need to extend to have
103+
* a valid frontier. Extending with GC_HEAP_LIMIT_SLOP is arbitrary. */
104+
if (!inFirstBlockOfChunk(currentChunk, frontier + GC_SEQUENCE_METADATA_SIZE)) {
105+
if (!HM_HH_extend(s, thread, GC_HEAP_LIMIT_SLOP)) {
106+
DIE("Ran out of space for Hierarchical Heap!");
107+
}
108+
currentChunk = thread->currentChunk;
109+
frontier = HM_getChunkFrontier(currentChunk);
110+
assert(isFrontierAligned(s, frontier));
111+
limit = HM_getChunkLimit(currentChunk);
112+
assert(frontier <= limit);
113+
}
114+
115+
s->frontier = frontier;
116+
s->limitPlusSlop = limit;
117+
s->limit = s->limitPlusSlop - GC_HEAP_LIMIT_SLOP;
25118

119+
assert(isFrontierAligned(s, s->frontier));
120+
assert(inFirstBlockOfChunk(currentChunk, s->frontier + GC_SEQUENCE_METADATA_SIZE));
26121
}
27122

28-
/* void initVectors(GC_state s, GC_thread thread) { */
29-
/* struct GC_vectorInit *inits; */
30-
/* HM_chunk currentChunk; */
31-
/* pointer frontier; */
32-
/* pointer limit; */
33-
/* uint32_t i; */
34-
35-
/* assert(isFrontierAligned(s, s->frontier)); */
36-
/* inits = s->vectorInits; */
37-
/* frontier = s->frontier; */
38-
/* limit = s->limitPlusSlop; */
39-
40-
/* currentChunk = HM_getChunkOf(frontier); */
41-
/* assert(currentChunk == thread->currentChunk); */
42-
/* assert(0 == thread->currentDepth); */
43-
44-
/* for (i = 0; i < s->vectorInitsLength; i++) { */
45-
/* size_t elementSize; */
46-
/* size_t dataBytes; */
47-
/* size_t objectSize; */
48-
/* uint32_t typeIndex; */
49-
50-
/* elementSize = inits[i].elementSize; */
51-
/* dataBytes = elementSize * inits[i].length; */
52-
/* objectSize = align(GC_SEQUENCE_METADATA_SIZE + dataBytes, s->alignment); */
53-
54-
/* #if ASSERT */
55-
/* assert(limit == HM_getChunkLimit(currentChunk)); */
56-
/* assert(frontier >= HM_getChunkFrontier(currentChunk)); */
57-
/* assert(frontier <= limit); */
58-
/* #endif */
59-
60-
/* /\* Extend with a new chunk, if there is not enough free space or if we have */
61-
/* * crossed a block boundary. *\/ */
62-
/* if ((size_t)(limit - frontier) < objectSize || */
63-
/* !inFirstBlockOfChunk(currentChunk, frontier + GC_SEQUENCE_METADATA_SIZE)) */
64-
/* { */
65-
/* HM_HH_updateValues(thread, frontier); */
66-
/* if (!HM_HH_extend(s, thread, objectSize)) { */
67-
/* DIE("Ran out of space for Hierarchical Heap!"); */
68-
/* } */
69-
/* s->frontier = HM_HH_getFrontier(thread); */
70-
/* s->limitPlusSlop = HM_HH_getLimit(thread); */
71-
/* s->limit = s->limitPlusSlop - GC_HEAP_LIMIT_SLOP; */
72-
73-
/* frontier = s->frontier; */
74-
/* limit = s->limitPlusSlop; */
75-
76-
/* currentChunk = HM_getChunkOf(frontier); */
77-
/* assert(currentChunk == thread->currentChunk); */
78-
/* } */
79-
80-
/* assert(isFrontierAligned(s, frontier)); */
81-
/* assert((size_t)(limit - frontier) >= objectSize); */
82-
/* assert(inFirstBlockOfChunk(currentChunk, frontier + GC_SEQUENCE_METADATA_SIZE)); */
83-
84-
/* *((GC_sequenceCounter*)(frontier)) = 0; */
85-
/* frontier = frontier + GC_SEQUENCE_COUNTER_SIZE; */
86-
/* *((GC_sequenceLength*)(frontier)) = inits[i].length; */
87-
/* frontier = frontier + GC_SEQUENCE_LENGTH_SIZE; */
88-
/* switch (elementSize) { */
89-
/* case 1: */
90-
/* typeIndex = WORD8_VECTOR_TYPE_INDEX; */
91-
/* break; */
92-
/* case 2: */
93-
/* typeIndex = WORD16_VECTOR_TYPE_INDEX; */
94-
/* break; */
95-
/* case 4: */
96-
/* typeIndex = WORD32_VECTOR_TYPE_INDEX; */
97-
/* break; */
98-
/* case 8: */
99-
/* typeIndex = WORD64_VECTOR_TYPE_INDEX; */
100-
/* break; */
101-
/* default: */
102-
/* die ("unknown element size in vectorInit: %"PRIuMAX"", */
103-
/* (uintmax_t)elementSize); */
104-
/* } */
105-
/* *((GC_header*)(frontier)) = buildHeaderFromTypeIndex (typeIndex); */
106-
/* frontier = frontier + GC_HEADER_SIZE; */
107-
/* // *((objptr*)(frontier)) = BOGUS_OBJPTR; */
108-
/* // frontier = frontier + OBJPTR_SIZE; */
109-
/* s->globals[inits[i].globalIndex] = pointerToObjptr(frontier, NULL); */
110-
/* if (DEBUG_DETAILED) */
111-
/* fprintf (stderr, "allocated vector at "FMTPTR"\n", */
112-
/* (uintptr_t)(s->globals[inits[i].globalIndex])); */
113-
/* memcpy (frontier, inits[i].words, dataBytes); */
114-
/* frontier += objectSize - GC_SEQUENCE_METADATA_SIZE; */
115-
/* } */
116-
117-
/* s->frontier = frontier; */
118-
119-
/* /\* If the last allocation passed a block boundary, we need to extend to have */
120-
/* * a valid frontier. Extending with GC_HEAP_LIMIT_SLOP is arbitrary. *\/ */
121-
/* if (!inFirstBlockOfChunk(currentChunk, frontier + GC_SEQUENCE_METADATA_SIZE)) */
122-
/* { */
123-
/* HM_HH_updateValues(thread, frontier); */
124-
/* if (!HM_HH_extend(s, thread, GC_HEAP_LIMIT_SLOP)) { */
125-
/* DIE("Ran out of space for Hierarchical Heap!"); */
126-
/* } */
127-
/* s->frontier = HM_HH_getFrontier(thread); */
128-
/* s->limitPlusSlop = HM_HH_getLimit(thread); */
129-
/* s->limit = s->limitPlusSlop - GC_HEAP_LIMIT_SLOP; */
130-
131-
/* frontier = s->frontier; */
132-
/* limit = s->limitPlusSlop; */
133-
134-
/* currentChunk = HM_getChunkOf(frontier); */
135-
/* assert(currentChunk == thread->currentChunk); */
136-
/* } */
137-
138-
/* assert(isFrontierAligned(s, s->frontier)); */
139-
/* assert(inFirstBlockOfChunk(currentChunk, s->frontier + GC_SEQUENCE_METADATA_SIZE)); */
140-
/* } */
141-
142123
GC_thread initThreadAndHeap(GC_state s, uint32_t depth) {
143124
GC_thread thread = newThreadWithHeap(s, sizeofStackInitialReserved(s), depth);
144125

0 commit comments

Comments
 (0)