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