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