about summary refs log blame commit diff stats
path: root/linux/106stream.subx
blob: 84d0580bb15420682491e3b060c761588c901b3f (plain) (tree)









































































                                                                                                                                                                              
# streams: data structure for operating on arrays in a stateful manner
#
# A stream looks like this:
#   write: int  # index at which writes go
#   read: int  # index that we've read until
#   data: (array byte)  # prefixed by size as usual
#
# some primitives for operating on streams:
#   - clear-stream (clears everything but the data size)
#   - rewind-stream (resets read pointer)

== code
#   instruction                     effective address                                                   register    displacement    immediate
# . op          subop               mod             rm32          base        index         scale       r32
# . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes

clear-stream:  # f: (addr stream byte)
    # . prologue
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    50/push-eax
    51/push-ecx
    # eax = f
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         0/r32/eax   8/disp8         .                 # copy *(ebp+8) to eax
    # var count/ecx: int = f->size
    8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(eax+8) to ecx
    # var max/ecx: (addr byte) = &f->data[f->size]
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   0xc/disp8       .                 # copy eax+ecx+12 to ecx
    # f->write = 0
    c7          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0/imm32           # copy to *eax
    # f->read = 0
    c7          0/subop/copy        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         0/imm32           # copy to *(eax+4)
    # - clear all stream data
    # - this isn't strictly necessary, and it can slow things down *a lot*, but better safe than sorry.
    # var curr/eax: (addr byte) = f->data
    81          0/subop/add         3/mod/direct    0/rm32/eax    .           .             .           .           .               0xc/imm32         # add to eax
$clear-stream:loop:
    # if (curr >= max) break
    39/compare                      3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # compare eax with ecx
    73/jump-if-addr>=  $clear-stream:end/disp8
    # *curr = 0
    c6          0/subop/copy-byte   0/mod/direct    0/rm32/eax    .           .             .           .           .               0/imm8            # copy byte to *eax
    # ++curr
    40/increment-eax
    eb/jump  $clear-stream:loop/disp8
$clear-stream:end:
    # . restore registers
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

rewind-stream:  # f: (addr stream byte)
    # . prologue
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    50/push-eax
    # eax = f
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         0/r32/eax   8/disp8         .                 # copy *(ebp+8) to eax
    # f->read = 0
    c7          0/subop/copy        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         0/imm32           # copy to *(eax+4)
$rewind-stream:end:
    # . restore registers
    58/pop-to-eax
    # . epilogue
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

