[MLton] IntInf alignment
Matthew Fluet
fluet at tti-c.org
Mon Dec 18 18:00:03 PST 2006
I'm seeing an assertion failure when using IntInf operations.
fenrir:~/devel/mlton/mlton.svn.trunk/regression fluet$ ./conv2
gc/new-object.c:90: assert((size_t)(p - s->frontier) <= bytes) failed.
Abort trap
This is asserting that we didn't request enough bytes to accommodate
rolling the frontier forward to an aligned address. In this case, the
problematic function is IntInf_toString, which is requesting bytes equal
to
arrayHeaderSize
+ 1 (* for the sign character *)
+ (digitsPerLimb (* computed from base *)
* numLimbs)
In general, this number of bytes may not be aligned (either mod 4 or mod
8). Hence, we fail the assertion, and we could potentially be rolling
the frontier beyond the limit, which is o.k., so long as we don't roll
beyond limitPlusSlop. I don't believe that rolling beyond limitPlusSlop
can happen: we would have needed to request some number of bytes such
that before the allocation:
bytes <= limitPlusSlop - frontier
and
align(frontier + bytes) > limitPlusSlop
but limitPlusSlop - frontier will always be 0 mod alignment, so
align(frontier + bytes) can't roll beyond limitPlusSlop.
Nonetheless, we should really be really be requesting sufficient bytes
to accommodate post alignment of the frontier, and leave the assertion
as is.
Digging around some, I discovered a few other anomalies:
In limit-check.fun, the function bigAllocation (line 430) handles the
limit check for a C call with a large constant or a non-constant number
of bytesNeeded. In both cases, the heap check is made with a number of
bytes equal to the bytesNeeded of the C call plus the bytes in an array
header plus the number of bytes required by the block.
First, I don't understand why the number of bytes in an array header is
added for the heap check. The size of the header has always been
included in the bytesNeeded argument of the IntInf primitives. So, we
are performing a limit check with more bytes than necessary and all of
the assertion checks in the runtime are being performed with the
bytesNeeded argument of the primitives. So, I believe that the
arrayHeaderSize can be dropped from bigAllocation heap check.
Second, I don't see why the the RSSA program that results from inserting
limit checks is necessarily well-formed. In particular, an inserted
limit check always precedes (in the CFG) all of the statements and the
transfer in a block. But, a C call with bytesNeeded might compute the
bytesNeeded using the statements in the block for which it is a
transfer; so, the variables referenced by the limit check might be
inserted before they are assigned, violating the (R)SSA condition.
Clearly, this hasn't been a problem in practice, since the RSSA type
checker would reject such a program. However, I don't see why this
isn't a possibility.
In any case, for the immediate problem, I propose the following:
1) Require any primitive or C call with bytesNeeded to include
sufficient bytes for any necessary headers and alignment restrictions.
[The only primitives or C calls with bytesNeeded are the IntInf
operations, which already satisfy the former, but not the later.]
2) Remove the extraneous arrayHeaderSize from bigAllocation.
3) Include a _build_const: "MLton_Align_align", with the obvious meaning.
4) Modify the IntInf implementation to include sufficient bytes for the
necessary alignment.
We have a couple of options with 4. Since the bytesNeeded are just a
request (the actual IntInf object size and frontier alignment are
handled by the runtime), we can always request a little more than
necessary, saving some instructions in the computation of the
bytesNeeded. For example, we always request a byte for the sign
character in IntInf_toString (and constant-fold that needed byte with
the bytes needed for the string header), rather than checking the sign
of argument at runtime. We could do the same thing with regards to the
alignment; namely, always request an additional 3 bytes (for alignment
mod 4) or 7 bytes (for alignment mod 8). Furthermore, we can
constant-fold these with the other constant bytes needed.
Aligning the bytesNeeded according to the alignment isn't prohibitively
expensive, but I don't see a big advantage to doing so.
More information about the MLton
mailing list