mirror of
https://github.com/ganelson/inform.git
synced 2024-07-16 22:14:23 +03:00
720 lines
122 KiB
HTML
720 lines
122 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
|
<html>
|
|
<head>
|
|
<title>Flex Template</title>
|
|
<link href="../docs-assets/Breadcrumbs.css" rel="stylesheet" rev="stylesheet" type="text/css">
|
|
<meta name="viewport" content="width=device-width initial-scale=1">
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
<meta http-equiv="Content-Language" content="en-gb">
|
|
|
|
<link href="../docs-assets/Contents.css" rel="stylesheet" rev="stylesheet" type="text/css">
|
|
<link href="../docs-assets/Progress.css" rel="stylesheet" rev="stylesheet" type="text/css">
|
|
<link href="../docs-assets/Navigation.css" rel="stylesheet" rev="stylesheet" type="text/css">
|
|
<link href="../docs-assets/Fonts.css" rel="stylesheet" rev="stylesheet" type="text/css">
|
|
<link href="../docs-assets/Base.css" rel="stylesheet" rev="stylesheet" type="text/css">
|
|
<script>
|
|
MathJax = {
|
|
tex: {
|
|
inlineMath: '$', '$'], ['\\(', '\\)'
|
|
},
|
|
svg: {
|
|
fontCache: 'global'
|
|
}
|
|
};
|
|
</script>
|
|
<script type="text/javascript" id="MathJax-script" async
|
|
src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js">
|
|
</script>
|
|
|
|
<link href="../docs-assets/Colours.css" rel="stylesheet" rev="stylesheet" type="text/css">
|
|
|
|
</head>
|
|
<body class="commentary-font">
|
|
<nav role="navigation">
|
|
<h1><a href="../index.html">
|
|
<img src="../docs-assets/Inform.png" height=72">
|
|
</a></h1>
|
|
<ul><li><a href="../index.html">home</a></li>
|
|
</ul><h2>Compiler</h2><ul>
|
|
<li><a href="../structure.html">structure</a></li>
|
|
<li><a href="../inbuildn.html">inbuild</a></li>
|
|
<li><a href="../inform7n.html">inform7</a></li>
|
|
<li><a href="../intern.html">inter</a></li>
|
|
<li><a href="../services.html">services</a></li>
|
|
<li><a href="../secrets.html">secrets</a></li>
|
|
</ul><h2>Other Tools</h2><ul>
|
|
<li><a href="../inblorbn.html">inblorb</a></li>
|
|
<li><a href="../indocn.html">indoc</a></li>
|
|
<li><a href="../inform6.html">inform6</a></li>
|
|
<li><a href="../inpolicyn.html">inpolicy</a></li>
|
|
<li><a href="../inrtpsn.html">inrtps</a></li>
|
|
</ul><h2>Resources</h2><ul>
|
|
<li><a href="../extensions.html">extensions</a></li>
|
|
<li><a href="../kits.html">kits</a></li>
|
|
</ul><h2>Repository</h2><ul>
|
|
<li><a href="https://github.com/ganelson/inform"><img src="../docs-assets/github.png" height=18> github</a></li>
|
|
</ul><h2>Related Projects</h2><ul>
|
|
<li><a href="../../../inweb/index.html">inweb</a></li>
|
|
<li><a href="../../../intest/index.html">intest</a></li>
|
|
|
|
</ul>
|
|
</nav>
|
|
<main role="main">
|
|
<!--Weave of 'Flex Template' generated by Inweb-->
|
|
<div class="breadcrumbs">
|
|
<ul class="crumbs"><li><a href="../index.html">Home</a></li><li><a href="../extensions.html">Kits</a></li><li><a href="index.html">BasicInformKit</a></li><li><b>Flex Template</b></li></ul></div>
|
|
<p class="purpose">To allocate flexible-sized blocks of memory as needed to hold arbitrary-length strings of text, stored actions or other block values.</p>
|
|
|
|
<ul class="toc"><li><a href="S-flx.html#SP1">§1. Blocks</a></li><li><a href="S-flx.html#SP2">§2. Multiple Blocks</a></li><li><a href="S-flx.html#SP3">§3. The Heap</a></li><li><a href="S-flx.html#SP4">§4. Initialisation</a></li><li><a href="S-flx.html#SP5">§5. Net Free Space</a></li><li><a href="S-flx.html#SP6">§6. Make Space</a></li><li><a href="S-flx.html#SP7">§7. Block Allocation</a></li><li><a href="S-flx.html#SP8">§8. Errors</a></li><li><a href="S-flx.html#SP9">§9. Merging</a></li><li><a href="S-flx.html#SP10">§10. Recutting</a></li><li><a href="S-flx.html#SP11">§11. Deallocation</a></li><li><a href="S-flx.html#SP12">§12. Resizing</a></li><li><a href="S-flx.html#SP13">§13. Block Size</a></li><li><a href="S-flx.html#SP14">§14. Debugging Routines</a></li></ul><hr class="tocbar">
|
|
|
|
<p class="commentary firstcommentary"><a id="SP1" class="paragraph-anchor"></a><b>§1. Blocks. </b>The purpose of the Flex routines is to manage flexible-sized "blocks" of
|
|
memory for any general-purpose use. The main customer for this service is
|
|
the system for creating texts, lists, stored actions, and so on, which
|
|
are collectively called "block values" because they store their data in
|
|
blocks allocated by Flex. But in this section, we're just managing
|
|
arrays of memory, and don't need to know what it's for.
|
|
</p>
|
|
|
|
<p class="commentary">A "block" is a continuous range of \(2^n\) bytes of memory, where \(n\geq 3\)
|
|
for a 16-bit VM (i.e., for the Z-machine) and \(n\geq 4\) for a 32-bit VM
|
|
(i.e., on Glulx). Internally, a block is divided into a header followed
|
|
by a data section.
|
|
</p>
|
|
|
|
<p class="commentary">The header size depends on the word size and the kind of block (see below). It
|
|
always begins with a byte specifying \(n\), the binary logarithm of its size,
|
|
except that if the top bit is set then we know this isn't a flex-allocated
|
|
block, which turns out to be convenient. Thus the largest block representable
|
|
is \(2^{127}\) bytes long, but somehow I think we can live with that. The second
|
|
byte contains a bitmap of (at present) four flags, whose meanings will be
|
|
explained below. The second {\it word} of the block, which might be at byte
|
|
offset 2 or 4 from the start of the block depending on the word-size of the
|
|
VM, is a number specifying the kind of value (if any) which the block contains
|
|
data of.
|
|
</p>
|
|
|
|
<p class="commentary">The header also contains a weak kind ID and a reference count, but the Flex
|
|
routines do nothing with either of these except to initialise them; they're
|
|
provided for the benefit of the <span class="extract"><span class="extract-syntax">BlockValue</span></span> system.
|
|
</p>
|
|
|
|
<p class="commentary">The data section of a block begins at the byte offset <span class="extract"><span class="extract-syntax">BLK_DATA_OFFSET</span></span>
|
|
from the address of the block: but see below for how multiple-blocks
|
|
behave differently.
|
|
</p>
|
|
|
|
<p class="commentary">These definitions must not be altered without making matching changes
|
|
to the compiler.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax"> = </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
|
|
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax"> = </span><span class="constant-syntax">$$00000001</span><span class="plain-syntax">;</span>
|
|
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_FLAG_16_BIT</span><span class="plain-syntax"> = </span><span class="constant-syntax">$$00000010</span><span class="plain-syntax">;</span>
|
|
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_FLAG_WORD</span><span class="plain-syntax"> = </span><span class="constant-syntax">$$00000100</span><span class="plain-syntax">;</span>
|
|
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_FLAG_RESIDENT</span><span class="plain-syntax"> = </span><span class="constant-syntax">$$00001000</span><span class="plain-syntax">;</span>
|
|
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_FLAG_TRUNCMULT</span><span class="plain-syntax"> = </span><span class="constant-syntax">$$00010000</span><span class="plain-syntax">;</span>
|
|
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax"> = </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
|
|
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_HEADER_RCOUNT</span><span class="plain-syntax"> = </span><span class="constant-syntax">2</span><span class="plain-syntax">;</span>
|
|
|
|
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax"> = </span><span class="constant-syntax">3</span><span class="plain-syntax">*</span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">;</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><a id="SP2" class="paragraph-anchor"></a><b>§2. Multiple Blocks. </b>Some of the data we want to store will be fixed in size, but some of it will
|
|
need to expand or contract. The latter can change unpredictably in size and
|
|
might at any point overflow their current storage, so they're stored in a
|
|
doubly linked list of blocks. The pointer to such a flexible-length array is
|
|
by definition the pointer to the block heading this linked list. For instance,
|
|
the data in a text
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="plain-syntax"> </span><span class="string-syntax">"But now I worship a celestiall Sunne"</span>
|
|
</pre>
|
|
<p class="commentary">might be stored in a list of blocks like so:
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">NULL</span><span class="plain-syntax"> <-- </span><span class="identifier-syntax">BN</span><span class="plain-syntax">: </span><span class="string-syntax">"But now I wor"</span><span class="plain-syntax"> <--> </span><span class="identifier-syntax">BN2</span><span class="plain-syntax">: </span><span class="string-syntax">"ship a celestiall Sunne"</span><span class="plain-syntax"> --> </span><span class="identifier-syntax">NULL</span>
|
|
</pre>
|
|
<p class="commentary">Note that the unique pointer to <span class="extract"><span class="extract-syntax">BN2</span></span> is the one in the header of the
|
|
<span class="extract"><span class="extract-syntax">BN</span></span> block. When we need to grow such a text, we add additional blocks;
|
|
if the text should shrink, blocks at the end can at our discretion be
|
|
deallocated. If the entire text should be deallocated, then all of the
|
|
blocks used for it are deallocated, starting at the back and working
|
|
towards the front.
|
|
</p>
|
|
|
|
<p class="commentary">A multiple-block is one whose flags byte contains the <span class="extract"><span class="extract-syntax">BLK_FLAG_MULTIPLE</span></span>.
|
|
This information is redundant since it could in principle be deduced from
|
|
the kind of value stored in the block, which is recorded in the
|
|
<span class="extract"><span class="extract-syntax">-->BLK_HEADER_KOV</span></span> word, but that would be too slow. <span class="extract"><span class="extract-syntax">BLK_FLAG_MULTIPLE</span></span>
|
|
can never change for a currently allocated block, just as it can never
|
|
change its KOV.
|
|
</p>
|
|
|
|
<p class="commentary">A multiple-block header is longer than that of an ordinary block, because
|
|
it contains two extra words: <span class="extract"><span class="extract-syntax">-->BLK_NEXT</span></span> is the next block in the
|
|
doubly-linked list of blocks representing the current value, or <span class="extract"><span class="extract-syntax">NULL</span></span>
|
|
if this is the end; <span class="extract"><span class="extract-syntax">-->BLK_PREV</span></span> is the previous block, or <span class="extract"><span class="extract-syntax">NULL</span></span> if this
|
|
is the beginning. The need to fit these two extra words in means that the
|
|
data section is deferred, and so for a multiple-block data begins at the
|
|
byte offset <span class="extract"><span class="extract-syntax">BLK_DATA_MULTI_OFFSET</span></span> rather than <span class="extract"><span class="extract-syntax">BLK_DATA_OFFSET</span></span>.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_DATA_MULTI_OFFSET</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax"> + </span><span class="constant-syntax">2</span><span class="plain-syntax">*</span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">;</span>
|
|
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> </span><span class="constant-syntax">3</span><span class="plain-syntax">;</span>
|
|
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> </span><span class="constant-syntax">4</span><span class="plain-syntax">;</span>
|
|
|
|
<span class="comment-syntax">Constant BLKVALUE_TRACE = 1; ! Uncomment this for debugging purposes</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><a id="SP3" class="paragraph-anchor"></a><b>§3. The Heap. </b>Properly speaking, a "heap" is a specific kind of structure often used for
|
|
managing uneven-sized or unpredictably changing data. We use "heap" here in
|
|
the looser sense of being an amorphous-sized collection of blocks of memory,
|
|
some free, others allocated; our actual representation of free space on the
|
|
heap is not a heap structure in computer science terms. (Though this segment
|
|
could easily be rewritten to make it so, or to adopt any other scheme which
|
|
might be faster.) The heap begins as a contiguous region of memory, but it
|
|
need not remain so: on Glulx we use dynamic memory allocation to extend it.
|
|
</p>
|
|
|
|
<p class="commentary">For I7 purposes we don't need a way to represent allocated memory, only
|
|
the free memory. A block is free if and only if it has <span class="extract"><span class="extract-syntax">-->BLK_HEADER_KOV</span></span>
|
|
equal to 0, which is never a valid kind of value, and also has the multiple
|
|
flag set. We do that because we construct the whole collection of free
|
|
blocks, at any given time, as a single, multiple-block "value": a doubly
|
|
linked list joined by the <span class="extract"><span class="extract-syntax">-->BLK_NEXT</span></span> and <span class="extract"><span class="extract-syntax"><--BLK_PREV</span></span>.
|
|
</p>
|
|
|
|
<p class="commentary">A single block, at the bottom of memory and never moving, never allocated
|
|
to anyone, is preserved in order to be the head of this linked list of
|
|
free blocks. This is a 16-byte (i.e., \(n=4\)) block, which we format when
|
|
the heap is initialised in <span class="extract"><span class="extract-syntax">HeapInitialise()</span></span>. Thus the heap is full
|
|
if and only if the <span class="extract"><span class="extract-syntax">-->BLK_NEXT</span></span> of the head-free-block is <span class="extract"><span class="extract-syntax">NULL</span></span>.
|
|
</p>
|
|
|
|
<p class="commentary">So far we have described a somewhat lax regime. After many allocations and
|
|
deallocations one could imagine the list of free blocks becoming a very
|
|
long list of individually small blocks, which would both make it difficult
|
|
to allocate large blocks, and also slow to look through the list. To
|
|
ameliorate matters, we maintain the following invariants:
|
|
</p>
|
|
|
|
<ul class="items"><li>(a) In the free blocks list, <span class="extract"><span class="extract-syntax">B-->BLK_NEXT</span></span> is always an address after <span class="extract"><span class="extract-syntax">B</span></span>;
|
|
</li><li>(b) For any contiguous run of free space blocks in memory (excluding the
|
|
head-free-block), taking up a total of \(T\) bytes, the last block in the run
|
|
has size \(2^n\) where \(n\) is the largest integer such that \(2^n\leq T\).
|
|
</li></ul>
|
|
<p class="commentary">For instance, there can never be two consecutive free blocks of size 128:
|
|
they would form a "run" in the sense of rule (b) of size \(T = 256\), and
|
|
when \(T\) is a power of two the run must contain a single block. In general,
|
|
it's easy to prove that the number of blocks in the run is exactly the
|
|
number of 1s when \(T\) is written out as a binary number, and that the
|
|
blocks are ordered in memory from small to large (the reverse of the
|
|
direction of reading, i.e., rightmost 1 digit first). Maintaining (b)
|
|
is a matter of being careful to fragment blocks only from the front when
|
|
smaller blocks are needed, and to rejoin from the back when blocks are
|
|
freed and added to the free space object.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="reserved-syntax">Array</span><span class="plain-syntax"> </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax"> -> (</span><span class="identifier-syntax">MEMORY_HEAP_SIZE</span><span class="plain-syntax"> + </span><span class="constant-syntax">16</span><span class="plain-syntax">); </span><span class="comment-syntax">Plus 16 to allow room for head-free-block</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><a id="SP4" class="paragraph-anchor"></a><b>§4. Initialisation. </b>To recap: the constant <span class="extract"><span class="extract-syntax">MEMORY_HEAP_SIZE</span></span> has been predefined by the Inform compiler,
|
|
and is always itself a power of 2, say \(2^n\). We therefore have \(2^n + 2^4\)
|
|
bytes available to us, and we format these as a free space list of two
|
|
blocks: the \(2^4\)-sized "head-free-block" described above followed by
|
|
a \(2^n\)-sized block exactly containing the whole of the rest of the heap.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="plain-syntax">[ </span><span class="identifier-syntax">HeapInitialise</span><span class="plain-syntax"> </span><span class="identifier-syntax">n</span><span class="plain-syntax"> </span><span class="identifier-syntax">bsize</span><span class="plain-syntax"> </span><span class="identifier-syntax">blk2</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">blk2</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax"> + </span><span class="constant-syntax">16</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax"> = </span><span class="constant-syntax">4</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_HEADER_RCOUNT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">MAX_POSITIVE_NUMBER</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">blk2</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">bsize</span><span class="plain-syntax">=1: </span><span class="identifier-syntax">bsize</span><span class="plain-syntax"> < </span><span class="identifier-syntax">MEMORY_HEAP_SIZE</span><span class="plain-syntax">: </span><span class="identifier-syntax">bsize</span><span class="plain-syntax">=</span><span class="identifier-syntax">bsize</span><span class="plain-syntax">*2) </span><span class="identifier-syntax">n</span><span class="plain-syntax">++;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">blk2</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax"> = </span><span class="identifier-syntax">n</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">blk2</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">blk2</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_HEADER_RCOUNT</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">blk2</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">blk2</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">blk2</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">];</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><a id="SP5" class="paragraph-anchor"></a><b>§5. Net Free Space. </b>"Net" in the sense of "after deductions for the headers": this is the
|
|
actual number of free bytes left on the heap which could be used for data.
|
|
Note that it is used to predict whether it is possible to fit something
|
|
further in: so there are two answers, depending on whether the something
|
|
is multiple-block data (with a larger header and therefore less room for
|
|
data) or single-block data (smaller header, more room).
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="plain-syntax">[ </span><span class="identifier-syntax">HeapNetFreeSpace</span><span class="plain-syntax"> </span><span class="identifier-syntax">multiple</span><span class="plain-syntax"> </span><span class="identifier-syntax">txb</span><span class="plain-syntax"> </span><span class="identifier-syntax">asize</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">txb</span><span class="plain-syntax">=</span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">: </span><span class="identifier-syntax">txb</span><span class="plain-syntax">~=</span><span class="identifier-syntax">NULL</span><span class="plain-syntax">: </span><span class="identifier-syntax">txb</span><span class="plain-syntax">=</span><span class="identifier-syntax">txb</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> + </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">txb</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">multiple</span><span class="plain-syntax">) </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> - </span><span class="identifier-syntax">BLK_DATA_MULTI_OFFSET</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> - </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">asize</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">];</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><a id="SP6" class="paragraph-anchor"></a><b>§6. Make Space. </b>The following routine determines if there is enough free space to accommodate
|
|
another <span class="extract"><span class="extract-syntax">size</span></span> bytes of data, given that it has to be multiple-block data if
|
|
the <span class="extract"><span class="extract-syntax">multiple</span></span> flag is set. If the answer turns out to be "no", we see if
|
|
the host virtual machine is able to allocate more for us: if it is, then
|
|
we ask for \(2^m\) further bytes, where \(2^m\) is at least <span class="extract"><span class="extract-syntax">size</span></span> plus the
|
|
worst-case header storage requirement (16 bytes), and in addition is large
|
|
enough to make it worth while allocating. We don't want to bother the VM
|
|
by asking for trivial amounts of memory.
|
|
</p>
|
|
|
|
<p class="commentary">This looks to be more memory than is needed, since after all we've asked
|
|
for enough that the new data can fit entirely into the new block allocated,
|
|
and we might have been able to squeeze some of it into the existing free
|
|
space. But it ensures that heap invariant (b) above is preserved, and
|
|
besides, running out of memory tends to be something you don't do only once.
|
|
</p>
|
|
|
|
<p class="commentary">(The code below is a refinement on the original, suggested by Jesse McGrew,
|
|
which handles non-multiple blocks better.)
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">SMALLEST_BLK_WORTH_ALLOCATING</span><span class="plain-syntax"> = </span><span class="constant-syntax">12</span><span class="plain-syntax">; </span><span class="comment-syntax">i.e. 2^12 = 4096 bytes</span>
|
|
|
|
<span class="plain-syntax">[ </span><span class="identifier-syntax">HeapMakeSpace</span><span class="plain-syntax"> </span><span class="identifier-syntax">size</span><span class="plain-syntax"> </span><span class="identifier-syntax">multiple</span><span class="plain-syntax"> </span><span class="identifier-syntax">newblocksize</span><span class="plain-syntax"> </span><span class="identifier-syntax">newblock</span><span class="plain-syntax"> </span><span class="identifier-syntax">B</span><span class="plain-syntax"> </span><span class="identifier-syntax">n</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (::) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">multiple</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">HeapNetFreeSpace</span><span class="plain-syntax">(</span><span class="identifier-syntax">multiple</span><span class="plain-syntax">) >= </span><span class="identifier-syntax">size</span><span class="plain-syntax">) </span><span class="reserved-syntax">rtrue</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">HeapLargestFreeBlock</span><span class="plain-syntax">(0) >= </span><span class="identifier-syntax">size</span><span class="plain-syntax">) </span><span class="reserved-syntax">rtrue</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">newblocksize</span><span class="plain-syntax"> = </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">n</span><span class="plain-syntax">=0: (</span><span class="identifier-syntax">n</span><span class="plain-syntax"><</span><span class="identifier-syntax">SMALLEST_BLK_WORTH_ALLOCATING</span><span class="plain-syntax">) || (</span><span class="identifier-syntax">newblocksize</span><span class="plain-syntax"><</span><span class="identifier-syntax">size</span><span class="plain-syntax">): </span><span class="identifier-syntax">n</span><span class="plain-syntax">++)</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">newblocksize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">newblocksize</span><span class="plain-syntax">*2;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">while</span><span class="plain-syntax"> (</span><span class="identifier-syntax">newblocksize</span><span class="plain-syntax"> < </span><span class="identifier-syntax">size</span><span class="plain-syntax">+16) </span><span class="identifier-syntax">newblocksize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">newblocksize</span><span class="plain-syntax">*2;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">newblock</span><span class="plain-syntax"> = </span><span class="identifier-syntax">VM_AllocateMemory</span><span class="plain-syntax">(</span><span class="identifier-syntax">newblocksize</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">newblock</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">rfalse</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">newblock</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax"> = </span><span class="identifier-syntax">n</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">newblock</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">newblock</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_HEADER_RCOUNT</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">newblock</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">newblock</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">newblock</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">B</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">:</span><span class="identifier-syntax">B</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">:</span><span class="identifier-syntax">B</span><span class="plain-syntax"> = </span><span class="identifier-syntax">B</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">)</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">B</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">B</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">newblock</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">newblock</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">B</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">jump</span><span class="plain-syntax"> </span><span class="identifier-syntax">Linked</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">newblock</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">newblock</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> .</span><span class="identifier-syntax">Linked</span><span class="plain-syntax">; ;</span>
|
|
<span class="plain-syntax"> #</span><span class="identifier-syntax">ifdef</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLKVALUE_TRACE</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"Increasing heap to free space map: "</span><span class="plain-syntax">; </span><span class="identifier-syntax">FlexDebugDecomposition</span><span class="plain-syntax">(</span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">, </span><span class="constant-syntax">0</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> #</span><span class="identifier-syntax">endif</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">rtrue</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">];</span>
|
|
|
|
<span class="plain-syntax">[ </span><span class="identifier-syntax">HeapLargestFreeBlock</span><span class="plain-syntax"> </span><span class="identifier-syntax">multiple</span><span class="plain-syntax"> </span><span class="identifier-syntax">txb</span><span class="plain-syntax"> </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> </span><span class="identifier-syntax">best</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">best</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">txb</span><span class="plain-syntax">=</span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">: </span><span class="identifier-syntax">txb</span><span class="plain-syntax">~=</span><span class="identifier-syntax">NULL</span><span class="plain-syntax">: </span><span class="identifier-syntax">txb</span><span class="plain-syntax">=</span><span class="identifier-syntax">txb</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">txb</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">multiple</span><span class="plain-syntax">) </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> - </span><span class="identifier-syntax">BLK_DATA_MULTI_OFFSET</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> - </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">asize</span><span class="plain-syntax"> > </span><span class="identifier-syntax">best</span><span class="plain-syntax">) </span><span class="identifier-syntax">best</span><span class="plain-syntax"> = </span><span class="identifier-syntax">asize</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">best</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">];</span>
|
|
|
|
<span class="plain-syntax">[ </span><span class="identifier-syntax">HeapDebug</span><span class="plain-syntax"> </span><span class="identifier-syntax">full</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">full</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"Managing a heap of initially "</span><span class="plain-syntax">, </span><span class="identifier-syntax">MEMORY_HEAP_SIZE</span><span class="plain-syntax">+16, </span><span class="string-syntax">" bytes.^"</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="identifier-syntax">HeapNetFreeSpace</span><span class="plain-syntax">(</span><span class="reserved-syntax">false</span><span class="plain-syntax">), </span><span class="string-syntax">" bytes currently free.^"</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"Free space decomposition: "</span><span class="plain-syntax">; </span><span class="identifier-syntax">FlexDebugDecomposition</span><span class="plain-syntax">(</span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"Free space map: "</span><span class="plain-syntax">; </span><span class="identifier-syntax">FlexDebug</span><span class="plain-syntax">(</span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="identifier-syntax">HeapNetFreeSpace</span><span class="plain-syntax">(</span><span class="reserved-syntax">false</span><span class="plain-syntax">), </span><span class="string-syntax">" of "</span><span class="plain-syntax">, </span><span class="identifier-syntax">MEMORY_HEAP_SIZE</span><span class="plain-syntax">+16, </span><span class="string-syntax">" bytes free.^"</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax">];</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><a id="SP7" class="paragraph-anchor"></a><b>§7. Block Allocation. </b>Now for the Flex routines. Those with names ending in <span class="extract"><span class="extract-syntax">Internal</span></span> are private
|
|
and should only be called by other Flex routines. Even the public ones must
|
|
be used with care, or memory leaks or crashes will occur.
|
|
</p>
|
|
|
|
<p class="commentary">The routine <span class="extract"><span class="extract-syntax">FlexAllocate(N, K, F)</span></span> allocates a block with room for <span class="extract"><span class="extract-syntax">size</span></span>
|
|
net bytes of data, which will have kind of value <span class="extract"><span class="extract-syntax">K</span></span> and with flags <span class="extract"><span class="extract-syntax">F</span></span>. If
|
|
the flags include <span class="extract"><span class="extract-syntax">BLK_FLAG_MULTIPLE</span></span>, this may be either a list of blocks
|
|
or a single block. It returns either the address of the block or else throws
|
|
run-time problem message and returns 0.
|
|
</p>
|
|
|
|
<p class="commentary">If it does succeed and return a nonzero address, then the caller must be
|
|
able to guarantee that <span class="extract"><span class="extract-syntax">FlexFree</span></span> will later be called, exactly once, on
|
|
this address. In other words, <span class="extract"><span class="extract-syntax">FlexAllocate</span></span> and <span class="extract"><span class="extract-syntax">FlexFree</span></span> behave somewhat
|
|
like C's <span class="extract"><span class="extract-syntax">malloc</span></span> and <span class="extract"><span class="extract-syntax">free</span></span> routines, with all the advantages and hazards
|
|
that implies.
|
|
</p>
|
|
|
|
<p class="commentary">In allocation, we try to find a block which is as close as possible to the
|
|
right size, and we may have to subdivide blocks: see case II below. For
|
|
instance, if a block of size \(2^n\) is available and we only need a block of
|
|
size \(2^k\) where \(k<n\) then we break it up in memory as a sequence of
|
|
blocks of size \(2^k, 2^k, 2^{k+1}, 2^{k+2}, ..., 2^{n-1}\): note that the
|
|
sum of these sizes is the \(2^n\) we started with. We then use the first
|
|
block of size \(2^k\). To continue the comparison with binary arithmetic,
|
|
this is like a subtraction with repeated carries:
|
|
$$ 10000000_2 - 00001000_2 = 01111000_2 $$
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexAllocate</span><span class="plain-syntax"> </span><span class="identifier-syntax">size</span><span class="plain-syntax"> </span><span class="identifier-syntax">kov</span><span class="plain-syntax"> </span><span class="identifier-syntax">flags</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">dsize</span><span class="plain-syntax"> </span><span class="identifier-syntax">n</span><span class="plain-syntax"> </span><span class="identifier-syntax">m</span><span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax"> </span><span class="identifier-syntax">min_m</span><span class="plain-syntax"> </span><span class="identifier-syntax">max_m</span><span class="plain-syntax"> </span><span class="identifier-syntax">smallest_oversized_block</span><span class="plain-syntax"> </span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax"> </span><span class="identifier-syntax">hsize</span><span class="plain-syntax"> </span><span class="identifier-syntax">head</span><span class="plain-syntax"> </span><span class="identifier-syntax">tail</span><span class="plain-syntax">;</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">HeapMakeSpace</span><span class="plain-syntax">(</span><span class="identifier-syntax">size</span><span class="plain-syntax">, </span><span class="identifier-syntax">flags</span><span class="plain-syntax"> & </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">) == </span><span class="reserved-syntax">false</span><span class="plain-syntax">) </span><span class="identifier-syntax">FlexError</span><span class="plain-syntax">(</span><span class="string-syntax">"ran out"</span><span class="plain-syntax">);</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">Calculate the header size for a block of this KOV</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> & </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">) </span><span class="identifier-syntax">hsize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_DATA_MULTI_OFFSET</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="identifier-syntax">hsize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">Calculate the data size</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">n</span><span class="plain-syntax">=0; </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">dsize</span><span class="plain-syntax">=1: ((</span><span class="identifier-syntax">dsize</span><span class="plain-syntax"> < </span><span class="identifier-syntax">hsize</span><span class="plain-syntax">+</span><span class="identifier-syntax">size</span><span class="plain-syntax">) || (</span><span class="identifier-syntax">n</span><span class="plain-syntax"><3+(</span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">/2))): </span><span class="identifier-syntax">dsize</span><span class="plain-syntax">=</span><span class="identifier-syntax">dsize</span><span class="plain-syntax">*2) </span><span class="identifier-syntax">n</span><span class="plain-syntax">++;</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">Seek a free block closest to the correct size, but starting from the</span>
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">block after the fixed head-free-block, which we can't touch</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">min_m</span><span class="plain-syntax"> = </span><span class="constant-syntax">10000</span><span class="plain-syntax">; </span><span class="identifier-syntax">max_m</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">free_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">:</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">:</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">m</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">Current block the ideal size</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">m</span><span class="plain-syntax"> == </span><span class="identifier-syntax">n</span><span class="plain-syntax">) </span><span class="reserved-syntax">jump</span><span class="plain-syntax"> </span><span class="identifier-syntax">CorrectSizeFound</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">Current block too large: find the smallest which is larger than needed</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">m</span><span class="plain-syntax"> > </span><span class="identifier-syntax">n</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">min_m</span><span class="plain-syntax"> > </span><span class="identifier-syntax">m</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">min_m</span><span class="plain-syntax"> = </span><span class="identifier-syntax">m</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">smallest_oversized_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">Current block too small: find the largest which is smaller than needed</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">m</span><span class="plain-syntax"> < </span><span class="identifier-syntax">n</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">max_m</span><span class="plain-syntax"> < </span><span class="identifier-syntax">m</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">max_m</span><span class="plain-syntax"> = </span><span class="identifier-syntax">m</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> }</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">min_m</span><span class="plain-syntax"> == </span><span class="constant-syntax">10000</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">Case I: No block is large enough to hold the entire size</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> & </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">FlexError</span><span class="plain-syntax">(</span><span class="string-syntax">"too fragmented"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">Set dsize to the size in bytes if the largest block available</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">dsize</span><span class="plain-syntax">=1: </span><span class="identifier-syntax">max_m</span><span class="plain-syntax"> > </span><span class="constant-syntax">0</span><span class="plain-syntax">: </span><span class="identifier-syntax">dsize</span><span class="plain-syntax">=</span><span class="identifier-syntax">dsize</span><span class="plain-syntax">*2) </span><span class="identifier-syntax">max_m</span><span class="plain-syntax">--;</span>
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">Split as a head (dsize-hsize), which we can be sure fits into one block,</span>
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">plus a tail (size-(dsize-hsize), which might be a list of blocks</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">head</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FlexAllocate</span><span class="plain-syntax">(</span><span class="identifier-syntax">dsize</span><span class="plain-syntax">-</span><span class="identifier-syntax">hsize</span><span class="plain-syntax">, </span><span class="identifier-syntax">kov</span><span class="plain-syntax">, </span><span class="identifier-syntax">flags</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">head</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">FlexError</span><span class="plain-syntax">(</span><span class="string-syntax">"for head block not available"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">tail</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FlexAllocate</span><span class="plain-syntax">(</span><span class="identifier-syntax">size</span><span class="plain-syntax">-(</span><span class="identifier-syntax">dsize</span><span class="plain-syntax">-</span><span class="identifier-syntax">hsize</span><span class="plain-syntax">), </span><span class="identifier-syntax">kov</span><span class="plain-syntax">, </span><span class="identifier-syntax">flags</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">tail</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">FlexError</span><span class="plain-syntax">(</span><span class="string-syntax">"for tail block not available"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">head</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">tail</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">tail</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">head</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">head</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">Case II: No block is the right size, but some exist which are too big</span>
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">Set dsize to the size in bytes of the smallest oversized block</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">dsize</span><span class="plain-syntax">=1,</span><span class="identifier-syntax">m</span><span class="plain-syntax">=1: </span><span class="identifier-syntax">m</span><span class="plain-syntax"><=</span><span class="identifier-syntax">min_m</span><span class="plain-syntax">: </span><span class="identifier-syntax">dsize</span><span class="plain-syntax">=</span><span class="identifier-syntax">dsize</span><span class="plain-syntax">*2) </span><span class="identifier-syntax">m</span><span class="plain-syntax">++;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">smallest_oversized_block</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">while</span><span class="plain-syntax"> (</span><span class="identifier-syntax">min_m</span><span class="plain-syntax"> > </span><span class="identifier-syntax">n</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">Repeatedly halve free_block at the front until the two smallest</span>
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">fragments left are the correct size: then take the frontmost</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">dsize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">dsize</span><span class="plain-syntax">/2;</span>
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">print "Halving size to ", dsize, "^";</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax"> + </span><span class="identifier-syntax">dsize</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">)</span>
|
|
<span class="plain-syntax"> (</span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">)--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax"> = (</span><span class="identifier-syntax">free_block</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax">) - </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_HEADER_RCOUNT</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">min_m</span><span class="plain-syntax">--;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">Once that is done, free_block points to a block which is exactly the</span>
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">right size, so we can fall into...</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">Case III: There is a free block which has the correct size.</span>
|
|
<span class="plain-syntax"> .</span><span class="identifier-syntax">CorrectSizeFound</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">Delete the free block from the double linked list of free blocks: note</span>
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">that it cannot be the head of this list, which is fixed</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">We remove final block, so previous is now final</span>
|
|
<span class="plain-syntax"> (</span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax">)--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">We remove a middle block, so join previous to next</span>
|
|
<span class="plain-syntax"> (</span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax">)--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> (</span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">)--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">KindAtomic</span><span class="plain-syntax">(</span><span class="identifier-syntax">kov</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_HEADER_RCOUNT</span><span class="plain-syntax"> = </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax"> = </span><span class="identifier-syntax">flags</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> & </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="comment-syntax">Zero out the data bytes in the memory allocated</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">i</span><span class="plain-syntax">=</span><span class="identifier-syntax">hsize</span><span class="plain-syntax">:</span><span class="identifier-syntax">i</span><span class="plain-syntax"><</span><span class="identifier-syntax">dsize</span><span class="plain-syntax">:</span><span class="identifier-syntax">i</span><span class="plain-syntax">++) </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">-></span><span class="identifier-syntax">i</span><span class="plain-syntax">=0;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">];</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><a id="SP8" class="paragraph-anchor"></a><b>§8. Errors. </b>In the event that <span class="extract"><span class="extract-syntax">FlexAllocate</span></span> returns 0, the caller may not be able
|
|
to survive, so the following is provided as a standardised way to halt
|
|
the virtual machine.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexError</span><span class="plain-syntax"> </span><span class="identifier-syntax">reason</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"*** Memory "</span><span class="plain-syntax">, (</span><span class="reserved-syntax">string</span><span class="plain-syntax">) </span><span class="identifier-syntax">reason</span><span class="plain-syntax">, </span><span class="string-syntax">" ***^"</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">RunTimeProblem</span><span class="plain-syntax">(</span><span class="identifier-syntax">RTP_HEAPERROR</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> @</span><span class="reserved-syntax">quit</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">];</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><a id="SP9" class="paragraph-anchor"></a><b>§9. Merging. </b>Given a free block <span class="extract"><span class="extract-syntax">block</span></span>, find the maximal contiguous run of free blocks
|
|
which contains it, and then call <span class="extract"><span class="extract-syntax">FlexRecutInternal</span></span> to recut it to conform to
|
|
invariant (b) above.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexMergeInternal</span><span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax"> </span><span class="identifier-syntax">first</span><span class="plain-syntax"> </span><span class="identifier-syntax">last</span><span class="plain-syntax"> </span><span class="identifier-syntax">pv</span><span class="plain-syntax"> </span><span class="identifier-syntax">nx</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">first</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">; </span><span class="identifier-syntax">last</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">while</span><span class="plain-syntax"> (</span><span class="identifier-syntax">last</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> == </span><span class="identifier-syntax">last</span><span class="plain-syntax">+</span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">last</span><span class="plain-syntax">))</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">last</span><span class="plain-syntax"> = </span><span class="identifier-syntax">last</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">while</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">first</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> + </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">first</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax">) == </span><span class="identifier-syntax">first</span><span class="plain-syntax">) &&</span>
|
|
<span class="plain-syntax"> (</span><span class="identifier-syntax">first</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">))</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">first</span><span class="plain-syntax"> = </span><span class="identifier-syntax">first</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">pv</span><span class="plain-syntax"> = </span><span class="identifier-syntax">first</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">nx</span><span class="plain-syntax"> = </span><span class="identifier-syntax">last</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> #</span><span class="identifier-syntax">ifdef</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLKVALUE_TRACE</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"Merging: "</span><span class="plain-syntax">; </span><span class="identifier-syntax">FlexDebugDecomposition</span><span class="plain-syntax">(</span><span class="identifier-syntax">pv</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">, </span><span class="identifier-syntax">nx</span><span class="plain-syntax">); </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"^"</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> #</span><span class="identifier-syntax">endif</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">FlexRecutInternal</span><span class="plain-syntax">(</span><span class="identifier-syntax">first</span><span class="plain-syntax">, </span><span class="identifier-syntax">last</span><span class="plain-syntax">)) {</span>
|
|
<span class="plain-syntax"> #</span><span class="identifier-syntax">ifdef</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLKVALUE_TRACE</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">" --> "</span><span class="plain-syntax">; </span><span class="identifier-syntax">FlexDebugDecomposition</span><span class="plain-syntax">(</span><span class="identifier-syntax">pv</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">, </span><span class="identifier-syntax">nx</span><span class="plain-syntax">); </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"^"</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> #</span><span class="identifier-syntax">endif</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax">];</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><a id="SP10" class="paragraph-anchor"></a><b>§10. Recutting. </b>Given a segment of the free block list, containing blocks known to be contiguous
|
|
in memory, we recut into a sequence of blocks satisfying invariant (b): we
|
|
repeatedly cut the largest \(2^m\)-sized chunk off the back end until it is all
|
|
used up.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexRecutInternal</span><span class="plain-syntax"> </span><span class="identifier-syntax">first</span><span class="plain-syntax"> </span><span class="identifier-syntax">last</span><span class="plain-syntax"> </span><span class="identifier-syntax">tsize</span><span class="plain-syntax"> </span><span class="identifier-syntax">backsize</span><span class="plain-syntax"> </span><span class="identifier-syntax">mfrom</span><span class="plain-syntax"> </span><span class="identifier-syntax">mto</span><span class="plain-syntax"> </span><span class="identifier-syntax">bnext</span><span class="plain-syntax"> </span><span class="identifier-syntax">backend</span><span class="plain-syntax"> </span><span class="identifier-syntax">n</span><span class="plain-syntax"> </span><span class="identifier-syntax">dsize</span><span class="plain-syntax"> </span><span class="identifier-syntax">fine_so_far</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">first</span><span class="plain-syntax"> == </span><span class="identifier-syntax">last</span><span class="plain-syntax">) </span><span class="reserved-syntax">rfalse</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">mfrom</span><span class="plain-syntax"> = </span><span class="identifier-syntax">first</span><span class="plain-syntax">; </span><span class="identifier-syntax">mto</span><span class="plain-syntax"> = </span><span class="identifier-syntax">last</span><span class="plain-syntax"> + </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">last</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">bnext</span><span class="plain-syntax"> = </span><span class="identifier-syntax">last</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">fine_so_far</span><span class="plain-syntax"> = </span><span class="reserved-syntax">true</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (:</span><span class="identifier-syntax">mto</span><span class="plain-syntax">></span><span class="identifier-syntax">mfrom</span><span class="plain-syntax">: </span><span class="identifier-syntax">mto</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mto</span><span class="plain-syntax"> - </span><span class="identifier-syntax">backsize</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">n</span><span class="plain-syntax">=0, </span><span class="identifier-syntax">backsize</span><span class="plain-syntax">=1: </span><span class="identifier-syntax">backsize</span><span class="plain-syntax">*2 <= </span><span class="identifier-syntax">mto</span><span class="plain-syntax">-</span><span class="identifier-syntax">mfrom</span><span class="plain-syntax">: </span><span class="identifier-syntax">n</span><span class="plain-syntax">++) </span><span class="identifier-syntax">backsize</span><span class="plain-syntax">=</span><span class="identifier-syntax">backsize</span><span class="plain-syntax">*2;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">fine_so_far</span><span class="plain-syntax">) && (</span><span class="identifier-syntax">backsize</span><span class="plain-syntax"> == </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">last</span><span class="plain-syntax">))) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">bnext</span><span class="plain-syntax"> = </span><span class="identifier-syntax">last</span><span class="plain-syntax">; </span><span class="identifier-syntax">last</span><span class="plain-syntax"> = </span><span class="identifier-syntax">last</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">bnext</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">last</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">last</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">bnext</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">continue</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">fine_so_far</span><span class="plain-syntax"> = </span><span class="reserved-syntax">false</span><span class="plain-syntax">; </span><span class="comment-syntax">From this point, "last" is meaningless</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">backend</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mto</span><span class="plain-syntax"> - </span><span class="identifier-syntax">backsize</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">backend</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax"> = </span><span class="identifier-syntax">n</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">backend</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">backend</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_HEADER_RCOUNT</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">backend</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">backend</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">bnext</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">bnext</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">bnext</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">backend</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">bnext</span><span class="plain-syntax"> = </span><span class="identifier-syntax">backend</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">fine_so_far</span><span class="plain-syntax">) </span><span class="reserved-syntax">rfalse</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">rtrue</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">];</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><a id="SP11" class="paragraph-anchor"></a><b>§11. Deallocation. </b>As noted above, <span class="extract"><span class="extract-syntax">FlexFree</span></span> must be called exactly once on each nonzero
|
|
pointer returned by <span class="extract"><span class="extract-syntax">FlexAllocate</span></span>.
|
|
</p>
|
|
|
|
<p class="commentary">There are two complications: first, when we free a multiple block we need
|
|
to free all of the blocks in the list, starting from the back end and
|
|
working forwards to the front — this is the job of <span class="extract"><span class="extract-syntax">FlexFree</span></span>. Second,
|
|
when any given block is freed it has to be put into the free block list
|
|
at the correct position to preserve invariant (a): it might either come
|
|
after all of the currently free blocks in memory, and have to be added to
|
|
the end of the list, or in between two, and have to be inserted mid-list,
|
|
but it can't be before all of them because the head-free-block is kept
|
|
lowest in memory of all possible blocks. (Note that Glulx can't allocate
|
|
memory dynamically which undercuts the ordinary array space created by I6:
|
|
I6 arrays fill up memory from the bottom.)
|
|
</p>
|
|
|
|
<p class="commentary">Certain blocks {\it outside} the heap are marked as "resident" in memory,
|
|
that is, are indestructible. This enables Inform to compile constant values.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexFree</span><span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax"> </span><span class="identifier-syntax">fromtxb</span><span class="plain-syntax"> </span><span class="identifier-syntax">ptxb</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">block</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">block</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax">) & </span><span class="identifier-syntax">BLK_FLAG_RESIDENT</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">block</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax">) & </span><span class="constant-syntax">$80</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax">; </span><span class="comment-syntax">not a flexible block at all</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">block</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax">) & </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) (</span><span class="identifier-syntax">block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax">)--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">fromtxb</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (:(</span><span class="identifier-syntax">block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">)~=</span><span class="identifier-syntax">NULL</span><span class="plain-syntax">:</span><span class="identifier-syntax">block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">) ;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">while</span><span class="plain-syntax"> (</span><span class="identifier-syntax">block</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">fromtxb</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">ptxb</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax">; </span><span class="identifier-syntax">FlexFreeSingleBlockInternal</span><span class="plain-syntax">(</span><span class="identifier-syntax">block</span><span class="plain-syntax">); </span><span class="identifier-syntax">block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">ptxb</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">FlexFreeSingleBlockInternal</span><span class="plain-syntax">(</span><span class="identifier-syntax">block</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax">];</span>
|
|
|
|
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexFreeSingleBlockInternal</span><span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax"> </span><span class="identifier-syntax">free</span><span class="plain-syntax"> </span><span class="identifier-syntax">nx</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_HEADER_RCOUNT</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">free</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">:</span><span class="identifier-syntax">free</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">:</span><span class="identifier-syntax">free</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">nx</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">nx</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">free</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">FlexMergeInternal</span><span class="plain-syntax">(</span><span class="identifier-syntax">block</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">UnsignedCompare</span><span class="plain-syntax">(</span><span class="identifier-syntax">nx</span><span class="plain-syntax">, </span><span class="identifier-syntax">block</span><span class="plain-syntax">) == </span><span class="constant-syntax">1</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">free</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">nx</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">nx</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">FlexMergeInternal</span><span class="plain-syntax">(</span><span class="identifier-syntax">block</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax">];</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><a id="SP12" class="paragraph-anchor"></a><b>§12. Resizing. </b>A block which has been allocated, but not yet freed, can sometimes have
|
|
its data capacity changed by <span class="extract"><span class="extract-syntax">FlexResize</span></span>.
|
|
</p>
|
|
|
|
<p class="commentary">When the data being stored stretches or shrinks, we will sometimes need
|
|
to change the size of the block(s) containing the data — though not always:
|
|
we might sometimes need to resize a 1052-byte text to a 1204-byte text and
|
|
find that we are sitting in a 2048-byte block in any case. We either shed
|
|
blocks from the end of the chain, or add new blocks at the end, that being
|
|
the simplest thing to do. Sometimes it might mean preserving a not very
|
|
efficient block division, but it minimises the churn of blocks being
|
|
allocated and freed, which is probably good.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexResize</span><span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax"> </span><span class="identifier-syntax">req</span><span class="plain-syntax"> </span><span class="identifier-syntax">newsize</span><span class="plain-syntax"> </span><span class="identifier-syntax">dsize</span><span class="plain-syntax"> </span><span class="identifier-syntax">newblk</span><span class="plain-syntax"> </span><span class="identifier-syntax">kov</span><span class="plain-syntax"> </span><span class="identifier-syntax">n</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax"> </span><span class="identifier-syntax">otxb</span><span class="plain-syntax"> </span><span class="identifier-syntax">flags</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">block</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">FlexError</span><span class="plain-syntax">(</span><span class="string-syntax">"failed resizing null block"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">kov</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">flags</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> & </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">FlexError</span><span class="plain-syntax">(</span><span class="string-syntax">"failed resizing inextensible block"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">otxb</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">newsize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">req</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (:: </span><span class="identifier-syntax">block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">n</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">dsize</span><span class="plain-syntax">=1: </span><span class="identifier-syntax">n</span><span class="plain-syntax">>0: </span><span class="identifier-syntax">n</span><span class="plain-syntax">--) </span><span class="identifier-syntax">dsize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">dsize</span><span class="plain-syntax">*2;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax"> = </span><span class="identifier-syntax">dsize</span><span class="plain-syntax"> - </span><span class="identifier-syntax">BLK_DATA_MULTI_OFFSET</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">newsize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">newsize</span><span class="plain-syntax"> - </span><span class="identifier-syntax">i</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">newsize</span><span class="plain-syntax"> > </span><span class="constant-syntax">0</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) </span><span class="reserved-syntax">continue</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">newblk</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FlexAllocate</span><span class="plain-syntax">(</span><span class="identifier-syntax">newsize</span><span class="plain-syntax">, </span><span class="identifier-syntax">kov</span><span class="plain-syntax">, </span><span class="identifier-syntax">flags</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">newblk</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">rfalse</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">newblk</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">newblk</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">FlexFree</span><span class="plain-syntax">(</span><span class="identifier-syntax">block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax">];</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><a id="SP13" class="paragraph-anchor"></a><b>§13. Block Size. </b>These two routines are provided for the use of the <span class="extract"><span class="extract-syntax">BlockValue</span></span> routines
|
|
only.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax"> </span><span class="identifier-syntax">txb</span><span class="plain-syntax"> </span><span class="identifier-syntax">bsize</span><span class="plain-syntax"> </span><span class="identifier-syntax">n</span><span class="plain-syntax"> </span><span class="identifier-syntax">m</span><span class="plain-syntax">; </span><span class="comment-syntax">Size of an individual block, including header</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">txb</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">m</span><span class="plain-syntax"> = </span><span class="identifier-syntax">txb</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">bsize</span><span class="plain-syntax">=1: </span><span class="identifier-syntax">n</span><span class="plain-syntax"><</span><span class="identifier-syntax">m</span><span class="plain-syntax">: </span><span class="identifier-syntax">bsize</span><span class="plain-syntax">=</span><span class="identifier-syntax">bsize</span><span class="plain-syntax">*2) </span><span class="identifier-syntax">n</span><span class="plain-syntax">++;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">bsize</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">];</span>
|
|
|
|
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexTotalSize</span><span class="plain-syntax"> </span><span class="identifier-syntax">txb</span><span class="plain-syntax"> </span><span class="identifier-syntax">size_in_bytes</span><span class="plain-syntax">; </span><span class="comment-syntax">Combined size of multiple-blocks for a value</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">txb</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">txb</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax">) & </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">)</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">txb</span><span class="plain-syntax">) - </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (:</span><span class="identifier-syntax">txb</span><span class="plain-syntax">~=</span><span class="identifier-syntax">NULL</span><span class="plain-syntax">:</span><span class="identifier-syntax">txb</span><span class="plain-syntax">=</span><span class="identifier-syntax">txb</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">size_in_bytes</span><span class="plain-syntax"> + </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">txb</span><span class="plain-syntax">) - </span><span class="identifier-syntax">BLK_DATA_MULTI_OFFSET</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">size_in_bytes</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">];</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><a id="SP14" class="paragraph-anchor"></a><b>§14. Debugging Routines. </b>These two routines are purely for testing the above code.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexDebug</span><span class="plain-syntax"> </span><span class="identifier-syntax">txb</span><span class="plain-syntax"> </span><span class="identifier-syntax">n</span><span class="plain-syntax"> </span><span class="identifier-syntax">k</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax"> </span><span class="identifier-syntax">bsize</span><span class="plain-syntax"> </span><span class="identifier-syntax">tot</span><span class="plain-syntax"> </span><span class="identifier-syntax">dtot</span><span class="plain-syntax"> </span><span class="identifier-syntax">kov</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">txb</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="string-syntax">"Block never created."</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">kov</span><span class="plain-syntax"> = </span><span class="identifier-syntax">txb</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"Block "</span><span class="plain-syntax">, </span><span class="identifier-syntax">txb</span><span class="plain-syntax">, </span><span class="string-syntax">" (kov "</span><span class="plain-syntax">, </span><span class="identifier-syntax">kov</span><span class="plain-syntax">, </span><span class="string-syntax">"): "</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (:</span><span class="identifier-syntax">txb</span><span class="plain-syntax">~=</span><span class="identifier-syntax">NULL</span><span class="plain-syntax">:</span><span class="identifier-syntax">txb</span><span class="plain-syntax"> = </span><span class="identifier-syntax">txb</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">k</span><span class="plain-syntax">++ == </span><span class="constant-syntax">100</span><span class="plain-syntax">) </span><span class="string-syntax">" ... and so on."</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">txb</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">kov</span><span class="plain-syntax">)</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"*Wrong kov="</span><span class="plain-syntax">, </span><span class="identifier-syntax">txb</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax">, </span><span class="string-syntax">"* "</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">n</span><span class="plain-syntax"> = </span><span class="identifier-syntax">txb</span><span class="plain-syntax">-></span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">bsize</span><span class="plain-syntax">=1:</span><span class="identifier-syntax">n</span><span class="plain-syntax">>0:</span><span class="identifier-syntax">n</span><span class="plain-syntax">--) </span><span class="identifier-syntax">bsize</span><span class="plain-syntax">=</span><span class="identifier-syntax">bsize</span><span class="plain-syntax">*2;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax"> = </span><span class="identifier-syntax">bsize</span><span class="plain-syntax"> - </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">dtot</span><span class="plain-syntax"> = </span><span class="identifier-syntax">dtot</span><span class="plain-syntax">+</span><span class="identifier-syntax">i</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">tot</span><span class="plain-syntax"> = </span><span class="identifier-syntax">tot</span><span class="plain-syntax">+</span><span class="identifier-syntax">bsize</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="identifier-syntax">txb</span><span class="plain-syntax">, </span><span class="string-syntax">"("</span><span class="plain-syntax">, </span><span class="identifier-syntax">bsize</span><span class="plain-syntax">, </span><span class="string-syntax">") > "</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="identifier-syntax">dtot</span><span class="plain-syntax">, </span><span class="string-syntax">" data in "</span><span class="plain-syntax">, </span><span class="identifier-syntax">tot</span><span class="plain-syntax">, </span><span class="string-syntax">" bytes^"</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">];</span>
|
|
|
|
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexDebugDecomposition</span><span class="plain-syntax"> </span><span class="identifier-syntax">from</span><span class="plain-syntax"> </span><span class="reserved-syntax">to</span><span class="plain-syntax"> </span><span class="identifier-syntax">txb</span><span class="plain-syntax"> </span><span class="identifier-syntax">pf</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="reserved-syntax">to</span><span class="plain-syntax">==0) </span><span class="reserved-syntax">to</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">txb</span><span class="plain-syntax">=</span><span class="identifier-syntax">from</span><span class="plain-syntax">:((</span><span class="identifier-syntax">txb</span><span class="plain-syntax">~=</span><span class="reserved-syntax">to</span><span class="plain-syntax">) && (</span><span class="identifier-syntax">txb</span><span class="plain-syntax">~=</span><span class="identifier-syntax">NULL</span><span class="plain-syntax">)):</span><span class="identifier-syntax">txb</span><span class="plain-syntax">=</span><span class="identifier-syntax">txb</span><span class="plain-syntax">--></span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">pf</span><span class="plain-syntax">) </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"+"</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">txb</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">pf</span><span class="plain-syntax"> = </span><span class="reserved-syntax">true</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"^"</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">];</span>
|
|
</pre>
|
|
<nav role="progress"><div class="progresscontainer">
|
|
<ul class="progressbar"><li class="progressprev"><a href="S-rlb.html">❮</a></li><li class="progresssection"><a href="S-dfn.html">dfn</a></li><li class="progresssection"><a href="S-utl.html">utl</a></li><li class="progresssection"><a href="S-gll.html">gll</a></li><li class="progresssection"><a href="S-zmc.html">zmc</a></li><li class="progresssection"><a href="S-prg.html">prg</a></li><li class="progresssection"><a href="S-mth.html">mth</a></li><li class="progresssection"><a href="S-fl.html">fl</a></li><li class="progresssection"><a href="S-srt.html">srt</a></li><li class="progresssection"><a href="S-tbl.html">tbl</a></li><li class="progresssection"><a href="S-mst.html">mst</a></li><li class="progresssection"><a href="S-rlb.html">rlb</a></li><li class="progresscurrent">flx</li><li class="progresssection"><a href="S-blc.html">blc</a></li><li class="progresssection"><a href="S-txt.html">txt</a></li><li class="progresssection"><a href="S-unc.html">unc</a></li><li class="progresssection"><a href="S-chr.html">chr</a></li><li class="progresssection"><a href="S-rgx.html">rgx</a></li><li class="progresssection"><a href="S-lst.html">lst</a></li><li class="progresssection"><a href="S-cmb.html">cmb</a></li><li class="progresssection"><a href="S-rlt.html">rlt</a></li><li class="progresssection"><a href="S-rlt2.html">rlt2</a></li><li class="progresssection"><a href="S-rtp.html">rtp</a></li><li class="progressnext"><a href="S-blc.html">❯</a></li></ul></div>
|
|
</nav><!--End of weave-->
|
|
|
|
</main>
|
|
</body>
|
|
</html>
|
|
|