# . . vim:nowrap:textwidth=0
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
















                                                                                                               
           
                                
                                  
                                                             
                             
                             
































                                                                                 
                                                                                                                                     
                         








































































































                                                                                                                                                                                                              
                                                             


















































                                                                                                                                                                                                     



                                     
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Mu - 310copy-bytes.subx</title>
<meta name="Generator" content="Vim/8.1">
<meta name="plugin-version" content="vim8.1_v1">
<meta name="syntax" content="none">
<meta name="settings" content="number_lines,use_css,pre_wrap,no_foldcolumn,expand_tabs,line_ids,prevent_copy=">
<meta name="colorscheme" content="minimal-light">
<style type="text/css">
<!--
pre { white-space: pre-wrap; font-family: monospace; color: #000000; background-color: #c6c6c6; }
body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; }
a { color:inherit; }
* { font-size:12pt; font-size: 1em; }
.subxComment { color: #005faf; }
.LineNr { }
.SpecialChar { color: #d70000; }
.subxS1Comment { color: #0000af; }
.subxFunction { color: #af5f00; text-decoration: underline; }
.Constant { color: #008787; }
.subxTest { color: #5f8700; }
-->
</style>

<script type='text/javascript'>
<!--

/* function to open any folds containing a jumped-to line before jumping to it */
function JumpToLine()
{
  var lineNum;
  lineNum = window.location.hash;
  lineNum = lineNum.substr(1); /* strip off '#' */

  if (lineNum.indexOf('L') == -1) {
    lineNum = 'L'+lineNum;
  }
  var lineElem = document.getElementById(lineNum);
  /* Always jump to new location even if the line was hidden inside a fold, or
   * we corrected the raw number to a line ID.
   */
  if (lineElem) {
    lineElem.scrollIntoView(true);
  }
  return true;
}
if ('onhashchange' in window) {
  window.onhashchange = JumpToLine;
}

-->
</script>
</head>
<body onload='JumpToLine();'>
<a href='https://github.com/akkartik/mu/blob/main/310copy-bytes.subx'>https://github.com/akkartik/mu/blob/main/310copy-bytes.subx</a>
<pre id='vimCodeElement'>
<span id="L1" class="LineNr">  1 </span><span class="subxComment"># Some helpers for copying non-overlapping regions of memory.</span>
<span id="L2" class="LineNr">  2 </span><span class="subxComment"># Really only intended to be called from code generated by mu.subx.</span>
<span id="L3" class="LineNr">  3 </span>
<span id="L4" class="LineNr">  4 </span>== code
<span id="L5" class="LineNr">  5 </span>
<span id="L6" class="LineNr">  6 </span><span class="subxFunction">copy-bytes</span>:  <span class="subxComment"># src: (addr byte), dest: (addr byte), size: int</span>
<span id="L7" class="LineNr">  7 </span>    <span class="subxComment"># pseudocode:</span>
<span id="L8" class="LineNr">  8 </span>    <span class="subxComment">#   curr-src/esi = src</span>
<span id="L9" class="LineNr">  9 </span>    <span class="subxComment">#   curr-dest/edi = dest</span>
<span id="L10" class="LineNr"> 10 </span>    <span class="subxComment">#   i/ecx = 0</span>
<span id="L11" class="LineNr"> 11 </span>    <span class="subxComment">#   while true</span>
<span id="L12" class="LineNr"> 12 </span>    <span class="subxComment">#     if (i &gt;= size) break</span>
<span id="L13" class="LineNr"> 13 </span>    <span class="subxComment">#     *curr-dest = *curr-src</span>
<span id="L14" class="LineNr"> 14 </span>    <span class="subxComment">#     ++curr-src</span>
<span id="L15" class="LineNr"> 15 </span>    <span class="subxComment">#     ++curr-dest</span>
<span id="L16" class="LineNr"> 16 </span>    <span class="subxComment">#     ++i</span>
<span id="L17" class="LineNr"> 17 </span>    <span class="subxComment">#</span>
<span id="L18" class="LineNr"> 18 </span>    <span class="subxS1Comment"># . prologue</span>
<span id="L19" class="LineNr"> 19 </span>    55/push-ebp
<span id="L20" class="LineNr"> 20 </span>    89/&lt;- %ebp 4/r32/esp
<span id="L21" class="LineNr"> 21 </span>    <span class="subxS1Comment"># . save registers</span>
<span id="L22" class="LineNr"> 22 </span>    50/push-eax
<span id="L23" class="LineNr"> 23 </span>    51/push-ecx
<span id="L24" class="LineNr"> 24 </span>    52/push-edx
<span id="L25" class="LineNr"> 25 </span>    56/push-esi
<span id="L26" class="LineNr"> 26 </span>    57/push-edi
<span id="L27" class="LineNr"> 27 </span>    <span class="subxComment"># curr-src/esi = src</span>
<span id="L28" class="LineNr"> 28 </span>    8b/-&gt; *(ebp+8) 6/r32/esi
<span id="L29" class="LineNr"> 29 </span>    <span class="subxComment"># curr-dest/edi = dest</span>
<span id="L30" class="LineNr"> 30 </span>    8b/-&gt; *(ebp+0xc) 7/r32/edi
<span id="L31" class="LineNr"> 31 </span>    <span class="subxComment"># var i/ecx: int = 0</span>
<span id="L32" class="LineNr"> 32 </span>    b9/copy-to-ecx 0/imm32
<span id="L33" class="LineNr"> 33 </span>    <span class="subxComment"># edx = size</span>
<span id="L34" class="LineNr"> 34 </span>    8b/-&gt; *(ebp+0x10) 2/r32/edx
<span id="L35" class="LineNr"> 35 </span>    {
<span id="L36" class="LineNr"> 36 </span>      <span class="subxComment"># if (i &gt;= size) break</span>
<span id="L37" class="LineNr"> 37 </span>      39/compare %ecx 2/r32/edx
<span id="L38" class="LineNr"> 38 </span>      7d/jump-if-&gt;=  <span class="Constant">break</span>/disp8
<span id="L39" class="LineNr"> 39 </span>      <span class="subxComment"># *curr-dest = *curr-src</span>
<span id="L40" class="LineNr"> 40 </span>      8a/byte-&gt; *esi 0/r32/AL
<span id="L41" class="LineNr"> 41 </span>      88/byte&lt;- *edi 0/r32/AL
<span id="L42" class="LineNr"> 42 </span>      <span class="subxComment"># update</span>
<span id="L43" class="LineNr"> 43 </span>      46/increment-esi
<span id="L44" class="LineNr"> 44 </span>      47/increment-edi
<span id="L45" class="LineNr"> 45 </span>      41/increment-ecx
<span id="L46" class="LineNr"> 46 </span>      eb/jump <span class="Constant">loop</span>/disp8
<span id="L47" class="LineNr"> 47 </span>    }
<span id="L48" class="LineNr"> 48 </span><span class="Constant">$copy-bytes:end</span>:
<span id="L49" class="LineNr"> 49 </span>    <span class="subxS1Comment"># . restore registers</span>
<span id="L50" class="LineNr"> 50 </span>    5f/pop-to-edi
<span id="L51" class="LineNr"> 51 </span>    5e/pop-to-esi
<span id="L52" class="LineNr"> 52 </span>    5a/pop-to-edx
<span id="L53" class="LineNr"> 53 </span>    59/pop-to-ecx
<span id="L54" class="LineNr"> 54 </span>    58/pop-to-eax
<span id="L55" class="LineNr"> 55 </span>    <span class="subxS1Comment"># . epilogue</span>
<span id="L56" class="LineNr"> 56 </span>    89/&lt;- %esp 5/r32/ebp
<span id="L57" class="LineNr"> 57 </span>    5d/pop-to-ebp
<span id="L58" class="LineNr"> 58 </span>    c3/return
<span id="L59" class="LineNr"> 59 </span>
<span id="L60" class="LineNr"> 60 </span><span class="subxFunction">stream-to-array</span>:  <span class="subxComment"># in: (addr stream _), out: (addr handle array _)</span>
<span id="L61" class="LineNr"> 61 </span>    <span class="subxS1Comment"># . prologue</span>
<span id="L62" class="LineNr"> 62 </span>    55/push-ebp
<span id="L63" class="LineNr"> 63 </span>    89/&lt;- %ebp 4/r32/esp
<span id="L64" class="LineNr"> 64 </span>    <span class="subxS1Comment"># . save registers</span>
<span id="L65" class="LineNr"> 65 </span>    50/push-eax
<span id="L66" class="LineNr"> 66 </span>    51/push-ecx
<span id="L67" class="LineNr"> 67 </span>    52/push-edx
<span id="L68" class="LineNr"> 68 </span>    56/push-esi
<span id="L69" class="LineNr"> 69 </span>    <span class="subxComment"># esi = s</span>
<span id="L70" class="LineNr"> 70 </span>    8b/-&gt; *(ebp+8) 6/r32/esi
<span id="L71" class="LineNr"> 71 </span>    <span class="subxComment"># var len/ecx: int = s-&gt;write - s-&gt;read</span>
<span id="L72" class="LineNr"> 72 </span>    8b/-&gt; *esi 1/r32/ecx
<span id="L73" class="LineNr"> 73 </span>    2b/subtract *(esi+4) 1/r32/ecx
<span id="L74" class="LineNr"> 74 </span>    <span class="subxComment"># allocate</span>
<span id="L75" class="LineNr"> 75 </span>    (<a href='120allocate.subx.html#L576'>allocate-array</a> <span class="SpecialChar"><a href='120allocate.subx.html#L27'>Heap</a></span> %ecx *(ebp+0xc))
<span id="L76" class="LineNr"> 76 </span>    <span class="subxComment"># var in/edx: (addr byte) = s-&gt;data + s-&gt;read</span>
<span id="L77" class="LineNr"> 77 </span>    8b/-&gt; *(esi+4) 2/r32/edx
<span id="L78" class="LineNr"> 78 </span>    8d/copy-address *(esi+edx+0xc) 2/r32/edx
<span id="L79" class="LineNr"> 79 </span>    <span class="subxComment"># var dest/eax: (addr byte) = data for out</span>
<span id="L80" class="LineNr"> 80 </span>    8b/-&gt; *(ebp+0xc) 0/r32/eax
<span id="L81" class="LineNr"> 81 </span>    (<a href='120allocate.subx.html#L256'>lookup</a> *eax *(eax+4))  <span class="subxComment"># =&gt; eax</span>
<span id="L82" class="LineNr"> 82 </span>    8d/copy-address *(eax+4) 0/r32/eax
<span id="L83" class="LineNr"> 83 </span>    <span class="subxComment">#</span>
<span id="L84" class="LineNr"> 84 </span>    (<a href='310copy-bytes.subx.html#L6'>copy-bytes</a> %edx %eax %ecx)
<span id="L85" class="LineNr"> 85 </span><span class="Constant">$stream-to-array:end</span>:
<span id="L86" class="LineNr"> 86 </span>    <span class="subxS1Comment"># . restore registers</span>
<span id="L87" class="LineNr"> 87 </span>    5e/pop-to-esi
<span id="L88" class="LineNr"> 88 </span>    5a/pop-to-edx
<span id="L89" class="LineNr"> 89 </span>    59/pop-to-ecx
<span id="L90" class="LineNr"> 90 </span>    58/pop-to-eax
<span id="L91" class="LineNr"> 91 </span>    <span class="subxS1Comment"># . epilogue</span>
<span id="L92" class="LineNr"> 92 </span>    89/&lt;- %esp 5/r32/ebp
<span id="L93" class="LineNr"> 93 </span>    5d/pop-to-ebp
<span id="L94" class="LineNr"> 94 </span>    c3/return
<span id="L95" class="LineNr"> 95 </span>
<span id="L96" class="LineNr"> 96 </span><span class="subxTest">test-stream-to-array</span>:
<span id="L97" class="LineNr"> 97 </span>    <span class="subxS1Comment"># . prologue</span>
<span id="L98" class="LineNr"> 98 </span>    55/push-ebp
<span id="L99" class="LineNr"> 99 </span>    89/&lt;- %ebp 4/r32/esp
<span id="L100" class="LineNr">100 </span>    <span class="subxComment"># setup</span>
<span id="L101" class="LineNr">101 </span>    (<a href='106stream.subx.html#L17'>clear-stream</a> <a href='112read-byte.subx.html#L331'>_test-input-stream</a>)
<span id="L102" class="LineNr">102 </span>    (<a href='108write.subx.html#L24'>write</a> <a href='112read-byte.subx.html#L331'>_test-input-stream</a> <span class="Constant">&quot;abc&quot;</span>)
<span id="L103" class="LineNr">103 </span>    <span class="subxComment"># skip something</span>
<span id="L104" class="LineNr">104 </span>    (<a href='112read-byte.subx.html#L273'>read-byte</a> <a href='112read-byte.subx.html#L331'>_test-input-stream</a>)  <span class="subxComment"># =&gt; eax</span>
<span id="L105" class="LineNr">105 </span>    <span class="subxComment"># var out/ecx: (handle array byte)</span>
<span id="L106" class="LineNr">106 </span>    68/push 0/imm32
<span id="L107" class="LineNr">107 </span>    68/push 0/imm32
<span id="L108" class="LineNr">108 </span>    89/&lt;- %ecx 4/r32/esp
<span id="L109" class="LineNr">109 </span>    <span class="subxComment">#</span>
<span id="L110" class="LineNr">110 </span>    (<a href='310copy-bytes.subx.html#L60'>stream-to-array</a> <a href='112read-byte.subx.html#L331'>_test-input-stream</a> %ecx)
<span id="L111" class="LineNr">111 </span>    (<a href='120allocate.subx.html#L256'>lookup</a> *ecx *(ecx+4))  <span class="subxComment"># =&gt; eax</span>
<span id="L112" class="LineNr">112 </span>    (<a href='105string-equal.subx.html#L220'>check-strings-equal</a> %eax <span class="Constant">&quot;bc&quot;</span>)
<span id="L113" class="LineNr">113 </span>    <span class="subxS1Comment"># . epilogue</span>
<span id="L114" class="LineNr">114 </span>    89/&lt;- %esp 5/r32/ebp
<span id="L115" class="LineNr">115 </span>    5d/pop-to-ebp
<span id="L116" class="LineNr">116 </span>    c3/return
<span id="L117" class="LineNr">117 </span>
<span id="L118" class="LineNr">118 </span><span class="subxComment"># like stream-to-array but ignore surrounding quotes</span>
<span id="L119" class="LineNr">119 </span><span class="subxComment"># we might do other stuff here later</span>
<span id="L120" class="LineNr">120 </span><span class="subxFunction">unquote-stream-to-array</span>:  <span class="subxComment"># in: (addr stream _), out: (addr handle array _)</span>
<span id="L121" class="LineNr">121 </span>    <span class="subxS1Comment"># . prologue</span>
<span id="L122" class="LineNr">122 </span>    55/push-ebp
<span id="L123" class="LineNr">123 </span>    89/&lt;- %ebp 4/r32/esp
<span id="L124" class="LineNr">124 </span>    <span class="subxS1Comment"># . save registers</span>
<span id="L125" class="LineNr">125 </span>    50/push-eax
<span id="L126" class="LineNr">126 </span>    51/push-ecx
<span id="L127" class="LineNr">127 </span>    52/push-edx
<span id="L128" class="LineNr">128 </span>    56/push-esi
<span id="L129" class="LineNr">129 </span>    <span class="subxComment"># esi = s</span>
<span id="L130" class="LineNr">130 </span>    8b/-&gt; *(ebp+8) 6/r32/esi
<span id="L131" class="LineNr">131 </span>    <span class="subxComment"># var len/ecx: int = s-&gt;write - s-&gt;read - 2</span>
<span id="L132" class="LineNr">132 </span>    8b/-&gt; *esi 1/r32/ecx
<span id="L133" class="LineNr">133 </span>    2b/subtract *(esi+4) 1/r32/ecx
<span id="L134" class="LineNr">134 </span>    81 7/subop/compare %ecx 2/imm32
<span id="L135" class="LineNr">135 </span>    7c/jump-if-&lt; $unquote-stream-to-array:end/disp8
<span id="L136" class="LineNr">136 </span>    81 5/subop/subtract %ecx 2/imm32
<span id="L137" class="LineNr">137 </span>    <span class="subxComment"># allocate</span>
<span id="L138" class="LineNr">138 </span>    (<a href='120allocate.subx.html#L576'>allocate-array</a> <span class="SpecialChar"><a href='120allocate.subx.html#L27'>Heap</a></span> %ecx *(ebp+0xc))
<span id="L139" class="LineNr">139 </span>    <span class="subxComment"># var in/edx: (addr byte) = s-&gt;data + s-&gt;read + 1</span>
<span id="L140" class="LineNr">140 </span>    8b/-&gt; *(esi+4) 2/r32/edx
<span id="L141" class="LineNr">141 </span>    8d/copy-address *(esi+edx+0xd) 2/r32/edx  <span class="subxComment"># Stream-data + 1</span>
<span id="L142" class="LineNr">142 </span>    <span class="subxComment"># var dest/eax: (addr byte) = data for out</span>
<span id="L143" class="LineNr">143 </span>    8b/-&gt; *(ebp+0xc) 0/r32/eax
<span id="L144" class="LineNr">144 </span>    (<a href='120allocate.subx.html#L256'>lookup</a> *eax *(eax+4))  <span class="subxComment"># =&gt; eax</span>
<span id="L145" class="LineNr">145 </span>    8d/copy-address *(eax+4) 0/r32/eax
<span id="L146" class="LineNr">146 </span>    <span class="subxComment">#</span>
<span id="L147" class="LineNr">147 </span>    (<a href='310copy-bytes.subx.html#L6'>copy-bytes</a> %edx %eax %ecx)
<span id="L148" class="LineNr">148 </span><span class="Constant">$unquote-stream-to-array:end</span>:
<span id="L149" class="LineNr">149 </span>    <span class="subxS1Comment"># . restore registers</span>
<span id="L150" class="LineNr">150 </span>    5e/pop-to-esi
<span id="L151" class="LineNr">151 </span>    5a/pop-to-edx
<span id="L152" class="LineNr">152 </span>    59/pop-to-ecx
<span id="L153" class="LineNr">153 </span>    58/pop-to-eax
<span id="L154" class="LineNr">154 </span>    <span class="subxS1Comment"># . epilogue</span>
<span id="L155" class="LineNr">155 </span>    89/&lt;- %esp 5/r32/ebp
<span id="L156" class="LineNr">156 </span>    5d/pop-to-ebp
<span id="L157" class="LineNr">157 </span>    c3/return
</pre>
</body>
</html>
<!-- vim: set foldmethod=manual : -->