https://github.com/akkartik/mu/blob/master/subx/058stream-equal.subx
  1 # some primitives for checking stream contents
  2 
  3 == code
  4 #   instruction                     effective address                                                   register    displacement    immediate
  5 # . op          subop               mod             rm32          base        index         scale       r32
  6 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
  7 
  8 #? Entry:  # run a single test, while debugging
  9 #?     e8/call test-next-stream-line-equal-stops-at-newline/disp32
 10 #?     # syscall(exit, Num-test-failures)
 11 #?     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/EBX   Num-test-failures/disp32          # copy *Num-test-failures to EBX
 12 #?     b8/copy-to-EAX  1/imm32/exit
 13 #?     cd/syscall  0x80/imm8
 14 
 15 # compare all the data in a stream (ignoring the read pointer)
 16 stream-data-equal?:  # f : (address stream), s : (address string) -> EAX : boolean
 17     # . prolog
 18     55/push-EBP
 19     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
 20     # . save registers
 21     51/push-ECX
 22     52/push-EDX
 23     56/push-ESI
 24     57/push-EDI
 25     # ESI = f
 26     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
 27     # max/EDX = f->data + f->write
 28     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy *ESI to EAX
 29     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
 30     # currf/ESI = f->data
 31     81          0/subop/add         3/mod/direct    6/rm32/ESI    .           .             .           .           .               0xc/imm32         # add to ESI
 32     # EDI = s
 33     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           7/r32/EDI   0xc/disp8       .                 # copy *(EBP+12) to EDI
 34     # if (f->write != s->length) return false
 35     39/compare                      0/mod/indirect  7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # compare *EDI and EAX
 36     75/jump-if-not-equal  $stream-data-equal?:false/disp8
 37     # currs/EDI = s->data
 38     81          0/subop/add         3/mod/direct    7/rm32/EDI    .           .             .           .           .               4/imm32           # add to EDI
 39     # EAX = ECX = 0
 40     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
 41     31/xor                          3/mod/direct    1/rm32/ECX    .           .             .           1/r32/ECX   .               .                 # clear ECX
 42 $stream-data-equal?:loop:
 43     # if (curr >= max) return true
 44     39/compare                      3/mod/direct    6/rm32/ESI    .           .             .           2/r32/EDX   .               .                 # compare ESI with EDX
 45     7d/jump-if-greater-or-equal  $stream-data-equal?:true/disp8
 46     # AL = *currs
 47     8a/copy-byte                    0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/AL    .               .                 # copy byte at *ESI to AL
 48     # CL = *curr
 49     8a/copy-byte                    0/mod/indirect  7/rm32/EDI    .           .             .           1/r32/CL    .               .                 # copy byte at *EDI to CL
 50     # if (EAX != ECX) return false
 51     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # compare EAX and ECX
 52     75/jump-if-not-equal  $stream-data-equal?:false/disp8
 53     # ++f
 54     46/increment-ESI
 55     # ++curr
 56     47/increment-EDI
 57     eb/jump $stream-data-equal?:loop/disp8
 58 $stream-data-equal?:false:
 59     b8/copy-to-EAX  0/imm32
 60     eb/jump  $stream-data-equal?:end/disp8
 61 $stream-data-equal?:true:
 62     b8/copy-to-EAX  1/imm32
 63 $stream-data-equal?:end:
 64     # . restore registers
 65     5f/pop-to-EDI
 66     5e/pop-to-ESI
 67     5a/pop-to-EDX
 68     59/pop-to-ECX
 69     # . epilog
 70     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
 71     5d/pop-to-EBP
 72     c3/return
 73 
 74 test-stream-data-equal:
 75     # . prolog
 76     55/push-EBP
 77     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
 78     # clear-stream(_test-stream)
 79     # . . push args
 80     68/push  _test-stream/imm32
 81     # . . call
 82     e8/call  clear-stream/disp32
 83     # . . discard args
 84     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
 85     # write(_test-stream, "Abc")
 86     # . . push args
 87     68/push  "Abc"/imm32
 88     68/push  _test-stream/imm32
 89     # . . call
 90     e8/call  write/disp32
 91     # . . discard args
 92     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
 93     # EAX = stream-data-equal?(_test-stream, "Abc")
 94     # . . push args
 95     68/push  "Abc"/imm32
 96     68/push  _test-stream/imm32
 97     # . . call
 98     e8/call  stream-data-equal?/disp32
 99     # . . discard args
