https://github.com/akkartik/mu/blob/main/123slice.subx

       1 # new data structure: a slice is an open interval of addresses [start, end)
       2 # that includes 'start' but not 'end'
       3
       4 == code
       5 #   instruction                     effective address                                                   register    displacement    immediate
       6 # . op          subop               mod             rm32          base        index         scale       r32
       7 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
       8
       9 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
      32
      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
      61
      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
      90
      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
     119
     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
     208
     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
     244
     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
     280
     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
     316
     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
     352
     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
     383
     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
     419
     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
     450
     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
     486
     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
     574
     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
     610
     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
     646
     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
     682
     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
     718
     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
     754
     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
     790
     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
     849
     850 $write-slice:abort:
     851     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "write-slice: out of space" 3 0)  # 3=cyan
     852     {
     853       eb/jump loop/disp8
     854     }
     855     # never gets here
     856
     857 test-write-slice:
     858     # . prologue
     859     55/push-ebp
     860     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
     861     # setup
     862     # . clear-stream(_test-stream)
     863     # . . push args
     864     68/push  _test-stream/imm32
     865     # . . call
     866     e8/call  clear-stream/disp32
     867     # . . discard args
     868     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
     869     # (eax..ecx) = "Abc"
     870     b8/copy-to-eax  "Abc"/imm32
     871     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
     872     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
     873     05/add-to-eax  4/imm32
     874     # var slice/ecx: slice = {eax, ecx}
     875     51/push-ecx
     876     50/push-eax
     877     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
     878     # write-slice(_test-stream, slice)
     879     # . . push args
     880     51/push-ecx
     881     68/push  _test-stream/imm32
     882     # . . call
     883     e8/call  write-slice/disp32
     884     # . . discard args
     885     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     886     # check-stream-equal(_test-stream, "Abc", msg)
     887     # . . push args
     888     68/push  "F - test-write-slice"/imm32
     889     68/push  "Abc"/imm32
     890     68/push  _test-stream/imm32
     891     # . . call
     892     e8/call  check-stream-equal/disp32
     893     # . . discard args
     894     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
     895     # . epilogue
     896     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
     897     5d/pop-to-ebp
     898     c3/return
     899
     900 # copy a slice into a new (dynamically allocated) string
     901 slice-to-string:  # ad: (addr allocation-descriptor), in: (addr slice), out: (addr handle array byte)
     902     # . prologue
     903     55/push-ebp
     904     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
     905     # . save registers
     906     50/push-eax
     907     51/push-ecx
     908     52/push-edx
     909     53/push-ebx
     910     56/push-esi
     911     # esi = in
     912     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
     913     # var curr/edx: (addr byte) = in->start
     914     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
     915     # var max/ebx: (addr byte) = in->end
     916     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           3/r32/ebx   4/disp8         .                 # copy *(esi+4) to ebx
     917     # var size/ecx: int = max - curr + 4  # total size of output string (including the initial 'size' field)
     918     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           3/r32/ebx   .               .                 # copy ebx to ecx
     919     29/subtract                     3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # subtract edx from ecx
     920     81          0/subop/add         3/mod/direct    1/rm32/ecx    .           .             .           .           .               4/imm32           # add to ecx
     921     # allocate(ad, size, out)
     922     # . . push args
     923     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
     924     51/push-ecx
     925     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
     926     # . . call
     927     e8/call  allocate/disp32
     928     # . . discard args
     929     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
     930     # eax = out->payload
     931     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0x10/disp8      .                 # copy *(ebp+16) to eax
     932     8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           0/r32/eax   4/disp8         .                 # copy *(eax+4) to eax
     933     # skip payload->allocid
     934     05/add-to-eax  4/imm32
     935     # if (eax == 0) abort
     936     3d/compare-eax-and  0/imm32
     937     74/jump-if-=  $slice-to-string:abort/disp8
     938     # out->size = size-4
     939     89/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy ecx to *eax
     940     81          5/subop/subtract    0/mod/indirect  0/rm32/eax    .           .             .           .           .               4/imm32           # subtract 4 from *eax
     941     # save out
     942     50/push-eax
     943 $slice-to-string:initialize:
     944     # eax = _append-4(eax+4, eax+size, curr, max)  # clobbering ecx
     945     # . . push args
     946     53/push-ebx
     947     52/push-edx
     948     # . . push eax+size (clobbering ecx)
     949     01/add                          3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # add eax to ecx
     950     51/push-ecx
     951     # . . push eax+4 (clobbering eax)
     952     81          0/subop/add         3/mod/direct    0/rm32/eax    .           .             .           .           .               4/imm32           # add to eax
     953     50/push-eax
     954     # . . call
     955     e8/call  _append-4/disp32
     956     # . . discard args
     957     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
     958     # restore out (assumes _append-4 can't error)
     959     58/pop-to-eax
     960 $slice-to-string:end:
     961     # . restore registers
     962     5e/pop-to-esi
     963     5b/pop-to-ebx
     964     5a/pop-to-edx
     965     59/pop-to-ecx
     966     58/pop-to-eax
     967     # . epilogue
     968     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
     969     5d/pop-to-ebp
     970     c3/return
     971
     972 $slice-to-string:abort:
     973     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "slice-to-string: out of space\n" 3 0)  # 3=cyan
     974     {
     975       eb/jump loop/disp8
     976     }
     977     # never gets here
     978
     979 test-slice-to-string:
     980     # . prologue
     981     55/push-ebp
     982     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
     983     # var ad/edx: allocation-descriptor containing 16 bytes
     984     # . var end/ecx: (addr byte)
     985     89/<- %ecx 4/r32/esp
     986     81 5/subop/subtract %esp 0x10/imm32
     987     # . var start/edx: (addr byte) = end - 0x10
     988     89/<- %edx 4/r32/esp
     989     # . ad = {start, end}
     990     51/push-ecx
     991     52/push-edx
     992     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
     993     # (eax..ecx) = "Abc"
     994     b8/copy-to-eax  "Abc"/imm32
     995     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
     996     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
     997     05/add-to-eax  4/imm32
     998     # var slice/ecx: slice = {eax, ecx}
     999     51/push-ecx
    1000     50/push-eax
    1001     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    1002     # var h/ebx: (handle array byte)
    1003     68/push  0/imm32
    1004     68/push  0/imm32
    1005     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           4/r32/esp   .               .                 # copy esp to ebx
    1006     # slice-to-string(ad, slice, h)
    1007     # . . push args
    1008     53/push-ebx
    1009     51/push-ecx
    1010     52/push-edx
    1011     # . . call
    1012     e8/call  slice-to-string/disp32
    1013     # . . discard args
    1014     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    1015     # eax = h->payload
    1016     8b/copy                         1/mod/*+disp8   3/rm32/ebx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(ebx+4) to eax
    1017     # skip payload->allocid
    1018     05/add-to-eax  4/imm32
    1019 +-- 26 lines: #?     # dump eax ---------------------------------------------------------------------------------------------------------------------------------------------------------
    1045     # eax = string-equal?(eax, "Abc")
    1046     # . . push args
    1047     68/push  "Abc"/imm32
    1048     50/push-eax
    1049     # . . call
    1050     e8/call  string-equal?/disp32
    1051     # . . discard args
    1052     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    1053     # check-ints-equal(eax, 1, msg)
    1054     # . . push args
    1055     68/push  "F - test-slice-to-string"/imm32
    1056     68/push  1/imm32/true
    1057     50/push-eax
    1058     # . . call
    1059     e8/call  check-ints-equal/disp32
    1060     # . . discard args
    1061     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    1062     # . reclaim locals
    1063     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x18/imm32        # add to esp
    1064     # . epilogue
    1065     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    1066     5d/pop-to-ebp
    1067     c3/return
    1068
    1069 # . . vim:nowrap:textwidth=0