From 8aeb85f04ee68b960a6d326aca1a17dec2f6d019 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 9 Dec 2019 01:26:58 -0800 Subject: 5806 --- html/056trace.subx.html | 1998 +++++++++++++++++++++++------------------------ 1 file changed, 989 insertions(+), 1009 deletions(-) (limited to 'html/056trace.subx.html') diff --git a/html/056trace.subx.html b/html/056trace.subx.html index 1da88893..61609cff 100644 --- a/html/056trace.subx.html +++ b/html/056trace.subx.html @@ -61,1015 +61,995 @@ if ('onhashchange' in window) { https://github.com/akkartik/mu/blob/master/056trace.subx
-   1 # primitives for emitting traces to a 'trace' stream, and for tests to make assertions on its contents
-   2 #
-   3 # A trace stream looks like a regular stream:
-   4 #   write : int  # index at which writes go
-   5 #   read : int  # index that we've read until
-   6 #   data : (array byte)  # prefixed by length as usual
-   7 # Usually the trace stream will be in a separate segment set aside for the purpose.
-   8 #
-   9 # primitives for operating on traces (arguments in quotes):
-  10 #   - initialize-trace-stream: populates Trace-stream with a new segment of the given 'size'
-  11 #   - trace: adds a 'line' to Trace-stream
-  12 #   - check-trace-contains: scans from Trace-stream's start for a matching 'line', prints a 'message' to stderr on failure
-  13 #   - check-trace-scans-to: scans from Trace-stream's read pointer for a matching 'line', prints a 'message' to stderr on failure
-  14 
-  15 == data
-  16 
-  17 # We'll save the address of the trace segment here.
-  18 Trace-stream:
-  19     0/imm32
-  20 
-  21 Trace-segment:
-  22     0/imm32/curr
-  23     0/imm32/limit
-  24 
-  25 # Fake trace-stream for tests.
-  26 # Also illustrates the layout of the real trace-stream (segment).
-  27 _test-trace-stream:
-  28     # current write index
-  29     0/imm32
-  30     # current read index
-  31     0/imm32
-  32     # length
-  33     8/imm32
-  34     # data
-  35     00 00 00 00 00 00 00 00  # 8 bytes
-  36 
-  37 == code
-  38 #   instruction                     effective address                                                   register    displacement    immediate
-  39 # . op          subop               mod             rm32          base        index         scale       r32
-  40 # . 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
-  41 
-  42 # Allocate a new segment for the trace stream, initialize its length, and save its address to Trace-stream.
-  43 # The Trace-stream segment will consist of variable-length lines separated by newlines (0x0a)
-  44 initialize-trace-stream:  # n : int
-  45     # . prologue
-  46     55/push-ebp
-  47     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-  48     # . save registers
-  49     50/push-eax
-  50     51/push-ecx
-  51     # ecx = n
-  52     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
-  53     # Trace-segment = new-segment(n)
-  54     # . . push args
-  55     68/push  Trace-segment/imm32
-  56     51/push-ecx
-  57     # . . call
-  58     e8/call  new-segment/disp32
-  59     # . . discard args
-  60     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-  61     # copy Trace-segment->curr to *Trace-stream
-  62     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-segment/disp32              # copy *Trace-segment to eax
-  63     # watch point to catch Trace-stream leaks
-  64 #? $watch-1:
-  65     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy eax to *Trace-stream
-  66     # Trace-stream->length = n - 12
-  67     # . ecx -= 12
-  68     81          5/subop/subtract    3/mod/direct    1/rm32/ecx    .           .             .           .           .               0xc/imm32         # subtract from ecx
-  69     # . Trace-stream->length = ecx
-  70     89/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           1/r32/ecx   8/disp8         .                 # copy ecx to *(eax+8)
-  71 $initialize-trace-stream:end:
-  72     # . restore registers
-  73     59/pop-to-ecx
-  74     58/pop-to-eax
-  75     # . epilogue
-  76     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-  77     5d/pop-to-ebp
-  78     c3/return
-  79 
-  80 # Append a string to the given trace stream.
-  81 # Silently give up if it's already full. Or truncate the string if there isn't enough room.
-  82 trace:  # line : (address string)
-  83     # . prologue
-  84     55/push-ebp
-  85     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-  86     # . save registers
-  87     50/push-eax
-  88     51/push-ecx
-  89     52/push-edx
-  90     53/push-ebx
-  91     56/push-esi
-  92     57/push-edi
-  93     # edi = *Trace-stream
-  94     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           7/r32/edi   Trace-stream/disp32               # copy *Trace-stream to edi
-  95     # esi = line
-  96     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
-  97     # ecx = t->write
-  98     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           1/r32/ecx   .               .                 # copy *edi to ecx
-  99     # edx = t->length
- 100     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           2/r32/edx   8/disp8         .                 # copy *(edi+8) to edx
- 101     # eax = _append-3(&t->data[t->write], &t->data[t->length], line)
- 102     # . . push line
- 103     56/push-esi
- 104     # . . push &t->data[t->length]
- 105     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    7/base/edi  2/index/edx   .           3/r32/ebx   0xc/disp8       .                 # copy edi+edx+12 to ebx
- 106     53/push-ebx
- 107     # . . push &t->data[t->write]
- 108     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    7/base/edi  1/index/ecx   .           3/r32/ebx   0xc/disp8       .                 # copy edi+ecx+12 to ebx
- 109     53/push-ebx
- 110     # . . call
- 111     e8/call  _append-3/disp32
- 112     # . . discard args
- 113     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 114     # if (eax == 0) return
- 115     3d/compare-eax-and  0/imm32
- 116     74/jump-if-equal  $trace:end/disp8
- 117     # t->write += eax
- 118     01/add                          0/mod/indirect  7/rm32/edi    .           .             .           0/r32/eax   .               .                 # add eax to *edi
- 119     # refresh ecx = t->write
- 120     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           1/r32/ecx   .               .                 # copy *edi to ecx
- 121     # eax = _append-3(&t->data[t->write], &t->data[t->length], line)
- 122     # . . push line
- 123     68/push  Newline/imm32
- 124     # . . push &t->data[t->length]
- 125     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    7/base/edi  2/index/edx   .           3/r32/ebx   0xc/disp8       .                 # copy edi+edx+12 to ebx
- 126     53/push-ebx
- 127     # . . push &t->data[t->write]
- 128     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    7/base/edi  1/index/ecx   .           3/r32/ebx   0xc/disp8       .                 # copy edi+ecx+12 to ebx
- 129     53/push-ebx
- 130     # . . call
- 131     e8/call  _append-3/disp32
- 132     # . . discard args
- 133     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 134     # t->write += eax
- 135     01/add                          0/mod/indirect  7/rm32/edi    .           .             .           0/r32/eax   .               .                 # add eax to *edi
- 136 $trace:end:
- 137     # . restore registers
- 138     5f/pop-to-edi
- 139     5e/pop-to-esi
- 140     5b/pop-to-ebx
- 141     5a/pop-to-edx
- 142     59/pop-to-ecx
- 143     58/pop-to-eax
- 144     # . epilogue
- 145     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
- 146     5d/pop-to-ebp
- 147     c3/return
- 148 
- 149 test-trace-single:
- 150     # push *Trace-stream
- 151     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
- 152     # *Trace-stream = _test-trace-stream
- 153     b8/copy-to-eax  _test-trace-stream/imm32
- 154     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy eax to *Trace-stream
- 155     # clear-trace-stream()
- 156     e8/call  clear-trace-stream/disp32
- 157     # trace("Ab")
- 158     # . . push args
- 159     68/push  "Ab"/imm32
- 160     # . . call
- 161     e8/call  trace/disp32
- 162     # . . discard args
- 163     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 164     # check-ints-equal(*_test-trace-stream->data, 41/A 62/b 0a/newline 00, msg)
- 165     # . . push args
- 166     68/push  "F - test-trace-single"/imm32
- 167     68/push  0x0a6241/imm32/Ab-newline
- 168     # . . push *_test-trace-stream->data
- 169     b8/copy-to-eax  _test-trace-stream/imm32
- 170     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           0xc/disp8       .                 # push *(eax+12)
- 171     # . . call
- 172     e8/call  check-ints-equal/disp32
- 173     # . . discard args
- 174     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 175     # pop into *Trace-stream
- 176     8f          0/subop/pop         0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # pop into *Trace-stream
- 177     # end
- 178     c3/return
- 179 
- 180 test-trace-appends:
- 181     # push *Trace-stream
- 182     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
- 183     # *Trace-stream = _test-trace-stream
- 184     b8/copy-to-eax  _test-trace-stream/imm32
- 185     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy eax to *Trace-stream
- 186     # clear-trace-stream()
- 187     e8/call  clear-trace-stream/disp32
- 188     # trace("C")
- 189     # . . push args
- 190     68/push  "C"/imm32
- 191     # . . call
- 192     e8/call  trace/disp32
- 193     # . . discard args
- 194     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 195     # trace("D")
- 196     # . . push args
- 197     68/push  "D"/imm32
- 198     # . . call
- 199     e8/call  trace/disp32
- 200     # . . discard args
- 201     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 202     # check-ints-equal(*_test-trace-stream->data, 43/C 0a/newline 44/D 0a/newline, msg)
- 203     # . . push args
- 204     68/push  "F - test-trace-appends"/imm32
- 205     68/push  0x0a440a43/imm32/C-newline-D-newline
- 206     # . . push *_test-trace-stream->data
- 207     b8/copy-to-eax  _test-trace-stream/imm32
- 208     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           0xc/disp8       .                 # push *(eax+12)
- 209     # . . call
- 210     e8/call  check-ints-equal/disp32
- 211     # . . discard args
- 212     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 213     # pop into *Trace-stream
- 214     8f          0/subop/pop         0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # pop into *Trace-stream
- 215     # end
- 216     c3/return
- 217 
- 218 test-trace-empty-line:
- 219     # push *Trace-stream
- 220     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
- 221     # *Trace-stream = _test-trace-stream
- 222     b8/copy-to-eax  _test-trace-stream/imm32
- 223     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy eax to *Trace-stream
- 224     # clear-trace-stream()
- 225     e8/call  clear-trace-stream/disp32
- 226     # trace("")
- 227     # . . push args
- 228     68/push  ""/imm32
- 229     # . . call
- 230     e8/call  trace/disp32
- 231     # . . discard args
- 232     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 233     # check-ints-equal(*_test-trace-stream->data, 0, msg)
- 234     # . . push args
- 235     68/push  "F - test-trace-empty-line"/imm32
- 236     68/push  0/imm32
- 237     # . . push *_test-trace-stream->data
- 238     b8/copy-to-eax  _test-trace-stream/imm32
- 239     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           0xc/disp8       .                 # push *(eax+12)
- 240     # . . call
- 241     e8/call  check-ints-equal/disp32
- 242     # . . discard args
- 243     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 244     # pop into *Trace-stream
- 245     8f          0/subop/pop         0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # pop into *Trace-stream
- 246     # end
- 247     c3/return
- 248 
- 249 check-trace-contains:  # line : (address string), msg : (address string)
- 250     # . prologue
- 251     55/push-ebp
- 252     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 253     # rewind-stream(*Trace-stream)
- 254     # . . push args
- 255     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
- 256     # . . call
- 257     e8/call  rewind-stream/disp32
- 258     # . . discard args
- 259     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 260     # check-trace-scans-to(line, msg)
- 261     # . . push args
- 262     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
- 263     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
- 264     # . . call
- 265     e8/call  check-trace-scans-to/disp32
- 266     # . . discard args
- 267     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 268 $check-trace-contains:end:
- 269     # . epilogue
- 270     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
- 271     5d/pop-to-ebp
- 272     c3/return
- 273 
- 274 check-trace-scans-to:  # line : (address string), msg : (address string)
- 275     # . prologue
- 276     55/push-ebp
- 277     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 278     # . save registers
- 279     50/push-eax
- 280     # eax = trace-scan(line)
- 281     # . . push args
- 282     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
- 283     # . . call
- 284     e8/call  trace-scan/disp32
- 285     # . . discard args
- 286     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 287     # check-ints-equal(eax, 1, msg)
- 288     # . . push args
- 289     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
- 290     68/push  1/imm32
- 291     50/push-eax
- 292     # . . call
- 293     e8/call check-ints-equal/disp32
- 294     # . . discard args
- 295     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 296 $check-trace-scans-to:end:
- 297     # . restore registers
- 298     58/pop-to-eax
- 299     # . epilogue
- 300     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
- 301     5d/pop-to-ebp
- 302     c3/return
- 303 
- 304 # Start scanning from Trace-stream->read for 'line'. If found, update Trace-stream->read and return true.
- 305 trace-scan:  # line : (address string) -> result/eax : boolean
- 306     # pseudocode:
- 307     #   push Trace-stream->read
- 308     #   while true:
- 309     #     if Trace-stream->read >= Trace-stream->write
- 310     #       break
- 311     #     if next-line-matches?(Trace-stream, line)
- 312     #       skip-next-line(Trace-stream)
- 313     #       dump saved copy of Trace-stream->read
- 314     #       return true
- 315     #     skip-next-line(Trace-stream)
- 316     #   pop saved copy of Trace-stream->read
- 317     #   return false
- 318     #
- 319     # . prologue
- 320     55/push-ebp
- 321     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 322     # . save registers
- 323     51/push-ecx
- 324     56/push-esi
- 325     # esi = *Trace-stream
- 326     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           6/r32/esi   Trace-stream/disp32               # copy *Trace-stream to esi
- 327     # ecx = Trace-stream->write
- 328     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx                   .                 # copy *esi to ecx
- 329     # push Trace-stream->read
- 330     ff          6/subop/push        1/mod/*+disp8   6/rm32/esi    .           .             .           .           4/disp8         .                 # push *(esi+4)
- 331 $trace-scan:loop:
- 332     # if (Trace-stream->read >= Trace-stream->write) return false
- 333     39/compare                      1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # compare ecx with *(esi+4)
- 334     7d/jump-if-greater-or-equal  $trace-scan:false/disp8
- 335     # eax = next-line-matches?(Trace-stream, line)
- 336     # . . push args
- 337     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
- 338     56/push-esi
- 339     # . . call
- 340     e8/call  next-line-matches?/disp32
- 341     # . . discard args
- 342     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 343     # if (eax == 0) continue
- 344     3d/compare-eax-and  0/imm32
- 345     74/jump-if-equal  $trace-scan:continue/disp8
- 346 $trace-scan:true:
- 347     # skip-next-line(Trace-stream)
- 348     # . . push args
- 349     56/push-esi
- 350     # . . call
- 351     e8/call  skip-next-line/disp32
- 352     # . . discard args
- 353     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 354     # dump saved copy of Trace-stream->read
- 355     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 356     # return true
- 357     b8/copy-to-eax  1/imm32/true
- 358     eb/jump  $trace-scan:end/disp8
- 359 $trace-scan:continue:
- 360     # skip-next-line(Trace-stream)
- 361     # . . push args
- 362     56/push-esi
- 363     # . . call
- 364     e8/call  skip-next-line/disp32
- 365     # . . discard args
- 366     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 367     eb/jump  $trace-scan:loop/disp8
- 368 $trace-scan:false:
- 369     # restore saved copy of Trace-stream->read
- 370     8f          0/subop/pop         1/mod/*+disp8   6/rm32/esi    .           .             .           .           4/disp8         .                 # pop to *(esi+4)
- 371     # return false
- 372     b8/copy-to-eax  0/imm32/false
- 373 $trace-scan:end:
- 374     # . restore registers
- 375     59/pop-to-ecx
- 376     # . epilogue
- 377     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
- 378     5d/pop-to-ebp
- 379     c3/return
- 380 
- 381 test-trace-scan-first:
- 382     # push *Trace-stream
- 383     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
- 384     # setup
- 385     # . *Trace-stream = _test-trace-stream
- 386     b8/copy-to-eax  _test-trace-stream/imm32
- 387     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy eax to *Trace-stream
- 388     # . clear-trace-stream()
- 389     e8/call  clear-trace-stream/disp32
- 390     # . trace("Ab")
- 391     # . . push args
- 392     68/push  "Ab"/imm32
- 393     # . . call
- 394     e8/call  trace/disp32
- 395     # . . discard args
- 396     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 397     # eax = trace-scan("Ab")
- 398     # . . push args
- 399     68/push  "Ab"/imm32
- 400     # . . call
- 401     e8/call  trace-scan/disp32
- 402     # . . discard args
- 403     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 404     # check-ints-equal(eax, 1, msg)
- 405     # . . push args
- 406     68/push  "F - test-trace-scan-first"/imm32
- 407     68/push  1/imm32
- 408     50/push-eax
- 409     # . . call
- 410     e8/call check-ints-equal/disp32
- 411     # . . discard args
- 412     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 413     # pop into *Trace-stream
- 414     8f          0/subop/pop         0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # pop into *Trace-stream
- 415     # . end
- 416     c3/return
- 417 
- 418 test-trace-scan-skips-lines-until-found:
- 419     # push *Trace-stream
- 420     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
- 421     # setup
- 422     # . *Trace-stream = _test-trace-stream
- 423     b8/copy-to-eax  _test-trace-stream/imm32
- 424     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy eax to *Trace-stream
- 425     # . clear-trace-stream()
- 426     e8/call  clear-trace-stream/disp32
- 427     # . trace("Ab")
- 428     # . . push args
- 429     68/push  "Ab"/imm32
- 430     # . . call
- 431     e8/call  trace/disp32
- 432     # . . discard args
- 433     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 434     # . trace("cd")
- 435     # . . push args
- 436     68/push  "cd"/imm32
- 437     # . . call
- 438     e8/call  trace/disp32
- 439     # . . discard args
- 440     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 441     # eax = trace-scan("cd")
- 442     # . . push args
- 443     68/push  "cd"/imm32
- 444     # . . call
- 445     e8/call  trace-scan/disp32
- 446     # . . discard args
- 447     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 448     # check-ints-equal(eax, 1, msg)
- 449     # . . push args
- 450     68/push  "F - test-trace-scan-skips-lines-until-found"/imm32
- 451     68/push  1/imm32
- 452     50/push-eax
- 453     # . . call
- 454     e8/call check-ints-equal/disp32
- 455     # . . discard args
- 456     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 457     # pop into *Trace-stream
- 458     8f          0/subop/pop         0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # pop into *Trace-stream
- 459     # . end
- 460     c3/return
- 461 
- 462 test-trace-second-scan-starts-where-first-left-off:
- 463     # push *Trace-stream
- 464     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
- 465     # setup
- 466     # . *Trace-stream = _test-trace-stream
- 467     b8/copy-to-eax  _test-trace-stream/imm32
- 468     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy eax to *Trace-stream
- 469     # . clear-trace-stream()
- 470     e8/call  clear-trace-stream/disp32
- 471     # . trace("Ab")
- 472     # . . push args
- 473     68/push  "Ab"/imm32
- 474     # . . call
- 475     e8/call  trace/disp32
- 476     # . . discard args
- 477     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 478     # . eax = trace-scan("Ab")
- 479     # . . push args
- 480     68/push  "Ab"/imm32
- 481     # . . call
- 482     e8/call  trace-scan/disp32
- 483     # . . discard args
- 484     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 485     # second scan fails
- 486     # . eax = trace-scan("Ab")
- 487     # . . push args
- 488     68/push  "Ab"/imm32
- 489     # . . call
- 490     e8/call  trace-scan/disp32
- 491     # . . discard args
- 492     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 493     # check-ints-equal(eax, 0, msg)
- 494     # . . push args
- 495     68/push  "F - test-trace-second-scan-starts-where-first-left-off"/imm32
- 496     68/push  0/imm32
- 497     50/push-eax
- 498     # . . call
- 499     e8/call check-ints-equal/disp32
- 500     # . . discard args
- 501     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 502     # pop into *Trace-stream
- 503     8f          0/subop/pop         0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # pop into *Trace-stream
- 504     # . end
- 505     c3/return
- 506 
- 507 test-trace-scan-failure-leaves-read-index-untouched:
- 508     # push *Trace-stream
- 509     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
- 510     # setup
- 511     # . *Trace-stream = _test-trace-stream
- 512     b8/copy-to-eax  _test-trace-stream/imm32
- 513     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy eax to *Trace-stream
- 514     # . clear-trace-stream()
- 515     e8/call  clear-trace-stream/disp32
- 516     # . trace("Ab")
- 517     # . . push args
- 518     68/push  "Ab"/imm32
- 519     # . . call
- 520     e8/call  trace/disp32
- 521     # . . discard args
- 522     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 523     # . check-ints-equal(_test-trace-stream->read, 0, msg)
- 524     # . . push args
- 525     68/push  "F - test-trace-second-scan-starts-where-first-left-off/precondition-failure"/imm32
- 526     68/push  0/imm32
- 527     b8/copy-to-eax  _test-trace-stream/imm32
- 528     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
- 529     # . . call
- 530     e8/call check-ints-equal/disp32
- 531     # . . discard args
- 532     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 533     # perform a failing scan
- 534     # . eax = trace-scan("Ax")
- 535     # . . push args
- 536     68/push  "Ax"/imm32
- 537     # . . call
- 538     e8/call  trace-scan/disp32
- 539     # . . discard args
- 540     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 541     # no change in read index
- 542     # . check-ints-equal(_test-trace-stream->read, 0, msg)
- 543     # . . push args
- 544     68/push  "F - test-trace-second-scan-starts-where-first-left-off"/imm32
- 545     68/push  0/imm32
- 546     b8/copy-to-eax  _test-trace-stream/imm32
- 547     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
- 548     # . . call
- 549     e8/call check-ints-equal/disp32
- 550     # . . discard args
- 551     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 552     # pop into *Trace-stream
- 553     8f          0/subop/pop         0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # pop into *Trace-stream
- 554     # . end
- 555     c3/return
- 556 
- 557 next-line-matches?:  # t : (address stream), line : (address string) -> result/eax : boolean
- 558     # pseudocode:
- 559     #   while true:
- 560     #     if (currl >= maxl) break
- 561     #     if (currt >= maxt) return false
- 562     #     if (*currt != *currl) return false
- 563     #     ++currt
- 564     #     ++currl
- 565     #   return *currt == '\n'
- 566     #
- 567     # . prologue
- 568     55/push-ebp
- 569     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 570     # . save registers
- 571     51/push-ecx
- 572     52/push-edx
- 573     53/push-ebx
- 574     56/push-esi
- 575     57/push-edi
- 576     # edx = line
- 577     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
- 578     # currl/esi = line->data
- 579     # . esi = line/edx->data
- 580     8d/copy-address                 1/mod/*+disp8   2/rm32/edx    .           .             .           6/r32/esi   4/disp8         .                 # copy edx+4 to esi
- 581     # maxl/ecx = line->data + line->size
- 582     # . eax = line/edx->size
- 583     8b/copy                         0/mod/indirect  2/rm32/edx    .           .                         0/r32/eax   .               .                 # copy *edx to eax
- 584     # . maxl/ecx = line->data/esi + line->size/eax
- 585     8d/copy-address                 0/mod/indirect  4/rm32/sib    6/base/esi  0/index/eax   .           1/r32/ecx   .               .                 # copy edx+eax to ecx
- 586     # edi = t
- 587     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
- 588     # ebx = t->data
- 589     8d/copy-address                 1/mod/*+disp8   7/rm32/edi    .           .             .           3/r32/ebx   0xc/disp8       .                 # copy edi+12 to ebx
- 590     # maxt/edx = t->data + t->write
- 591     # . eax = t->write
- 592     8b/copy                         0/mod/indirect  7/rm32/edi    .           .                         0/r32/eax   .               .                 # copy *edi to eax
- 593     # . maxt/edx = t->data/ebx + t->write/eax
- 594     8d/copy-address                 0/mod/indirect  4/rm32/sib    3/base/ebx  0/index/eax   .           2/r32/edx   .               .                 # copy ebx+eax to edx
- 595     # currt/edi = t->data + t->read
- 596     # . eax = t/edi->read
- 597     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .                         0/r32/eax   4/disp8         .                 # copy *(edi+4) to eax
- 598     # . currt/edi = t->data/ebx + t->read/eax
- 599     8d/copy-address                 0/mod/indirect  4/rm32/sib    3/base/ebx  0/index/eax   .           7/r32/edi   .               .                 # copy ebx+eax to edi
- 600 $next-line-matches?:loop:
- 601     # if (currl/esi >= maxl/ecx) break
- 602     39/compare                      3/mod/direct    6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # compare esi and ecx
- 603     73/jump-if-greater-or-equal-unsigned  $next-line-matches?:break/disp8
- 604     # if (currt/edi >= maxt/edx) return false
- 605     # . eax = false
- 606     b8/copy-to-eax  0/imm32/false
- 607     39/compare                      3/mod/direct    7/rm32/edi    .           .             .           2/r32/edx   .               .                 # compare edi and edx
- 608     73/jump-if-greater-or-equal-unsigned  $next-line-matches?:end/disp8
- 609     # if (*currt/edi != *currl/esi) return false
- 610     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
- 611     31/xor                          3/mod/direct    3/rm32/eax    .           .             .           3/r32/eax   .               .                 # clear ebx
- 612     # . eax = (char) *currt/edi
- 613     8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .                         0/r32/eax   .               .                 # copy *edi to eax
- 614     # . ebx = (char) *currl/esi
- 615     8a/copy-byte                    0/mod/indirect  6/rm32/esi    .           .                         3/r32/ebx   .               .                 # copy *esi to ebx
- 616     # . eax >= ebx
- 617     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
- 618     # . eax = false
- 619     b8/copy-to-eax  0/imm32/false
- 620     75/jump-if-not-equal  $next-line-matches?:end/disp8
- 621     # ++currt/edi
- 622     47/increment-edi
- 623     # ++currl/esi
- 624     46/increment-esi
- 625     eb/jump  $next-line-matches?:loop/disp8
- 626 $next-line-matches?:break:
- 627     # return *currt == '\n'
- 628     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
- 629     # . eax = (char) *currt
- 630     8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .                         0/r32/eax   .               .                 # copy *edi to eax
- 631     3d/compare-eax-and  0xa/imm32/newline
- 632     # . eax = false
- 633     b8/copy-to-eax  1/imm32/true
- 634     74/jump-if-equal  $next-line-matches?:end/disp8
- 635     b8/copy-to-eax  0/imm32/true
- 636 $next-line-matches?:end:
- 637     # . restore registers
- 638     5f/pop-to-edi
- 639     5e/pop-to-esi
- 640     5b/pop-to-ebx
- 641     5a/pop-to-edx
- 642     59/pop-to-ecx
- 643     # . epilogue
- 644     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
- 645     5d/pop-to-ebp
- 646     c3/return
- 647 
- 648 test-next-line-matches?-no-match-1:
- 649     # next line of "ABABA" does not match "blah blah"
- 650     # . eax = next-line-matches?(_test-stream-line-ABABA, "blah blah")
- 651     # . . push args
- 652     68/push  "blah blah"/imm32
- 653     68/push  _test-stream-line-ABABA/imm32
- 654     # . . call
- 655     e8/call  next-line-matches?/disp32
- 656     # . . discard args
- 657     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 658     # . check-ints-equal(eax, 0, msg)
- 659     # . . push args
- 660     68/push  "F - test-next-line-matches?-no-match-1"/imm32
- 661     68/push  0/imm32
- 662     50/push-eax
- 663     # . . call
- 664     e8/call  check-ints-equal/disp32
- 665     # . . discard args
- 666     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 667     c3/return
- 668 
- 669 test-next-line-matches?-no-match-2:
- 670     # next line of "ABABA" does not match ""
- 671     # . eax = next-line-matches?(_test-stream-line-ABABA, "")
- 672     # . . push args
- 673     68/push  ""/imm32
- 674     68/push  _test-stream-line-ABABA/imm32
- 675     # . . call
- 676     e8/call  next-line-matches?/disp32
- 677     # . . discard args
- 678     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 679     # . check-ints-equal(eax, 0, msg)
- 680     # . . push args
- 681     68/push  "F - test-next-line-matches?-no-match-2"/imm32
- 682     68/push  0/imm32
- 683     50/push-eax
- 684     # . . call
- 685     e8/call  check-ints-equal/disp32
- 686     # . . discard args
- 687     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 688     c3/return
- 689 
- 690 test-next-line-matches?-no-match-3:
- 691     # next line of "ABABA" does not match  "AA"
- 692     # . eax = next-line-matches?(_test-stream-line-ABABA, "AA")
- 693     # . . push args
- 694     68/push  "AA"/imm32
- 695     68/push  _test-stream-line-ABABA/imm32
- 696     # . . call
- 697     e8/call  next-line-matches?/disp32
- 698     # . . discard args
- 699     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 700     # . check-ints-equal(eax, 0, msg)
- 701     # . . push args
- 702     68/push  "F - test-next-line-matches?-no-match-3"/imm32
- 703     68/push  0/imm32
- 704     50/push-eax
- 705     # . . call
- 706     e8/call  check-ints-equal/disp32
- 707     # . . discard args
- 708     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 709     c3/return
- 710 
- 711 test-next-line-matches?-match:
- 712     # next line of "ABABA" matches "ABABA"
- 713     # . eax = next-line-matches?(_test-stream-line-ABABA, "ABABA")
- 714     # . . push args
- 715     68/push  "ABABA"/imm32
- 716     68/push  _test-stream-line-ABABA/imm32
- 717     # . . call
- 718     e8/call  next-line-matches?/disp32
- 719     # . . discard args
- 720     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 721     # . check-ints-equal(eax, 1, msg)
- 722     # . . push args
- 723     68/push  "F - test-next-line-matches?-match"/imm32
- 724     68/push  1/imm32
- 725     50/push-eax
- 726     # . . call
- 727     e8/call  check-ints-equal/disp32
- 728     # . . discard args
- 729     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 730     c3/return
- 731 
- 732 # move t->read to _after_ next newline
- 733 skip-next-line:  # t : (address stream)
- 734     # pseudocode:
- 735     #   max = t->data + t->write
- 736     #   i = t->read
- 737     #   curr = t->data + t->read
- 738     #   while true
- 739     #     if (curr >= max) break
- 740     #     ++i
- 741     #     if (*curr == '\n') break
- 742     #     ++curr
- 743     #   t->read = i
- 744     #
- 745     # . prologue
- 746     55/push-ebp
- 747     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 748     # . save registers
- 749     50/push-eax
- 750     51/push-ecx
- 751     52/push-edx
- 752     53/push-ebx
- 753     # ecx = t
- 754     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
- 755     # edx = t/ecx->data
- 756     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           2/r32/edx   0xc/disp8       .                 # copy ecx+12 to edx
- 757     # eax = t/ecx->write
- 758     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
- 759     # max/ebx = t->data/edx + t->write/eax
- 760     8d/copy-address                 0/mod/indirect  4/rm32/sib    2/base/edx  0/index/eax   .           3/r32/ebx   .               .                 # copy edx+eax to ebx
- 761     # eax = t/ecx->read
- 762     8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(ecx+4) to edx
- 763     # curr/ecx = t->data/edx + t->read/eax
- 764     8d/copy-address                 0/mod/indirect  4/rm32/sib    2/base/edx  0/index/eax   .           1/r32/ecx   .               .                 # copy edx+eax to ecx
- 765     # i/edx = eax
- 766     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           0/r32/eax   .               .                 # copy eax to edx
- 767 $skip-next-line:loop:
- 768     # if (curr/ecx >= max/ebx) break
- 769     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           3/r32/ebx   .               .                 # compare ecx and ebx
- 770     73/jump-if-greater-or-equal-unsigned  $skip-next-line:end/disp8
- 771     # ++i/edx
- 772     42/increment-edx
- 773     # if (*curr/ecx == '\n') break
- 774     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
- 775     8a/copy-byte                    0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
- 776     3d/compare-eax-and  0a/imm32/newline
- 777     74/jump-if-equal  $skip-next-line:end/disp8
- 778     # ++curr/ecx
- 779     41/increment-ecx
- 780     # loop
- 781     eb/jump  $skip-next-line:loop/disp8
- 782 $skip-next-line:end:
- 783     # ecx = t
- 784     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
- 785     # t/ecx->read = i/edx
- 786     89/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           2/r32/edx   4/disp8         .                 # copy edx to *(ecx+4)
- 787     # . restore registers
- 788     5b/pop-to-ebx
- 789     5a/pop-to-edx
- 790     59/pop-to-ecx
- 791     58/pop-to-eax
- 792     # . epilogue
- 793     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
- 794     5d/pop-to-ebp
- 795     c3/return
- 796 
- 797 test-skip-next-line-empty:
- 798     # skipping next line in empty stream leaves read pointer at 0
- 799     # . skip-next-line(_test-stream-empty)
- 800     # . . push args
- 801     68/push  _test-stream-empty/imm32
- 802     # . . call
- 803     e8/call  skip-next-line/disp32
- 804     # . . discard args
- 805     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 806     # . check-ints-equal(_test-stream-empty->read, 0, msg)
- 807     # . . push args
- 808     68/push  "F - test-skip-next-line-empty"/imm32
- 809     68/push  0/imm32
- 810     b8/copy-to-eax  _test-stream-empty/imm32
- 811     8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           0/r32/eax   4/disp8         .                 # copy *(eax+4) to eax
- 812     50/push-eax
- 813     # . . call
- 814     e8/call  check-ints-equal/disp32
- 815     # . . discard args
- 816     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 817     c3/return
- 818 
- 819 test-skip-next-line-filled:
- 820     # skipping next line increments read pointer by length of line + 1 (for newline)
- 821     # . skip-next-line(_test-stream-filled)
- 822     # . . push args
- 823     68/push  _test-stream-filled/imm32
- 824     # . . call
- 825     e8/call  skip-next-line/disp32
- 826     # . . discard args
- 827     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 828     # . check-ints-equal(_test-stream-filled->read, 5, msg)
- 829     # . . push args
- 830     68/push  "F - test-skip-next-line-filled"/imm32
- 831     68/push  5/imm32
- 832     b8/copy-to-eax  _test-stream-filled/imm32
- 833     8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           0/r32/eax   4/disp8         .                 # copy *(eax+4) to eax
- 834     50/push-eax
- 835     # . . call
- 836     e8/call  check-ints-equal/disp32
- 837     # . . discard args
- 838     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 839     c3/return
- 840 
- 841 clear-trace-stream:
- 842     # . prologue
- 843     55/push-ebp
- 844     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 845     # . save registers
- 846     50/push-eax
- 847     51/push-ecx
- 848     # eax = *Trace-stream
- 849     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy *Trace-stream to eax
- 850     # ecx = t->length
- 851     8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(eax+8) to ecx
- 852     # ecx = &t->data[t->length]
- 853     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
- 854     # t->write = 0
- 855     c7          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0/imm32           # copy to *eax
- 856     # t->read = 0
- 857     c7          0/subop/copy        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         0/imm32           # copy to *(eax+4)
- 858     # eax = t->data
- 859     81          0/subop/add         3/mod/direct    0/rm32/eax    .           .             .           .           .               0xc/imm32         # add to eax
- 860 $clear-trace-stream:loop:
- 861     # if (eax >= ecx) break
- 862     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # compare eax with ecx
- 863     73/jump-if-greater-or-equal-unsigned  $clear-trace-stream:end/disp8
- 864     # *eax = 0
- 865     c7          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0/imm32           # copy to *eax
- 866     # eax += 4
- 867     81          0/subop/add         3/mod/direct    0/rm32/eax    .           .             .           .           .               4/imm32           # add to eax
- 868     eb/jump  $clear-trace-stream:loop/disp8
- 869 $clear-trace-stream:end:
- 870     # . restore registers
- 871     59/pop-to-ecx
- 872     58/pop-to-eax
- 873     # . epilogue
- 874     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
- 875     5d/pop-to-ebp
- 876     c3/return
- 877 
- 878 # - helpers
- 879 
- 880 # 3-argument variant of _append
- 881 _append-3:  # out : address, outend : address, s : (array byte) -> num_bytes_appended/eax
- 882     # . prologue
- 883     55/push-ebp
- 884     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 885     # . save registers
- 886     51/push-ecx
- 887     # eax = _append-4(out, outend, &s->data[0], &s->data[s->length])
- 888     # . . push &s->data[s->length]
- 889     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         0/r32/eax   0x10/disp8      .                 # copy *(ebp+16) to eax
- 890     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
- 891     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
- 892     51/push-ecx
- 893     # . . push &s->data[0]
- 894     8d/copy-address                 1/mod/*+disp8   0/rm32/eax    .           .             .           1/r32/ecx   4/disp8         .                 # copy eax+4 to ecx
- 895     51/push-ecx
- 896     # . . push outend
- 897     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
- 898     # . . push out
- 899     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
- 900     # . . call
- 901     e8/call  _append-4/disp32
- 902     # . . discard args
- 903     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
- 904 $_append-3:end:
- 905     # . restore registers
- 906     59/pop-to-ecx
- 907     # . epilogue
- 908     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
- 909     5d/pop-to-ebp
- 910     c3/return
- 911 
- 912 # 4-argument variant of _append
- 913 _append-4:  # out : address, outend : address, in : address, inend : address -> num_bytes_appended/eax
- 914     # . prologue
- 915     55/push-ebp
- 916     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 917     # . save registers
- 918     51/push-ecx
- 919     52/push-edx
- 920     53/push-ebx
- 921     56/push-esi
- 922     57/push-edi
- 923     # eax/num_bytes_appended = 0
- 924     b8/copy-to-eax  0/imm32
- 925     # edi = out
- 926     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
- 927     # edx = outend
- 928     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
- 929     # esi = in
- 930     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0x10/disp8      .                 # copy *(ebp+16) to esi
- 931     # ecx = inend
- 932     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x14/disp8      .                 # copy *(ebp+20) to ecx
- 933 $_append-4:loop:
- 934     # if (in >= inend) break
- 935     39/compare                      3/mod/direct    6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # compare esi with ecx
- 936     73/jump-if-greater-or-equal-unsigned  $_append-4:end/disp8
- 937     # if (out >= outend) abort  # just to catch test failures fast
- 938     39/compare                      3/mod/direct    7/rm32/edi    .           .             .           2/r32/edx   .               .                 # compare edi with edx
- 939     73/jump-if-greater-or-equal-unsigned  $_append-4:abort/disp8
- 940     # *out = *in
- 941     8a/copy-byte                    0/mod/indirect  6/rm32/esi    .           .             .           3/r32/BL    .               .                 # copy byte at *esi to BL
- 942     88/copy-byte                    0/mod/indirect  7/rm32/edi    .           .             .           3/r32/BL    .               .                 # copy byte at BL to *edi
- 943     # ++num_bytes_appended
- 944     40/increment-eax
- 945     # ++in
- 946     46/increment-esi
- 947     # ++out
- 948     47/increment-edi
- 949     eb/jump  $_append-4:loop/disp8
- 950 $_append-4:end:
- 951     # . restore registers
- 952     5f/pop-to-edi
- 953     5e/pop-to-esi
- 954     5b/pop-to-ebx
- 955     5a/pop-to-edx
- 956     59/pop-to-ecx
- 957     # . epilogue
- 958     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
- 959     5d/pop-to-ebp
- 960     c3/return
- 961 
- 962 $_append-4:abort:
- 963     # . _write(2/stderr, error)
- 964     # . . push args
- 965     68/push  "stream overflow\n"/imm32
- 966     68/push  2/imm32/stderr
- 967     # . . call
- 968     e8/call  _write/disp32
- 969     # . . discard args
- 970     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 971     # . syscall(exit, 1)
- 972     bb/copy-to-ebx  1/imm32
- 973     b8/copy-to-eax  1/imm32/exit
- 974     cd/syscall  0x80/imm8
- 975     # never gets here
- 976 
- 977 == data
- 978 
- 979 _test-stream-line-ABABA:
- 980     # write
- 981     8/imm32
- 982     # read
- 983     0/imm32
- 984     # length
- 985     8/imm32
- 986     # data
- 987     41 42 41 42 41 0a 00 00  # 8 bytes
- 988 
- 989 _test-stream-empty:
- 990     # write
- 991     0/imm32
- 992     # read
- 993     0/imm32
- 994     # length
- 995     8/imm32
- 996     # data
- 997     00 00 00 00 00 00 00 00  # 8 bytes
- 998 
- 999 _test-stream-filled:
-1000     # write
-1001     8/imm32
-1002     # read
-1003     0/imm32
-1004     # length
-1005     8/imm32
-1006     # data
-1007     41 41 41 41 0a 41 41 41  # 8 bytes
-1008 
-1009 # . . vim:nowrap:textwidth=0
+  1 # primitives for emitting traces to a 'trace' stream, and for tests to make assertions on its contents
+  2 #
+  3 # A trace stream looks like a regular stream:
+  4 #   write : int  # index at which writes go
+  5 #   read : int  # index that we've read until
+  6 #   data : (array byte)  # prefixed by length as usual
+  7 # Usually the trace stream will be in a separate segment set aside for the purpose.
+  8 #
+  9 # primitives for operating on traces (arguments in quotes):
+ 10 #   - initialize-trace-stream: populates Trace-stream with a new segment of the given 'size'
+ 11 #   - trace: adds a 'line' to Trace-stream
+ 12 #   - check-trace-contains: scans from Trace-stream's start for a matching 'line', prints a 'message' to stderr on failure
+ 13 #   - check-trace-scans-to: scans from Trace-stream's read pointer for a matching 'line', prints a 'message' to stderr on failure
+ 14 
+ 15 == data
+ 16 
+ 17 Trace-stream:  # (handle stream byte)
+ 18     0/imm32
+ 19     # we don't have safe handles (fat pointers) yet
+ 20 
+ 21 Trace-segment:
+ 22     0/imm32/curr
+ 23     0/imm32/limit
+ 24 
+ 25 # Fake trace-stream for tests.
+ 26 # Also illustrates the layout of the real trace-stream (segment).
+ 27 _test-trace-stream:  # (ref stream byte)
+ 28     # current write index
+ 29     0/imm32
+ 30     # current read index
+ 31     0/imm32
+ 32     # length
+ 33     8/imm32
+ 34     # data
+ 35     00 00 00 00 00 00 00 00  # 8 bytes
+ 36 
+ 37 == code
+ 38 #   instruction                     effective address                                                   register    displacement    immediate
+ 39 # . op          subop               mod             rm32          base        index         scale       r32
+ 40 # . 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
+ 41 
+ 42 # Allocate a new segment for the trace stream, initialize its length, and save its address to Trace-stream.
+ 43 # The Trace-stream segment will consist of variable-length lines separated by newlines (0x0a)
+ 44 initialize-trace-stream:  # n : int
+ 45     # . prologue
+ 46     55/push-ebp
+ 47     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 48     # . save registers
+ 49     50/push-eax
+ 50     51/push-ecx
+ 51     # ecx = n
+ 52     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
+ 53     # Trace-segment = new-segment(n)
+ 54     # . . push args
+ 55     68/push  Trace-segment/imm32
+ 56     51/push-ecx
+ 57     # . . call
+ 58     e8/call  new-segment/disp32
+ 59     # . . discard args
+ 60     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 61     # copy Trace-segment->curr to *Trace-stream
+ 62     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-segment/disp32              # copy *Trace-segment to eax
+ 63 #?     # watch point to catch Trace-stream leaks
+ 64 #? $watch-1:
+ 65     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy eax to *Trace-stream
+ 66     # Trace-stream->length = n - 12
+ 67     # . ecx -= 12
+ 68     81          5/subop/subtract    3/mod/direct    1/rm32/ecx    .           .             .           .           .               0xc/imm32         # subtract from ecx
+ 69     # . Trace-stream->length = ecx
+ 70     89/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           1/r32/ecx   8/disp8         .                 # copy ecx to *(eax+8)
+ 71 $initialize-trace-stream:end:
+ 72     # . restore registers
+ 73     59/pop-to-ecx
+ 74     58/pop-to-eax
+ 75     # . epilogue
+ 76     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 77     5d/pop-to-ebp
+ 78     c3/return
+ 79 
+ 80 # Append a string to the given trace stream.
+ 81 # Silently give up if it's already full. Or truncate the string if there isn't enough room.
+ 82 trace:  # line : (address array byte)
+ 83     # . prologue
+ 84     55/push-ebp
+ 85     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 86     # . save registers
+ 87     50/push-eax
+ 88     51/push-ecx
+ 89     52/push-edx
+ 90     53/push-ebx
+ 91     56/push-esi
+ 92     57/push-edi
+ 93     # var edi : (address stream byte) = *Trace-stream
+ 94     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           7/r32/edi   Trace-stream/disp32               # copy *Trace-stream to edi
+ 95     # esi = line
+ 96     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+ 97     # var ecx : int = t->write
+ 98     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           1/r32/ecx   .               .                 # copy *edi to ecx
+ 99     # var edx : int = t->length
+100     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           2/r32/edx   8/disp8         .                 # copy *(edi+8) to edx
+101     # eax = _append-3(&t->data[t->write], &t->data[t->length], line)
+102     # . . push line
+103     56/push-esi
+104     # . . push &t->data[t->length]
+105     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    7/base/edi  2/index/edx   .           3/r32/ebx   0xc/disp8       .                 # copy edi+edx+12 to ebx
+106     53/push-ebx
+107     # . . push &t->data[t->write]
+108     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    7/base/edi  1/index/ecx   .           3/r32/ebx   0xc/disp8       .                 # copy edi+ecx+12 to ebx
+109     53/push-ebx
+110     # . . call
+111     e8/call  _append-3/disp32
+112     # . . discard args
+113     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+114     # if (eax == 0) return
+115     3d/compare-eax-and  0/imm32
+116     74/jump-if-equal  $trace:end/disp8
+117     # t->write += eax
+118     01/add                          0/mod/indirect  7/rm32/edi    .           .             .           0/r32/eax   .               .                 # add eax to *edi
+119     # refresh ecx = t->write
+120     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           1/r32/ecx   .               .                 # copy *edi to ecx
+121     # eax = _append-3(&t->data[t->write], &t->data[t->length], line)
+122     # . . push line
+123     68/push  Newline/imm32
+124     # . . push &t->data[t->length]
+125     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    7/base/edi  2/index/edx   .           3/r32/ebx   0xc/disp8       .                 # copy edi+edx+12 to ebx
+126     53/push-ebx
+127     # . . push &t->data[t->write]
+128     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    7/base/edi  1/index/ecx   .           3/r32/ebx   0xc/disp8       .                 # copy edi+ecx+12 to ebx
+129     53/push-ebx
+130     # . . call
+131     e8/call  _append-3/disp32
+132     # . . discard args
+133     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+134     # t->write += eax
+135     01/add                          0/mod/indirect  7/rm32/edi    .           .             .           0/r32/eax   .               .                 # add eax to *edi
+136 $trace:end:
+137     # . restore registers
+138     5f/pop-to-edi
+139     5e/pop-to-esi
+140     5b/pop-to-ebx
+141     5a/pop-to-edx
+142     59/pop-to-ecx
+143     58/pop-to-eax
+144     # . epilogue
+145     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+146     5d/pop-to-ebp
+147     c3/return
+148 
+149 test-trace-single:
+150     # push *Trace-stream
+151     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
+152     # *Trace-stream = _test-trace-stream
+153     b8/copy-to-eax  _test-trace-stream/imm32
+154     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy eax to *Trace-stream
+155     # clear-trace-stream()
+156     e8/call  clear-trace-stream/disp32
+157     # trace("Ab")
+158     # . . push args
+159     68/push  "Ab"/imm32
+160     # . . call
+161     e8/call  trace/disp32
+162     # . . discard args
+163     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+164     # check-ints-equal(*_test-trace-stream->data, 41/A 62/b 0a/newline 00, msg)
+165     # . . push args
+166     68/push  "F - test-trace-single"/imm32
+167     68/push  0x0a6241/imm32/Ab-newline
+168     # . . push *_test-trace-stream->data
+169     b8/copy-to-eax  _test-trace-stream/imm32
+170     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           0xc/disp8       .                 # push *(eax+12)
+171     # . . call
+172     e8/call  check-ints-equal/disp32
+173     # . . discard args
+174     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+175     # pop into *Trace-stream
+176     8f          0/subop/pop         0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # pop into *Trace-stream
+177     # end
+178     c3/return
+179 
+180 test-trace-appends:
+181     # push *Trace-stream
+182     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
+183     # *Trace-stream = _test-trace-stream
+184     b8/copy-to-eax  _test-trace-stream/imm32
+185     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy eax to *Trace-stream
+186     # clear-trace-stream()
+187     e8/call  clear-trace-stream/disp32
+188     # trace("C")
+189     # . . push args
+190     68/push  "C"/imm32
+191     # . . call
+192     e8/call  trace/disp32
+193     # . . discard args
+194     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+195     # trace("D")
+196     # . . push args
+197     68/push  "D"/imm32
+198     # . . call
+199     e8/call  trace/disp32
+200     # . . discard args
+201     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+202     # check-ints-equal(*_test-trace-stream->data, 43/C 0a/newline 44/D 0a/newline, msg)
+203     # . . push args
+204     68/push  "F - test-trace-appends"/imm32
+205     68/push  0x0a440a43/imm32/C-newline-D-newline
+206     # . . push *_test-trace-stream->data
+207     b8/copy-to-eax  _test-trace-stream/imm32
+208     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           0xc/disp8       .                 # push *(eax+12)
+209     # . . call
+210     e8/call  check-ints-equal/disp32
+211     # . . discard args
+212     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+213     # pop into *Trace-stream
+214     8f          0/subop/pop         0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # pop into *Trace-stream
+215     # end
+216     c3/return
+217 
+218 test-trace-empty-line:
+219     # push *Trace-stream
+220     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
+221     # *Trace-stream = _test-trace-stream
+222     b8/copy-to-eax  _test-trace-stream/imm32
+223     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy eax to *Trace-stream
+224     # clear-trace-stream()
+225     e8/call  clear-trace-stream/disp32
+226     # trace("")
+227     # . . push args
+228     68/push  ""/imm32
+229     # . . call
+230     e8/call  trace/disp32
+231     # . . discard args
+232     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+233     # check-ints-equal(*_test-trace-stream->data, 0, msg)
+234     # . . push args
+235     68/push  "F - test-trace-empty-line"/imm32
+236     68/push  0/imm32
+237     # . . push *_test-trace-stream->data
+238     b8/copy-to-eax  _test-trace-stream/imm32
+239     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           0xc/disp8       .                 # push *(eax+12)
+240     # . . call
+241     e8/call  check-ints-equal/disp32
+242     # . . discard args
+243     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+244     # pop into *Trace-stream
+245     8f          0/subop/pop         0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # pop into *Trace-stream
+246     # end
+247     c3/return
+248 
+249 check-trace-contains:  # line : (address string), msg : (address string)
+250     # . prologue
+251     55/push-ebp
+252     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+253     # rewind-stream(*Trace-stream)
+254     # . . push args
+255     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
+256     # . . call
+257     e8/call  rewind-stream/disp32
+258     # . . discard args
+259     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+260     # check-trace-scans-to(line, msg)
+261     # . . push args
+262     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+263     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+264     # . . call
+265     e8/call  check-trace-scans-to/disp32
+266     # . . discard args
+267     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+268 $check-trace-contains:end:
+269     # . epilogue
+270     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+271     5d/pop-to-ebp
+272     c3/return
+273 
+274 check-trace-scans-to:  # line : (address string), msg : (address string)
+275     # . prologue
+276     55/push-ebp
+277     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+278     # . save registers
+279     50/push-eax
+280     # eax = trace-scan(line)
+281     # . . push args
+282     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+283     # . . call
+284     e8/call  trace-scan/disp32
+285     # . . discard args
+286     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+287     # check-ints-equal(eax, 1, msg)
+288     # . . push args
+289     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+290     68/push  1/imm32
+291     50/push-eax
+292     # . . call
+293     e8/call check-ints-equal/disp32
+294     # . . discard args
+295     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+296 $check-trace-scans-to:end:
+297     # . restore registers
+298     58/pop-to-eax
+299     # . epilogue
+300     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+301     5d/pop-to-ebp
+302     c3/return
+303 
+304 # Start scanning from Trace-stream->read for 'line'. If found, update Trace-stream->read and return true.
+305 trace-scan:  # line : (address array byte) -> result/eax : boolean
+306     # pseudocode:
+307     #   push Trace-stream->read
+308     #   while true:
+309     #     if Trace-stream->read >= Trace-stream->write
+310     #       break
+311     #     if next-line-matches?(Trace-stream, line)
+312     #       skip-next-line(Trace-stream)
+313     #       dump saved copy of Trace-stream->read
+314     #       return true
+315     #     skip-next-line(Trace-stream)
+316     #   pop saved copy of Trace-stream->read
+317     #   return false
+318     #
+319     # . prologue
+320     55/push-ebp
+321     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+322     # . save registers
+323     51/push-ecx
+324     56/push-esi
+325     # esi = *Trace-stream
+326     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           6/r32/esi   Trace-stream/disp32               # copy *Trace-stream to esi
+327     # ecx = Trace-stream->write
+328     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx                   .                 # copy *esi to ecx
+329     # push Trace-stream->read
+330     ff          6/subop/push        1/mod/*+disp8   6/rm32/esi    .           .             .           .           4/disp8         .                 # push *(esi+4)
+331 $trace-scan:loop:
+332     # if (Trace-stream->read >= Trace-stream->write) return false
+333     39/compare                      1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # compare ecx with *(esi+4)
+334     7d/jump-if-greater-or-equal  $trace-scan:false/disp8
+335     # eax = next-line-matches?(Trace-stream, line)
+336     # . . push args
+337     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+338     56/push-esi
+339     # . . call
+340     e8/call  next-line-matches?/disp32
+341     # . . discard args
+342     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+343     # if (eax == false) continue
+344     3d/compare-eax-and  0/imm32/false
+345     74/jump-if-equal  $trace-scan:continue/disp8
+346 $trace-scan:true:
+347     # skip-next-line(Trace-stream)
+348     # . . push args
+349     56/push-esi
+350     # . . call
+351     e8/call  skip-next-line/disp32
+352     # . . discard args
+353     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+354     # dump saved copy of Trace-stream->read
+355     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+356     # return true
+357     b8/copy-to-eax  1/imm32/true
+358     eb/jump  $trace-scan:end/disp8
+359 $trace-scan:continue:
+360     # skip-next-line(Trace-stream)
+361     # . . push args
+362     56/push-esi
+363     # . . call
+364     e8/call  skip-next-line/disp32
+365     # . . discard args
+366     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+367     eb/jump  $trace-scan:loop/disp8
+368 $trace-scan:false:
+369     # restore saved copy of Trace-stream->read
+370     8f          0/subop/pop         1/mod/*+disp8   6/rm32/esi    .           .             .           .           4/disp8         .                 # pop to *(esi+4)
+371     # return false
+372     b8/copy-to-eax  0/imm32/false
+373 $trace-scan:end:
+374     # . restore registers
+375     59/pop-to-ecx
+376     # . epilogue
+377     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+378     5d/pop-to-ebp
+379     c3/return
+380 
+381 test-trace-scan-first:
+382     # push *Trace-stream
+383     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
+384     # setup
+385     # . *Trace-stream = _test-trace-stream
+386     b8/copy-to-eax  _test-trace-stream/imm32
+387     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy eax to *Trace-stream
+388     # . clear-trace-stream()
+389     e8/call  clear-trace-stream/disp32
+390     # . trace("Ab")
+391     # . . push args
+392     68/push  "Ab"/imm32
+393     # . . call
+394     e8/call  trace/disp32
+395     # . . discard args
+396     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+397     # eax = trace-scan("Ab")
+398     # . . push args
+399     68/push  "Ab"/imm32
+400     # . . call
+401     e8/call  trace-scan/disp32
+402     # . . discard args
+403     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+404     # check-ints-equal(eax, 1, msg)
+405     # . . push args
+406     68/push  "F - test-trace-scan-first"/imm32
+407     68/push  1/imm32
+408     50/push-eax
+409     # . . call
+410     e8/call check-ints-equal/disp32
+411     # . . discard args
+412     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+413     # pop into *Trace-stream
+414     8f          0/subop/pop         0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # pop into *Trace-stream
+415     # . end
+416     c3/return
+417 
+418 test-trace-scan-skips-lines-until-found:
+419     # push *Trace-stream
+420     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
+421     # setup
+422     # . *Trace-stream = _test-trace-stream
+423     b8/copy-to-eax  _test-trace-stream/imm32
+424     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy eax to *Trace-stream
+425     # . clear-trace-stream()
+426     e8/call  clear-trace-stream/disp32
+427     # . trace("Ab")
+428     # . . push args
+429     68/push  "Ab"/imm32
+430     # . . call
+431     e8/call  trace/disp32
+432     # . . discard args
+433     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+434     # . trace("cd")
+435     # . . push args
+436     68/push  "cd"/imm32
+437     # . . call
+438     e8/call  trace/disp32
+439     # . . discard args
+440     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+441     # eax = trace-scan("cd")
+442     # . . push args
+443     68/push  "cd"/imm32
+444     # . . call
+445     e8/call  trace-scan/disp32
+446     # . . discard args
+447     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+448     # check-ints-equal(eax, 1, msg)
+449     # . . push args
+450     68/push  "F - test-trace-scan-skips-lines-until-found"/imm32
+451     68/push  1/imm32
+452     50/push-eax
+453     # . . call
+454     e8/call check-ints-equal/disp32
+455     # . . discard args
+456     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+457     # pop into *Trace-stream
+458     8f          0/subop/pop         0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # pop into *Trace-stream
+459     # . end
+460     c3/return
+461 
+462 test-trace-second-scan-starts-where-first-left-off:
+463     # push *Trace-stream
+464     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
+465     # setup
+466     # . *Trace-stream = _test-trace-stream
+467     b8/copy-to-eax  _test-trace-stream/imm32
+468     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy eax to *Trace-stream
+469     # . clear-trace-stream()
+470     e8/call  clear-trace-stream/disp32
+471     # . trace("Ab")
+472     # . . push args
+473     68/push  "Ab"/imm32
+474     # . . call
+475     e8/call  trace/disp32
+476     # . . discard args
+477     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+478     # . eax = trace-scan("Ab")
+479     # . . push args
+480     68/push  "Ab"/imm32
+481     # . . call
+482     e8/call  trace-scan/disp32
+483     # . . discard args
+484     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+485     # second scan fails
+486     # . eax = trace-scan("Ab")
+487     # . . push args
+488     68/push  "Ab"/imm32
+489     # . . call
+490     e8/call  trace-scan/disp32
+491     # . . discard args
+492     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+493     # check-ints-equal(eax, 0, msg)
+494     # . . push args
+495     68/push  "F - test-trace-second-scan-starts-where-first-left-off"/imm32
+496     68/push  0/imm32
+497     50/push-eax
+498     # . . call
+499     e8/call check-ints-equal/disp32
+500     # . . discard args
+501     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+502     # pop into *Trace-stream
+503     8f          0/subop/pop         0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # pop into *Trace-stream
+504     # . end
+505     c3/return
+506 
+507 test-trace-scan-failure-leaves-read-index-untouched:
+508     # push *Trace-stream
+509     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
+510     # setup
+511     # . *Trace-stream = _test-trace-stream
+512     b8/copy-to-eax  _test-trace-stream/imm32
+513     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy eax to *Trace-stream
+514     # . clear-trace-stream()
+515     e8/call  clear-trace-stream/disp32
+516     # . trace("Ab")
+517     # . . push args
+518     68/push  "Ab"/imm32
+519     # . . call
+520     e8/call  trace/disp32
+521     # . . discard args
+522     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+523     # . check-ints-equal(_test-trace-stream->read, 0, msg)
+524     # . . push args
+525     68/push  "F - test-trace-second-scan-starts-where-first-left-off/precondition-failure"/imm32
+526     68/push  0/imm32
+527     b8/copy-to-eax  _test-trace-stream/imm32
+528     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+529     # . . call
+530     e8/call check-ints-equal/disp32
+531     # . . discard args
+532     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+533     # perform a failing scan
+534     # . eax = trace-scan("Ax")
+535     # . . push args
+536     68/push  "Ax"/imm32
+537     # . . call
+538     e8/call  trace-scan/disp32
+539     # . . discard args
+540     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+541     # no change in read index
+542     # . check-ints-equal(_test-trace-stream->read, 0, msg)
+543     # . . push args
+544     68/push  "F - test-trace-second-scan-starts-where-first-left-off"/imm32
+545     68/push  0/imm32
+546     b8/copy-to-eax  _test-trace-stream/imm32
+547     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+548     # . . call
+549     e8/call check-ints-equal/disp32
+550     # . . discard args
+551     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+552     # pop into *Trace-stream
+553     8f          0/subop/pop         0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # pop into *Trace-stream
+554     # . end
+555     c3/return
+556 
+557 next-line-matches?:  # t : (address stream byte), line : (address array byte) -> result/eax : boolean
+558     # pseudocode:
+559     #   while true:
+560     #     if (currl >= maxl) break
+561     #     if (currt >= maxt) return false
+562     #     if (*currt != *currl) return false
+563     #     ++currt
+564     #     ++currl
+565     #   return *currt == '\n'
+566     #
+567     # . prologue
+568     55/push-ebp
+569     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+570     # . save registers
+571     51/push-ecx
+572     52/push-edx
+573     53/push-ebx
+574     56/push-esi
+575     57/push-edi
+576     # edx = line
+577     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
+578     # var currl/esi : (address byte) = line->data
+579     # . esi = line/edx->data
+580     8d/copy-address                 1/mod/*+disp8   2/rm32/edx    .           .             .           6/r32/esi   4/disp8         .                 # copy edx+4 to esi
+581     # var maxl/ecx : (address byte) = &line->data[line->size]
+582     # . eax = line/edx->size
+583     8b/copy                         0/mod/indirect  2/rm32/edx    .           .                         0/r32/eax   .               .                 # copy *edx to eax
+584     # . maxl = &line->data[line->size]
+585     8d/copy-address                 0/mod/indirect  4/rm32/sib    6/base/esi  0/index/eax   .           1/r32/ecx   .               .                 # copy edx+eax to ecx
+586     # edi = t
+587     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
+588     # var ebx : (address byte) = t->data
+589     8d/copy-address                 1/mod/*+disp8   7/rm32/edi    .           .             .           3/r32/ebx   0xc/disp8       .                 # copy edi+12 to ebx
+590     # var maxt/edx : (address byte) = &t->data[t->write]
+591     # . eax = t->write
+592     8b/copy                         0/mod/indirect  7/rm32/edi    .           .                         0/r32/eax   .               .                 # copy *edi to eax
+593     # . maxt = &t->data[t->write]
+594     8d/copy-address                 0/mod/indirect  4/rm32/sib    3/base/ebx  0/index/eax   .           2/r32/edx   .               .                 # copy ebx+eax to edx
+595     # var currt/edi : (address byte) = &t->data[t->read]
+596     # . eax = t/edi->read
+597     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .                         0/r32/eax   4/disp8         .                 # copy *(edi+4) to eax
+598     # . currt = &t->data[t->read]
+599     8d/copy-address                 0/mod/indirect  4/rm32/sib    3/base/ebx  0/index/eax   .           7/r32/edi   .               .                 # copy ebx+eax to edi
+600 $next-line-matches?:loop:
+601     # if (currl >= maxl) break
+602     39/compare                      3/mod/direct    6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # compare esi and ecx
+603     73/jump-if-greater-or-equal-unsigned  $next-line-matches?:break/disp8
+604     # if (currt >= maxt) return false
+605     # . eax = false
+606     b8/copy-to-eax  0/imm32/false
+607     39/compare                      3/mod/direct    7/rm32/edi    .           .             .           2/r32/edx   .               .                 # compare edi and edx
+608     73/jump-if-greater-or-equal-unsigned  $next-line-matches?:end/disp8
+609     # if (*currt != *currl) return false
+610     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
+611     31/xor                          3/mod/direct    3/rm32/eax    .           .             .           3/r32/eax   .               .                 # clear ebx
+612     # . eax : byte = *currt
+613     8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .                         0/r32/eax   .               .                 # copy *edi to eax
+614     # . ebx : byte = *currl
+615     8a/copy-byte                    0/mod/indirect  6/rm32/esi    .           .                         3/r32/ebx   .               .                 # copy *esi to ebx
+616     # . eax >= ebx
+617     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
+618     # . eax = false
+619     b8/copy-to-eax  0/imm32/false
+620     75/jump-if-not-equal  $next-line-matches?:end/disp8
+621     # ++currt
+622     47/increment-edi
+623     # ++currl
+624     46/increment-esi
+625     eb/jump  $next-line-matches?:loop/disp8
+626 $next-line-matches?:break:
+627     # return *currt == '\n'
+628     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
+629     # . eax : byte = *currt
+630     8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .                         0/r32/eax   .               .                 # copy *edi to eax
+631     3d/compare-eax-and  0xa/imm32/newline
+632     # . eax = false
+633     b8/copy-to-eax  1/imm32/true
+634     74/jump-if-equal  $next-line-matches?:end/disp8
+635     b8/copy-to-eax  0/imm32/true
+636 $next-line-matches?:end:
+637     # . restore registers
+638     5f/pop-to-edi
+639     5e/pop-to-esi
+640     5b/pop-to-ebx
+641     5a/pop-to-edx
+642     59/pop-to-ecx
+643     # . epilogue
+644     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+645     5d/pop-to-ebp
+646     c3/return
+647 
+648 test-next-line-matches?-no-match-1:
+649     # next line of "ABABA" does not match "blah blah"
+650     # . eax = next-line-matches?(_test-stream-line-ABABA, "blah blah")
+651     # . . push args
+652     68/push  "blah blah"/imm32
+653     68/push  _test-stream-line-ABABA/imm32
+654     # . . call
+655     e8/call  next-line-matches?/disp32
+656     # . . discard args
+657     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+658     # . check-ints-equal(eax, 0, msg)
+659     # . . push args
+660     68/push  "F - test-next-line-matches?-no-match-1"/imm32
+661     68/push  0/imm32
+662     50/push-eax
+663     # . . call
+664     e8/call  check-ints-equal/disp32
+665     # . . discard args
+666     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+667     c3/return
+668 
+669 test-next-line-matches?-no-match-2:
+670     # next line of "ABABA" does not match ""
+671     # . eax = next-line-matches?(_test-stream-line-ABABA, "")
+672     # . . push args
+673     68/push  ""/imm32
+674     68/push  _test-stream-line-ABABA/imm32
+675     # . . call
+676     e8/call  next-line-matches?/disp32
+677     # . . discard args
+678     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+679     # . check-ints-equal(eax, 0, msg)
+680     # . . push args
+681     68/push  "F - test-next-line-matches?-no-match-2"/imm32
+682     68/push  0/imm32
+683     50/push-eax
+684     # . . call
+685     e8/call  check-ints-equal/disp32
+686     # . . discard args
+687     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+688     c3/return
+689 
+690 test-next-line-matches?-no-match-3:
+691     # next line of "ABABA" does not match  "AA"
+692     # . eax = next-line-matches?(_test-stream-line-ABABA, "AA")
+693     # . . push args
+694     68/push  "AA"/imm32
+695     68/push  _test-stream-line-ABABA/imm32
+696     # . . call
+697     e8/call  next-line-matches?/disp32
+698     # . . discard args
+699     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+700     # . check-ints-equal(eax, 0, msg)
+701     # . . push args
+702     68/push  "F - test-next-line-matches?-no-match-3"/imm32
+703     68/push  0/imm32
+704     50/push-eax
+705     # . . call
+706     e8/call  check-ints-equal/disp32
+707     # . . discard args
+708     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+709     c3/return
+710 
+711 test-next-line-matches?-match:
+712     # next line of "ABABA" matches "ABABA"
+713     # . eax = next-line-matches?(_test-stream-line-ABABA, "ABABA")
+714     # . . push args
+715     68/push  "ABABA"/imm32
+716     68/push  _test-stream-line-ABABA/imm32
+717     # . . call
+718     e8/call  next-line-matches?/disp32
+719     # . . discard args
+720     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+721     # . check-ints-equal(eax, 1, msg)
+722     # . . push args
+723     68/push  "F - test-next-line-matches?-match"/imm32
+724     68/push  1/imm32
+725     50/push-eax
+726     # . . call
+727     e8/call  check-ints-equal/disp32
+728     # . . discard args
+729     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+730     c3/return
+731 
+732 # move t->read to _after_ next newline
+733 skip-next-line:  # t : (address stream byte)
+734     # pseudocode:
+735     #   max = &t->data[t->write]
+736     #   i = t->read
+737     #   curr = &t->data[t->read]
+738     #   while true
+739     #     if (curr >= max) break
+740     #     ++i
+741     #     if (*curr == '\n') break
+742     #     ++curr
+743     #   t->read = i
+744     #
+745     # . prologue
+746     55/push-ebp
+747     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+748     # . save registers
+749     50/push-eax
+750     51/push-ecx
+751     52/push-edx
+752     53/push-ebx
+753     # ecx = t
+754     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
+755     # edx = t->data
+756     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           2/r32/edx   0xc/disp8       .                 # copy ecx+12 to edx
+757     # eax = t->write
+758     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
+759     # var max/ebx : (address byte) = &t->data[t->write]
+760     8d/copy-address                 0/mod/indirect  4/rm32/sib    2/base/edx  0/index/eax   .           3/r32/ebx   .               .                 # copy edx+eax to ebx
+761     # eax = t->read
+762     8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(ecx+4) to edx
+763     # var curr/ecx : (address byte) = &t->data[t->read]
+764     8d/copy-address                 0/mod/indirect  4/rm32/sib    2/base/edx  0/index/eax   .           1/r32/ecx   .               .                 # copy edx+eax to ecx
+765     # var i/edx : int = t->read
+766     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           0/r32/eax   .               .                 # copy eax to edx
+767 $skip-next-line:loop:
+768     # if (curr >= max) break
+769     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           3/r32/ebx   .               .                 # compare ecx and ebx
+770     73/jump-if-greater-or-equal-unsigned  $skip-next-line:end/disp8
+771     # ++i
+772     42/increment-edx
+773     # if (*curr == '\n') break
+774     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
+775     8a/copy-byte                    0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
+776     3d/compare-eax-and  0a/imm32/newline
+777     74/jump-if-equal  $skip-next-line:end/disp8
+778     # ++curr
+779     41/increment-ecx
+780     # loop
+781     eb/jump  $skip-next-line:loop/disp8
+782 $skip-next-line:end:
+783     # ecx = t
+784     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
+785     # t->read = i
+786     89/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           2/r32/edx   4/disp8         .                 # copy edx to *(ecx+4)
+787     # . restore registers
+788     5b/pop-to-ebx
+789     5a/pop-to-edx
+790     59/pop-to-ecx
+791     58/pop-to-eax
+792     # . epilogue
+793     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+794     5d/pop-to-ebp
+795     c3/return
+796 
+797 test-skip-next-line-empty:
+798     # skipping next line in empty stream leaves read pointer at 0
+799     # . skip-next-line(_test-stream-empty)
+800     # . . push args
+801     68/push  _test-stream-empty/imm32
+802     # . . call
+803     e8/call  skip-next-line/disp32
+804     # . . discard args
+805     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+806     # . check-ints-equal(_test-stream-empty->read, 0, msg)
+807     # . . push args
+808     68/push  "F - test-skip-next-line-empty"/imm32
+809     68/push  0/imm32
+810     b8/copy-to-eax  _test-stream-empty/imm32
+811     8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           0/r32/eax   4/disp8         .                 # copy *(eax+4) to eax
+812     50/push-eax
+813     # . . call
+814     e8/call  check-ints-equal/disp32
+815     # . . discard args
+816     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+817     c3/return
+818 
+819 test-skip-next-line-filled:
+820     # skipping next line increments read pointer by length of line + 1 (for newline)
+821     # . skip-next-line(_test-stream-filled)
+822     # . . push args
+823     68/push  _test-stream-filled/imm32
+824     # . . call
+825     e8/call  skip-next-line/disp32
+826     # . . discard args
+827     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+828     # . check-ints-equal(_test-stream-filled->read, 5, msg)
+829     # . . push args
+830     68/push  "F - test-skip-next-line-filled"/imm32
+831     68/push  5/imm32
+832     b8/copy-to-eax  _test-stream-filled/imm32
+833     8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           0/r32/eax   4/disp8         .                 # copy *(eax+4) to eax
+834     50/push-eax
+835     # . . call
+836     e8/call  check-ints-equal/disp32
+837     # . . discard args
+838     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+839     c3/return
+840 
+841 clear-trace-stream:
+842     # . prologue
+843     55/push-ebp
+844     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+845     # clear-stream(*Trace-stream)
+846     # . . push args
+847     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
+848     # . . call
+849     e8/call  clear-stream/disp32
+850     # . . discard args
+851     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+852 $clear-trace-stream:end:
+853     # . epilogue
+854     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+855     5d/pop-to-ebp
+856     c3/return
+857 
+858 # - helpers
+859 
+860 # 3-argument variant of _append
+861 _append-3:  # out : (address byte), outend : (address byte), s : (address array byte) -> num_bytes_appended/eax
+862     # . prologue
+863     55/push-ebp
+864     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+865     # . save registers
+866     51/push-ecx
+867     # eax = _append-4(out, outend, &s->data[0], &s->data[s->length])
+868     # . . push &s->data[s->length]
+869     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         0/r32/eax   0x10/disp8      .                 # copy *(ebp+16) to eax
+870     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+871     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
+872     51/push-ecx
+873     # . . push &s->data[0]
+874     8d/copy-address                 1/mod/*+disp8   0/rm32/eax    .           .             .           1/r32/ecx   4/disp8         .                 # copy eax+4 to ecx
+875     51/push-ecx
+876     # . . push outend
+877     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+878     # . . push out
+879     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+880     # . . call
+881     e8/call  _append-4/disp32
+882     # . . discard args
+883     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+884 $_append-3:end:
+885     # . restore registers
+886     59/pop-to-ecx
+887     # . epilogue
+888     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+889     5d/pop-to-ebp
+890     c3/return
+891 
+892 # 4-argument variant of _append
+893 _append-4:  # out : (address byte), outend : (address byte), in : (address byte), inend : (address byte) -> num_bytes_appended/eax : int
+894     # . prologue
+895     55/push-ebp
+896     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+897     # . save registers
+898     51/push-ecx
+899     52/push-edx
+900     53/push-ebx
+901     56/push-esi
+902     57/push-edi
+903     # num_bytes_appended = 0
+904     b8/copy-to-eax  0/imm32
+905     # edi = out
+906     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
+907     # edx = outend
+908     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
+909     # esi = in
+910     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0x10/disp8      .                 # copy *(ebp+16) to esi
+911     # ecx = inend
+912     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x14/disp8      .                 # copy *(ebp+20) to ecx
+913 $_append-4:loop:
+914     # if (in >= inend) break
+915     39/compare                      3/mod/direct    6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # compare esi with ecx
+916     73/jump-if-greater-or-equal-unsigned  $_append-4:end/disp8
+917     # if (out >= outend) abort  # just to catch test failures fast
+918     39/compare                      3/mod/direct    7/rm32/edi    .           .             .           2/r32/edx   .               .                 # compare edi with edx
+919     73/jump-if-greater-or-equal-unsigned  $_append-4:abort/disp8
+920     # *out = *in
+921     8a/copy-byte                    0/mod/indirect  6/rm32/esi    .           .             .           3/r32/BL    .               .                 # copy byte at *esi to BL
+922     88/copy-byte                    0/mod/indirect  7/rm32/edi    .           .             .           3/r32/BL    .               .                 # copy byte at BL to *edi
+923     # ++num_bytes_appended
+924     40/increment-eax
+925     # ++in
+926     46/increment-esi
+927     # ++out
+928     47/increment-edi
+929     eb/jump  $_append-4:loop/disp8
+930 $_append-4:end:
+931     # . restore registers
+932     5f/pop-to-edi
+933     5e/pop-to-esi
+934     5b/pop-to-ebx
+935     5a/pop-to-edx
+936     59/pop-to-ecx
+937     # . epilogue
+938     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+939     5d/pop-to-ebp
+940     c3/return
+941 
+942 $_append-4:abort:
+943     # . _write(2/stderr, error)
+944     # . . push args
+945     68/push  "stream overflow\n"/imm32
+946     68/push  2/imm32/stderr
+947     # . . call
+948     e8/call  _write/disp32
+949     # . . discard args
+950     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+951     # . syscall(exit, 1)
+952     bb/copy-to-ebx  1/imm32
+953     b8/copy-to-eax  1/imm32/exit
+954     cd/syscall  0x80/imm8
+955     # never gets here
+956 
+957 == data
+958 
+959 _test-stream-line-ABABA:  # (ref stream byte)
+960     # write
+961     8/imm32
+962     # read
+963     0/imm32
+964     # length
+965     8/imm32
+966     # data
+967     41 42 41 42 41 0a 00 00  # 8 bytes
+968 
+969 _test-stream-empty:  # (ref stream byte)
+970     # write
+971     0/imm32
+972     # read
+973     0/imm32
+974     # length
+975     8/imm32
+976     # data
+977     00 00 00 00 00 00 00 00  # 8 bytes
+978 
+979 _test-stream-filled:  # (ref stream byte)
+980     # write
+981     8/imm32
+982     # read
+983     0/imm32
+984     # length
+985     8/imm32
+986     # data
+987     41 41 41 41 0a 41 41 41  # 8 bytes
+988 
+989 # . . vim:nowrap:textwidth=0
 
-- cgit 1.4.1-2-gfad0