1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
|
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="generator" content="AsciiDoc 8.6.8">
<title>MLNLFFIImplementation</title>
<link rel="stylesheet" href="./asciidoc.css" type="text/css">
<link rel="stylesheet" href="./pygments.css" type="text/css">
<script type="text/javascript" src="./asciidoc.js"></script>
<script type="text/javascript">
/*<![CDATA[*/
asciidoc.install();
/*]]>*/
</script>
<link rel="stylesheet" href="./mlton.css" type="text/css"/>
</head>
<body class="article">
<div id="banner">
<div id="banner-home">
<a href="./Home">MLton 20130715</a>
</div>
</div>
<div id="header">
<h1>MLNLFFIImplementation</h1>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph"><p>MLton’s implementation(s) of the <a href="MLNLFFI">MLNLFFI</a> library differs from the
SML/NJ implementation in two important ways:</p></div>
<div class="ulist"><ul>
<li>
<p>
MLton cannot utilize the <span class="monospaced">Unsafe.cast</span> "cheat" described in Section
3.7 of <a href="References#Blume01">Blume01</a>. (MLton’s representation of
<a href="Closure">closures</a> and
<a href="PackedRepresentation">aggressive representation</a> optimizations make
an <span class="monospaced">Unsafe.cast</span> even more "unsafe" than in other implementations.)
</p>
<div class="openblock">
<div class="content">
<div class="paragraph"><p>We have considered two solutions:</p></div>
<div class="ulist"><ul>
<li>
<p>
One solution is to utilize an additional type parameter (as
described in Section 3.7 of <a href="References#Blume01">Blume01</a>):
</p>
<div class="openblock">
<div class="content">
<div class="quoteblock">
<div class="content">
<div class="listingblock">
<div class="content"><div class="highlight"><pre><span class="k">signature</span><span class="w"> </span><span class="n">C</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">sig</span><span class="w"></span>
<span class="w"> </span><span class="k">type</span><span class="w"> </span><span class="p">(</span><span class="n">'t</span><span class="p">,</span><span class="w"> </span><span class="n">'f</span><span class="p">,</span><span class="w"> </span><span class="n">'c</span><span class="p">)</span><span class="w"> </span><span class="n">obj</span><span class="w"></span>
<span class="w"> </span><span class="k">eqtype</span><span class="w"> </span><span class="p">(</span><span class="n">'t</span><span class="p">,</span><span class="w"> </span><span class="n">'f</span><span class="p">,</span><span class="w"> </span><span class="n">'c</span><span class="p">)</span><span class="w"> </span><span class="n">obj'</span><span class="w"></span>
<span class="w"> </span><span class="p">...</span><span class="w"></span>
<span class="w"> </span><span class="k">type</span><span class="w"> </span><span class="p">(</span><span class="n">'o</span><span class="p">,</span><span class="w"> </span><span class="n">'f</span><span class="p">)</span><span class="w"> </span><span class="n">ptr</span><span class="w"></span>
<span class="w"> </span><span class="k">eqtype</span><span class="w"> </span><span class="p">(</span><span class="n">'o</span><span class="p">,</span><span class="w"> </span><span class="n">'f</span><span class="p">)</span><span class="w"> </span><span class="n">ptr'</span><span class="w"></span>
<span class="w"> </span><span class="p">...</span><span class="w"></span>
<span class="w"> </span><span class="k">type</span><span class="w"> </span><span class="n">'f</span><span class="w"> </span><span class="n">fptr</span><span class="w"></span>
<span class="w"> </span><span class="k">type</span><span class="w"> </span><span class="n">'f</span><span class="w"> </span><span class="n">ptr'</span><span class="w"></span>
<span class="w"> </span><span class="p">...</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">T</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="k">sig</span><span class="w"></span>
<span class="w"> </span><span class="k">type</span><span class="w"> </span><span class="p">(</span><span class="n">'t</span><span class="p">,</span><span class="w"> </span><span class="n">'f</span><span class="p">)</span><span class="w"> </span><span class="n">typ</span><span class="w"></span>
<span class="w"> </span><span class="p">...</span><span class="w"></span>
<span class="w"> </span><span class="k">end</span><span class="w"></span>
<span class="k">end</span><span class="w"></span>
</pre></div></div></div>
<div class="paragraph"><p>The rule for <span class="monospaced">('t, 'f, 'c) obj</span>,<span class="monospaced">('t, 'f, 'c) ptr</span>, and also <span class="monospaced">('t, 'f)
T.typ</span> is that whenever <span class="monospaced">F fptr</span> occurs within the instantiation of
<span class="monospaced">'t</span>, then <span class="monospaced">'f</span> must be instantiated to <span class="monospaced">F</span>. In all other cases, <span class="monospaced">'f</span>
will be instantiated to <span class="monospaced">unit</span>.</p></div>
</div>
<div class="attribution">
</div></div>
<div class="paragraph"><p>(In the actual MLton implementation, an abstract type <span class="monospaced">naf</span>
(not-a-function) is used instead of <span class="monospaced">unit</span>.)</p></div>
<div class="paragraph"><p>While this means that type-annotated programs may not type-check under
both the SML/NJ implementation and the MLton implementation, this
should not be a problem in practice. Tools, like <span class="monospaced">ml-nlffigen</span>, which
are necessarily implementation dependent (in order to make
<a href="CallingFromSMLToCFunctionPointer">calls through a C function
pointer</a>), may be easily extended to emit the additional type
parameter. Client code which uses such generated glue-code (e.g.,
Section 1 of <a href="References#Blume01">Blume01</a>) need rarely write type-annotations,
thanks to the magic of type inference.</p></div>
</div></div>
</li>
<li>
<p>
The above implementation suffers from two disadvantages.
</p>
<div class="openblock">
<div class="content">
<div class="paragraph"><p>First, it changes the MLNLFFI Library interface, meaning that the same
program may not type-check under both the SML/NJ implementation and
the MLton implementation (though, in light of type inference and the
richer <span class="monospaced">MLRep</span> structure provided by MLton, this point is mostly
moot).</p></div>
<div class="paragraph"><p>Second, it appears to unnecessarily duplicate type information. For
example, an external C variable of type <span class="monospaced">int (* f[3])(int)</span> (that is,
an array of three function pointers), would be represented by the SML
type <span class="monospaced">(((sint -> sint) fptr, dec dg3) arr, sint -> sint, rw) obj</span>.
One might well ask why the <span class="monospaced">'f</span> instantiation (<span class="monospaced">sint -> sint</span> in this
case) cannot be <em>extracted</em> from the <span class="monospaced">'t</span> instantiation
(<span class="monospaced">((sint -> sint) fptr, dec dg3) arr</span> in this case), obviating the
need for a separate <em>function-type</em> type argument. There are a number
of components to an complete answer to this question. Foremost is the
fact that <a href="StandardML"> Standard ML</a> supports neither (general)
type-level functions nor intensional polymorphism.</p></div>
<div class="paragraph"><p>A more direct answer for MLNLFFI is that in the SML/NJ implemention,
the definition of the types <span class="monospaced">('t, 'c) obj</span> and <span class="monospaced">('t, 'c) ptr</span> are made
in such a way that the type variables <span class="monospaced">'t</span> and <span class="monospaced">'c</span> are <a href="PhantomType">
phantom</a> (not contributing to the run-time representation of an
<span class="monospaced">('t, 'c) obj</span> or <span class="monospaced">('t, 'c) ptr</span> value), despite the fact that the
types <span class="monospaced">((sint -> sint) fptr, rw) ptr</span> and
<span class="monospaced">((double -> double) fptr, rw) ptr</span> necessarily carry distinct (and
type incompatible) run-time (C-)type information (RTTI), corresponding
to the different calling conventions of the two C functions. The
<span class="monospaced">Unsafe.cast</span> "cheat" overcomes the type incompatibility without
introducing a new type variable (as in the first solution above).</p></div>
<div class="paragraph"><p>Hence, the reason that <em>function-type</em> type cannot be extracted from
the <span class="monospaced">'t</span> type variable instantiation is that the type of the
representation of RTTI doesn’t even <em>see</em> the (phantom) <span class="monospaced">'t</span> type
variable. The solution which presents itself is to give up on the
phantomness of the <span class="monospaced">'t</span> type variable, making it available to the
representation of RTTI.</p></div>
<div class="paragraph"><p>This is not without some small drawbacks. Because many of the types
used to instantiate <span class="monospaced">'t</span> carry more structure than is strictly
necessary for <span class="monospaced">'t</span>'s RTTI, it is sometimes necessary to wrap and
unwrap RTTI to accommodate the additional structure. (In the other
implementations, the corresponding operations can pass along the RTTI
unchanged.) However, these coercions contribute minuscule overhead;
in fact, in a majority of cases, MLton’s optimizations will completely
eliminate the RTTI from the final program.</p></div>
</div></div>
</li>
</ul></div>
<div class="paragraph"><p>The implementation distributed with MLton uses the second solution.</p></div>
<div class="paragraph"><p>Bonus question: Why can’t one use a <a href="UniversalType"> universal type</a>
to eliminate the use of <span class="monospaced">Unsafe.cast</span>?</p></div>
<div class="ulist"><ul>
<li>
<p>
Answer: ???
</p>
</li>
</ul></div>
</div></div>
</li>
<li>
<p>
MLton (in both of the above implementations) provides a richer
<span class="monospaced">MLRep</span> structure, utilizing <span class="monospaced">Int<em><N></em></span> and <span class="monospaced">Word<em><N></em></span>
structures.
</p>
<div class="openblock">
<div class="content">
<div class="listingblock">
<div class="content"><div class="highlight"><pre><span class="k">structure</span><span class="w"> </span><span class="n">MLRep</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">struct</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">Char</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w"> </span><span class="k">struct</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">Signed</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Int8</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">Unsigned</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Word8</span><span class="w"></span>
<span class="w"> </span><span class="cm">(* word-style bit-operations on integers... *)</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n"><:SignedBitops</span><span class="p">:></span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">IntBitOps</span><span class="p">(</span><span class="k">structure</span><span class="w"> </span><span class="n">I</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Signed</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">W</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Unsigned</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="k">end</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">Short</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w"> </span><span class="k">struct</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">Signed</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Int16</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">Unsigned</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Word16</span><span class="w"></span>
<span class="w"> </span><span class="cm">(* word-style bit-operations on integers... *)</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n"><:SignedBitops</span><span class="p">:></span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">IntBitOps</span><span class="p">(</span><span class="k">structure</span><span class="w"> </span><span class="n">I</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Signed</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">W</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Unsigned</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="k">end</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">Int</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w"> </span><span class="k">struct</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">Signed</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Int32</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">Unsigned</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Word32</span><span class="w"></span>
<span class="w"> </span><span class="cm">(* word-style bit-operations on integers... *)</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n"><:SignedBitops</span><span class="p">:></span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">IntBitOps</span><span class="p">(</span><span class="k">structure</span><span class="w"> </span><span class="n">I</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Signed</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">W</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Unsigned</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="k">end</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">Long</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w"> </span><span class="k">struct</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">Signed</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Int32</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">Unsigned</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Word32</span><span class="w"></span>
<span class="w"> </span><span class="cm">(* word-style bit-operations on integers... *)</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n"><:SignedBitops</span><span class="p">:></span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">IntBitOps</span><span class="p">(</span><span class="k">structure</span><span class="w"> </span><span class="n">I</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Signed</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">W</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Unsigned</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="k">end</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n"><:LongLong</span><span class="p">:></span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w"> </span><span class="k">struct</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">Signed</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Int64</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">Unsigned</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Word64</span><span class="w"></span>
<span class="w"> </span><span class="cm">(* word-style bit-operations on integers... *)</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n"><:SignedBitops</span><span class="p">:></span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">IntBitOps</span><span class="p">(</span><span class="k">structure</span><span class="w"> </span><span class="n">I</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Signed</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">W</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Unsigned</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="k">end</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">Float</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Real32</span><span class="w"></span>
<span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">Double</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Real64</span><span class="w"></span>
<span class="k">end</span><span class="w"></span>
</pre></div></div></div>
<div class="paragraph"><p>This would appear to be a better interface, even when an
implementation must choose <span class="monospaced">Int32</span> and <span class="monospaced">Word32</span> as the representation
for smaller C-types.</p></div>
</div></div>
</li>
</ul></div>
</div>
</div>
</div>
<div id="footnotes"><hr></div>
<div id="footer">
<div id="footer-text">
</div>
<div id="footer-badges">
</div>
</div>
</body>
</html>
|