https://github.com/akkartik/mu/blob/master/075array-equal.subx
  1 # Comparing arrays of numbers.
  2 
  3 == code
  4 #   instruction                     effective address                                                   register    displacement    immediate
  5 # . op          subop               mod             rm32          base        index         scale       r32
  6 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
  7 
  8 Entry:
  9     # initialize heap
 10     # . Heap = new-segment(64KB)
 11     # . . push args
 12     68/push  Heap/imm32
 13     68/push  0x10000/imm32/64KB
 14     # . . call
 15     e8/call  new-segment/disp32
 16     # . . discard args
 17     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 18 
 19     e8/call  run-tests/disp32  # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
 20 $array-equal-main:end:
 21     # syscall(exit, Num-test-failures)
 22     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/ebx   Num-test-failures/disp32          # copy *Num-test-failures to ebx
 23     b8/copy-to-eax  1/imm32/exit
 24     cd/syscall  0x80/imm8
 25 
 26 array-equal?:  # a : (address array int), b : (address array int) -> eax : boolean
 27     # pseudocode:
 28     #   lena = a->length
 29     #   if (lena != b->length) return false
 30     #   i = 0
 31     #   curra = a->data
 32     #   currb = b->data
 33     #   while i < lena
 34     #     i1 = *curra
 35     #     i2 = *currb
 36     #     if (c1 != c2) return false
 37     #     i+=4, curra+=4, currb+=4
 38     #   return true
 39     #
 40     # registers:
 41     #   i: ecx
 42     #   lena: edx
 43     #   curra: esi
 44     #   currb: edi
 45     #   i1: eax
 46     #   i2: ebx
 47     #
 48     # . prolog
 49     55/push-ebp
 50     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
 51     # . save registers
 52     51/push-ecx
 53     52/push-edx
 54     53/push-ebx
 55     56/push-esi
 56     57/push-edi
 57     # esi = a
 58     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
 59     # edi = b
 60     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
 61     # lena/edx = a->length
 62     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
 63 $array-equal?:lengths:
 64     # if (lena != b->length) return false
 65     39/compare                      0/mod/indirect  7/rm32/edi    .           .             .           2/r32/edx   .               .                 # compare *edi and edx
 66     75/jump-if-not-equal  $array-equal?:false/disp8
 67     # curra/esi = a->data
 68     81          0/subop/add         3/mod/direct    6/rm32/esi    .           .             .           .           .               4/imm32           # add to esi
 69     # currb/edi = b->data
 70     81          0/subop/add         3/mod/direct    7/rm32/edi    .           .             .           .           .               4/imm32           # add to edi
 71     # i/ecx = i1/eax = i2/ebx = 0
 72     31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
 73 $array-equal?:loop:
 74     # if (i >= lena) return true
 75     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
 76     7d/jump-if-greater-or-equal  $array-equal?:true/disp8
 77     # i1 = *curra
 78     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy *esi to eax
 79     # i2 = *currb
 80     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           3/r32/ebx   .               .                 # copy *edi to ebx
 81     # if (i1 != i2) return false
 82     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
 83     75/jump-if-not-equal  $array-equal?:false/disp8
 84     # i += 4
 85     81          0/subop/add         3/mod/direct    1/rm32/ecx    .           .             .           .           .               4/imm32           # add to ecx
 86     # currs += 4
 87     81          0/subop/add         3/mod/direct    6/rm32/esi    .           .             .           .           .               4/imm32           # add to esi
 88     # currb += 4
 89     81          0/subop/add         3/mod/direct    7/rm32/edi    .           .             .           .           .               4/imm32           # add to edi
 90     eb/jump  $array-equal?:loop/disp8
 91 $array-equal?:true:
 92     b8/copy-to-eax  1/imm32
 93     eb/jump  $array-equal?:end/disp8
 94 $array-equal?:false:
 95     b8/copy-to-eax  0/imm32
 96 $array-equal?:end:
 97     # . restore registers
 98     5f/pop-to-edi
 99     5e/pop-to-esi
