https://github.com/akkartik/mu/blob/main/linux/109stream-equal.subx

      1 # some primitives for checking stream contents
      2
      3 == code
      4 #   instruction                     effective address                                                   register    displacement    immediate
      5 # . op          subop               mod             rm32          base        index         scale       r32
      6 # . 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
      7
      8 # compare all the data in a stream (ignoring the read pointer)
      9 stream-data-equal?:  # f: (addr stream byte), s: (addr array byte) -> result/eax: boolean
     10     # . prologue
     11     55/push-ebp
     12     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
     13     # . save registers
     14     51/push-ecx
     15     52/push-edx
     16     56/push-esi
     17     57/push-edi
     18     # esi = f
     19     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
     20     # eax = f->write
     21     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy *esi to eax
     22     # var maxf/edx: (addr byte) = &f->data[f->write]
     23     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  0/index/eax   .           2/r32/edx   0xc/disp8       .                 # copy esi+eax+12 to edx
     24     # var currf/esi: (addr byte) = f->data
     25     81          0/subop/add         3/mod/direct    6/rm32/esi    .           .             .           .           .               0xc/imm32         # add to esi
     26     # edi = s
     27     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
     28 $stream-data-equal?:compare-sizes:
     29     # if (f->write != s->size) return false
     30     39/compare                      0/mod/indirect  7/rm32/edi    .           .             .           0/r32/eax   .               .                 # compare *edi and eax
     31     75/jump-if-!=  $stream-data-equal?:false/disp8
     32     # var currs/edi: (addr byte) = s->data
     33     81          0/subop/add         3/mod/direct    7/rm32/edi    .           .             .           .           .               4/imm32           # add to edi
     34     # var eax: byte = 0
     35     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
     36     # var ecx: byte = 0
     37     31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
     38 $stream-data-equal?:loop:
     39     # if (currf >= maxf) return true
     40     39/compare                      3/mod/direct    6/rm32/esi    .           .             .           2/r32/edx   .               .                 # compare esi with edx
     41     73/jump-if-addr>=  $stream-data-equal?:true/disp8
     42     # AL = *currs
     43     8a/copy-byte                    0/mod/indirect  6/rm32/esi    .           .             .           0/r32/AL    .               .                 # copy byte at *esi to AL
     44     # CL = *curr
     45     8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .             .           1/r32/CL    .               .                 # copy byte at *edi to CL
     46     # if (eax != ecx) return false
     47     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # compare eax and ecx
     48     75/jump-if-!=  $stream-data-equal?:false/disp8
     49     # ++f
     50     46/increment-esi
     51     # ++curr
     52     47/increment-edi
     53     eb/jump $stream-data-equal?:loop/disp8
     54 $stream-data-equal?:false:
     55     b8/copy-to-eax  0/imm32
     56     eb/jump  $stream-data-equal?:end/disp8
     57 $stream-data-equal?:true:
     58     b8/copy-to-eax  1/imm32
     59 $stream-data-equal?:end:
     60     # . restore registers
     61     5f/pop-to-edi
     62     5e/pop-to-esi
     63     5a/pop-to-edx
     64     59/pop-to-ecx
     65     # . epilogue
     66     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
     67     5d/pop-to-ebp
     68     c3/return
     69
     70 test-stream-data-equal:
     71     # . prologue
     72     55/push-ebp
     73     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
     74     # clear-stream(_test-stream)
     75     # . . push args
     76     68/push  _test-stream/imm32
     77     # . . call
     78     e8/call  clear-stream/disp32
     79     # . . discard args
     80     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
     81     # write(_test-stream, "Abc")
     82     # . . push args
     83     68/push  "Abc"/imm32
     84     68/push  _test-stream/imm32
     85     # . . call
     86     e8/call  write/disp32
     87     # . . discard args
     88     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     89     # eax = stream-data-equal?(_test-stream, "Abc")
     90     # . . push args
     91     68/push  "Abc"/imm32
     92     68/push  _test-stream/imm32
     93     # . . call
     94     e8/call  stream-data-equal?/disp32
     95     # . . discard args
     96     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     97     # check-ints-equal(eax, 1, msg)
     98     # . . push args
     99     68/push  "F - test-stream-data-equal"/imm32
    100     68/push  1/imm32
    101     50/push-eax
    102     # . . call
    103     e8/call  check-ints-equal/disp32
    104     # . . discard args
    105     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    106     # . epilogue
    107     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    108     5d/pop-to-ebp
    109     c3/return
    110
    111 test-stream-data-equal-2:
    112     # . prologue
    113     55/push-ebp
    114     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    115     # clear-stream(_test-stream)
    116     # . . push args
    117     68/push  _test-stream/imm32
    118     # . . call
    119     e8/call  clear-stream/disp32
    120     # . . discard args
    121     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    122     # write(_test-stream, "Abc")
    123     # . . push args
    124     68/push  "Abc"/imm32
    125     68/push  _test-stream/imm32
    126     # . . call
    127     e8/call  write/disp32
    128     # . . discard args
    129     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    130     # eax = stream-data-equal?(_test-stream, "Abd")
    131     # . . push args
    132     68/push  "Abd"/imm32
    133     68/push  _test-stream/imm32
    134     # . . call
    135     e8/call  stream-data-equal?/disp32
    136     # . . discard args
    137     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    138     # check-ints-equal(eax, 0, msg)
    139     # . . push args
    140     68/push  "F - test-stream-data-equal-2"/imm32
    141     68/push  0/imm32
    142     50/push-eax
    143     # . . call
    144     e8/call  check-ints-equal/disp32
    145     # . . discard args
    146     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    147     # . epilogue
    148     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    149     5d/pop-to-ebp
    150     c3/return
    151
    152 test-stream-data-equal-size-check:
    153     # . prologue
    154     55/push-ebp
    155     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    156     # clear-stream(_test-stream)
    157     # . . push args
    158     68/push  _test-stream/imm32
    159     # . . call
    160     e8/call  clear-stream/disp32
    161     # . . discard args
    162     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    163     # write(_test-stream, "Abc")
    164     # . . push args
    165     68/push  "Abc"/imm32
    166     68/push  _test-stream/imm32
    167     # . . call
    168     e8/call  write/disp32
    169     # . . discard args
    170     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    171     # eax = stream-data-equal?(_test-stream, "Abcd")
    172     # . . push args
    173     68/push  "Abcd"/imm32
    174     68/push  _test-stream/imm32
    175     # . . call
    176     e8/call  stream-data-equal?/disp32
    177     # . . discard args
    178     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    179     # check-ints-equal(eax, 0, msg)
    180     # . . push args
    181     68/push  "F - test-stream-data-equal-size-check"/imm32
    182     68/push  0/imm32
    183     50/push-eax
    184     # . . call
    185     e8/call  check-ints-equal/disp32
    186     # . . discard args
    187     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    188     # . epilogue
    189     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    190     5d/pop-to-ebp
    191     c3/return
    192
    193 # helper for later tests
    194 check-stream-equal:  # f: (addr stream byte), s: (addr array byte), msg: (addr array byte)
    195     # . prologue
    196     55/push-ebp
    197     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    198     # . save registers
    199     50/push-eax
    200     # eax = stream-data-equal?(f, s)
    201     # . . push args
    202     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    203     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    204     # . . call
    205     e8/call  stream-data-equal?/disp32
    206     # . . discard args
    207     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    208     # check-ints-equal(eax, 1, msg)
    209     # . . push args
    210     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
    211     68/push  1/imm32
    212     50/push-eax
    213     # . . call
    214     e8/call  check-ints-equal/disp32
    215     # . . discard args
    216     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    217 $check-stream-equal:end:
    218     # . restore registers
    219     58/pop-to-eax
    220     # . epilogue
    221     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    222     5d/pop-to-ebp
    223     c3/return
    224
    225 # scan the next line until newline starting from f->read and compare it with
    226 # 's' (ignoring the trailing newline)
    227 # on success, set f->read to after the next newline
    228 # on failure, leave f->read unmodified
    229 # this function is usually used only in tests, so we repeatedly write f->read
    230 next-stream-line-equal?:  # f: (addr stream byte), s: (addr array byte) -> result/eax: boolean
    231     # pseudocode:
    232     #   currf = f->read  # bound: f->write
    233     #   currs = 0  # bound: s->size
    234     #   while true
    235     #     if currf >= f->write
    236     #       return currs >= s->size
    237     #     if f[currf] == '\n'
    238     #       ++currf
    239     #       return currs >= s->size
    240     #     if (currs >= s->size) return false  # the current line of f still has data to match
    241     #     if (f[currf] != s[currs]) return false
    242     #     ++currf
    243     #     ++currs
    244     #
    245     # collapsing the two branches that can return true:
    246     #   currf = f->read  # bound: f->write
    247     #   currs = 0  # bound: s->size
    248     #   while true
    249     #     if (currf >= f->write) break
    250     #     if (f[currf] == '\n') break
    251     #     if (currs >= s->size) return false  # the current line of f still has data to match
    252     #     if (f[currf] != s[currs]) return false
    253     #     ++currf
    254     #     ++currs
    255     #   ++currf  # skip '\n'
    256     #   return currs >= s->size
    257     # Here the final `++currf` is sometimes unnecessary (if we're already at the end of the stream)
    258     #
    259     # registers:
    260     #   f: esi
    261     #   s: edi
    262     #   currf: ecx
    263     #   currs: edx
    264     #   f[currf]: eax
    265     #   s[currs]: ebx
    266     #
    267     # . prologue
    268     55/push-ebp
    269     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    270     # . save registers
    271     51/push-ecx
    272     52/push-edx
    273     56/push-esi
    274     57/push-edi
    275     # esi = f
    276     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
    277     # var currf/ecx: int = f->read
    278     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(esi+4) to ecx
    279     # edi = s
    280     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
    281     # var currs/edx: int = 0
    282     31/xor                          3/mod/direct    2/rm32/edx    .           .             .           2/r32/edx   .               .                 # clear edx
    283     # var c1/eax: byte = 0
    284     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
    285     # var c2/ebx: byte = 0
    286     31/xor                          3/mod/direct    3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # clear ebx
    287 $next-stream-line-equal?:loop:
    288     # if (currf >= f->write) break
    289     3b/compare                      0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # compare ecx with *esi
    290     7d/jump-if->=  $next-stream-line-equal?:break/disp8
    291     # c1 = f->data[f->read]
    292     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/AL    0xc/disp8       .                 # copy byte at *(esi+ecx+12) to AL
    293     # if (c1 == '\n') break
    294     3d/compare-eax-and  0xa/imm32/newline
    295     74/jump-if-=  $next-stream-line-equal?:break/disp8
    296     # if (currs >= s->size) return false
    297     3b/compare                      0/mod/indirect  7/rm32/edi    .           .             .           2/r32/edx   .               .                 # compare edx with *edi
    298     7d/jump-if->=  $next-stream-line-equal?:false/disp8
    299     # c2 = s->data[currs]
    300     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    7/base/edi  2/index/edx   .           3/r32/BL    4/disp8         .                 # copy byte at *(edi+edx+4) to BL
    301     # if (c1 != c2) return false
    302     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
    303     75/jump-if-!=  $next-stream-line-equal?:false/disp8
    304     # ++currf
    305     41/increment-ecx
    306     # ++currs
    307     42/increment-edx
    308     eb/jump $next-stream-line-equal?:loop/disp8
    309 $next-stream-line-equal?:break:
    310     # ++currf
    311     41/increment-ecx
    312     # if (currs >= s->size) return true
    313     3b/compare                      0/mod/indirect  7/rm32/edi    .           .             .           2/r32/edx   .               .                 # compare edx with *edi
    314     7c/jump-if-<  $next-stream-line-equal?:false/disp8
    315 $next-stream-line-equal?:true:
    316     b8/copy-to-eax  1/imm32
    317     # persist f->read on success
    318     89/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy ecx to *(esi+4)
    319     eb/jump  $next-stream-line-equal?:end/disp8
    320 $next-stream-line-equal?:false:
    321     b8/copy-to-eax  0/imm32
    322 $next-stream-line-equal?:end:
    323     # . restore registers
    324     5f/pop-to-edi
    325     5e/pop-to-esi
    326     5a/pop-to-edx
    327     59/pop-to-ecx
    328     # . epilogue
    329     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    330     5d/pop-to-ebp
    331     c3/return
    332
    333 test-next-stream-line-equal-stops-at-newline:
    334     # . prologue
    335     55/push-ebp
    336     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    337     # clear-stream(_test-stream)
    338     # . . push args
    339     68/push  _test-stream/imm32
    340     # . . call
    341     e8/call  clear-stream/disp32
    342     # . . discard args
    343     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    344     # write(_test-stream, "Abc\ndef")
    345     # . . push args
    346     68/push  "Abc\ndef"/imm32
    347     68/push  _test-stream/imm32
    348     # . . call
    349     e8/call  write/disp32
    350     # . . discard args
    351     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    352     # eax = next-stream-line-equal?(_test-stream, "Abc")
    353     # . . push args
    354     68/push  "Abc"/imm32
    355     68/push  _test-stream/imm32
    356     # . . call
    357     e8/call  next-stream-line-equal?/disp32
    358     # . . discard args
    359     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    360     # check-ints-equal(eax, 1, msg)
    361     # . . push args
    362     68/push  "F - test-next-stream-line-equal-stops-at-newline"/imm32
    363     68/push  1/imm32
    364     50/push-eax
    365     # . . call
    366     e8/call  check-ints-equal/disp32
    367     # . . discard args
    368     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    369     # . epilogue
    370     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    371     5d/pop-to-ebp
    372     c3/return
    373
    374 test-next-stream-line-equal-stops-at-newline-2:
    375     # . prologue
    376     55/push-ebp
    377     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    378     # clear-stream(_test-stream)
    379     # . . push args
    380     68/push  _test-stream/imm32
    381     # . . call
    382     e8/call  clear-stream/disp32
    383     # . . discard args
    384     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    385     # write(_test-stream, "Abc\ndef")
    386     # . . push args
    387     68/push  "Abc\ndef"/imm32
    388     68/push  _test-stream/imm32
    389     # . . call
    390     e8/call  write/disp32
    391     # . . discard args
    392     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    393     # eax = next-stream-line-equal?(_test-stream, "def")
    394     # . . push args
    395     68/push  "def"/imm32
    396     68/push  _test-stream/imm32
    397     # . . call
    398     e8/call  next-stream-line-equal?/disp32
    399     # . . discard args
    400     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    401     # check-ints-equal(eax, 0, msg)
    402     # . . push args
    403     68/push  "F - test-next-stream-line-equal-stops-at-newline-2"/imm32
    404     68/push  0/imm32
    405     50/push-eax
    406     # . . call
    407     e8/call  check-ints-equal/disp32
    408     # . . discard args
    409     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    410     # . epilogue
    411     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    412     5d/pop-to-ebp
    413     c3/return
    414
    415 test-next-stream-line-equal-skips-newline:
    416     # . prologue
    417     55/push-ebp
    418     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    419     # clear-stream(_test-stream)
    420     # . . push args
    421     68/push  _test-stream/imm32
    422     # . . call
    423     e8/call  clear-stream/disp32
    424     # . . discard args
    425     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    426     # write(_test-stream, "Abc\ndef\n")
    427     # . . push args
    428     68/push  "Abc\ndef\n"/imm32
    429     68/push  _test-stream/imm32
    430     # . . call
    431     e8/call  write/disp32
    432     # . . discard args
    433     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    434     # next-stream-line-equal?(_test-stream, "Abc")
    435     # . . push args
    436     68/push  "Abc"/imm32
    437     68/push  _test-stream/imm32
    438     # . . call
    439     e8/call  next-stream-line-equal?/disp32
    440     # . . discard args
    441     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    442     # eax = next-stream-line-equal?(_test-stream, "def")
    443     # . . push args
    444     68/push  "def"/imm32
    445     68/push  _test-stream/imm32
    446     # . . call
    447     e8/call  next-stream-line-equal?/disp32
    448     # . . discard args
    449     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    450     # check-ints-equal(eax, 1, msg)
    451     # . . push args
    452     68/push  "F - test-next-stream-line-equal-skips-newline"/imm32
    453     68/push  1/imm32
    454     50/push-eax
    455     # . . call
    456     e8/call  check-ints-equal/disp32
    457     # . . discard args
    458     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    459     # . epilogue
    460     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    461     5d/pop-to-ebp
    462     c3/return
    463
    464 test-next-stream-line-equal-handles-final-line:
    465     # . prologue
    466     55/push-ebp
    467     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    468     # clear-stream(_test-stream)
    469     # . . push args
    470     68/push  _test-stream/imm32
    471     # . . call
    472     e8/call  clear-stream/disp32
    473     # . . discard args
    474     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    475     # write(_test-stream, "Abc\ndef")
    476     # . . push args
    477     68/push  "Abc\ndef"/imm32
    478     68/push  _test-stream/imm32
    479     # . . call
    480     e8/call  write/disp32
    481     # . . discard args
    482     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    483     # next-stream-line-equal?(_test-stream, "Abc")
    484     # . . push args
    485     68/push  "Abc"/imm32
    486     68/push  _test-stream/imm32
    487     # . . call
    488     e8/call  next-stream-line-equal?/disp32
    489     # . . discard args
    490     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    491     # eax = next-stream-line-equal?(_test-stream, "def")
    492     # . . push args
    493     68/push  "def"/imm32
    494     68/push  _test-stream/imm32
    495     # . . call
    496     e8/call  next-stream-line-equal?/disp32
    497     # . . discard args
    498     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    499     # check-ints-equal(eax, 1, msg)
    500     # . . push args
    501     68/push  "F - test-next-stream-line-equal-skips-newline"/imm32
    502     68/push  1/imm32
    503     50/push-eax
    504     # . . call
    505     e8/call  check-ints-equal/disp32
    506     # . . discard args
    507     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    508     # . epilogue
    509     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    510     5d/pop-to-ebp
    511     c3/return
    512
    513 test-next-stream-line-equal-always-fails-after-Eof:
    514     # . prologue
    515     55/push-ebp
    516     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    517     # clear-stream(_test-stream)
    518     # . . push args
    519     68/push  _test-stream/imm32
    520     # . . call
    521     e8/call  clear-stream/disp32
    522     # . . discard args
    523     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    524     # write nothing
    525     # eax = next-stream-line-equal?(_test-stream, "")
    526     # . . push args
    527     68/push  ""/imm32
    528     68/push  _test-stream/imm32
    529     # . . call
    530     e8/call  next-stream-line-equal?/disp32
    531     # . . discard args
    532     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    533     # check-ints-equal(eax, 0, msg)
    534     # . . push args
    535     68/push  "F - test-next-stream-line-equal-always-fails-after-Eof"/imm32
    536     68/push  1/imm32
    537     50/push-eax
    538     # . . call
    539     e8/call  check-ints-equal/disp32
    540     # . . discard args
    541     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    542     # eax = next-stream-line-equal?(_test-stream, "")
    543     # . . push args
    544     68/push  ""/imm32
    545     68/push  _test-stream/imm32
    546     # . . call
    547     e8/call  next-stream-line-equal?/disp32
    548     # . . discard args
    549     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    550     # check-ints-equal(eax, 0, msg)
    551     # . . push args
    552     68/push  "F - test-next-stream-line-equal-always-fails-after-Eof/2"/imm32
    553     68/push  1/imm32
    554     50/push-eax
    555     # . . call
    556     e8/call  check-ints-equal/disp32
    557     # . . discard args
    558     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    559     # . epilogue
    560     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    561     5d/pop-to-ebp
    562     c3/return
    563
    564 # helper for later tests
    565 check-next-stream-line-equal:  # f: (addr stream byte), s: (addr array byte), msg: (addr array byte)
    566     # . prologue
    567     55/push-ebp
    568     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    569     # . save registers
    570     50/push-eax
    571     # eax = next-stream-line-equal?(f, s)
    572     # . . push args
    573     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    574     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    575     # . . call
    576     e8/call  next-stream-line-equal?/disp32
    577     # . . discard args
    578     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    579     # check-ints-equal(eax, 1, msg)
    580     # . . push args
    581     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
    582     68/push  1/imm32
    583     50/push-eax
    584     # . . call
    585     e8/call  check-ints-equal/disp32
    586     # . . discard args
    587     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    588     # . restore registers
    589     58/pop-to-eax
    590     # . epilogue
    591     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    592     5d/pop-to-ebp
    593     c3/return
    594
    595 # . . vim:nowrap:textwidth=0