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