100     5b/pop-to-ebx
101     5a/pop-to-edx
102     59/pop-to-ecx
103     # . epilog
104     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
105     5d/pop-to-ebp
106     c3/return
107 
108 test-compare-empty-with-empty-array:
109     # . prolog
110     55/push-ebp
111     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
112     # var ecx = []
113     68/push  0/imm32/size
114     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
115     # var edx = []
116     68/push  0/imm32/size
117     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
118     # eax = array-equal?(ecx, edx)
119     # . . push args
120     52/push-edx
121     51/push-ecx
122     # . . call
123     e8/call  array-equal?/disp32
124     # . . discard args
125     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
126     # check-ints-equal(eax, 1, msg)
127     # . . push args
128     68/push  "F - test-compare-empty-with-empty-array"/imm32
129     68/push  1/imm32/true
130     50/push-eax
131     # . . call
132     e8/call  check-ints-equal/disp32
133     # . . discard args
134     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
135     # . epilog
136     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
137     5d/pop-to-ebp
138     c3/return
139 
140 test-compare-empty-with-non-empty-array:  # also checks length-mismatch code path
141     # . prolog
142     55/push-ebp
143     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
144     # var ecx = [1]
145     68/push  1/imm32
146     68/push  4/imm32/size
147     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
148     # var edx = []
149     68/push  0/imm32/size
150     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
151     # eax = array-equal?(ecx, edx)
152     # . . push args
153     52/push-edx
154     51/push-ecx
155     # . . call
156     e8/call  array-equal?/disp32
157     # . . discard args
158     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
159     # check-ints-equal(eax, 0, msg)
160     # . . push args
161     68/push  "F - test-compare-empty-with-non-empty-array"/imm32
162     68/push  0/imm32/false
163     50/push-eax
164     # . . call
165     e8/call  check-ints-equal/disp32
166     # . . discard args
167     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
168     # . epilog
169     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
170     5d/pop-to-ebp
171     c3/return
172 
173 test-compare-equal-arrays:
174     # . prolog
175     55/push-ebp
176     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
177     # var ecx = [1, 2, 3]
178     68/push  3/imm32
179     68/push  2/imm32
180     68/push  1/imm32
181     68/push  0xc/imm32/size
182     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
183     # var edx = [1, 2, 3]
184     68/push  3/imm32
185     68/push  2/imm32
186     68/push  1/imm32
187     68/push  0xc/imm32/size
188     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
189     # eax = array-equal?(ecx, edx)
190     # . . push args
191     52/push-edx
192     51/push-ecx
193     # . . call
194     e8/call  array-equal?/disp32
195     # . . discard args
196     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
197     # check-ints-equal(eax, 1, msg)
198     # . . push args
199     68/push  "F - test-compare-equal-arrays"/imm32
200     68/push  1/imm32/true
201     50/push-eax
202     # . . call
203     e8/call  check-ints-equal/disp32
204     # . . discard args
205     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
206     # . epilog
207     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
208     5d/pop-to-ebp
209     c3/return
210 
211 test-compare-inequal-arrays-equal-lengths:
212     # . prolog
213     55/push-ebp
214     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
215     # var ecx = [1, 4, 3]
216     68/push  3/imm32
217     68/push  4/imm32
218     68/push  1/imm32
219     68/push  0xc/imm32/size
220     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
221     # var edx = [1, 2, 3]
222     68/push  3/imm32
223     68/push  2/imm32
224     68/push  1/imm32
225     68/push  0xc/imm32/size
226     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
227     # eax = array-equal?(ecx, edx)
228     # . . push args
229     52/push-edx
230     51/push-ecx
231     # . . call
232     e8/call  array-equal?/disp32
233     # . . discard args
234     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
235     # check-ints-equal(eax, 0, msg)
236     # . . push args
237     68/push  "F - test-compare-inequal-arrays-equal-lengths"/imm32
238     68/push  0/imm32/false
239     50/push-eax
240     # . . call
241     e8/call  check-ints-equal/disp32
242     # . . discard args
243     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
244     # . epilog
245     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
246     5d/pop-to-ebp
247     c3/return
248 
249 parse-array-of-ints:  # ad : (address allocation-descriptor), s : (address string) -> result/eax : (address array int)
250     # pseudocode
251     #   end = s->data + s->length
252     #   curr = s->data
253     #   size = 0
254     #   while true
255     #     if (curr >= end) break
256     #     curr = skip-chars-matching-in-slice(curr, end, ' ')
257     #     if (curr >= end) break
258     #     curr = skip-chars-not-matching-in-slice(curr, end, ' ')
259     #     ++size
260     #   result = allocate(ad, (size+1)*4)
261     #   result->size = (size+1)*4
262     #   var slice = {s->data, 0}
263     #   out = result->data
264     #   while true
265     #     if (slice->start >= end) break
266     #     slice->start = skip-chars-matching-in-slice(slice->start, end, ' ')
267     #     if (slice->start >= end) break
268     #     slice->end = skip-chars-not-matching-in-slice(slice->start, end, ' ')
269     #     *out = parse-hex-int(slice)
270     #     out += 4
271     #     slice->start = slice->end
272     #   return result
273     #
274     # . prolog
275     55/push-ebp
276     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
277     # . save registers
278     51/push-ecx
279     52/push-edx
280     53/push-ebx
281     56/push-esi
282     57/push-edi
283     # esi = s
284     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
285     # curr/ecx = s->data
286     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy esi+4 to ecx
287     # end/edx = s->data + s->length
288     # . edx = s->length
289     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
290     # . edx += curr
291     01/add                          3/mod/direct    2/rm32/edx    .           .             .           1/r32/ecx   .               .                 # add ecx to edx
292     # size/ebx = 0
293     31/xor                          3/mod/direct    3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # clear ebx
294 $parse-array-of-ints:loop1:
295     # if (curr >= end) break
296     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
297     73/jump-if-greater-or-equal-unsigned  $parse-array-of-ints:break1/disp8
298     # curr = skip-chars-matching-in-slice(curr, end, ' ')
299     # . eax = skip-chars-matching-in-slice(curr, end, ' ')
300     # . . push args
301     68/push  0x20/imm32/space
302     52/push-edx
303     51/push-ecx
304     # . . call
305     e8/call  skip-chars-matching-in-slice/disp32
306     # . . discard args
307     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
308     # . ecx = eax
309     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy eax to ecx
310     # if (curr >= end) break
311     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
312     73/jump-if-greater-or-equal-unsigned  $parse-array-of-ints:break1/disp8
313     # curr = skip-chars-not-matching-in-slice(curr, end, ' ')
314     # . eax = skip-chars-not-matching-in-slice(curr, end, ' ')
315     # . . push args
316     68/push  0x20/imm32/space
317     52/push-edx
318     51/push-ecx
319     # . . call
320     e8/call  skip-chars-not-matching-in-slice/disp32
321     # . . discard args
322     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
323     # . ecx = eax
324     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy eax to ecx
325     # size += 4
326     81          0/subop/add         3/mod/direct    3/rm32/ebx    .           .             .           .           .               4/imm32           # add to ebx
327     eb/jump  $parse-array-of-ints:loop1/disp8
328 $parse-array-of-ints:break1:
329     # result/edi = allocate(ad, size+4)
330     # . eax = allocate(ad, size+4)
331     # . . push args
332     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # copy ebx to eax
333     05/add-to-eax  4/imm32
334     50/push-eax
335     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
336     # . . call
337     e8/call  allocate/disp32
338     # . . discard args
339     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
340     # . edi = eax
341     89/copy                         3/mod/direct    7/rm32/edi    .           .             .           0/r32/eax   .               .                 # copy eax to edi
342     # result->size = size
343     89/copy                         0/mod/indirect  0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # copy ebx to *eax
344 $parse-array-of-ints:pass2:
345     # var slice/ecx = {s->data, 0}
346     # . push 0
347     68/push  0/imm32/end
348     # . push s->data
349     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy esi+4 to ecx
350     51/push-ecx
351     # . bookmark
352     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
353     # out/ebx = result->data
354     8d/copy-address                 1/mod/*+disp8   0/rm32/eax    .           .             .           3/r32/ebx   4/disp8         .                 # copy eax+4 to ebx
355 $parse-array-of-ints:loop2:
356     # if (slice->start >= end) break
357     39/compare                      0/mod/indirect  1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare *ecx with edx
358     73/jump-if-greater-or-equal-unsigned  $parse-array-of-ints:end/disp8
359     # slice->start = skip-chars-matching-in-slice(slice->start, end, ' ')
360     # . eax = skip-chars-matching-in-slice(slice->start, end, ' ')
361     # . . push args
362     68/push  0x20/imm32/space
363     52/push-edx
364     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
365     # . . call
366     e8/call  skip-chars-matching-in-slice/disp32
367     # . . discard args
368     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
369     # . slice->start = eax
370     89/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy eax to *ecx
371     # if (slice->start >= end) break
372     39/compare                      0/mod/indirect  1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare *ecx with edx
373     73/jump-if-greater-or-equal-unsigned  $parse-array-of-ints:end/disp8
374     # slice->end = skip-chars-not-matching-in-slice(slice->start, end, ' ')
375     # . eax = skip-chars-not-matching-in-slice(curr, end, ' ')
376     # . . push args
377     68/push  0x20/imm32/space
378     52/push-edx
379     50/push-eax
380     # . . call
381     e8/call  skip-chars-not-matching-in-slice/disp32
382     # . . discard args
383     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
384     # . slice->end = eax
385     89/copy                         1/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy eax to *(ecx+4)
386     # *out = parse-hex-int(slice)
387     # . eax = parse-hex-int(slice)
388     # . . push args
389     51/push-ecx
390     # . . call
391     e8/call  parse-hex-int/disp32
392     # . . discard args
393     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
394     # *out = eax
395     89/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to *ebx
396     # out += 4
397     81          0/subop/add         3/mod/direct    3/rm32/ebx    .           .             .           .           .               4/imm32           # add to ebx
398     # slice->start = slice->end
399     8b/copy                         1/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(ecx+4) to eax
400     89/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy eax to *ecx
401     81          0/subop/add         3/mod/direct    1/rm32/ecx    .           .             .           .           .               4/imm32           # add to ecx
402     eb/jump  $parse-array-of-ints:loop2/disp8
403 $parse-array-of-ints:end:
404     # return edi
405     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           7/r32/edi   .               .                 # copy edi to eax
406     # . reclaim locals
407     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
408     # . restore registers
409     5f/pop-to-edi
410     5e/pop-to-esi
411     5b/pop-to-ebx
412     5a/pop-to-edx
413     59/pop-to-ecx
414     # . epilog
415     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
416     5d/pop-to-ebp
417     c3/return
418 
419 test-parse-array-of-ints:
420     # . prolog
421     55/push-ebp
422     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
423     # var ecx = [1, 2, 3]
424     68/push  3/imm32
425     68/push  2/imm32
426     68/push  1/imm32
427     68/push  0xc/imm32/size
428     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
429     # eax = parse-array-of-ints(Heap, "1 2 3")
430     # . . push args
431     68/push  "1 2 3"/imm32
432     68/push  Heap/imm32
433     # . . call
434     e8/call  parse-array-of-ints/disp32
435     # . . discard args
436     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
437     # eax = array-equal?(ecx, eax)
438     # . . push args
439     50/push-eax
440     51/push-ecx
441     # . . call
442     e8/call  array-equal?/disp32
443     # . . discard args
444     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
445     # check-ints-equal(eax, 1, msg)
446     # . . push args
447     68/push  "F - test-parse-array-of-ints"/imm32
448     68/push  1/imm32/true
449     50/push-eax
450     # . . call
451     e8/call  check-ints-equal/disp32
452     # . . discard args
453     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
454     # . epilog
455     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
456     5d/pop-to-ebp
457     c3/return
458 
459 test-parse-array-of-ints-empty:
460     # - empty string = empty array
461     # . prolog
462     55/push-ebp
463     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
464     # eax = parse-array-of-ints(Heap, "")
465     # . . push args
466     68/push  ""/imm32
467     68/push  Heap/imm32
468     # . . call
469     e8/call  parse-array-of-ints/disp32
470     # . . discard args
471     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
472     # check-ints-equal(*eax, 0, msg)
473     # . . push args
474     68/push  "F - test-parse-array-of-ints-empty"/imm32
475     68/push  0/imm32/size
476     ff          6/subop/push        0/mod/indirect  0/rm32/eax    .           .             .           .           .               .                 # push *eax
477     # . . call
478     e8/call  check-ints-equal/disp32
479     # . . discard args
480     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
481     # . epilog
482     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
483     5d/pop-to-ebp
484     c3/return
485 
486 test-parse-array-of-ints-just-whitespace:
487     # - just whitespace = empty array
488     # . prolog
489     55/push-ebp
490     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
491     # eax = parse-array-of-ints(Heap, " ")
492     # . . push args
493     68/push  " "/imm32
494     68/push  Heap/imm32
495     # . . call
496     e8/call  parse-array-of-ints/disp32
497     # . . discard args
498     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
499     # check-ints-equal(*eax, 0, msg)
500     # . . push args
501     68/push  "F - test-parse-array-of-ints-empty"/imm32
502     68/push  0/imm32/size
503     ff          6/subop/push        0/mod/indirect  0/rm32/eax    .           .             .           .           .               .                 # push *eax
504     # . . call
505     e8/call  check-ints-equal/disp32
506     # . . discard args
507     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
508     # . epilog
509     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
510     5d/pop-to-ebp
511     c3/return
512 
513 test-parse-array-of-ints-extra-whitespace:
514     # . prolog
515     55/push-ebp
516     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
517     # var ecx = [1, 2, 3]
518     68/push  3/imm32
519     68/push  2/imm32
520     68/push  1/imm32
521     68/push  0xc/imm32/size
522     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
523     # eax = parse-array-of-ints(Heap, " 1 2  3  ")
524     # . . push args
525     68/push  " 1 2  3  "/imm32
526     68/push  Heap/imm32
527     # . . call
528     e8/call  parse-array-of-ints/disp32
529     # . . discard args
530     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
531     # eax = array-equal?(ecx, eax)
532     # . . push args
533     50/push-eax
534     51/push-ecx
535     # . . call
536     e8/call  array-equal?/disp32
537     # . . discard args
538     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
539     # check-ints-equal(eax, 1, msg)
540     # . . push args
541     68/push  "F - test-parse-array-of-ints-extra-whitespace"/imm32
542     68/push  1/imm32/true
543     50/push-eax
544     # . . call
545     e8/call  check-ints-equal/disp32
546     # . . discard args
547     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
548     # . epilog
549     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
550     5d/pop-to-ebp
551     c3/return
552 
553 # helper for later tests
554 # compare an array with a string representation of an array literal
555 check-array-equal:  # a : (address array int), expected : (address string), msg : (address string)
556     # . prolog
557     55/push-ebp
558     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
559     # . save registers
560     50/push-eax
561     # var b/ecx = parse-array-of-ints(Heap, expected)
562     # . eax = parse-array-of-ints(Heap, expected)
563     # . . push args
564     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
565     68/push  Heap/imm32
566     # . . call
567     e8/call  parse-array-of-ints/disp32
568     # . . discard args
569     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
570     # . b = eax
571     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy eax to ecx
572     # eax = array-equal?(a, b)
573     # . . push args
574     51/push-ecx
575     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
576     # . . call
577     e8/call  array-equal?/disp32
578     # . . discard args
579     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
580     # check-ints-equal(eax, 1, msg)
581     # . . push args
582     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
583     68/push  1/imm32
584     50/push-eax
585     # . . call
586     e8/call  check-ints-equal/disp32
587     # . . discard args
588     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
589 $check-array-equal:end:
590     # . restore registers
591     58/pop-to-eax
592     # . epilog
593     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
594     5d/pop-to-ebp
595     c3/return
596 
597 test-check-array-equal:
598     # . prolog
599     55/push-ebp
600     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
601     # var ecx = [1, 2, 3]
602     68/push  3/imm32
603     68/push  2/imm32
604     68/push  1/imm32
605     68/push  0xc/imm32/size
606     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
607     # check-array-equal(ecx, "1 2 3", "msg")
608     # . . push args
609     68/push  "F - test-check-array-equal"/imm32
610     68/push  "1 2 3"/imm32
611     51/push-ecx
612     # . . call
613     e8/call  check-array-equal/disp32
614     # . . discard args
615     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
616     # . epilog
617     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
618     5d/pop-to-ebp
619     c3/return
620 
621 == data
622 
623 Heap:
624   # curr
625   0/imm32
626   # limit
627   0/imm32
628 
629 # . . vim:nowrap:textwidth=0