100     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
101     # check-ints-equal(EAX, 1, msg)
102     # . . push args
103     68/push  "F - test-stream-data-equal"/imm32
104     68/push  1/imm32
105     50/push-EAX
106     # . . call
107     e8/call  check-ints-equal/disp32
108     # . . discard args
109     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
110     # . epilog
111     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
112     5d/pop-to-EBP
113     c3/return
114 
115 test-stream-data-equal-2:
116     # . prolog
117     55/push-EBP
118     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
119     # clear-stream(_test-stream)
120     # . . push args
121     68/push  _test-stream/imm32
122     # . . call
123     e8/call  clear-stream/disp32
124     # . . discard args
125     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
126     # write(_test-stream, "Abc")
127     # . . push args
128     68/push  "Abc"/imm32
129     68/push  _test-stream/imm32
130     # . . call
131     e8/call  write/disp32
132     # . . discard args
133     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
134     # EAX = stream-data-equal?(_test-stream, "Abd")
135     # . . push args
136     68/push  "Abd"/imm32
137     68/push  _test-stream/imm32
138     # . . call
139     e8/call  stream-data-equal?/disp32
140     # . . discard args
141     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
142     # check-ints-equal(EAX, 0, msg)
143     # . . push args
144     68/push  "F - test-stream-data-equal-2"/imm32
145     68/push  0/imm32
146     50/push-EAX
147     # . . call
148     e8/call  check-ints-equal/disp32
149     # . . discard args
150     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
151     # . epilog
152     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
153     5d/pop-to-EBP
154     c3/return
155 
156 test-stream-data-equal-length-check:
157     # . prolog
158     55/push-EBP
159     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
160     # clear-stream(_test-stream)
161     # . . push args
162     68/push  _test-stream/imm32
163     # . . call
164     e8/call  clear-stream/disp32
165     # . . discard args
166     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
167     # write(_test-stream, "Abc")
168     # . . push args
169     68/push  "Abc"/imm32
170     68/push  _test-stream/imm32
171     # . . call
172     e8/call  write/disp32
173     # . . discard args
174     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
175     # EAX = stream-data-equal?(_test-stream, "Abcd")
176     # . . push args
177     68/push  "Abcd"/imm32
178     68/push  _test-stream/imm32
179     # . . call
180     e8/call  stream-data-equal?/disp32
181     # . . discard args
182     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
183     # check-ints-equal(EAX, 0, msg)
184     # . . push args
185     68/push  "F - test-stream-data-equal-length-check"/imm32
186     68/push  0/imm32
187     50/push-EAX
188     # . . call
189     e8/call  check-ints-equal/disp32
190     # . . discard args
191     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
192     # . epilog
193     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
194     5d/pop-to-EBP
195     c3/return
196 
197 # helper for later tests
198 check-stream-equal:  # f : (address stream), s : (address string), msg : (address string)
199     # . prolog
200     55/push-EBP
201     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
202     # . save registers
203     50/push-EAX
204     # EAX = stream-data-equal?(f, s)
205     # . . push args
206     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
207     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
208     # . . call
209     e8/call  stream-data-equal?/disp32
210     # . . discard args
211     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
212     # check-ints-equal(EAX, 1, msg)
213     # . . push args
214     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x10/disp8      .                 # push *(EBP+16)
215     68/push  1/imm32
216     50/push-EAX
217     # . . call
218     e8/call  check-ints-equal/disp32
219     # . . discard args
220     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
221     # . restore registers
222     58/pop-to-EAX
223     # . epilog
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 : (address stream), s : (address string) -> EAX : boolean
234     # pseudocode:
235     #   currf = f->read  # bound: f->write
236     #   currs = 0  # bound : s->length
237     #   while true:
238     #     if (currf >= f->write)
239     #       return currs >= s->length
240     #     if (f[currf] == '\n')
241     #       ++currf
242     #       return currs >= s->length
243     #     if (currs >= s->length) 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->length
251     #   while true:
252     #     if (currf >= f->write) break
253     #     if (f[currf] == '\n') break
254     #     if (currs >= s->length) 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->length
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     # . prolog
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     # currf/ECX = 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     # currs/EDX = 0
285     31/xor                          3/mod/direct    2/rm32/EDX    .           .             .           2/r32/EDX   .               .                 # clear EDX
286     # EAX = EBX = 0
287     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
288     31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
289 $next-stream-line-equal?:loop:
290     # if (currf >= f->write) break
291     3b/compare                      0/mod/indirect  6/rm32/ESI    .           .             .           1/r32/ECX   .               .                 # compare ECX with *ESI
292     7d/jump-if-greater-or-equal  $next-stream-line-equal?:break/disp8
293     # AL = *(f->data + f->read)
294     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
295     # if (EAX == '\n') break
296     81          7/subop/compare     3/mod/direct    0/rm32/EAX    .           .             .           .           .               0xa/imm32/newline # compare EAX
297     74/jump-if-equal  $next-stream-line-equal?:break/disp8
298     # if (currs >= s->length) return false
299     3b/compare                      0/mod/indirect  7/rm32/EDI    .           .             .           2/r32/EDX   .               .                 # compare EDX with *EDI
300     7d/jump-if-greater-or-equal  $next-stream-line-equal?:false/disp8
301     # BL = *(s->data + currs)
302     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
303     # if (EAX != EBX) return false
304     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           3/r32/EBX   .               .                 # compare EAX and EBX
305     75/jump-if-not-equal  $next-stream-line-equal?:false/disp8
306     # ++currf
307     41/increment-ECX
308     # ++currs
309     42/increment-EDX
310     eb/jump $next-stream-line-equal?:loop/disp8
311 $next-stream-line-equal?:break:
312     # ++currf
313     41/increment-ECX
314     # if (currs >= s->length) return true
315     3b/compare                      0/mod/indirect  7/rm32/EDI    .           .             .           2/r32/EDX   .               .                 # compare EDX with *EDI
316     7c/jump-if-lesser  $next-stream-line-equal?:false/disp8
317 $next-stream-line-equal?:true:
318     b8/copy-to-EAX  1/imm32
319     # persist f->read on success
320     89/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy ECX to *(ESI+4)
321     eb/jump  $next-stream-line-equal?:end/disp8
322 $next-stream-line-equal?:false:
323     b8/copy-to-EAX  0/imm32
324 $next-stream-line-equal?:end:
325     # . restore registers
326     5f/pop-to-EDI
327     5e/pop-to-ESI
328     5a/pop-to-EDX
329     59/pop-to-ECX
330     # . epilog
331     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
332     5d/pop-to-EBP
333     c3/return
334 
335 test-next-stream-line-equal-stops-at-newline:
336     # . prolog
337     55/push-EBP
338     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
339     # clear-stream(_test-stream)
340     # . . push args
341     68/push  _test-stream/imm32
342     # . . call
343     e8/call  clear-stream/disp32
344     # . . discard args
345     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
346     # write(_test-stream, "Abc\ndef")
347     # . write(_test-stream, "Abc")
348     # . . push args
349     68/push  "Abc"/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     # . write(_test-stream, Newline)
356     # . . push args
357     68/push  Newline/imm32
358     68/push  _test-stream/imm32
359     # . . call
360     e8/call  write/disp32
361     # . . discard args
362     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
363     # . write(_test-stream, "def")
364     # . . push args
365     68/push  "def"/imm32
366     68/push  _test-stream/imm32
367     # . . call
368     e8/call  write/disp32
369     # . . discard args
370     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
371     # EAX = next-stream-line-equal?(_test-stream, "Abc")
372     # . . push args
373     68/push  "Abc"/imm32
374     68/push  _test-stream/imm32
375     # . . call
376     e8/call  next-stream-line-equal?/disp32
377     # . . discard args
378     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
379     # check-ints-equal(EAX, 1, msg)
380     # . . push args
381     68/push  "F - test-next-stream-line-equal-stops-at-newline"/imm32
382     68/push  1/imm32
383     50/push-EAX
384     # . . call
385     e8/call  check-ints-equal/disp32
386     # . . discard args
387     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
388     # . epilog
389     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
390     5d/pop-to-EBP
391     c3/return
392 
393 test-next-stream-line-equal-stops-at-newline-2:
394     # . prolog
395     55/push-EBP
396     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
397     # clear-stream(_test-stream)
398     # . . push args
399     68/push  _test-stream/imm32
400     # . . call
401     e8/call  clear-stream/disp32
402     # . . discard args
403     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
404     # write(_test-stream, "Abc\ndef")
405     # . write(_test-stream, "Abc")
406     # . . push args
407     68/push  "Abc"/imm32
408     68/push  _test-stream/imm32
409     # . . call
410     e8/call  write/disp32
411     # . . discard args
412     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
413     # . write(_test-stream, Newline)
414     # . . push args
415     68/push  Newline/imm32
416     68/push  _test-stream/imm32
417     # . . call
418     e8/call  write/disp32
419     # . . discard args
420     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
421     # . write(_test-stream, "def")
422     # . . push args
423     68/push  "def"/imm32
424     68/push  _test-stream/imm32
425     # . . call
426     e8/call  write/disp32
427     # . . discard args
428     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
429     # EAX = next-stream-line-equal?(_test-stream, "def")
430     # . . push args
431     68/push  "def"/imm32
432     68/push  _test-stream/imm32
433     # . . call
434     e8/call  next-stream-line-equal?/disp32
435     # . . discard args
436     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
437     # check-ints-equal(EAX, 0, msg)
438     # . . push args
439     68/push  "F - test-next-stream-line-equal-stops-at-newline-2"/imm32
440     68/push  0/imm32
441     50/push-EAX
442     # . . call
443     e8/call  check-ints-equal/disp32
444     # . . discard args
445     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
446     # . epilog
447     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
448     5d/pop-to-EBP
449     c3/return
450 
451 test-next-stream-line-equal-skips-newline:
452     # . prolog
453     55/push-EBP
454     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
455     # clear-stream(_test-stream)
456     # . . push args
457     68/push  _test-stream/imm32
458     # . . call
459     e8/call  clear-stream/disp32
460     # . . discard args
461     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
462     # write(_test-stream, "Abc\ndef\n")
463     # . write(_test-stream, "Abc")
464     # . . push args
465     68/push  "Abc"/imm32
466     68/push  _test-stream/imm32
467     # . . call
468     e8/call  write/disp32
469     # . . discard args
470     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
471     # . write(_test-stream, Newline)
472     # . . push args
473     68/push  Newline/imm32
474     68/push  _test-stream/imm32
475     # . . call
476     e8/call  write/disp32
477     # . . discard args
478     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
479     # . write(_test-stream, "def")
480     # . . push args
481     68/push  "def"/imm32
482     68/push  _test-stream/imm32
483     # . . call
484     e8/call  write/disp32
485     # . . discard args
486     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
487     # . write(_test-stream, Newline)
488     # . . push args
489     68/push  Newline/imm32
490     68/push  _test-stream/imm32
491     # . . call
492     e8/call  write/disp32
493     # . . discard args
494     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
495     # next-stream-line-equal?(_test-stream, "Abc")
496     # . . push args
497     68/push  "Abc"/imm32
498     68/push  _test-stream/imm32
499     # . . call
500     e8/call  next-stream-line-equal?/disp32
501     # . . discard args
502     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
503     # EAX = next-stream-line-equal?(_test-stream, "def")
504     # . . push args
505     68/push  "def"/imm32
506     68/push  _test-stream/imm32
507     # . . call
508     e8/call  next-stream-line-equal?/disp32
509     # . . discard args
510     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
511     # check-ints-equal(EAX, 1, msg)
512     # . . push args
513     68/push  "F - test-next-stream-line-equal-skips-newline"/imm32
514     68/push  1/imm32
515     50/push-EAX
516     # . . call
517     e8/call  check-ints-equal/disp32
518     # . . discard args
519     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
520     # . epilog
521     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
522     5d/pop-to-EBP
523     c3/return
524 
525 test-next-stream-line-equal-handles-final-line:
526     # . prolog
527     55/push-EBP
528     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
529     # clear-stream(_test-stream)
530     # . . push args
531     68/push  _test-stream/imm32
532     # . . call
533     e8/call  clear-stream/disp32
534     # . . discard args
535     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
536     # write(_test-stream, "Abc\ndef")
537     # . write(_test-stream, "Abc")
538     # . . push args
539     68/push  "Abc"/imm32
540     68/push  _test-stream/imm32
541     # . . call
542     e8/call  write/disp32
543     # . . discard args
544     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
545     # . write(_test-stream, Newline)
546     # . . push args
547     68/push  Newline/imm32
548     68/push  _test-stream/imm32
549     # . . call
550     e8/call  write/disp32
551     # . . discard args
552     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
553     # . write(_test-stream, "def")
554     # . . push args
555     68/push  "def"/imm32
556     68/push  _test-stream/imm32
557     # . . call
558     e8/call  write/disp32
559     # . . discard args
560     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
561     # next-stream-line-equal?(_test-stream, "Abc")
562     # . . push args
563     68/push  "Abc"/imm32
564     68/push  _test-stream/imm32
565     # . . call
566     e8/call  next-stream-line-equal?/disp32
567     # . . discard args
568     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
569     # EAX = next-stream-line-equal?(_test-stream, "def")
570     # . . push args
571     68/push  "def"/imm32
572     68/push  _test-stream/imm32
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     68/push  "F - test-next-stream-line-equal-skips-newline"/imm32
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     # . epilog
587     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
588     5d/pop-to-EBP
589     c3/return
590 
591 test-next-stream-line-equal-always-fails-after-eof:
592     # . prolog
593     55/push-EBP
594     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
595     # clear-stream(_test-stream)
596     # . . push args
597     68/push  _test-stream/imm32
598     # . . call
599     e8/call  clear-stream/disp32
600     # . . discard args
601     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
602     # write nothing
603     # EAX = next-stream-line-equal?(_test-stream, "")
604     # . . push args
605     68/push  ""/imm32
606     68/push  _test-stream/imm32
607     # . . call
608     e8/call  next-stream-line-equal?/disp32
609     # . . discard args
610     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
611     # check-ints-equal(EAX, 0, msg)
612     # . . push args
613     68/push  "F - test-next-stream-line-equal-always-fails-after-eof"/imm32
614     68/push  1/imm32
615     50/push-EAX
616     # . . call
617     e8/call  check-ints-equal/disp32
618     # . . discard args
619     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
620     # EAX = next-stream-line-equal?(_test-stream, "")
621     # . . push args
622     68/push  ""/imm32
623     68/push  _test-stream/imm32
624     # . . call
625     e8/call  next-stream-line-equal?/disp32
626     # . . discard args
627     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
628     # check-ints-equal(EAX, 0, msg)
629     # . . push args
630     68/push  "F - test-next-stream-line-equal-always-fails-after-eof/2"/imm32
631     68/push  1/imm32
632     50/push-EAX
633     # . . call
634     e8/call  check-ints-equal/disp32
635     # . . discard args
636     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
637     # . epilog
638     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
639     5d/pop-to-EBP
640     c3/return
641 
642 # helper for later tests
643 check-next-stream-line-equal:
644     # . prolog
645     55/push-EBP
646     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
647     # . save registers
648     50/push-EAX
649     # EAX = next-stream-line-equal?(f, s)
650     # . . push args
651     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
652     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
653     # . . call
654     e8/call  next-stream-line-equal?/disp32
655     # . . discard args
656     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
657     # check-ints-equal(EAX, 1, msg)
658     # . . push args
659     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x10/disp8      .                 # push *(EBP+16)
660     68/push  1/imm32
661     50/push-EAX
662     # . . call
663     e8/call  check-ints-equal/disp32
664     # . . discard args
665     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
666     # . restore registers
667     58/pop-to-EAX
668     # . epilog
669     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
670     5d/pop-to-EBP
671     c3/return