https://github.com/akkartik/mu/blob/master/subx/072slice.subx

      1 # new data structure: a slice is an open interval of addresses [start, end)
      2 # that includes 'start' but not 'end'
      3
      4 == code
      5 #   instruction                     effective address                                                   register    displacement    immediate
      6 # . op          subop               mod             rm32          base        index         scale       r32
      7 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
      8
      9 #? Entry:  # run a single test, while debugging
     10 #?     e8/call test-slice-to-string/disp32
     11 #?     # syscall(exit, Num-test-failures)
     12 #?     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/EBX   Num-test-failures/disp32          # copy *Num-test-failures to EBX
     13 #?     b8/copy-to-EAX  1/imm32/exit
     14 #?     cd/syscall  0x80/imm8
     15
     16 slice-empty?:  # s : (address slice) -> EAX : boolean
     17     # . prolog
     18     55/push-EBP
     19     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
     20     # . save registers
     21     51/push-ECX
     22     # ECX = s
     23     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   8/disp8         .                 # copy *(EBP+8) to ECX
     24     # if (s->start == s->end) return true
     25     # . EAX = s->start
     26     8b/copy                         0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # copy *ECX to EAX
     27     # . compare EAX and s->end
     28     39/compare                      1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # compare EAX and *(ECX+4)
     29     b8/copy-to-EAX  1/imm32/true
     30     74/jump-if-equal  $slice-empty?:end/disp8
     31     b8/copy-to-EAX  0/imm32/false
     32 $slice-empty?:end:
     33     # . restore registers
     34     59/pop-to-ECX
     35     # . epilog
     36     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
     37     5d/pop-to-EBP
     38     c3/return
     39
     40 test-slice-empty-true:
     41     # . prolog
     42     55/push-EBP
     43     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
     44     # var slice/ECX = {34, 34}
     45     68/push  34/imm32/end
     46     68/push  34/imm32/start
     47     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
     48     # slice-empty?(slice)
     49     # . . push args
     50     51/push-ECX
     51     # . . call
     52     e8/call  slice-empty?/disp32
     53     # . . discard args
     54     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
     55     # check-ints-equal(EAX, 1, msg)
     56     # . . push args
     57     68/push  "F - test-slice-empty-true"/imm32
     58     68/push  1/imm32
     59     50/push-EAX
     60     # . . call
     61     e8/call  check-ints-equal/disp32
     62     # . . discard args
     63     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
     64     # . epilog
     65     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
     66     5d/pop-to-EBP
     67     c3/return
     68
     69 test-slice-empty-false:
     70     # . prolog
     71     55/push-EBP
     72     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
     73     # var slice/ECX = {34, 23}
     74     68/push  23/imm32/end
     75     68/push  34/imm32/start
     76     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
     77     # slice-empty?(slice)
     78     # . . push args
     79     51/push-ECX
     80     # . . call
     81     e8/call  slice-empty?/disp32
     82     # . . discard args
     83     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
     84     # check-ints-equal(EAX, 0, msg)
     85     # . . push args
     86     68/push  "F - test-slice-empty-false"/imm32
     87     68/push  0/imm32
     88     50/push-EAX
     89     # . . call
     90     e8/call  check-ints-equal/disp32
     91     # . . discard args
     92     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
     93     # . epilog
     94     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
     95     5d/pop-to-EBP
     96     c3/return
     97
     98 slice-equal?:  # s : (address slice), p : (address string) -> EAX : boolean
     99     # pseudocode:
    100     #   if (p == 0) return (s == 0)
    101     #   currs = s->start
    102     #   maxs = s->end
    103     #   if (maxs - currs != p->length) return false
    104     #   currp = p->data
    105     #   while currs < maxs
    106     #     if (*currs != *currp) return false
    107     #     ++currs
    108     #     ++currp
    109     #   return true
    110     #
    111     # registers:
    112     #   currs: EDX
    113     #   maxs: ESI
    114     #   currp: EBX
    115     #   *currs: EAX
    116     #   *currp: ECX
    117     #
    118     # . prolog
    119     55/push-EBP
    120     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    121     # . save registers
    122     51/push-ECX
    123     52/push-EDX
    124     53/push-EBX
    125     56/push-ESI
    126     # ESI = s
    127     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
    128     # currs/EDX = s->start
    129     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           2/r32/EDX   .               .                 # copy *ESI to EDX
    130     # maxs/ESI = s->end
    131     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           6/r32/ESI   4/disp8         .                 # copy *(ESI+4) to ESI
    132     # EAX = maxs - currs
    133     89/copy                         3/mod/direct    0/rm32/EAX    .           .             .           6/r32/ESI   .               .                 # copy ESI to EAX
    134     29/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           2/r32/EDX   .               .                 # subtract EDX from EAX
    135     # EBX = p
    136     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           3/r32/EBX   0xc/disp8       .                 # copy *(EBP+12) to EBX
    137     # if (p != 0) goto next check
    138     81          7/subop/compare     3/mod/direct    3/rm32/EBX    .           .             .           .           .               0/imm32           # compare EBX
    139     75/jump-if-not-equal  $slice-equal?:nonnull-string/disp8
    140 $slice-equal?:null-string:
    141     # return s->start == s->end
    142     3d/compare-EAX-and  0/imm32
    143     74/jump-if-equal  $slice-equal?:true/disp8
    144     eb/jump  $slice-equal?:false/disp8
    145 $slice-equal?:nonnull-string:
    146     # if (EAX != p->length) return false
    147     39/compare                      0/mod/indirect  3/rm32/EBX    .           .             .           0/r32/EAX   .               .                 # compare *EBX and EAX
    148     75/jump-if-not-equal  $slice-equal?:false/disp8
    149     # currp/EBX = p->data
    150     81          0/subop/add         3/mod/direct    3/rm32/EBX    .           .             .           .           .               4/imm32           # add to EBX
    151     # EAX = ECX = 0
    152     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
    153     31/xor                          3/mod/direct    1/rm32/ECX    .           .             .           1/r32/ECX   .               .                 # clear ECX
    154 $slice-equal?:loop:
    155     # if (currs >= maxs) return true
    156     39/compare                      3/mod/direct    2/rm32/EDX    .           .             .           6/r32/ESI   .               .                 # compare EDX with ESI
    157     7d/jump-if-greater-or-equal  $slice-equal?:true/disp8
    158     # AL = *currp
    159     8a/copy-byte                    0/mod/indirect  3/rm32/EBX    .           .             .           0/r32/AL    .               .                 # copy byte at *EBX to AL
    160     # CL = *currs
    161     8a/copy-byte                    0/mod/indirect  2/rm32/EDX    .           .             .           1/r32/CL    .               .                 # copy byte at *EDX to CL
    162     # if (EAX != ECX) return false
    163     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # compare EAX and ECX
    164     75/jump-if-not-equal  $slice-equal?:false/disp8
    165     # ++currp
    166     43/increment-EBX
    167     # ++currs
    168     42/increment-EDX
    169     eb/jump $slice-equal?:loop/disp8
    170 $slice-equal?:false:
    171     b8/copy-to-EAX  0/imm32
    172     eb/jump  $slice-equal?:end/disp8
    173 $slice-equal?:true:
    174     b8/copy-to-EAX  1/imm32
    175 $slice-equal?:end:
    176     # . restore registers
    177     5e/pop-to-ESI
    178     5b/pop-to-EBX
    179     5a/pop-to-EDX
    180     59/pop-to-ECX
    181     # . epilog
    182     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    183     5d/pop-to-EBP
    184     c3/return
    185
    186 test-slice-equal:
    187     # - slice-equal?(slice("Abc"), "Abc") == 1
    188     # . prolog
    189     55/push-EBP
    190     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    191     # var slice/ECX
    192     68/push  _test-slice-data-3/imm32/end
    193     68/push  _test-slice-data-0/imm32/start
    194     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
    195     # EAX = slice-equal?(ECX, "Abc")
    196     # . . push args
    197     68/push  "Abc"/imm32
    198     51/push-ECX
    199     # . . call
    200     e8/call  slice-equal?/disp32
    201     # . . discard args
    202     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    203     # check-ints-equal(EAX, 1, msg)
    204     # . . push args
    205     68/push  "F - test-slice-equal"/imm32
    206     68/push  1/imm32
    207     50/push-EAX
    208     # . . call
    209     e8/call  check-ints-equal/disp32
    210     # . . discard args
    211     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
    212     # . epilog
    213     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    214     5d/pop-to-EBP
    215     c3/return
    216
    217 test-slice-equal-false:
    218     # - slice-equal?(slice("bcd"), "Abc") == 0
    219     # . prolog
    220     55/push-EBP
    221     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    222     # var slice/ECX
    223     68/push  _test-slice-data-4/imm32/end
    224     68/push  _test-slice-data-1/imm32/start
    225     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
    226     # EAX = slice-equal?(ECX, "Abc")
    227     # . . push args
    228     68/push  "Abc"/imm32
    229     51/push-ECX
    230     # . . call
    231     e8/call  slice-equal?/disp32
    232     # . . discard args
    233     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    234     # check-ints-equal(EAX, 0, msg)
    235     # . . push args
    236     68/push  "F - test-slice-equal-false"/imm32
    237     68/push  0/imm32
    238     50/push-EAX
    239     # . . call
    240     e8/call  check-ints-equal/disp32
    241     # . . discard args
    242     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
    243     # . epilog
    244     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    245     5d/pop-to-EBP
    246     c3/return
    247
    248 test-slice-equal-too-long:
    249     # - slice-equal?(slice("Abcd"), "Abc") == 0
    250     # . prolog
    251     55/push-EBP
    252     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    253     # var slice/ECX
    254     68/push  _test-slice-data-4/imm32/end
    255     68/push  _test-slice-data-0/imm32/start
    256     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
    257     # EAX = slice-equal?(ECX, "Abc")
    258     # . . push args
    259     68/push  "Abc"/imm32
    260     51/push-ECX
    261     # . . call
    262     e8/call  slice-equal?/disp32
    263     # . . discard args
    264     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    265     # check-ints-equal(EAX, 0, msg)
    266     # . . push args
    267     68/push  "F - test-slice-equal-too-long"/imm32
    268     68/push  0/imm32
    269     50/push-EAX
    270     # . . call
    271     e8/call  check-ints-equal/disp32
    272     # . . discard args
    273     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
    274     # . epilog
    275     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    276     5d/pop-to-EBP
    277     c3/return
    278
    279 test-slice-equal-too-short:
    280     # - slice-equal?(slice("A"), "Abc") == 0
    281     # . prolog
    282     55/push-EBP
    283     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    284     # var slice/ECX
    285     68/push  _test-slice-data-1/imm32/end
    286     68/push  _test-slice-data-0/imm32/start
    287     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
    288     # EAX = slice-equal?(ECX, "Abc")
    289     # . . push args
    290     68/push  "Abc"/imm32
    291     51/push-ECX
    292     # . . call
    293     e8/call  slice-equal?/disp32
    294     # . . discard args
    295     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    296     # check-ints-equal(EAX, 0, msg)
    297     # . . push args
    298     68/push  "F - test-slice-equal-too-short"/imm32
    299     68/push  0/imm32
    300     50/push-EAX
    301     # . . call
    302     e8/call  check-ints-equal/disp32
    303     # . . discard args
    304     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
    305     # . epilog
    306     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    307     5d/pop-to-EBP
    308     c3/return
    309
    310 test-slice-equal-empty:
    311     # - slice-equal?(slice(""), "Abc") == 0
    312     # . prolog
    313     55/push-EBP
    314     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    315     # var slice/ECX
    316     68/push  _test-slice-data-0/imm32/end
    317     68/push  _test-slice-data-0/imm32/start
    318     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
    319     # EAX = slice-equal?(ECX, "Abc")
    320     # . . push args
    321     68/push  "Abc"/imm32
    322     51/push-ECX
    323     # . . call
    324     e8/call  slice-equal?/disp32
    325     # . . discard args
    326     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    327     # check-ints-equal(EAX, 0, msg)
    328     # . . push args
    329     68/push  "F - test-slice-equal-empty"/imm32
    330     68/push  0/imm32
    331     50/push-EAX
    332     # . . call
    333     e8/call  check-ints-equal/disp32
    334     # . . discard args
    335     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
    336     # . epilog
    337     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    338     5d/pop-to-EBP
    339     c3/return
    340
    341 test-slice-equal-with-empty:
    342     # - slice-equal?(slice("Ab"), "") == 0
    343     # . prolog
    344     55/push-EBP
    345     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    346     # var slice/ECX
    347     68/push  _test-slice-data-2/imm32/end
    348     68/push  _test-slice-data-0/imm32/start
    349     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
    350     # EAX = slice-equal?(ECX, "")
    351     # . . push args
    352     68/push  ""/imm32
    353     51/push-ECX
    354     # . . call
    355     e8/call  slice-equal?/disp32
    356     # . . discard args
    357     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    358     # check-ints-equal(EAX, 0, msg)
    359     # . . push args
    360     68/push  "F - test-slice-equal-with-empty"/imm32
    361     68/push  0/imm32
    362     50/push-EAX
    363     # . . call
    364     e8/call  check-ints-equal/disp32
    365     # . . discard args
    366     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
    367     # . epilog
    368     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    369     5d/pop-to-EBP
    370     c3/return
    371
    372 test-slice-equal-empty-with-empty:
    373     # - slice-equal?(slice(""), "") == 1
    374     # . prolog
    375     55/push-EBP
    376     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    377     # var slice/ECX
    378     68/push  _test-slice-data-0/imm32/end
    379     68/push  _test-slice-data-0/imm32/start
    380     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
    381     # EAX = slice-equal?(ECX, "")
    382     # . . push args
    383     68/push  ""/imm32
    384     51/push-ECX
    385     # . . call
    386     e8/call  slice-equal?/disp32
    387     # . . discard args
    388     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    389     # check-ints-equal(EAX, 1, msg)
    390     # . . push args
    391     68/push  "F - test-slice-equal-empty-with-empty"/imm32
    392     68/push  1/imm32
    393     50/push-EAX
    394     # . . call
    395     e8/call  check-ints-equal/disp32
    396     # . . discard args
    397     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
    398     # . epilog
    399     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    400     5d/pop-to-EBP
    401     c3/return
    402
    403 test-slice-equal-with-null:
    404     # - slice-equal?(slice("Ab"), null) == 0
    405     # . prolog
    406     55/push-EBP
    407     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    408     # var slice/ECX
    409     68/push  _test-slice-data-2/imm32/end
    410     68/push  _test-slice-data-0/imm32/start
    411     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
    412     # EAX = slice-equal?(ECX, 0)
    413     # . . push args
    414     68/push  0/imm32
    415     51/push-ECX
    416     # . . call
    417     e8/call  slice-equal?/disp32
    418     # . . discard args
    419     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    420     # check-ints-equal(EAX, 0, msg)
    421     # . . push args
    422     68/push  "F - test-slice-equal-with-null"/imm32
    423     68/push  0/imm32
    424     50/push-EAX
    425     # . . call
    426     e8/call  check-ints-equal/disp32
    427     # . . discard args
    428     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
    429     # . epilog
    430     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    431     5d/pop-to-EBP
    432     c3/return
    433
    434 slice-starts-with?:  # s : (address slice), head : (address string) -> EAX : boolean
    435     # pseudocode
    436     #   lenh = head->length
    437     #   if (lenh > s->end - s->start) return false
    438     #   i = 0
    439     #   currs = s->start
    440     #   currp = head->data
    441     #   while i < lenh
    442     #     if (*currs != *currh) return false
    443     #     ++i
    444     #     ++currs
    445     #     ++currh
    446     #   return true
    447     #
    448     # registers:
    449     #   currs: ESI
    450     #   currh: EDI
    451     #   *currs: EAX
    452     #   *currh: EBX
    453     #   i: ECX
    454     #   lenh: EDX
    455     #
    456     # . prolog
    457     55/push-EBP
    458     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    459     # . save registers
    460     51/push-ECX
    461     52/push-EDX
    462     53/push-EBX
    463     56/push-ESI
    464     57/push-EDI
    465     # ESI = s
    466     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
    467     # ECX = s->end - s->start
    468     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
    469     2b/subtract                     0/mod/indirect  6/rm32/ESI    .           .             .           1/r32/ECX   .               .                 # subtract *ESI from ECX
    470     # EDI = head
    471     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           7/r32/EDI   0xc/disp8       .                 # copy *(EBP+12) to EDI
    472     # lenh/EDX = head->length
    473     8b/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           2/r32/EDX   .               .                 # copy *EDI to EDX
    474     # if (lenh > s->end - s->start) return false
    475     39/compare                      3/mod/direct    2/rm32/EDX    .           .             .           1/r32/ECX   .               .                 # compare EDX with ECX
    476     7f/jump-if-greater  $slice-starts-with?:false/disp8
    477     # currs/ESI = s->start
    478     8b/subtract                     0/mod/indirect  6/rm32/ESI    .           .             .           6/r32/ESI   .               .                 # copy *ESI to ESI
    479     # currh/EDI = head->data
    480     81          0/subop/add         3/mod/direct    7/rm32/EDI    .           .             .           .           .               4/imm32           # add to EDI
    481     # i/ECX = 0
    482     31/xor                          3/mod/direct    1/rm32/ECX    .           .             .           1/r32/ECX   .               .                 # clear ECX
    483     # EAX = EBX = 0
    484     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
    485     31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
    486 $slice-starts-with?:loop:
    487     # if (i >= lenh) return true
    488     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
    489     7d/jump-if-greater-or-equal  $slice-starts-with?:true/disp8
    490     # AL = *currs
    491     8a/copy-byte                    0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/AL    .               .                 # copy byte at *ESI to AL
    492     # BL = *currh
    493     8a/copy-byte                    0/mod/indirect  7/rm32/EDI    .           .             .           3/r32/BL    .               .                 # copy byte at *EDI to BL
    494     # if (*currs != *currh) return false
    495     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           3/r32/EBX   .               .                 # compare EAX and EBX
    496     75/jump-if-not-equal  $slice-starts-with?:false/disp8
    497     # ++i
    498     41/increment-ECX
    499     # ++currs
    500     46/increment-ESI
    501     # ++currh
    502     47/increment-EDI
    503     eb/jump $slice-starts-with?:loop/disp8
    504 $slice-starts-with?:true:
    505     b8/copy-to-EAX  1/imm32
    506     eb/jump  $slice-starts-with?:end/disp8
    507 $slice-starts-with?:false:
    508     b8/copy-to-EAX  0/imm32
    509 $slice-starts-with?:end:
    510     # . restore registers
    511     5f/pop-to-EDI
    512     5e/pop-to-ESI
    513     5b/pop-to-EBX
    514     5a/pop-to-EDX
    515     59/pop-to-ECX
    516     # . epilog
    517     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    518     5d/pop-to-EBP
    519     c3/return
    520
    521 test-slice-starts-with-single-character:
    522     # - slice-starts-with?(slice("Abc"), "A") == 1
    523     # . prolog
    524     55/push-EBP
    525     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    526     # var slice/ECX
    527     68/push  _test-slice-data-3/imm32/end
    528     68/push  _test-slice-data-0/imm32/start
    529     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
    530     # EAX = slice-starts-with?(ECX, "A")
    531     # . . push args
    532     68/push  "A"/imm32
    533     51/push-ECX
    534     # . . call
    535     e8/call  slice-starts-with?/disp32
    536     # . . discard args
    537     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    538     # check-ints-equal(EAX, 1, msg)
    539     # . . push args
    540     68/push  "F - test-slice-starts-with-single-character"/imm32
    541     68/push  1/imm32
    542     50/push-EAX
    543     # . . call
    544     e8/call  check-ints-equal/disp32
    545     # . . discard args
    546     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
    547     # . epilog
    548     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    549     5d/pop-to-EBP
    550     c3/return
    551
    552 test-slice-starts-with-empty-string:
    553     # - slice-starts-with?(slice("Abc"), "") == 1
    554     # . prolog
    555     55/push-EBP
    556     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    557     # var slice/ECX
    558     68/push  _test-slice-data-3/imm32/end
    559     68/push  _test-slice-data-0/imm32/start
    560     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
    561     # EAX = slice-starts-with?(ECX, "")
    562     # . . push args
    563     68/push  ""/imm32
    564     51/push-ECX
    565     # . . call
    566     e8/call  slice-starts-with?/disp32
    567     # . . discard args
    568     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    569     # check-ints-equal(EAX, 1, msg)
    570     # . . push args
    571     68/push  "F - test-slice-starts-with-empty-string"/imm32
    572     68/push  1/imm32
    573     50/push-EAX
    574     # . . call
    575     e8/call  check-ints-equal/disp32
    576     # . . discard args
    577     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
    578     # . epilog
    579     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    580     5d/pop-to-EBP
    581     c3/return
    582
    583 test-slice-starts-with-multiple-characters:
    584     # - slice-starts-with?(slice("Abc"), "Ab") == 1
    585     # . prolog
    586     55/push-EBP
    587     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    588     # var slice/ECX
    589     68/push  _test-slice-data-3/imm32/end
    590     68/push  _test-slice-data-0/imm32/start
    591     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
    592     # EAX = slice-starts-with?(ECX, "Ab")
    593     # . . push args
    594     68/push  "Ab"/imm32
    595     51/push-ECX
    596     # . . call
    597     e8/call  slice-starts-with?/disp32
    598     # . . discard args
    599     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    600     # check-ints-equal(EAX, 1, msg)
    601     # . . push args
    602     68/push  "F - test-slice-starts-with-multiple-characters"/imm32
    603     68/push  1/imm32
    604     50/push-EAX
    605     # . . call
    606     e8/call  check-ints-equal/disp32
    607     # . . discard args
    608     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
    609     # . epilog
    610     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    611     5d/pop-to-EBP
    612     c3/return
    613
    614 test-slice-starts-with-entire-string:
    615     # - slice-starts-with?(slice("Abc"), "Abc") == 1
    616     # . prolog
    617     55/push-EBP
    618     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    619     # var slice/ECX
    620     68/push  _test-slice-data-3/imm32/end
    621     68/push  _test-slice-data-0/imm32/start
    622     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
    623     # EAX = slice-starts-with?(ECX, "Abc")
    624     # . . push args
    625     68/push  "Abc"/imm32
    626     51/push-ECX
    627     # . . call
    628     e8/call  slice-starts-with?/disp32
    629     # . . discard args
    630     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    631     # check-ints-equal(EAX, 1, msg)
    632     # . . push args
    633     68/push  "F - test-slice-starts-with-entire-string"/imm32
    634     68/push  1/imm32
    635     50/push-EAX
    636     # . . call
    637     e8/call  check-ints-equal/disp32
    638     # . . discard args
    639     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
    640     # . epilog
    641     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    642     5d/pop-to-EBP
    643     c3/return
    644
    645 test-slice-starts-with-fails:
    646     # - slice-starts-with?(slice("Abc"), "Abd") == 1
    647     # . prolog
    648     55/push-EBP
    649     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    650     # var slice/ECX
    651     68/push  _test-slice-data-3/imm32/end
    652     68/push  _test-slice-data-0/imm32/start
    653     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
    654     # EAX = slice-starts-with?(ECX, "Abd")
    655     # . . push args
    656     68/push  "Abd"/imm32
    657     51/push-ECX
    658     # . . call
    659     e8/call  slice-starts-with?/disp32
    660     # . . discard args
    661     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    662     # check-ints-equal(EAX, 0, msg)
    663     # . . push args
    664     68/push  "F - test-slice-starts-with-fails"/imm32
    665     68/push  0/imm32
    666     50/push-EAX
    667     # . . call
    668     e8/call  check-ints-equal/disp32
    669     # . . discard args
    670     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
    671     # . epilog
    672     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    673     5d/pop-to-EBP
    674     c3/return
    675
    676 test-slice-starts-with-fails-2:
    677     # - slice-starts-with?(slice("Abc"), "Ac") == 1
    678     # . prolog
    679     55/push-EBP
    680     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    681     # var slice/ECX
    682     68/push  _test-slice-data-3/imm32/end
    683     68/push  _test-slice-data-0/imm32/start
    684     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
    685     # EAX = slice-starts-with?(ECX, "Ac")
    686     # . . push args
    687     68/push  "Ac"/imm32
    688     51/push-ECX
    689     # . . call
    690     e8/call  slice-starts-with?/disp32
    691     # . . discard args
    692     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    693     # check-ints-equal(EAX, 0, msg)
    694     # . . push args
    695     68/push  "F - test-slice-starts-with-fails-2"/imm32
    696     68/push  0/imm32
    697     50/push-EAX
    698     # . . call
    699     e8/call  check-ints-equal/disp32
    700     # . . discard args
    701     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
    702     # . epilog
    703     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    704     5d/pop-to-EBP
    705     c3/return
    706
    707 write-slice:  # out : (address buffered-file), s : (address slice)
    708     # . prolog
    709     55/push-EBP
    710     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    711     # . save registers
    712     50/push-EAX
    713     51/push-ECX
    714     52/push-EDX
    715     53/push-EBX
    716     56/push-ESI
    717     57/push-EDI
    718     # ESI = s
    719     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   0xc/disp8       .                 # copy *(EBP+12) to ESI
    720     # curr/ECX = s->start
    721     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           1/r32/ECX   .               .                 # copy *ESI to ECX
    722     # max/ESI = s->end
    723     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           6/r32/ESI   4/disp8         .                 # copy *(ESI+4) to ESI
    724     # EDI = out
    725     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .                         7/r32/EDI   8/disp8         .                 # copy *(EBP+8) to EDI
    726     # EDX = out->length
    727     8b/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           2/r32/EDX   0xc/disp8       .                 # copy *(EDI+12) to EDX
    728     # EBX = out->write
    729     8b/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           3/r32/EBX   4/disp8         .                 # copy *(EDI+4) to EBX
    730 $write-slice:loop:
    731     # if (curr >= max) break
    732     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           6/r32/ESI   .               .                 # compare ECX with ESI
    733     7d/jump-if-greater-or-equal  $write-slice:loop-end/disp8
    734     # if (out->write >= out->length) flush and clear out's stream
    735     39/compare                      3/mod/direct    3/rm32/EBX    .           .             .           2/r32/EDX   .               .                 # compare EBX with EDX
    736     7c/jump-if-lesser  $write-slice:to-stream/disp8
    737     # . persist out->write
    738     89/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           3/r32/EBX   4/disp8         .                 # copy EBX to *(EDI+4)
    739     # . flush(out)
    740     # . . push args
    741     57/push-EDI
    742     # . . call
    743     e8/call  flush/disp32
    744     # . . discard args
    745     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
    746     # . clear-stream(stream = out+4)
    747     # . . push args
    748     8d/copy-address                 1/mod/*+disp8   7/rm32/EDI    .           .             .           0/r32/EAX   4/disp8         .                 # copy EDI+4 to EAX
    749     50/push-EAX
    750     # . . call
    751     e8/call  clear-stream/disp32
    752     # . . discard args
    753     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
    754     # . out->write must now be 0; update its cache at EBX
    755     31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
    756 $write-slice:to-stream:
    757     # out->data[out->write] = *in
    758     # . AL = *in
    759     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
    760     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
    761     # . out->data[out->write] = AL
    762     88/copy-byte                    1/mod/*+disp8   4/rm32/sib    7/base/EDI  3/index/EBX   .           0/r32/AL    0x10/disp8      .                 # copy AL to *(EDI+EBX+16)
    763     # ++out->write
    764     43/increment-EBX
    765     # ++in
    766     41/increment-ECX
    767     eb/jump  $write-slice:loop/disp8
    768 $write-slice:loop-end:
    769     # persist necessary variables from registers
    770     89/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           3/r32/EBX   4/disp8         .                 # copy EBX to *(EDI+4)
    771 $write-slice:end:
    772     # . restore registers
    773     5f/pop-to-EDI
    774     5e/pop-to-ESI
    775     5b/pop-to-EBX
    776     5a/pop-to-EDX
    777     59/pop-to-ECX
    778     58/pop-to-EAX
    779     # . epilog
    780     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    781     5d/pop-to-EBP
    782     c3/return
    783
    784 test-write-slice:
    785     # . prolog
    786     55/push-EBP
    787     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    788     # setup
    789     # . clear-stream(_test-stream)
    790     # . . push args
    791     68/push  _test-stream/imm32
    792     # . . call
    793     e8/call  clear-stream/disp32
    794     # . . discard args
    795     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
    796     # . clear-stream(_test-buffered-file+4)
    797     # . . push args
    798     b8/copy-to-EAX  _test-buffered-file/imm32
    799     05/add-to-EAX  4/imm32
    800     50/push-EAX
    801     # . . call
    802     e8/call  clear-stream/disp32
    803     # . . discard args
    804     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
    805     # var slice/ECX = "Abc"
    806     68/push  _test-slice-data-3/imm32/end
    807     68/push  _test-slice-data-0/imm32/start
    808     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
    809     # write-slice(_test-buffered-file, slice)
    810     # . . push args
    811     51/push-ECX
    812     68/push  _test-buffered-file/imm32
    813     # . . call
    814     e8/call  write-slice/disp32
    815     # . . discard args
    816     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    817     # flush(_test-buffered-file)
    818     # . . push args
    819     68/push  _test-buffered-file/imm32
    820     # . . call
    821     e8/call  flush/disp32
    822     # . . discard args
    823     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
    824     # check-stream-equal(_test-stream, "Abc", msg)
    825     # . . push args
    826     68/push  "F - test-write-slice"/imm32
    827     68/push  "Abc"/imm32
    828     68/push  _test-stream/imm32
    829     # . . call
    830     e8/call  check-stream-equal/disp32
    831     # . . discard args
    832     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
    833     # . epilog
    834     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    835     5d/pop-to-EBP
    836     c3/return
    837
    838 # copy a slice into a new (dynamically allocated) string
    839 slice-to-string:  # ad : (address allocation-descriptor), in : (address slice) -> out/EAX : (address array)
    840     # . prolog
    841     55/push-EBP
    842     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    843     # . save registers
    844     51/push-ECX
    845     52/push-EDX
    846     53/push-EBX
    847     56/push-ESI
    848     # ESI = in
    849     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   0xc/disp8       .                 # copy *(EBP+12) to ESI
    850     # curr/EDX = in->start
    851     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           2/r32/EDX   .               .                 # copy *ESI to EDX
    852     # max/EBX = in->end
    853     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           3/r32/EBX   4/disp8         .                 # copy *(ESI+4) to EBX
    854     # size/ECX = max - curr + 4  # total size of output string (including the initial length)
    855     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           3/r32/EBX   .               .                 # copy EBX to ECX
    856     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # subtract EDX from ECX
    857     81          0/subop/add         3/mod/direct    1/rm32/ECX    .           .             .           .           .               4/imm32           # add to ECX
    858     # out/EAX = allocate(ad, size)
    859     # . . push args
    860     51/push-ECX
    861     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
    862     # . . call
    863     e8/call  allocate/disp32
    864     # . . discard args
    865     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    866     # if (EAX == 0) abort
    867     3d/compare-EAX-and  0/imm32
    868     74/jump-if-equal  $slice-to-string:abort/disp8
    869     # *out = size-4
    870     89/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy ECX to *EAX
    871     81          5/subop/subtract    0/mod/indirect  0/rm32/EAX    .           .             .           .           .               4/imm32           # subtract 4 from *EAX
    872     # save out
    873     50/push-EAX
    874     # EAX = _append-4(EAX+4, EAX+size, curr, max)  # clobbering ECX
    875     # . . push args
    876     53/push-EBX
    877     52/push-EDX
    878     # . . push EAX+size (clobbering ECX)
    879     01/add                          3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # add EAX to ECX
    880     51/push-ECX
    881     # . . push EAX+4 (clobbering EAX)
    882     81          0/subop/add         3/mod/direct    0/rm32/EAX    .           .             .           .           .               4/imm32           # add to EAX
    883     50/push-EAX
    884     # . . call
    885     e8/call  _append-4/disp32
    886     # . . discard args
    887     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
    888     # restore out (assumes _append-4 can't error)
    889     58/pop-to-EAX
    890 $slice-to-string:end:
    891     # . restore registers
    892     5e/pop-to-ESI
    893     5b/pop-to-EBX
    894     5a/pop-to-EDX
    895     59/pop-to-ECX
    896     # . epilog
    897     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    898     5d/pop-to-EBP
    899     c3/return
    900
    901 $slice-to-string:abort:
    902     # . _write(2/stderr, error)
    903     # . . push args
    904     68/push  "slice-to-string: out of space"/imm32
    905     68/push  2/imm32/stderr
    906     # . . call
    907     e8/call  _write/disp32
    908     # . . discard args
    909     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    910     # . syscall(exit, 1)
    911     bb/copy-to-EBX  1/imm32
    912     b8/copy-to-EAX  1/imm32/exit
    913     cd/syscall  0x80/imm8
    914     # never gets here
    915
    916 test-slice-to-string:
    917     # . prolog
    918     55/push-EBP
    919     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    920     # var slice/ECX = "Abc"
    921     68/push  _test-slice-data-3/imm32/end
    922     68/push  _test-slice-data-0/imm32/start
    923     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
    924     # EAX = slice-to-string(Heap, slice)
    925     # . . push args
    926     51/push-ECX
    927     68/push  Heap/imm32
    928     # . . call
    929     e8/call  slice-to-string/disp32
    930     # . . discard args
    931     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    932 +-- 26 lines: #?     # dump word-slice -----------------------------------------------------------------------------------------------------------------------
    958     # EAX = string-equal?(EAX, "Abc")
    959     # . . push args
    960     68/push  "Abc"/imm32
    961     50/push-EAX
    962     # . . call
    963     e8/call  string-equal?/disp32
    964     # . . discard args
    965     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    966     # check-ints-equal(EAX, 1, msg)
    967     # . . push args
    968     68/push  "F - test-slice-to-string"/imm32
    969     68/push  1/imm32/true
    970     50/push-EAX
    971     # . . call
    972     e8/call  check-ints-equal/disp32
    973     # . . discard args
    974     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
    975     # . epilog
    976     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    977     5d/pop-to-EBP
    978     c3/return
    979
    980 == data
    981
    982 _test-slice-data-0:
    983     41/A
    984 _test-slice-data-1:
    985     62/b
    986 _test-slice-data-2:
    987     63/c
    988 _test-slice-data-3:
    989     64/d
    990 _test-slice-data-4:
    991
    992 # . _. vim:nowrap:textwidth=0