make room for a task before fractional numbers
[mu.git] / linux / 123slice.subx
blobf23abc24aaa2627fb8f98ab1ddd7197d4c93bb18
1 # new data structure: a slice is an open interval of addresses [start, end)
2 # that includes 'start' but not 'end'
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
9 slice-empty?:  # s: (addr slice) -> result/eax: boolean
10     # . prologue
11     55/push-ebp
12     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
13     # . save registers
14     51/push-ecx
15     # ecx = s
16     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
17     # if (s->start >= s->end) return true
18     # . eax = s->start
19     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
20     # . if (eax >= s->end) return true
21     3b/compare                      1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # compare eax with *(ecx+4)
22     b8/copy-to-eax  1/imm32/true
23     73/jump-if-addr>=  $slice-empty?:end/disp8
24     b8/copy-to-eax  0/imm32/false
25 $slice-empty?:end:
26     # . restore registers
27     59/pop-to-ecx
28     # . epilogue
29     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
30     5d/pop-to-ebp
31     c3/return
33 test-slice-empty-true:
34     # . prologue
35     55/push-ebp
36     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
37     # var slice/ecx: slice = {34, 34}
38     68/push  34/imm32/end
39     68/push  34/imm32/start
40     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
41     # slice-empty?(slice)
42     # . . push args
43     51/push-ecx
44     # . . call
45     e8/call  slice-empty?/disp32
46     # . . discard args
47     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
48     # check-ints-equal(eax, 1, msg)
49     # . . push args
50     68/push  "F - test-slice-empty-true"/imm32
51     68/push  1/imm32
52     50/push-eax
53     # . . call
54     e8/call  check-ints-equal/disp32
55     # . . discard args
56     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
57     # . epilogue
58     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
59     5d/pop-to-ebp
60     c3/return
62 test-slice-empty-false:
63     # . prologue
64     55/push-ebp
65     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
66     # var slice/ecx: slice = {32, 34}
67     68/push  34/imm32/end
68     68/push  32/imm32/start
69     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
70     # slice-empty?(slice)
71     # . . push args
72     51/push-ecx
73     # . . call
74     e8/call  slice-empty?/disp32
75     # . . discard args
76     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
77     # check-ints-equal(eax, 0, msg)
78     # . . push args
79     68/push  "F - test-slice-empty-false"/imm32
80     68/push  0/imm32
81     50/push-eax
82     # . . call
83     e8/call  check-ints-equal/disp32
84     # . . discard args
85     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
86     # . epilogue
87     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
88     5d/pop-to-ebp
89     c3/return
91 test-slice-empty-if-start-greater-than-end:
92     # . prologue
93     55/push-ebp
94     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
95     # var slice/ecx: slice = {34, 32}
96     68/push  32/imm32/end
97     68/push  34/imm32/start
98     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
99     # slice-empty?(slice)
100     # . . push args
101     51/push-ecx
102     # . . call
103     e8/call  slice-empty?/disp32
104     # . . discard args
105     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
106     # check-ints-equal(eax, 1, msg)
107     # . . push args
108     68/push  "F - test-slice-empty-if-start-greater-than-end"/imm32
109     68/push  1/imm32
110     50/push-eax
111     # . . call
112     e8/call  check-ints-equal/disp32
113     # . . discard args
114     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
115     # . epilogue
116     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
117     5d/pop-to-ebp
118     c3/return
120 slice-equal?:  # s: (addr slice), p: (addr array byte) -> result/eax: boolean
121     # pseudocode:
122     #   if (p == 0) return (s == 0)
123     #   currs = s->start
124     #   maxs = s->end
125     #   if (maxs - currs != p->size) return false
126     #   currp = p->data
127     #   while currs < maxs
128     #     if (*currs != *currp) return false
129     #     ++currs
130     #     ++currp
131     #   return true
132     #
133     # registers:
134     #   currs: edx
135     #   maxs: esi
136     #   currp: ebx
137     #   *currs: eax
138     #   *currp: ecx
139     #
140     # . prologue
141     55/push-ebp
142     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
143     # . save registers
144     51/push-ecx
145     52/push-edx
146     53/push-ebx
147     56/push-esi
148     # esi = s
149     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
150     # var currs/edx: (addr byte) = s->start
151     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
152     # var maxs/esi: (addr byte) = s->end
153     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           6/r32/esi   4/disp8         .                 # copy *(esi+4) to esi
154     # var ssize/eax: int = maxs - currs
155     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           6/r32/esi   .               .                 # copy esi to eax
156     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           2/r32/edx   .               .                 # subtract edx from eax
157     # ebx = p
158     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           3/r32/ebx   0xc/disp8       .                 # copy *(ebp+12) to ebx
159     # if (p != 0) goto next check
160     81          7/subop/compare     3/mod/direct    3/rm32/ebx    .           .             .           .           .               0/imm32           # compare ebx
161     75/jump-if-!=  $slice-equal?:nonnull-string/disp8
162 $slice-equal?:null-string:
163     # return s->start == s->end
164     3d/compare-eax-and  0/imm32
165     74/jump-if-=  $slice-equal?:true/disp8
166     eb/jump  $slice-equal?:false/disp8
167 $slice-equal?:nonnull-string:
168     # if (ssize != p->size) return false
169     39/compare                      0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # compare *ebx and eax
170     75/jump-if-!=  $slice-equal?:false/disp8
171     # var currp/ebx: (addr byte) = p->data
172     81          0/subop/add         3/mod/direct    3/rm32/ebx    .           .             .           .           .               4/imm32           # add to ebx
173     # var c1/eax: byte = 0
174     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
175     # var c2/ecx: byte = 0
176     31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
177 $slice-equal?:loop:
178     # if (currs >= maxs) return true
179     39/compare                      3/mod/direct    2/rm32/edx    .           .             .           6/r32/esi   .               .                 # compare edx with esi
180     73/jump-if-addr>=  $slice-equal?:true/disp8
181     # c1 = *currp
182     8a/copy-byte                    0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/AL    .               .                 # copy byte at *ebx to AL
183     # c2 = *currs
184     8a/copy-byte                    0/mod/indirect  2/rm32/edx    .           .             .           1/r32/CL    .               .                 # copy byte at *edx to CL
185     # if (c1 != c2) return false
186     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # compare eax and ecx
187     75/jump-if-!=  $slice-equal?:false/disp8
188     # ++currp
189     43/increment-ebx
190     # ++currs
191     42/increment-edx
192     eb/jump $slice-equal?:loop/disp8
193 $slice-equal?:false:
194     b8/copy-to-eax  0/imm32
195     eb/jump  $slice-equal?:end/disp8
196 $slice-equal?:true:
197     b8/copy-to-eax  1/imm32
198 $slice-equal?:end:
199     # . restore registers
200     5e/pop-to-esi
201     5b/pop-to-ebx
202     5a/pop-to-edx
203     59/pop-to-ecx
204     # . epilogue
205     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
206     5d/pop-to-ebp
207     c3/return
209 test-slice-equal:
210     # - slice-equal?(slice("Abc"), "Abc") == 1
211     # . prologue
212     55/push-ebp
213     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
214     # (eax..ecx) = "Abc"
215     b8/copy-to-eax  "Abc"/imm32
216     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
217     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
218     05/add-to-eax  4/imm32
219     # var slice/ecx: slice = {eax, ecx}
220     51/push-ecx
221     50/push-eax
222     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
223     # eax = slice-equal?(ecx, "Abc")
224     # . . push args
225     68/push  "Abc"/imm32
226     51/push-ecx
227     # . . call
228     e8/call  slice-equal?/disp32
229     # . . discard args
230     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
231     # check-ints-equal(eax, 1, msg)
232     # . . push args
233     68/push  "F - test-slice-equal"/imm32
234     68/push  1/imm32
235     50/push-eax
236     # . . call
237     e8/call  check-ints-equal/disp32
238     # . . discard args
239     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
240     # . epilogue
241     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
242     5d/pop-to-ebp
243     c3/return
245 test-slice-equal-false:
246     # - slice-equal?(slice("bcd"), "Abc") == 0
247     # . prologue
248     55/push-ebp
249     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
250     # (eax..ecx) = "bcd"
251     b8/copy-to-eax  "bcd"/imm32
252     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
253     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
254     05/add-to-eax  4/imm32
255     # var slice/ecx: slice = {eax, ecx}
256     51/push-ecx
257     50/push-eax
258     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
259     # eax = slice-equal?(ecx, "Abc")
260     # . . push args
261     68/push  "Abc"/imm32
262     51/push-ecx
263     # . . call
264     e8/call  slice-equal?/disp32
265     # . . discard args
266     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
267     # check-ints-equal(eax, 0, msg)
268     # . . push args
269     68/push  "F - test-slice-equal-false"/imm32
270     68/push  0/imm32
271     50/push-eax
272     # . . call
273     e8/call  check-ints-equal/disp32
274     # . . discard args
275     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
276     # . epilogue
277     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
278     5d/pop-to-ebp
279     c3/return
281 test-slice-equal-too-long:
282     # - slice-equal?(slice("Abcd"), "Abc") == 0
283     # . prologue
284     55/push-ebp
285     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
286     # (eax..ecx) = "Abcd"
287     b8/copy-to-eax  "Abcd"/imm32
288     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
289     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
290     05/add-to-eax  4/imm32
291     # var slice/ecx: slice = {eax, ecx}
292     51/push-ecx
293     50/push-eax
294     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
295     # eax = slice-equal?(ecx, "Abc")
296     # . . push args
297     68/push  "Abc"/imm32
298     51/push-ecx
299     # . . call
300     e8/call  slice-equal?/disp32
301     # . . discard args
302     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
303     # check-ints-equal(eax, 0, msg)
304     # . . push args
305     68/push  "F - test-slice-equal-too-long"/imm32
306     68/push  0/imm32
307     50/push-eax
308     # . . call
309     e8/call  check-ints-equal/disp32
310     # . . discard args
311     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
312     # . epilogue
313     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
314     5d/pop-to-ebp
315     c3/return
317 test-slice-equal-too-short:
318     # - slice-equal?(slice("A"), "Abc") == 0
319     # . prologue
320     55/push-ebp
321     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
322     # (eax..ecx) = "A"
323     b8/copy-to-eax  "A"/imm32
324     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
325     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
326     05/add-to-eax  4/imm32
327     # var slice/ecx: slice = {eax, ecx}
328     51/push-ecx
329     50/push-eax
330     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
331     # eax = slice-equal?(ecx, "Abc")
332     # . . push args
333     68/push  "Abc"/imm32
334     51/push-ecx
335     # . . call
336     e8/call  slice-equal?/disp32
337     # . . discard args
338     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
339     # check-ints-equal(eax, 0, msg)
340     # . . push args
341     68/push  "F - test-slice-equal-too-short"/imm32
342     68/push  0/imm32
343     50/push-eax
344     # . . call
345     e8/call  check-ints-equal/disp32
346     # . . discard args
347     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
348     # . epilogue
349     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
350     5d/pop-to-ebp
351     c3/return
353 test-slice-equal-empty:
354     # - slice-equal?(slice(""), "Abc") == 0
355     # . prologue
356     55/push-ebp
357     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
358     # var slice/ecx: slice
359     68/push  0/imm32/end
360     68/push  0/imm32/start
361     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
362     # eax = slice-equal?(ecx, "Abc")
363     # . . push args
364     68/push  "Abc"/imm32
365     51/push-ecx
366     # . . call
367     e8/call  slice-equal?/disp32
368     # . . discard args
369     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
370     # check-ints-equal(eax, 0, msg)
371     # . . push args
372     68/push  "F - test-slice-equal-empty"/imm32
373     68/push  0/imm32
374     50/push-eax
375     # . . call
376     e8/call  check-ints-equal/disp32
377     # . . discard args
378     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
379     # . epilogue
380     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
381     5d/pop-to-ebp
382     c3/return
384 test-slice-equal-with-empty:
385     # - slice-equal?(slice("Ab"), "") == 0
386     # . prologue
387     55/push-ebp
388     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
389     # (eax..ecx) = "Ab"
390     b8/copy-to-eax  "Ab"/imm32
391     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
392     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
393     05/add-to-eax  4/imm32
394     # var slice/ecx: slice = {eax, ecx}
395     51/push-ecx
396     50/push-eax
397     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
398     # eax = slice-equal?(ecx, "")
399     # . . push args
400     68/push  ""/imm32
401     51/push-ecx
402     # . . call
403     e8/call  slice-equal?/disp32
404     # . . discard args
405     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
406     # check-ints-equal(eax, 0, msg)
407     # . . push args
408     68/push  "F - test-slice-equal-with-empty"/imm32
409     68/push  0/imm32
410     50/push-eax
411     # . . call
412     e8/call  check-ints-equal/disp32
413     # . . discard args
414     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
415     # . epilogue
416     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
417     5d/pop-to-ebp
418     c3/return
420 test-slice-equal-empty-with-empty:
421     # - slice-equal?(slice(""), "") == 1
422     # . prologue
423     55/push-ebp
424     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
425     # var slice/ecx: slice
426     68/push  0/imm32/end
427     68/push  0/imm32/start
428     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
429     # eax = slice-equal?(ecx, "")
430     # . . push args
431     68/push  ""/imm32
432     51/push-ecx
433     # . . call
434     e8/call  slice-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, 1, msg)
438     # . . push args
439     68/push  "F - test-slice-equal-empty-with-empty"/imm32
440     68/push  1/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     # . epilogue
447     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
448     5d/pop-to-ebp
449     c3/return
451 test-slice-equal-with-null:
452     # - slice-equal?(slice("Ab"), null) == 0
453     # . prologue
454     55/push-ebp
455     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
456     # (eax..ecx) = "Ab"
457     b8/copy-to-eax  "Ab"/imm32
458     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
459     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
460     05/add-to-eax  4/imm32
461     # var slice/ecx: slice = {eax, ecx}
462     51/push-ecx
463     50/push-eax
464     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
465     # eax = slice-equal?(ecx, 0)
466     # . . push args
467     68/push  0/imm32
468     51/push-ecx
469     # . . call
470     e8/call  slice-equal?/disp32
471     # . . discard args
472     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
473     # check-ints-equal(eax, 0, msg)
474     # . . push args
475     68/push  "F - test-slice-equal-with-null"/imm32
476     68/push  0/imm32
477     50/push-eax
478     # . . call
479     e8/call  check-ints-equal/disp32
480     # . . discard args
481     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
482     # . epilogue
483     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
484     5d/pop-to-ebp
485     c3/return
487 slice-starts-with?:  # s: (addr slice), head: (addr array byte) -> result/eax: boolean
488     # pseudocode
489     #   hsize = head->size
490     #   if (hsize > s->end - s->start) return false
491     #   i = 0
492     #   currs = s->start
493     #   currp = head->data
494     #   while i < hsize
495     #     if (*currs != *currh) return false
496     #     ++i
497     #     ++currs
498     #     ++currh
499     #   return true
500     #
501     # registers:
502     #   currs: esi
503     #   currh: edi
504     #   *currs: eax
505     #   *currh: ebx
506     #   i: ecx
507     #   hsize: edx
508     #
509     # . prologue
510     55/push-ebp
511     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
512     # . save registers
513     51/push-ecx
514     52/push-edx
515     53/push-ebx
516     56/push-esi
517     57/push-edi
518     # esi = s
519     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
520     # var lens/ecx: int = s->end - s->start
521     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(esi+4) to ecx
522     2b/subtract                     0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # subtract *esi from ecx
523     # edi = head
524     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
525     # var hsize/edx: int = head->size
526     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           2/r32/edx   .               .                 # copy *edi to edx
527     # if (hsize > lens) return false
528     39/compare                      3/mod/direct    2/rm32/edx    .           .             .           1/r32/ecx   .               .                 # compare edx with ecx
529     7f/jump-if->  $slice-starts-with?:false/disp8
530     # var currs/esi: (addr byte) = s->start
531     8b/subtract                     0/mod/indirect  6/rm32/esi    .           .             .           6/r32/esi   .               .                 # copy *esi to esi
532     # var currh/edi: (addr byte) = head->data
533     81          0/subop/add         3/mod/direct    7/rm32/edi    .           .             .           .           .               4/imm32           # add to edi
534     # var i/ecx: int = 0
535     31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
536     # var c1/eax: byte = 0
537     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
538     # var c2/ebx: byte = 0
539     31/xor                          3/mod/direct    3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # clear ebx
540 $slice-starts-with?:loop:
541     # if (i >= hsize) return true
542     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
543     7d/jump-if->=  $slice-starts-with?:true/disp8
544     # c1 = *currs
545     8a/copy-byte                    0/mod/indirect  6/rm32/esi    .           .             .           0/r32/AL    .               .                 # copy byte at *esi to AL
546     # c2 = *currh
547     8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .             .           3/r32/BL    .               .                 # copy byte at *edi to BL
548     # if (c1 != c2) return false
549     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
550     75/jump-if-!=  $slice-starts-with?:false/disp8
551     # ++i
552     41/increment-ecx
553     # ++currs
554     46/increment-esi
555     # ++currh
556     47/increment-edi
557     eb/jump $slice-starts-with?:loop/disp8
558 $slice-starts-with?:true:
559     b8/copy-to-eax  1/imm32
560     eb/jump  $slice-starts-with?:end/disp8
561 $slice-starts-with?:false:
562     b8/copy-to-eax  0/imm32
563 $slice-starts-with?:end:
564     # . restore registers
565     5f/pop-to-edi
566     5e/pop-to-esi
567     5b/pop-to-ebx
568     5a/pop-to-edx
569     59/pop-to-ecx
570     # . epilogue
571     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
572     5d/pop-to-ebp
573     c3/return
575 test-slice-starts-with-single-character:
576     # - slice-starts-with?(slice("Abc"), "A") == 1
577     # . prologue
578     55/push-ebp
579     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
580     # (eax..ecx) = "Abc"
581     b8/copy-to-eax  "Abc"/imm32
582     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
583     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
584     05/add-to-eax  4/imm32
585     # var slice/ecx: slice = {eax, ecx}
586     51/push-ecx
587     50/push-eax
588     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
589     # eax = slice-starts-with?(ecx, "A")
590     # . . push args
591     68/push  "A"/imm32
592     51/push-ecx
593     # . . call
594     e8/call  slice-starts-with?/disp32
595     # . . discard args
596     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
597     # check-ints-equal(eax, 1, msg)
598     # . . push args
599     68/push  "F - test-slice-starts-with-single-character"/imm32
600     68/push  1/imm32
601     50/push-eax
602     # . . call
603     e8/call  check-ints-equal/disp32
604     # . . discard args
605     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
606     # . epilogue
607     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
608     5d/pop-to-ebp
609     c3/return
611 test-slice-starts-with-empty-string:
612     # - slice-starts-with?(slice("Abc"), "") == 1
613     # . prologue
614     55/push-ebp
615     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
616     # (eax..ecx) = "Abc"
617     b8/copy-to-eax  "Abc"/imm32
618     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
619     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
620     05/add-to-eax  4/imm32
621     # var slice/ecx: slice = {eax, ecx}
622     51/push-ecx
623     50/push-eax
624     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
625     # eax = slice-starts-with?(ecx, "")
626     # . . push args
627     68/push  ""/imm32
628     51/push-ecx
629     # . . call
630     e8/call  slice-starts-with?/disp32
631     # . . discard args
632     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
633     # check-ints-equal(eax, 1, msg)
634     # . . push args
635     68/push  "F - test-slice-starts-with-empty-string"/imm32
636     68/push  1/imm32
637     50/push-eax
638     # . . call
639     e8/call  check-ints-equal/disp32
640     # . . discard args
641     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
642     # . epilogue
643     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
644     5d/pop-to-ebp
645     c3/return
647 test-slice-starts-with-multiple-characters:
648     # - slice-starts-with?(slice("Abc"), "Ab") == 1
649     # . prologue
650     55/push-ebp
651     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
652     # (eax..ecx) = "Abc"
653     b8/copy-to-eax  "Abc"/imm32
654     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
655     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
656     05/add-to-eax  4/imm32
657     # var slice/ecx: slice = {eax, ecx}
658     51/push-ecx
659     50/push-eax
660     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
661     # eax = slice-starts-with?(ecx, "Ab")
662     # . . push args
663     68/push  "Ab"/imm32
664     51/push-ecx
665     # . . call
666     e8/call  slice-starts-with?/disp32
667     # . . discard args
668     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
669     # check-ints-equal(eax, 1, msg)
670     # . . push args
671     68/push  "F - test-slice-starts-with-multiple-characters"/imm32
672     68/push  1/imm32
673     50/push-eax
674     # . . call
675     e8/call  check-ints-equal/disp32
676     # . . discard args
677     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
678     # . epilogue
679     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
680     5d/pop-to-ebp
681     c3/return
683 test-slice-starts-with-entire-string:
684     # - slice-starts-with?(slice("Abc"), "Abc") == 1
685     # . prologue
686     55/push-ebp
687     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
688     # (eax..ecx) = "Abc"
689     b8/copy-to-eax  "Abc"/imm32
690     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
691     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
692     05/add-to-eax  4/imm32
693     # var slice/ecx: slice = {eax, ecx}
694     51/push-ecx
695     50/push-eax
696     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
697     # eax = slice-starts-with?(ecx, "Abc")
698     # . . push args
699     68/push  "Abc"/imm32
700     51/push-ecx
701     # . . call
702     e8/call  slice-starts-with?/disp32
703     # . . discard args
704     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
705     # check-ints-equal(eax, 1, msg)
706     # . . push args
707     68/push  "F - test-slice-starts-with-entire-string"/imm32
708     68/push  1/imm32
709     50/push-eax
710     # . . call
711     e8/call  check-ints-equal/disp32
712     # . . discard args
713     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
714     # . epilogue
715     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
716     5d/pop-to-ebp
717     c3/return
719 test-slice-starts-with-fails:
720     # - slice-starts-with?(slice("Abc"), "Abd") == 1
721     # . prologue
722     55/push-ebp
723     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
724     # (eax..ecx) = "Abc"
725     b8/copy-to-eax  "Abc"/imm32
726     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
727     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
728     05/add-to-eax  4/imm32
729     # var slice/ecx: slice = {eax, ecx}
730     51/push-ecx
731     50/push-eax
732     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
733     # eax = slice-starts-with?(ecx, "Abd")
734     # . . push args
735     68/push  "Abd"/imm32
736     51/push-ecx
737     # . . call
738     e8/call  slice-starts-with?/disp32
739     # . . discard args
740     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
741     # check-ints-equal(eax, 0, msg)
742     # . . push args
743     68/push  "F - test-slice-starts-with-fails"/imm32
744     68/push  0/imm32
745     50/push-eax
746     # . . call
747     e8/call  check-ints-equal/disp32
748     # . . discard args
749     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
750     # . epilogue
751     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
752     5d/pop-to-ebp
753     c3/return
755 test-slice-starts-with-fails-2:
756     # - slice-starts-with?(slice("Abc"), "Ac") == 1
757     # . prologue
758     55/push-ebp
759     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
760     # (eax..ecx) = "Abc"
761     b8/copy-to-eax  "Abc"/imm32
762     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
763     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
764     05/add-to-eax  4/imm32
765     # var slice/ecx: slice = {eax, ecx}
766     51/push-ecx
767     50/push-eax
768     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
769     # eax = slice-starts-with?(ecx, "Ac")
770     # . . push args
771     68/push  "Ac"/imm32
772     51/push-ecx
773     # . . call
774     e8/call  slice-starts-with?/disp32
775     # . . discard args
776     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
777     # check-ints-equal(eax, 0, msg)
778     # . . push args
779     68/push  "F - test-slice-starts-with-fails-2"/imm32
780     68/push  0/imm32
781     50/push-eax
782     # . . call
783     e8/call  check-ints-equal/disp32
784     # . . discard args
785     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
786     # . epilogue
787     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
788     5d/pop-to-ebp
789     c3/return
791 # write a slice to a stream
792 # abort if the stream doesn't have enough space
793 write-slice:  # out: (addr stream byte), s: (addr slice)
794     # . prologue
795     55/push-ebp
796     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
797     # . save registers
798     50/push-eax
799     51/push-ecx
800     52/push-edx
801     53/push-ebx
802     56/push-esi
803     57/push-edi
804     # esi = s
805     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
806     # var curr/ecx: (addr byte) = s->start
807     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
808     # var max/esi: (addr byte) = s->end
809     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           6/r32/esi   4/disp8         .                 # copy *(esi+4) to esi
810     # edi = out
811     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
812     # edx = out->size
813     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           2/r32/edx   8/disp8         .                 # copy *(edi+8) to edx
814     # ebx = out->write
815     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           3/r32/ebx   .               .                 # copy *edi to ebx
816 $write-slice:loop:
817     # if (curr >= max) break
818     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           6/r32/esi   .               .                 # compare ecx with esi
819     73/jump-if-addr>=  $write-slice:loop-end/disp8
820     # if (out->write >= out->size) abort
821     39/compare                      3/mod/direct    3/rm32/ebx    .           .             .           2/r32/edx   .               .                 # compare ebx with edx
822     7d/jump-if->=  $write-slice:abort/disp8
823     # out->data[out->write] = *in
824     # . AL = *in
825     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
826     8a/copy-byte                    0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/AL    .               .                 # copy byte at *ecx to AL
827     # . out->data[out->write] = AL
828     88/copy-byte                    1/mod/*+disp8   4/rm32/sib    7/base/edi  3/index/ebx   .           0/r32/AL    0xc/disp8       .                 # copy AL to *(edi+ebx+12)
829     # ++out->write
830     43/increment-ebx
831     # ++in
832     41/increment-ecx
833     eb/jump  $write-slice:loop/disp8
834 $write-slice:loop-end:
835     # persist out->write
836     89/copy                         0/mod/indirect  7/rm32/edi    .           .             .           3/r32/ebx   .               .                 # copy ebx to *edi
837 $write-slice:end:
838     # . restore registers
839     5f/pop-to-edi
840     5e/pop-to-esi
841     5b/pop-to-ebx
842     5a/pop-to-edx
843     59/pop-to-ecx
844     58/pop-to-eax
845     # . epilogue
846     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
847     5d/pop-to-ebp
848     c3/return
850 $write-slice:abort:
851     # . _write(2/stderr, error)
852     # . . push args
853     68/push  "write-slice: out of space"/imm32
854     68/push  2/imm32/stderr
855     # . . call
856     e8/call  _write/disp32
857     # . . discard args
858     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
859     # . syscall_exit(1)
860     bb/copy-to-ebx  1/imm32
861     e8/call  syscall_exit/disp32
862     # never gets here
864 test-write-slice:
865     # . prologue
866     55/push-ebp
867     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
868     # setup
869     # . clear-stream(_test-stream)
870     # . . push args
871     68/push  _test-stream/imm32
872     # . . call
873     e8/call  clear-stream/disp32
874     # . . discard args
875     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
876     # (eax..ecx) = "Abc"
877     b8/copy-to-eax  "Abc"/imm32
878     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
879     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
880     05/add-to-eax  4/imm32
881     # var slice/ecx: slice = {eax, ecx}
882     51/push-ecx
883     50/push-eax
884     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
885     # write-slice(_test-stream, slice)
886     # . . push args
887     51/push-ecx
888     68/push  _test-stream/imm32
889     # . . call
890     e8/call  write-slice/disp32
891     # . . discard args
892     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
893     # check-stream-equal(_test-stream, "Abc", msg)
894     # . . push args
895     68/push  "F - test-write-slice"/imm32
896     68/push  "Abc"/imm32
897     68/push  _test-stream/imm32
898     # . . call
899     e8/call  check-stream-equal/disp32
900     # . . discard args
901     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
902     # . epilogue
903     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
904     5d/pop-to-ebp
905     c3/return
907 # write a slice to a buffered-file
908 write-slice-buffered:  # out: (addr buffered-file), s: (addr slice)
909     # . prologue
910     55/push-ebp
911     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
912     # . save registers
913     50/push-eax
914     51/push-ecx
915     52/push-edx
916     53/push-ebx
917     56/push-esi
918     57/push-edi
919     # esi = s
920     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
921     # var curr/ecx: (addr byte) = s->start
922     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
923     # var max/esi: (addr byte) = s->end
924     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           6/r32/esi   4/disp8         .                 # copy *(esi+4) to esi
925     # edi = out
926     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
927     # edx = out->size
928     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(edi+12) to edx
929     # ebx = out->write
930     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           3/r32/ebx   4/disp8         .                 # copy *(edi+4) to ebx
931 $write-slice-buffered:loop:
932     # if (curr >= max) break
933     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           6/r32/esi   .               .                 # compare ecx with esi
934     73/jump-if-addr>=  $write-slice-buffered:loop-end/disp8
935     # if (out->write >= out->size) flush and clear out's stream
936     39/compare                      3/mod/direct    3/rm32/ebx    .           .             .           2/r32/edx   .               .                 # compare ebx with edx
937     7c/jump-if-<  $write-slice-buffered:to-stream/disp8
938     # . persist out->write
939     89/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           3/r32/ebx   4/disp8         .                 # copy ebx to *(edi+4)
940     # . flush(out)
941     # . . push args
942     57/push-edi
943     # . . call
944     e8/call  flush/disp32
945     # . . discard args
946     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
947     # . clear-stream(stream = out+4)
948     # . . push args
949     8d/copy-address                 1/mod/*+disp8   7/rm32/edi    .           .             .           0/r32/eax   4/disp8         .                 # copy edi+4 to eax
950     50/push-eax
951     # . . call
952     e8/call  clear-stream/disp32
953     # . . discard args
954     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
955     # . out->write must now be 0; update its cache at ebx
956     31/xor                          3/mod/direct    3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # clear ebx
957 $write-slice-buffered:to-stream:
958     # out->data[out->write] = *in
959     # . AL = *in
960     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
961     8a/copy-byte                    0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/AL    .               .                 # copy byte at *ecx to AL
962     # . out->data[out->write] = AL
963     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)
964     # ++out->write
965     43/increment-ebx
966     # ++in
967     41/increment-ecx
968     eb/jump  $write-slice-buffered:loop/disp8
969 $write-slice-buffered:loop-end:
970     # persist necessary variables from registers
971     89/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           3/r32/ebx   4/disp8         .                 # copy ebx to *(edi+4)
972 $write-slice-buffered:end:
973     # . restore registers
974     5f/pop-to-edi
975     5e/pop-to-esi
976     5b/pop-to-ebx
977     5a/pop-to-edx
978     59/pop-to-ecx
979     58/pop-to-eax
980     # . epilogue
981     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
982     5d/pop-to-ebp
983     c3/return
985 test-write-slice-buffered:
986     # . prologue
987     55/push-ebp
988     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
989     # setup
990     # . clear-stream(_test-stream)
991     # . . push args
992     68/push  _test-stream/imm32
993     # . . call
994     e8/call  clear-stream/disp32
995     # . . discard args
996     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
997     # . clear-stream($_test-buffered-file->buffer)
998     # . . push args
999     68/push  $_test-buffered-file->buffer/imm32
1000     # . . call
1001     e8/call  clear-stream/disp32
1002     # . . discard args
1003     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1004     # (eax..ecx) = "Abc"
1005     b8/copy-to-eax  "Abc"/imm32
1006     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
1007     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
1008     05/add-to-eax  4/imm32
1009     # var slice/ecx: slice = {eax, ecx}
1010     51/push-ecx
1011     50/push-eax
1012     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
1013     # write-slice-buffered(_test-buffered-file, slice)
1014     # . . push args
1015     51/push-ecx
1016     68/push  _test-buffered-file/imm32
1017     # . . call
1018     e8/call  write-slice-buffered/disp32
1019     # . . discard args
1020     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1021     # flush(_test-buffered-file)
1022     # . . push args
1023     68/push  _test-buffered-file/imm32
1024     # . . call
1025     e8/call  flush/disp32
1026     # . . discard args
1027     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1028     # check-stream-equal(_test-stream, "Abc", msg)
1029     # . . push args
1030     68/push  "F - test-write-slice-buffered"/imm32
1031     68/push  "Abc"/imm32
1032     68/push  _test-stream/imm32
1033     # . . call
1034     e8/call  check-stream-equal/disp32
1035     # . . discard args
1036     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
1037     # . epilogue
1038     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
1039     5d/pop-to-ebp
1040     c3/return
1042 # copy a slice into a new (dynamically allocated) string
1043 slice-to-string:  # ad: (addr allocation-descriptor), in: (addr slice), out: (addr handle array byte)
1044     # . prologue
1045     55/push-ebp
1046     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
1047     # . save registers
1048     50/push-eax
1049     51/push-ecx
1050     52/push-edx
1051     53/push-ebx
1052     56/push-esi
1053     # esi = in
1054     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
1055     # var curr/edx: (addr byte) = in->start
1056     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
1057     # var max/ebx: (addr byte) = in->end
1058     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           3/r32/ebx   4/disp8         .                 # copy *(esi+4) to ebx
1059     # var size/ecx: int = max - curr + 4  # total size of output string (including the initial 'size' field)
1060     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           3/r32/ebx   .               .                 # copy ebx to ecx
1061     29/subtract                     3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # subtract edx from ecx
1062     81          0/subop/add         3/mod/direct    1/rm32/ecx    .           .             .           .           .               4/imm32           # add to ecx
1063     # allocate(ad, size, out)
1064     # . . push args
1065     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
1066     51/push-ecx
1067     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
1068     # . . call
1069     e8/call  allocate/disp32
1070     # . . discard args
1071     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
1072     # eax = out->payload
1073     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0x10/disp8      .                 # copy *(ebp+16) to eax
1074     8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           0/r32/eax   4/disp8         .                 # copy *(eax+4) to eax
1075     # skip payload->allocid
1076     05/add-to-eax  4/imm32
1077     # if (eax == 0) abort
1078     3d/compare-eax-and  0/imm32
1079     74/jump-if-=  $slice-to-string:abort/disp8
1080     # out->size = size-4
1081     89/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy ecx to *eax
1082     81          5/subop/subtract    0/mod/indirect  0/rm32/eax    .           .             .           .           .               4/imm32           # subtract 4 from *eax
1083     # save out
1084     50/push-eax
1085 $slice-to-string:initialize:
1086     # eax = _append-4(eax+4, eax+size, curr, max)  # clobbering ecx
1087     # . . push args
1088     53/push-ebx
1089     52/push-edx
1090     # . . push eax+size (clobbering ecx)
1091     01/add                          3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # add eax to ecx
1092     51/push-ecx
1093     # . . push eax+4 (clobbering eax)
1094     81          0/subop/add         3/mod/direct    0/rm32/eax    .           .             .           .           .               4/imm32           # add to eax
1095     50/push-eax
1096     # . . call
1097     e8/call  _append-4/disp32
1098     # . . discard args
1099     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
1100     # restore out (assumes _append-4 can't error)
1101     58/pop-to-eax
1102 $slice-to-string:end:
1103     # . restore registers
1104     5e/pop-to-esi
1105     5b/pop-to-ebx
1106     5a/pop-to-edx
1107     59/pop-to-ecx
1108     58/pop-to-eax
1109     # . epilogue
1110     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
1111     5d/pop-to-ebp
1112     c3/return
1114 $slice-to-string:abort:
1115     # . _write(2/stderr, error)
1116     # . . push args
1117     68/push  "slice-to-string: out of space\n"/imm32
1118     68/push  2/imm32/stderr
1119     # . . call
1120     e8/call  _write/disp32
1121     # . . discard args
1122     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1123     # . syscall_exit(1)
1124     bb/copy-to-ebx  1/imm32
1125     e8/call  syscall_exit/disp32
1126     # never gets here
1128 test-slice-to-string:
1129     # . prologue
1130     55/push-ebp
1131     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
1132     # var heap/edx: allocation-descriptor
1133     68/push  0/imm32/limit
1134     68/push  0/imm32/curr
1135     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
1136     # heap = new-segment(512)
1137     # . . push args
1138     52/push-edx
1139     68/push  0x200/imm32
1140     # . . call
1141     e8/call  new-segment/disp32
1142     # . . discard args
1143     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1144     # (eax..ecx) = "Abc"
1145     b8/copy-to-eax  "Abc"/imm32
1146     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
1147     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
1148     05/add-to-eax  4/imm32
1149     # var slice/ecx: slice = {eax, ecx}
1150     51/push-ecx
1151     50/push-eax
1152     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
1153     # var h/ebx: (handle array byte)
1154     68/push  0/imm32
1155     68/push  0/imm32
1156     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           4/r32/esp   .               .                 # copy esp to ebx
1157     # slice-to-string(heap, slice, h)
1158     # . . push args
1159     53/push-ebx
1160     51/push-ecx
1161     52/push-edx
1162     # . . call
1163     e8/call  slice-to-string/disp32
1164     # . . discard args
1165     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
1166     # eax = h->payload
1167     8b/copy                         1/mod/*+disp8   3/rm32/ebx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(ebx+4) to eax
1168     # skip payload->allocid
1169     05/add-to-eax  4/imm32
1170 #?     # dump eax {{{
1171 #?     # . write(2/stderr, "AA: ")
1172 #?     # . . push args
1173 #?     68/push  "AA: "/imm32
1174 #?     68/push  2/imm32/stderr
1175 #?     # . . call
1176 #?     e8/call  write/disp32
1177 #?     # . . discard args
1178 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1179 #?     # . write(2/stderr, eax)
1180 #?     # . . push args
1181 #?     50/push-eax
1182 #?     68/push  2/imm32/stderr
1183 #?     # . . call
1184 #?     e8/call  write/disp32
1185 #?     # . . discard args
1186 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1187 #?     # . write(2/stderr, "$\n")
1188 #?     # . . push args
1189 #?     68/push  "$\n"/imm32
1190 #?     68/push  2/imm32/stderr
1191 #?     # . . call
1192 #?     e8/call  write/disp32
1193 #?     # . . discard args
1194 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1195 #?     # }}}
1196     # eax = string-equal?(eax, "Abc")
1197     # . . push args
1198     68/push  "Abc"/imm32
1199     50/push-eax
1200     # . . call
1201     e8/call  string-equal?/disp32
1202     # . . discard args
1203     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1204     # check-ints-equal(eax, 1, msg)
1205     # . . push args
1206     68/push  "F - test-slice-to-string"/imm32
1207     68/push  1/imm32/true
1208     50/push-eax
1209     # . . call
1210     e8/call  check-ints-equal/disp32
1211     # . . discard args
1212     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
1213     # . reclaim locals
1214     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x18/imm32        # add to esp
1215     # . epilogue
1216     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
1217     5d/pop-to-ebp
1218     c3/return
1220 # . . vim:nowrap:textwidth=0