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 +-- 34 lines: #?     # dump word-slice -----------------------------------------------------------------------------------------------------------------------
 966     # EAX = string-equal?(EAX, "Abc")
 967     # . . push args
 968     68/push  "Abc"/imm32
 969     50/push-EAX
 970     # . . call
 971     e8/call  string-equal?/disp32
 972     # . . discard args
 973     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
 974     # check-ints-equal(EAX, 1, msg)
 975     # . . push args
 976     68/push  "F - test-slice-to-string"/imm32
 977     68/push  1/imm32/true
 978     50/push-EAX
 979     # . . call
 980     e8/call  check-ints-equal/disp32
 981     # . . discard args
 982     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
 983     # . epilog
 984     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
 985     5d/pop-to-EBP
 986     c3/return
 987 
 988 == data
 989 
 990 _test-slice-data-0:
 991     41/A
 992 _test-slice-data-1:
 993     62/b
 994 _test-slice-data-2:
 995     63/c
 996 _test-slice-data-3:
 997     64/d
 998 _test-slice-data-4:
 999 
1000 # . _. vim:nowrap:textwidth=0