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