mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-03-26 00:34:17 -07:00
Write "advanced topics" chapter of the user guide.
Copied from Perforce Change: 180303 ServerID: perforce.ravenbrook.com
This commit is contained in:
parent
f16a8b3629
commit
d1bc2a6855
10 changed files with 507 additions and 308 deletions
|
|
@ -1,12 +1,13 @@
|
|||
;;; test-common.scm -- common definitions for the Scheme tests
|
||||
|
||||
(define (check exp result)
|
||||
(write-string "test: ") (write exp) (newline)
|
||||
(write-string "expect: ") (write result) (newline)
|
||||
(define actually (eval exp))
|
||||
(write-string "got: ") (write actually) (newline)
|
||||
(if (not (equal? actually result))
|
||||
(error "failed!")))
|
||||
(let ((actually (eval exp)))
|
||||
(if (not (equal? actually result))
|
||||
(begin
|
||||
(write-string "test: ") (write exp) (newline)
|
||||
(write-string "expect: ") (write result) (newline)
|
||||
(write-string "got: ") (write actually) (newline)
|
||||
(error "failed!")))))
|
||||
|
||||
;; Return (f (f (f ... (f a) ... ))) with n invocations of f.
|
||||
(define (church n f a)
|
||||
|
|
|
|||
448
mps/manual/source/diagrams/symbol-table.svg
Normal file
448
mps/manual/source/diagrams/symbol-table.svg
Normal file
|
|
@ -0,0 +1,448 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="510"
|
||||
height="390"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.2 r9819"
|
||||
sodipodi:docname="New document 1">
|
||||
<defs
|
||||
id="defs4">
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mend"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path3899"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="DotM"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="DotM"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path3955"
|
||||
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
|
||||
transform="matrix(0.4,0,0,0.4,2.96,0.4)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="288.99598"
|
||||
inkscape:cy="182.34538"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:window-width="1276"
|
||||
inkscape:window-height="756"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2985"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-662.36218)">
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="rect2987"
|
||||
width="90"
|
||||
height="20"
|
||||
x="80"
|
||||
y="672.36218" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="90"
|
||||
y="686.36218"
|
||||
id="text3757"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3759"
|
||||
x="90"
|
||||
y="686.36218"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Verdana;-inkscape-font-specification:Verdana">TABLE</tspan></text>
|
||||
<rect
|
||||
y="692.36218"
|
||||
x="80"
|
||||
height="20"
|
||||
width="90"
|
||||
id="rect3761"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3763"
|
||||
y="706.36218"
|
||||
x="90"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="706.36218"
|
||||
x="90"
|
||||
id="tspan3765"
|
||||
sodipodi:role="line">keys</tspan></text>
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="rect3767"
|
||||
width="90"
|
||||
height="20"
|
||||
x="80"
|
||||
y="712.36218" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="90"
|
||||
y="726.36218"
|
||||
id="text3769"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3771"
|
||||
x="90"
|
||||
y="726.36218"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Verdana;-inkscape-font-specification:Verdana">values</tspan></text>
|
||||
<rect
|
||||
y="892.36218"
|
||||
x="140"
|
||||
height="20"
|
||||
width="90"
|
||||
id="rect3773"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3775"
|
||||
y="906.36218"
|
||||
x="150"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="906.36218"
|
||||
x="150"
|
||||
id="tspan3777"
|
||||
sodipodi:role="line">STRING</tspan></text>
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="rect3779"
|
||||
width="90"
|
||||
height="30"
|
||||
x="140"
|
||||
y="912.36218" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="150"
|
||||
y="932.36218"
|
||||
id="text3781"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3783"
|
||||
x="150"
|
||||
y="932.36218"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Verdana;-inkscape-font-specification:Verdana">"name"</tspan></text>
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="rect3791"
|
||||
width="90"
|
||||
height="20"
|
||||
x="270"
|
||||
y="892.36218" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="280"
|
||||
y="906.36218"
|
||||
id="text3793"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3795"
|
||||
x="280"
|
||||
y="906.36218"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Verdana;-inkscape-font-specification:Verdana">SYMBOL</tspan></text>
|
||||
<rect
|
||||
y="912.36218"
|
||||
x="270"
|
||||
height="20"
|
||||
width="90"
|
||||
id="rect3797"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3799"
|
||||
y="926.36218"
|
||||
x="280"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="926.36218"
|
||||
x="280"
|
||||
id="tspan3801"
|
||||
sodipodi:role="line">name</tspan></text>
|
||||
<rect
|
||||
y="792.36218"
|
||||
x="10"
|
||||
height="20"
|
||||
width="90"
|
||||
id="rect3809"
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<rect
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="rect3815"
|
||||
width="90"
|
||||
height="20"
|
||||
x="10"
|
||||
y="812.36218" />
|
||||
<rect
|
||||
y="832.36218"
|
||||
x="10"
|
||||
height="20"
|
||||
width="90"
|
||||
id="rect3821"
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<rect
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="rect3827"
|
||||
width="90"
|
||||
height="20"
|
||||
x="10"
|
||||
y="852.36218" />
|
||||
<rect
|
||||
y="872.36218"
|
||||
x="10"
|
||||
height="20"
|
||||
width="90"
|
||||
id="rect3829"
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<rect
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="rect3831"
|
||||
width="90"
|
||||
height="20"
|
||||
x="10"
|
||||
y="892.36218" />
|
||||
<rect
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="rect3833"
|
||||
width="90"
|
||||
height="20"
|
||||
x="10"
|
||||
y="912.36218" />
|
||||
<rect
|
||||
y="932.36218"
|
||||
x="10"
|
||||
height="20"
|
||||
width="90"
|
||||
id="rect3835"
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<rect
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="rect3837"
|
||||
width="90"
|
||||
height="20"
|
||||
x="10"
|
||||
y="952.36218" />
|
||||
<rect
|
||||
y="972.36218"
|
||||
x="10"
|
||||
height="20"
|
||||
width="90"
|
||||
id="rect3839"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<rect
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="rect3841"
|
||||
width="90"
|
||||
height="20"
|
||||
x="10"
|
||||
y="992.36218" />
|
||||
<rect
|
||||
y="1012.3622"
|
||||
x="10"
|
||||
height="20"
|
||||
width="90"
|
||||
id="rect3843"
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<rect
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="rect3845"
|
||||
width="90"
|
||||
height="20"
|
||||
x="390"
|
||||
y="792.36218" />
|
||||
<rect
|
||||
y="812.36218"
|
||||
x="390"
|
||||
height="20"
|
||||
width="90"
|
||||
id="rect3847"
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<rect
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="rect3849"
|
||||
width="90"
|
||||
height="20"
|
||||
x="390"
|
||||
y="832.36218" />
|
||||
<rect
|
||||
y="852.36218"
|
||||
x="390"
|
||||
height="20"
|
||||
width="90"
|
||||
id="rect3851"
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<rect
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="rect3853"
|
||||
width="90"
|
||||
height="20"
|
||||
x="390"
|
||||
y="872.36218" />
|
||||
<rect
|
||||
y="892.36218"
|
||||
x="390"
|
||||
height="20"
|
||||
width="90"
|
||||
id="rect3855"
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<rect
|
||||
y="912.36218"
|
||||
x="390"
|
||||
height="20"
|
||||
width="90"
|
||||
id="rect3857"
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<rect
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="rect3859"
|
||||
width="90"
|
||||
height="20"
|
||||
x="390"
|
||||
y="932.36218" />
|
||||
<rect
|
||||
y="952.36218"
|
||||
x="390"
|
||||
height="20"
|
||||
width="90"
|
||||
id="rect3861"
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="rect3863"
|
||||
width="90"
|
||||
height="20"
|
||||
x="390"
|
||||
y="972.36218" />
|
||||
<rect
|
||||
y="992.36218"
|
||||
x="390"
|
||||
height="20"
|
||||
width="90"
|
||||
id="rect3865"
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<rect
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="rect3867"
|
||||
width="90"
|
||||
height="20"
|
||||
x="390"
|
||||
y="1012.3622" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotM);marker-end:url(#Arrow1Mend)"
|
||||
d="m 150,722.36218 240,70"
|
||||
id="path3871"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotM);marker-end:url(#Arrow1Mend)"
|
||||
d="m 150,702.36218 c 30,0 40,0 40,20 0,10 0.007,6.68771 0,30 0,20 -10,20 -40,20 -28.52438,0 -57.43061,0.005 -100,0 -30,0 -40,0 -40,20"
|
||||
id="path3875"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccscc" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotM);marker-end:url(#Arrow1Mend)"
|
||||
d="m 460,982.36218 c 30,0 40,0 40,-30 l 0,-150 c 0,-20 -10,-30 -30,-30 -40,0 -70.83211,0 -170,0 -19.06193,0 -30,10 -30,30 0,17.94046 0,49.89376 0,90"
|
||||
id="path3879"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccsssc" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotM);marker-end:url(#Arrow1Mend)"
|
||||
d="m 80,982.36218 c 30,0 40,0 40,-20 l 0,-50 c 0,-20 10,-20 20,-20"
|
||||
id="path3883"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotM);marker-end:url(#Arrow1Mend)"
|
||||
d="m 340,922.36218 c 0,20 0,30 -20,30 l -40,0 c -20,0 -30,-10 -30,-39 0,-31 -10,-41 -30,-41 l -50,0 c -20,0 -30,0 -30,20"
|
||||
id="path3885"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="20"
|
||||
y="1046.3622"
|
||||
id="text4699"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4701"
|
||||
x="20"
|
||||
y="1046.3622"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Verdana;-inkscape-font-specification:Verdana">keys</tspan></text>
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text4703"
|
||||
y="1046.3622"
|
||||
x="400"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="1046.3622"
|
||||
x="400"
|
||||
id="tspan4705"
|
||||
sodipodi:role="line">values</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 19 KiB |
|
|
@ -170,11 +170,11 @@ implements the environment as a list of *frames*, each of which is a
|
|||
list of *bindings*, each binding being a pair of a symbol and its
|
||||
value, as shown here:
|
||||
|
||||
.. figure:: ../diagrams/scheme-env.svg
|
||||
:align: center
|
||||
:alt: Diagram: The environment data structure in the Scheme interpreter.
|
||||
.. figure:: ../diagrams/scheme-env.svg
|
||||
:align: center
|
||||
:alt: Diagram: The environment data structure in the Scheme interpreter.
|
||||
|
||||
The environment data structure in the Scheme interpreter.
|
||||
The environment data structure in the Scheme interpreter.
|
||||
|
||||
In this case, because the evaluation is taking place at top level,
|
||||
there is only one frame in the environment (the global frame). And
|
||||
|
|
|
|||
|
|
@ -11,3 +11,5 @@ Guide
|
|||
lang
|
||||
debug
|
||||
perf
|
||||
advanced
|
||||
|
||||
|
|
|
|||
|
|
@ -32,14 +32,14 @@ I'll be quoting the relevant sections of code as needed, but you may
|
|||
find it helpful to experiment with this interpeter yourself, in either
|
||||
of its versions:
|
||||
|
||||
:download:`scheme-malloc.c <../../../example/scheme/scheme-malloc.c>`
|
||||
:download:`scheme-malloc.c <../../../example/scheme/scheme-malloc.c>`
|
||||
|
||||
The Scheme interpreter before integration with the MPS, using
|
||||
:term:`malloc` and :term:`free (2)` for memory management.
|
||||
The Scheme interpreter before integration with the MPS, using
|
||||
:term:`malloc` and :term:`free (2)` for memory management.
|
||||
|
||||
:download:`scheme.c <../../../example/scheme/scheme.c>`
|
||||
:download:`scheme.c <../../../example/scheme/scheme.c>`
|
||||
|
||||
The Scheme interpreter after integration with the MPS.
|
||||
The Scheme interpreter after integration with the MPS.
|
||||
|
||||
This simple interpreter allocates two kinds of objects on the
|
||||
:term:`heap`:
|
||||
|
|
@ -476,11 +476,11 @@ The :term:`forward method` is a function of type
|
|||
object, and its task is to replace the old object with a
|
||||
:term:`forwarding object` pointing to the new location of the object.
|
||||
|
||||
.. figure:: ../diagrams/copying.svg
|
||||
:align: center
|
||||
:alt: Diagram: Copying garbage collection.
|
||||
.. figure:: ../diagrams/copying.svg
|
||||
:align: center
|
||||
:alt: Diagram: Copying garbage collection.
|
||||
|
||||
Copying garbage collection.
|
||||
Copying garbage collection.
|
||||
|
||||
The forwarding object must satisfy these properties:
|
||||
|
||||
|
|
@ -785,6 +785,8 @@ And finally the :term:`pool`::
|
|||
single: root; creating
|
||||
single: Scheme; root
|
||||
|
||||
.. _guide-lang-root:
|
||||
|
||||
Roots
|
||||
-----
|
||||
|
||||
|
|
|
|||
|
|
@ -75,11 +75,11 @@ Technical introduction
|
|||
The figure below gives a simplified picture of a program's memory from
|
||||
the point of view of the Memory Pool System.
|
||||
|
||||
.. figure:: ../diagrams/overview.svg
|
||||
:align: center
|
||||
:alt: Diagram: Overview of the Memory Pool System.
|
||||
.. figure:: ../diagrams/overview.svg
|
||||
:align: center
|
||||
:alt: Diagram: Overview of the Memory Pool System.
|
||||
|
||||
Overview of the Memory Pool System.
|
||||
Overview of the Memory Pool System.
|
||||
|
||||
The **arena** is the top-level data structure in the MPS. An
|
||||
:term:`arena` is responsible for requesting :term:`memory (3)` from
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ AWL (Automatic Weak Linked)
|
|||
===========================
|
||||
|
||||
**AWL** is an :term:`automatically managed <automatic memory
|
||||
management>` :term:`pool class` that may contain :term:`weak
|
||||
references (1)`.
|
||||
management>` :term:`non-moving <non-moving garbage collector>`
|
||||
:term:`pool class` that may contain :term:`weak references (1)`.
|
||||
|
||||
The purpose of this pool class is to allow the client to implement
|
||||
:term:`weak-key <weak-key hash table>`, :term:`weak-value <weak-value
|
||||
|
|
@ -117,7 +117,8 @@ Dependent objects
|
|||
In order to support prompt deletion of values in a :term:`weak-key
|
||||
hash table` when the key is :term:`splatted <splat>` (and prompt
|
||||
deletion of keys in a :term:`weak-value hash table`), an AWL pool
|
||||
allows each object to have a :dfn:`dependent object`.
|
||||
allows each object to have a :dfn:`dependent object`. (This is where
|
||||
the "Linked" in the name of the pool class comes from.)
|
||||
|
||||
The dependent object is specified by the ``find_dependent`` argument
|
||||
to :c:func:`mps_pool_create` when creating an AWL pool. This is a
|
||||
|
|
@ -355,4 +356,4 @@ AWL interface
|
|||
|
||||
The dependent object need not be in memory managed by the MPS, but
|
||||
if it is, then it must be in a :term:`non-moving <non-moving
|
||||
garbage collection>` pool in the same arena as ``addr``.
|
||||
garbage collector>` pool in the same arena as ``addr``.
|
||||
|
|
|
|||
|
|
@ -107,108 +107,11 @@ program that registers the same block multiple times must cope with
|
|||
either behaviour.
|
||||
|
||||
|
||||
.. index::
|
||||
single: finalization; example
|
||||
single: Scheme; finalization
|
||||
single: Scheme; ports
|
||||
|
||||
Example: ports in Scheme
|
||||
------------------------
|
||||
|
||||
In Scheme, an open file is represented by a *port*. In the toy Scheme
|
||||
example, a port is a wrapper around a Standard C file handle::
|
||||
|
||||
typedef struct port_s {
|
||||
type_t type; /* TYPE_PORT */
|
||||
obj_t name; /* name of stream */
|
||||
FILE *stream;
|
||||
} port_s;
|
||||
|
||||
The Scheme procedure ``open-input-file`` takes a filename and returns
|
||||
a port:
|
||||
|
||||
.. code-block:: c
|
||||
:emphasize-lines: 21
|
||||
|
||||
/* (open-input-file filename)
|
||||
* Opens filename for input, with empty file options, and returns the
|
||||
* obtained port.
|
||||
* See R4RS 6.10.1
|
||||
*/
|
||||
static obj_t entry_open_input_file(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t filename;
|
||||
FILE *stream;
|
||||
obj_t port;
|
||||
mps_addr_t port_ref;
|
||||
eval_args(operator->operator.name, env, op_env, operands, 1, &filename);
|
||||
unless(TYPE(filename) == TYPE_STRING)
|
||||
error("%s: argument must be a string", operator->operator.name);
|
||||
stream = fopen(filename->string.string, "r");
|
||||
if(stream == NULL)
|
||||
error("%s: cannot open input file", operator->operator.name);
|
||||
port = make_port(filename, stream);
|
||||
|
||||
port_ref = port;
|
||||
mps_finalize(arena, &port_ref);
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
Each time around the read–eval–print loop, the interpreter polls the
|
||||
message queue for finalization messages, and when it finds one it
|
||||
closes the port's underlying file handle:
|
||||
|
||||
.. code-block:: c
|
||||
:emphasize-lines: 9, 12
|
||||
|
||||
mps_message_type_t type;
|
||||
|
||||
while (mps_message_queue_type(&type, arena)) {
|
||||
mps_message_t message;
|
||||
mps_bool_t b;
|
||||
b = mps_message_get(&message, arena, type);
|
||||
assert(b); /* we just checked there was one */
|
||||
|
||||
if (type == mps_message_type_finalization()) {
|
||||
mps_addr_t port_ref;
|
||||
obj_t port;
|
||||
mps_message_finalization_ref(&port_ref, arena, message);
|
||||
port = port_ref;
|
||||
assert(TYPE(port) == TYPE_PORT);
|
||||
printf("Port to file \"%s\" is dying. Closing file.\n",
|
||||
port->port.name->string.string);
|
||||
(void)fclose(port->port.stream);
|
||||
} else {
|
||||
/* ... handle other message types ... */
|
||||
}
|
||||
|
||||
mps_message_discard(arena, message);
|
||||
}
|
||||
|
||||
Here's an example session showing finalization taking place:
|
||||
|
||||
.. code-block:: none
|
||||
:emphasize-lines: 8
|
||||
|
||||
MPS Toy Scheme Example
|
||||
9960, 0> (open-input-file "scheme.c")
|
||||
#[port "scheme.c"]
|
||||
10064, 0> (gc)
|
||||
Collection started.
|
||||
Why: Client requests: immediate full collection.
|
||||
Clock: 3401
|
||||
Port to file "scheme.c" is dying. Closing file.
|
||||
Collection finished.
|
||||
live 10040
|
||||
condemned 10088
|
||||
not_condemned 0
|
||||
clock: 3807
|
||||
|
||||
|
||||
.. index::
|
||||
pair: finalization; cautions
|
||||
|
||||
.. _topic-finalization-cautions:
|
||||
|
||||
Cautions
|
||||
--------
|
||||
|
||||
|
|
@ -233,7 +136,9 @@ Cautions
|
|||
finalization messages are only processed at the end of the
|
||||
read–eval–print loop, so a program that opens many files may run
|
||||
out of handles even though the associated objects are all
|
||||
finalizable, as shown here::
|
||||
finalizable, as shown here:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
MPS Toy Scheme Example
|
||||
9960, 0> (define (repeat n f _) (if (eqv? n 0) '() (repeat (- n 1) f (f))))
|
||||
|
|
|
|||
|
|
@ -291,6 +291,8 @@ For example::
|
|||
.. index::
|
||||
pair: object format; cautions
|
||||
|
||||
.. _topic-format-cautions:
|
||||
|
||||
Cautions
|
||||
--------
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ client program needs to recognize and correctly deal with such cases).
|
|||
|
||||
The interface is intended to support (amongst other things)
|
||||
address-based hash tables and that will be used as a running example.
|
||||
See the section :ref:`guide-advanced-location` in the Guide for a more
|
||||
detailed look at this example.
|
||||
|
||||
|
||||
Terminology
|
||||
|
|
@ -45,49 +47,6 @@ if any of the blocks whose location has been depended on might have
|
|||
moved since the respective dependency was made.
|
||||
|
||||
|
||||
.. index::
|
||||
single: location dependency; example
|
||||
single: hash table; address-based example
|
||||
single: Scheme; address-based hash table
|
||||
|
||||
Example: ``eq?`` hash table
|
||||
---------------------------
|
||||
|
||||
The toy Scheme interpreter contains a simple address-based (``eq?``)
|
||||
hash table implementation. It hashes the addresses of its keys, and so
|
||||
depends on their location.
|
||||
|
||||
If it fails to take account of this location dependency, the hash
|
||||
tables become invalid after a garbage collection. In the interaction
|
||||
shown below (with a naïve version of the code) you'll see that
|
||||
although the keys remain present in the table after garbage
|
||||
collection, they cannot be found. This is because their locations (and
|
||||
hence their hashes) have changed, but their positions in the table
|
||||
have not been updated to match.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
MPS Toy Scheme Example
|
||||
10240, 0> (define ht (make-eq-hashtable))
|
||||
ht
|
||||
10584, 0> (hashtable-set! ht 'one 1)
|
||||
10768, 0> (hashtable-set! ht 'two 2)
|
||||
10952, 0> (hashtable-set! ht 'three 3)
|
||||
11136, 0> ht
|
||||
#[hashtable (two 2) (three 3) (one 1)]
|
||||
11136, 0> (hashtable-ref ht 'two #f)
|
||||
2
|
||||
11280, 0> (gc)
|
||||
11304, 1> (hashtable-ref ht 'one #f)
|
||||
#f
|
||||
11448, 1> (hashtable-ref ht 'two #f)
|
||||
#f
|
||||
11592, 1> (hashtable-ref ht 'three #f)
|
||||
#f
|
||||
11736, 1> ht
|
||||
#[hashtable (two 2) (three 3) (one 1)]
|
||||
|
||||
|
||||
.. index::
|
||||
single: location dependency; creating
|
||||
|
||||
|
|
@ -99,49 +58,28 @@ The :term:`client program` must provide space for the
|
|||
larger structure. This structure can be in memory managed by the MPS
|
||||
or elsewhere; that doesn't matter.
|
||||
|
||||
For example, the Scheme interpreter inlines the location dependency in
|
||||
its hash table structure:
|
||||
For example, the toy Scheme interpreter inlines the location
|
||||
dependency in its hash table structure:
|
||||
|
||||
.. code-block:: c
|
||||
:emphasize-lines: 3
|
||||
:emphasize-lines: 5
|
||||
|
||||
typedef struct table_s {
|
||||
type_t type; /* TYPE_TABLE */
|
||||
hash_t hash; /* hash function */
|
||||
cmp_t cmp; /* comparison function */
|
||||
mps_ld_s ld; /* location dependency */
|
||||
obj_t buckets; /* hash buckets */
|
||||
} table_s;
|
||||
|
||||
Before the first use, the location dependency must be reset by calling
|
||||
function :c:func:`mps_ld_reset`.
|
||||
the function :c:func:`mps_ld_reset`.
|
||||
|
||||
.. note::
|
||||
|
||||
This means that it is not possible to statically create a location
|
||||
dependency that has been reset.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: c
|
||||
:emphasize-lines: 15
|
||||
|
||||
static obj_t make_table(void)
|
||||
{
|
||||
obj_t obj;
|
||||
mps_addr_t addr;
|
||||
size_t size = ALIGN(sizeof(table_s));
|
||||
do {
|
||||
mps_res_t res = mps_reserve(&addr, obj_ap, size);
|
||||
if (res != MPS_RES_OK) error("out of memory in make_table");
|
||||
obj = addr;
|
||||
obj->table.type = TYPE_TABLE;
|
||||
obj->table.buckets = NULL;
|
||||
} while (!mps_commit(obj_ap, addr, size));
|
||||
total += size;
|
||||
obj->table.buckets = make_buckets(8);
|
||||
mps_ld_reset(&obj->table.ld, arena);
|
||||
return obj;
|
||||
}
|
||||
|
||||
You can call :c:func:`mps_ld_reset` at any later point to clear all
|
||||
dependencies from the structure. For example, this is normally done
|
||||
whenever :c:func:`mps_ld_isstale` returns true.
|
||||
|
|
@ -164,43 +102,20 @@ references from one dependency to another.
|
|||
|
||||
For example, in an address-based hash table implementation, each key
|
||||
that is added to the table must be added to the dependency before its
|
||||
address is hashed. In the toy Scheme interpreter, addresses are hashed
|
||||
during the call to the function ``buckets_find``, so the key must be
|
||||
added to the location dependency before that:
|
||||
address is hashed. In the toy Scheme interpreter this is most easily
|
||||
done in the function that hashes an address:
|
||||
|
||||
.. code-block:: c
|
||||
:emphasize-lines: 4
|
||||
|
||||
static int table_try_set(obj_t tbl, obj_t key, obj_t value)
|
||||
static unsigned long eq_hash(obj_t obj, mps_ld_t ld)
|
||||
{
|
||||
struct bucket_s *b;
|
||||
mps_ld_add(&tbl->table.ld, arena, key);
|
||||
b = buckets_find(tbl->table.buckets, key);
|
||||
if (b == NULL)
|
||||
return 0;
|
||||
if (b->key == NULL)
|
||||
b->key = key;
|
||||
b->value = value;
|
||||
return 1;
|
||||
union {char s[sizeof(obj_t)]; obj_t addr;} u;
|
||||
if (ld) mps_ld_add(ld, arena, obj);
|
||||
u.addr = obj;
|
||||
return hash(u.s, sizeof(obj_t));
|
||||
}
|
||||
|
||||
static void table_set(obj_t tbl, obj_t key, obj_t value)
|
||||
{
|
||||
if (!table_try_set(tbl, key, value)) {
|
||||
int res;
|
||||
table_rehash(tbl, tbl->table.buckets->buckets.length * 2, NULL);
|
||||
res = table_try_set(tbl, key, value);
|
||||
assert(res); /* rehash should have made room */
|
||||
}
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
The garbage collector may run at any time during this operation,
|
||||
so the table may already be stale while the new key and value are
|
||||
being added. We postpone worrying about this until the next
|
||||
lookup, when the staleness will be discovered.
|
||||
|
||||
|
||||
.. index::
|
||||
single: location dependency; testing staleness
|
||||
|
|
@ -244,46 +159,15 @@ point you need to:
|
|||
3. re-add a dependency on each block.
|
||||
|
||||
For example, in the case of a hash table you should rehash based on
|
||||
the new locations of the blocks:
|
||||
the new locations of the blocks.
|
||||
|
||||
.. code-block:: c
|
||||
:emphasize-lines: 13, 19, 37
|
||||
|
||||
/* Rehash 'tbl' so that it has 'new_length' buckets. If 'key' is found
|
||||
* during this process, return the bucket containing 'key', otherwise
|
||||
* return NULL.
|
||||
*/
|
||||
static struct bucket_s *table_rehash(obj_t tbl, size_t new_length, obj_t key)
|
||||
{
|
||||
size_t i;
|
||||
obj_t new_buckets;
|
||||
struct bucket_s *key_bucket = NULL;
|
||||
|
||||
assert(tbl->type.type == TYPE_TABLE);
|
||||
new_buckets = make_buckets(new_length);
|
||||
mps_ld_reset(&tbl->table.ld, arena);
|
||||
|
||||
for (i = 0; i < tbl->table.buckets->buckets.length; ++i) {
|
||||
struct bucket_s *old_b = &tbl->table.buckets->buckets.bucket[i];
|
||||
if (old_b->key != NULL) {
|
||||
struct bucket_s *b;
|
||||
mps_ld_add(&tbl->table.ld, arena, old_b->key);
|
||||
b = buckets_find(new_buckets, old_b->key);
|
||||
assert(b != NULL); /* new table shouldn't be full */
|
||||
assert(b->key == NULL); /* shouldn't be in new table */
|
||||
*b = *old_b;
|
||||
if (b->key == key) key_bucket = b;
|
||||
}
|
||||
}
|
||||
|
||||
tbl->table.buckets = new_buckets;
|
||||
return key_bucket;
|
||||
}
|
||||
:emphasize-lines: 6
|
||||
|
||||
static obj_t table_ref(obj_t tbl, obj_t key)
|
||||
{
|
||||
struct bucket_s *b = buckets_find(tbl->table.buckets, key);
|
||||
if (b && b->key != NULL)
|
||||
struct bucket_s *b = buckets_find(tbl, tbl->table.buckets, key, NULL);
|
||||
if (b && b->key != NULL && b->key != obj_deleted)
|
||||
return b->value;
|
||||
if (mps_ld_isstale(&tbl->table.ld, arena, key)) {
|
||||
b = table_rehash(tbl, tbl->table.buckets->buckets.length, key);
|
||||
|
|
@ -306,52 +190,6 @@ back to a non-address-based version of the computation: here, since
|
|||
it might as well find the bucket containing ``key`` at the same time
|
||||
and return it.
|
||||
|
||||
By adding the line::
|
||||
|
||||
puts("Stale!");
|
||||
|
||||
after :c:func:`mps_ld_isstale` returns true, we get to see when the
|
||||
location dependency becomes stale and the table has to be rehashed.
|
||||
|
||||
.. code-block:: none
|
||||
:emphasize-lines: 21, 23
|
||||
|
||||
MPS Toy Scheme Example
|
||||
10240, 0> (define ht (make-eq-hashtable))
|
||||
ht
|
||||
10584, 0> (hashtable-set! ht 'one 1)
|
||||
10768, 0> ht
|
||||
#[hashtable (one 1)]
|
||||
10768, 0> (gc)
|
||||
10792, 1> (hashtable-ref ht 'one #f)
|
||||
Stale!
|
||||
1
|
||||
11080, 1> (hashtable-set! ht 'two 2)
|
||||
11264, 1> (gc)
|
||||
11288, 2> (hashtable-ref ht 'one #f)
|
||||
Stale!
|
||||
1
|
||||
11576, 2> (hashtable-set! ht 'three 3)
|
||||
11760, 2> (hashtable-ref ht 'two #f)
|
||||
2
|
||||
11904, 2> (gc)
|
||||
11928, 3> (hashtable-ref ht 'one #f)
|
||||
1
|
||||
12072, 3> (hashtable-ref ht 'two #f)
|
||||
Stale!
|
||||
2
|
||||
12360, 3> (hashtable-ref ht 'three #f)
|
||||
3
|
||||
|
||||
.. note::
|
||||
|
||||
In case you're puzzled by the highlighted lines: the symbol
|
||||
``'one`` must not have been moved by the collection, and so was
|
||||
found in the table at the correct location. Thus
|
||||
:c:func:`mps_ld_isstale` was not called. The symbol ``'two`` did
|
||||
move in the collection, so it's not found in the table, and that
|
||||
causes :c:func:`mps_ld_isstale` to be tested.
|
||||
|
||||
|
||||
.. index::
|
||||
pair: location dependency; thread safety
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue