https://github.com/akkartik/mu/blob/master/subx/072slice.subx
  1 # new data structure: a slice is an open interval of addresses [start, end)
  2 # that includes 'start' but not 'end'
  3 
  4 == code
  5 #   instruction                     effective address                                                   register    displacement    immediate
  6 # . op          subop               mod             rm32          base        index         scale       r32
  7 # . 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
  8 
  9 # main:
 10     e8/call  run-tests/disp32  # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
 11     # syscall(exit, Num-test-failures)
 12     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/EBX   Num-test-failures/disp32          # copy *Num-test-failures to EBX
 13     b8/copy-to-EAX  1/imm32/exit
 14     cd/syscall  0x80/imm8
 15 
 16 slice-empty?:  # s : (address slice) -> 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     # ECX = s
 23     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   8/disp8         .                 # copy *(EBP+8) to ECX
 24     # if (s->start == s->end) return true
 25     # . EAX = s->start
 26     8b/copy                         0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # copy *ECX to EAX
 27     # . compare EAX with s->end
 28     39/compare                      1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # compare EAX and *(ECX+4)
 29     b8/copy-to-EAX  1/imm32/true
 30     74/jump-if-equal  $slice-empty?:end/disp8
 31     b8/copy-to-EAX  0/imm32/false
 32 $slice-empty?:end:
 33     # . restore registers
 34     59/pop-to-ECX
 35     # . epilog
 36     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
 37     5d/pop-to-EBP
 38     c3/return
 39 
 40 test-slice-empty-true:
 41     # . prolog
 42     55/push-EBP
 43     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
 44     # var slice/ECX = {34, 34}
 45     68/push  34/imm32/end
 46     68/push  34/imm32/start
 47     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
 48     # slice-empty?(slice)
 49     # . . push args
 50     51/push-ECX
 51     # . . call
 52     e8/call  slice-empty?/disp32
 53     # . . discard args
 54     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
 55     # check-ints-equal(EAX, 1, msg)
 56     # . . push args
 57     68/push  "F - test-slice-empty-true"/imm32
 58     68/push  1/imm32
 59     50/push-EAX
 60     # . . call
 61     e8/call  check-ints-equal/disp32
 62     # . . discard args
 63     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
 64     # . epilog
 65     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
 66     5d/pop-to-EBP
 67     c3/return
 68 
 69 test-slice-empty-false:
 70     # . prolog
 71     55/push-EBP
 72     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
 73     # var slice/ECX = {34, 23}
 74     68/push  23/imm32/end
 75     68/push  34/imm32/start
 76     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
 77     # slice-empty?(slice)
 78     # . . push args
 79     51/push-ECX
 80     # . . call
 81     e8/call  slice-empty?/disp32
 82     # . . discard args
 83     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
 84     # check-ints-equal(EAX, 0, msg)
 85     # . . push args
 86     68/push  "F - test-slice-empty-false"/imm32
 87     68/push  0/imm32
 88     50/push-EAX
 89     # . . call
 90     e8/call  check-ints-equal/disp32
 91     # . . discard args
 92     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
 93     # . epilog
 94     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
 95     5d/pop-to-EBP
 96     c3/return
 97 
 98 slice-equal?:  # s : (address slice), p : (address string) -> EAX : boolean
 99     # pseudocode:
100     #   currs = s->start
101     #   maxs = s->end
102     #   if (maxs - currs != p->length) return false
103     #   currp = p->data
104     #   while (currs < maxs)
105     #     if (*currs != *currp) return false
106     #     ++currs
107     #     ++currp
108     #   return true
109     #
110     # registers:
111     #   currs: EDX
112     #   maxs: ESI
113     #   currp: EBX
114     #   *currs: EAX
115     #   *currp: ECX
116     #
117     # . prolog
118     55/push-EBP
119     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
120     # . save registers
121     51/push-ECX
122     52/push-EDX
123     53/push-EBX
124     56/push-ESI
125     # ESI = s
126     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
127     # currs/EDX = s->start
128     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           2/r32/EDX   .               .                 # copy *ESI to EDX
129     # maxs/ESI = s->end
130     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           6/r32/ESI   4/disp8         .                 # copy *(ESI+4) to ESI
131     # EBX = p
132     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           3/r32/EBX   0xc/disp8       .                 # copy *(EBP+12) to EBX
133     # EAX = maxs - currs
134     89/copy                         3/mod/direct    0/rm32/EAX    .           .             .           6/r32/ESI   .               .                 # copy ESI to EAX
135     29/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           2/r32/EDX   .               .                 # subtract EDX from EAX
136     # if (EAX != p->length) return false
137     39/compare                      0/mod/indirect  3/rm32/EBX    .           .             .           0/r32/EAX   .               .                 # compare *EBX and EAX
138     75/jump-if-not-equal  $slice-equal?:false/disp8
139     # currp/EBX = p->data
140     81          0/subop/add         3/mod/direct    3/rm32/EBX    .           .             .           .           .               4/imm32           # add to EBX
141     # EAX = ECX = 0
142     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
143     31/xor                          3/mod/direct    1/rm32/ECX    .           .             .           1/r32/ECX   .               .                 # clear ECX
144 $slice-equal?:loop:
145     # if (currs >= maxs) return true
146     39/compare                      3/mod/direct    2/rm32/EDX    .           .             .           6/r32/ESI   .               .                 # compare EDX and ESI
147     7d/jump-if-greater-or-equal  $slice-equal?:true/disp8
148     # AL = *currp
149     8a/copy-byte                    0/mod/indirect  3/rm32/EBX    .           .             .           0/r32/AL    .               .                 # copy byte at *EBX to AL
150     # CL = *currs
151     8a/copy-byte                    0/mod/indirect  2/rm32/EDX    .           .             .           1/r32/CL    .               .                 # copy byte at *EDX to CL
152     # if (EAX != ECX) return false
153     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # compare EAX and ECX
154     75/jump-if-not-equal  $slice-equal?:false/disp8
155     # ++currp
156     43/increment-EBX
157     # ++currs
158     42/increment-EDX
159     eb/jump $slice-equal?:loop/disp8
160 $slice-equal?:false:
161     b8/copy-to-EAX  0/imm32
162     eb/jump  $slice-equal?:end/disp8
163 $slice-equal?:true:
164     b8/copy-to-EAX  1/imm32
165 $slice-equal?:end:
166     # . restore registers
167     5e/pop-to-ESI
168     5b/pop-to-EBX
169     5a/pop-to-EDX
170     59/pop-to-ECX
171     # . epilog
172     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
173     5d/pop-to-EBP
174     c3/return
175 
176 test-slice-equal:
177     # - slice-equal?(slice("Abc"), "Abc") == 1
178     # . prolog
179     55/push-EBP
180     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
181     # var slice/ECX
182     68/push  _test-slice-data-3/imm32/end
183     68/push  _test-slice-data-0/imm32/start
184     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
185     # EAX = slice-equal?(ECX, "Abc")
186     # . . push args
187     68/push  "Abc"/imm32
188     51/push-ECX
189     # . . call
190     e8/call  slice-equal?/disp32
191     # . . discard args
192     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
193     # check-ints-equal(EAX, 1, msg)
194     # . . push args
195     68/push  "F - test-slice-equal"/imm32
196     68/push  1/imm32
197     50/push-EAX
198     # . . call
199     e8/call  check-ints-equal/disp32
200     # . . discard args
201     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
202     # . epilog
203     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
204     5d/pop-to-EBP
205     c3/return
206 
207 test-slice-equal-false:
208     # - slice-equal?(slice("bcd"), "Abc") == 0
209     # . prolog
210     55/push-EBP
211     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
212     # var slice/ECX
213     68/push  _test-slice-data-4/imm32/end
214     68/push  _test-slice-data-1/imm32/start
215     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
216     # EAX = slice-equal?(ECX, "Abc")
217     # . . push args
218     68/push  "Abc"/imm32
219     51/push-ECX
220     # . . call
221     e8/call  slice-equal?/disp32
222     # . . discard args
223     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
224     # check-ints-equal(EAX, 0, msg)
225     # . . push args
226     68/push  "F - test-slice-equal-false"/imm32
227     68/push  0/imm32
228     50/push-EAX
229     # . . call
230     e8/call  check-ints-equal/disp32
231     # . . discard args
232     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
233     # . epilog
234     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
235     5d/pop-to-EBP
236     c3/return
237 
238 test-slice-equal-too-long:
239     # - slice-equal?(slice("Abcd"), "Abc") == 0
240     # . prolog
241     55/push-EBP
242     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
243     # var slice/ECX
244     68/push  _test-slice-data-4/imm32/end
245     68/push  _test-slice-data-0/imm32/start
246     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
247     # EAX = slice-equal?(ECX, "Abc")
248     # . . push args
249     68/push  "Abc"/imm32
250     51/push-ECX
251     # . . call
252     e8/call  slice-equal?/disp32
253     # . . discard args
254     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
255     # check-ints-equal(EAX, 0, msg)
256     # . . push args
257     68/push  "F - test-slice-equal-too-long"/imm32
258     68/push  0/imm32
259     50/push-EAX
260     # . . call
261     e8/call  check-ints-equal/disp32
262     # . . discard args
263     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
264     # . epilog
265     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
266     5d/pop-to-EBP
267     c3/return
268 
269 test-slice-equal-too-short:
270     # - slice-equal?(slice("A"), "Abc") == 0
271     # . prolog
272     55/push-EBP
273     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
274     # var slice/ECX
275     68/push  _test-slice-data-1/imm32/end
276     68/push  _test-slice-data-0/imm32/start
277     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
278     # EAX = slice-equal?(ECX, "Abc")
279     # . . push args
280     68/push  "Abc"/imm32
281     51/push-ECX
282     # . . call
283     e8/call  slice-equal?/disp32
284     # . . discard args
285     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
286     # check-ints-equal(EAX, 0, msg)
287     # . . push args
288     68/push  "F - test-slice-equal-too-short"/imm32
289     68/push  0/imm32
290     50/push-EAX
291     # . . call
292     e8/call  check-ints-equal/disp32
293     # . . discard args
294     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
295     # . epilog
296     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
297     5d/pop-to-EBP
298     c3/return
299 
300 test-slice-equal-empty:
301     # - slice-equal?(slice(""), "Abc") == 0
302     # . prolog
303     55/push-EBP
304     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
305     # var slice/ECX
306     68/push  _test-slice-data-0/imm32/end
307     68/push  _test-slice-data-0/imm32/start
308     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
309     # EAX = slice-equal?(ECX, "Abc")
310     # . . push args
311     68/push  "Abc"/imm32
312     51/push-ECX
313     # . . call
314     e8/call  slice-equal?/disp32
315     # . . discard args
316     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
317     # check-ints-equal(EAX, 0, msg)
318     # . . push args
319     68/push  "F - test-slice-equal-empty"/imm32
320     68/push  0/imm32
321     50/push-EAX
322     # . . call
323     e8/call  check-ints-equal/disp32
324     # . . discard args
325     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
326     # . epilog
327     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
328     5d/pop-to-EBP
329     c3/return
330 
331 test-slice-equal-with-empty:
332     # - slice-equal?(slice("Ab"), "") == 0
333     # . prolog
334     55/push-EBP
335     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
336     # var slice/ECX
337     68/push  _test-slice-data-2/imm32/end
338     68/push  _test-slice-data-0/imm32/start
339     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
340     # EAX = slice-equal?(ECX, "")
341     # . . push args
342     68/push  ""/imm32
343     51/push-ECX
344     # . . call
345     e8/call  slice-equal?/disp32
346     # . . discard args
347     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
348     # check-ints-equal(EAX, 0, msg)
349     # . . push args
350     68/push  "F - test-slice-equal-with-empty"/imm32
351     68/push  0/imm32
352     50/push-EAX
353     # . . call
354     e8/call  check-ints-equal/disp32
355     # . . discard args
356     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
357     # . epilog
358     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
359     5d/pop-to-EBP
360     c3/return
361 
362 test-slice-equal-empty-with-empty:
363     # - slice-equal?(slice(""), "") == 1
364     # . prolog
365     55/push-EBP
366     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
367     # var slice/ECX
368     68/push  _test-slice-data-0/imm32/end
369     68/push  _test-slice-data-0/imm32/start
370     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
371     # EAX = slice-equal?(ECX, "")
372     # . . push args
373     68/push  ""/imm32
374     51/push-ECX
375     # . . call
376     e8/call  slice-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-slice-equal-empty-with-empty"/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 write-slice:  # out : (address buffered-file), s : (address slice)
394     # . prolog
395     55/push-EBP
396     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
397     # . save registers
398     50/push-EAX
399     51/push-ECX
400     52/push-EDX
401     53/push-EBX
402     56/push-ESI
403     57/push-EDI
404     # ESI = s
405     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   0xc/disp8       .                 # copy *(EBP+12) to ESI
406     # curr/ECX = s->start
407     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           1/r32/ECX   .               .                 # copy *ESI to ECX
408     # max/ESI = s->end
409     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           6/r32/ESI   4/disp8         .                 # copy *(ESI+4) to ESI
410     # EDI = f
411     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .                         7/r32/EDI   8/disp8         .                 # copy *(EBP+8) to EDI
412     # EDX = f->length
413     8b/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           2/r32/EDX   0xc/disp8       .                 # copy *(EDI+12) to EDX
414     # EBX = f->write
415     8b/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           3/r32/EBX   4/disp8         .                 # copy *(EDI+4) to EBX
416 $write-slice:loop:
417     # if (curr >= max) break
418     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           6/r32/ESI   .               .                 # compare ECX with ESI
419     7d/jump-if-greater-or-equal  $write-slice:loop-end/disp8
420     # if (f->write >= f->length) flush and clear f's stream
421     39/compare                      3/mod/direct    3/rm32/EBX    .           .             .           2/r32/EDX   .               .                 # compare EBX with EDX
422     7c/jump-if-lesser  $write-slice:to-stream/disp8
423     # . persist f->write
424     89/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           3/r32/EBX   4/disp8         .                 # copy EBX to *(EDI+4)
425     # . flush(f)
426     # . . push args
427     57/push-EDI
428     # . . call
429     e8/call  flush/disp32
430     # . . discard args
431     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
432     # . clear-stream(stream = f+4)
433     # . . push args
434     8d/copy-address                 1/mod/*+disp8   7/rm32/EDI    .           .             .           0/r32/EAX   4/disp8         .                 # copy EDI+4 to EAX
435     50/push-EAX
436     # . . call
437     e8/call  clear-stream/disp32
438     # . . discard args
439     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
440     # . f->write must now be 0; update its cache at EBX
441     31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
442 $write-slice:to-stream:
443     # f->data[f->write] = *in
444     # . AL = *in
445     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
446     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
447     # . f->data[f->write] = AL
448     88/copy-byte                    1/mod/*+disp8   4/rm32/sib    7/base/EDI  3/index/EBX   .           0/r32/AL    0x10/disp8      .                 # copy AL to *(EDI+EBX+16)
449     # ++f->write
450     43/increment-EBX
451     # ++in
452     41/increment-ECX
453     eb/jump  $write-slice:loop/disp8
454 $write-slice:loop-end:
455     # persist necessary variables from registers
456     89/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           3/r32/EBX   4/disp8         .                 # copy EBX to *(EDI+4)
457 $write-slice:end:
458     # . restore registers
459     5f/pop-to-EDI
460     5e/pop-to-ESI
461     5b/pop-to-EBX
462     5a/pop-to-EDX
463     59/pop-to-ECX
464     58/pop-to-EAX
465     # . epilog
466     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
467     5d/pop-to-EBP
468     c3/return
469 
470 test-write-slice:
471     # . prolog
472     55/push-EBP
473     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
474     # setup
475     # . clear-stream(_test-stream)
476     # . . push args
477     68/push  _test-stream/imm32
478     # . . call
479     e8/call  clear-stream/disp32
480     # . . discard args
481     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
482     # . clear-stream(_test-buffered-file+4)
483     # . . push args
484     b8/copy-to-EAX  _test-buffered-file/imm32
485     05/add-to-EAX  4/imm32
486     50/push-EAX
487     # . . call
488     e8/call  clear-stream/disp32
489     # . . discard args
490     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
491     # var slice/ECX = "Abc"
492     68/push  _test-slice-data-3/imm32/end
493     68/push  _test-slice-data-0/imm32/start
494     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
495     # write-slice(_test-buffered-file, slice)
496     # . . push args
497     51/push-ECX
498     68/push  _test-buffered-file/imm32
499     # . . call
500     e8/call  write-slice/disp32
501     # . . discard args
502     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
503     # flush(_test-buffered-file)
504     # . . push args
505     68/push  _test-buffered-file/imm32
506     # . . call
507     e8/call  flush/disp32
508     # . . discard args
509     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
510     # check-stream-equal(_test-stream, "Abc", msg)
511     # . . push args
512     68/push  "F - test-write-slice"/imm32
513     68/push  "Abc"/imm32
514     68/push  _test-stream/imm32
515     # . . call
516     e8/call  check-stream-equal/disp32
517     # . . discard args
518     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
519     # . epilog
520     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
521     5d/pop-to-EBP
522     c3/return
523 
524 # write an entire stream's contents to a buffered-file
525 # ways to do this:
526 #   - construct a 'maximal slice' and pass it to write-slice
527 #   - flush the buffered-file and pass the stream directly to its fd (disabling buffering)
528 # we'll go with the first way for now
529 write-stream-buffered:  # f : (address buffered-file), s : (address stream)
530     # . prolog
531     55/push-EBP
532     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
533     # . save registers
534     50/push-EAX
535     56/push-ESI
536     # ESI = s
537     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   0xc/disp8       .                 # copy *(EBP+12) to ESI
538     # var slice/ECX = {s->data, s->data + s->write}
539     # . push s->data + s->write
540     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy *ESI to EAX
541     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/ESI  0/index/EAX   .           0/r32/EAX   0xc/disp8       .                 # copy ESI+EAX+12 to EAX
542     50/push-EAX
543     # . push s->data
544     8d/copy-address                 1/mod/*+disp8   6/rm32/ESI    .           .             .           0/r32/EAX   0xc/disp8       .                 # copy ESI+12 to EAX
545     50/push-EAX
546     # . ECX = ESP
547     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
548     # write-slice(f, slice)
549     # . . push args
550     51/push-ECX
551     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
552     # . . call
553     e8/call  write-slice/disp32
554     # . . discard args
555     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
556 $write-stream-buffered:end:
557     # . restore registers
558     5e/pop-to-ESI
559     58/pop-to-EAX
560     # . epilog
561     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
562     5d/pop-to-EBP
563     c3/return
564 
565 test-write-stream-buffered:
566     # . prolog
567     55/push-EBP
568     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
569     # setup
570     # . clear-stream(_test-stream)
571     # . . push args
572     68/push  _test-stream/imm32
573     # . . call
574     e8/call  clear-stream/disp32
575     # . . discard args
576     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
577     # . clear-stream(_test-buffered-file+4)
578     # . . push args
579     b8/copy-to-EAX  _test-buffered-file/imm32
580     05/add-to-EAX  4/imm32
581     50/push-EAX
582     # . . call
583     e8/call  clear-stream/disp32
584     # . . discard args
585     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
586     # . clear-stream(_test-tmp-stream)
587     # . . push args
588     68/push  _test-tmp-stream/imm32
589     # . . call
590     e8/call  clear-stream/disp32
591     # . . discard args
592     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
593     # initialize input
594     # . write(_test-tmp-stream, "abcd")
595     # . . push args
596     68/push  "abcd"/imm32
597     68/push  _test-tmp-stream/imm32
598     # . . call
599     e8/call  write/disp32
600     # . . discard args
601     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
602     # perform the write-stream-buffered
603     # . write-stream-buffered(_test-buffered-file, _test-tmp-stream)
604     # . . push args
605     68/push  _test-tmp-stream/imm32
606     68/push  _test-buffered-file/imm32
607     # . . call
608     e8/call  write-stream-buffered/disp32
609     # . . discard args
610     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
611     # check that the write happened as expected
612     # . flush(_test-buffered-file)
613     # . . push args
614     68/push  _test-buffered-file/imm32
615     # . . call
616     e8/call  flush/disp32
617     # . . discard args
618     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
619     # . check-stream-equal(_test-stream, "abcd", msg)
620     # . . push args
621     68/push  "F - test-write-stream-buffered"/imm32
622     68/push  "abcd"/imm32
623     68/push  _test-stream/imm32
624     # . . call
625     e8/call  check-stream-equal/disp32
626     # . . discard args
627     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
628     # . epilog
629     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
630     5d/pop-to-EBP
631     c3/return
632 
633 == data
634 
635 _test-slice-data-0:
636     41/A
637 _test-slice-data-1:
638     62/b
639 _test-slice-data-2:
640     63/c
641 _test-slice-data-3:
642     64/d
643 _test-slice-data-4:
644 
645 # . _. vim:nowrap:textwidth=0