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