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