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