From ec73ed1230d75deb0f913a32617c9f1e0a5ca640 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Fri, 10 Jul 2020 23:44:10 -0700 Subject: 6631 --- html/123slice.subx.html | 1260 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1260 insertions(+) create mode 100644 html/123slice.subx.html (limited to 'html/123slice.subx.html') diff --git a/html/123slice.subx.html b/html/123slice.subx.html new file mode 100644 index 00000000..3edd7130 --- /dev/null +++ b/html/123slice.subx.html @@ -0,0 +1,1260 @@ + + + + +Mu - 123slice.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/123slice.subx +
+   1 # new data structure: a slice is an open interval of addresses [start, end)
+   2 # that includes 'start' but not 'end'
+   3 
+   4 == code
+   5 #   instruction                     effective address                                                   register    displacement    immediate
+   6 # . op          subop               mod             rm32          base        index         scale       r32
+   7 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+   8 
+   9 slice-empty?:  # s: (addr slice) -> result/eax: boolean
+  10     # . prologue
+  11     55/push-ebp
+  12     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+  13     # . save registers
+  14     51/push-ecx
+  15     # ecx = s
+  16     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
+  17     # if (s->start >= s->end) return true
+  18     # . eax = s->start
+  19     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
+  20     # . if (eax >= s->end) return true
+  21     3b/compare                      1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # compare eax with *(ecx+4)
+  22     b8/copy-to-eax  1/imm32/true
+  23     73/jump-if-addr>=  $slice-empty?:end/disp8
+  24     b8/copy-to-eax  0/imm32/false
+  25 $slice-empty?:end:
+  26     # . restore registers
+  27     59/pop-to-ecx
+  28     # . epilogue
+  29     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+  30     5d/pop-to-ebp
+  31     c3/return
+  32 
+  33 test-slice-empty-true:
+  34     # . prologue
+  35     55/push-ebp
+  36     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+  37     # var slice/ecx: slice = {34, 34}
+  38     68/push  34/imm32/end
+  39     68/push  34/imm32/start
+  40     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+  41     # slice-empty?(slice)
+  42     # . . push args
+  43     51/push-ecx
+  44     # . . call
+  45     e8/call  slice-empty?/disp32
+  46     # . . discard args
+  47     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+  48     # check-ints-equal(eax, 1, msg)
+  49     # . . push args
+  50     68/push  "F - test-slice-empty-true"/imm32
+  51     68/push  1/imm32
+  52     50/push-eax
+  53     # . . call
+  54     e8/call  check-ints-equal/disp32
+  55     # . . discard args
+  56     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+  57     # . epilogue
+  58     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+  59     5d/pop-to-ebp
+  60     c3/return
+  61 
+  62 test-slice-empty-false:
+  63     # . prologue
+  64     55/push-ebp
+  65     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+  66     # var slice/ecx: slice = {32, 34}
+  67     68/push  34/imm32/end
+  68     68/push  32/imm32/start
+  69     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+  70     # slice-empty?(slice)
+  71     # . . push args
+  72     51/push-ecx
+  73     # . . call
+  74     e8/call  slice-empty?/disp32
+  75     # . . discard args
+  76     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+  77     # check-ints-equal(eax, 0, msg)
+  78     # . . push args
+  79     68/push  "F - test-slice-empty-false"/imm32
+  80     68/push  0/imm32
+  81     50/push-eax
+  82     # . . call
+  83     e8/call  check-ints-equal/disp32
+  84     # . . discard args
+  85     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+  86     # . epilogue
+  87     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+  88     5d/pop-to-ebp
+  89     c3/return
+  90 
+  91 test-slice-empty-if-start-greater-than-end:
+  92     # . prologue
+  93     55/push-ebp
+  94     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+  95     # var slice/ecx: slice = {34, 32}
+  96     68/push  32/imm32/end
+  97     68/push  34/imm32/start
+  98     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+  99     # slice-empty?(slice)
+ 100     # . . push args
+ 101     51/push-ecx
+ 102     # . . call
+ 103     e8/call  slice-empty?/disp32
+ 104     # . . discard args
+ 105     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 106     # check-ints-equal(eax, 1, msg)
+ 107     # . . push args
+ 108     68/push  "F - test-slice-empty-if-start-greater-than-end"/imm32
+ 109     68/push  1/imm32
+ 110     50/push-eax
+ 111     # . . call
+ 112     e8/call  check-ints-equal/disp32
+ 113     # . . discard args
+ 114     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 115     # . epilogue
+ 116     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 117     5d/pop-to-ebp
+ 118     c3/return
+ 119 
+ 120 slice-equal?:  # s: (addr slice), p: (addr array byte) -> result/eax: boolean
+ 121     # pseudocode:
+ 122     #   if (p == 0) return (s == 0)
+ 123     #   currs = s->start
+ 124     #   maxs = s->end
+ 125     #   if (maxs - currs != p->size) return false
+ 126     #   currp = p->data
+ 127     #   while currs < maxs
+ 128     #     if (*currs != *currp) return false
+ 129     #     ++currs
+ 130     #     ++currp
+ 131     #   return true
+ 132     #
+ 133     # registers:
+ 134     #   currs: edx
+ 135     #   maxs: esi
+ 136     #   currp: ebx
+ 137     #   *currs: eax
+ 138     #   *currp: ecx
+ 139     #
+ 140     # . prologue
+ 141     55/push-ebp
+ 142     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 143     # . save registers
+ 144     51/push-ecx
+ 145     52/push-edx
+ 146     53/push-ebx
+ 147     56/push-esi
+ 148     # esi = s
+ 149     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+ 150     # var currs/edx: (addr byte) = s->start
+ 151     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
+ 152     # var maxs/esi: (addr byte) = s->end
+ 153     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           6/r32/esi   4/disp8         .                 # copy *(esi+4) to esi
+ 154     # var ssize/eax: int = maxs - currs
+ 155     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           6/r32/esi   .               .                 # copy esi to eax
+ 156     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           2/r32/edx   .               .                 # subtract edx from eax
+ 157     # ebx = p
+ 158     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           3/r32/ebx   0xc/disp8       .                 # copy *(ebp+12) to ebx
+ 159     # if (p != 0) goto next check
+ 160     81          7/subop/compare     3/mod/direct    3/rm32/ebx    .           .             .           .           .               0/imm32           # compare ebx
+ 161     75/jump-if-!=  $slice-equal?:nonnull-string/disp8
+ 162 $slice-equal?:null-string:
+ 163     # return s->start == s->end
+ 164     3d/compare-eax-and  0/imm32
+ 165     74/jump-if-=  $slice-equal?:true/disp8
+ 166     eb/jump  $slice-equal?:false/disp8
+ 167 $slice-equal?:nonnull-string:
+ 168     # if (ssize != p->size) return false
+ 169     39/compare                      0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # compare *ebx and eax
+ 170     75/jump-if-!=  $slice-equal?:false/disp8
+ 171     # var currp/ebx: (addr byte) = p->data
+ 172     81          0/subop/add         3/mod/direct    3/rm32/ebx    .           .             .           .           .               4/imm32           # add to ebx
+ 173     # var c1/eax: byte = 0
+ 174     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
+ 175     # var c2/ecx: byte = 0
+ 176     31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
+ 177 $slice-equal?:loop:
+ 178     # if (currs >= maxs) return true
+ 179     39/compare                      3/mod/direct    2/rm32/edx    .           .             .           6/r32/esi   .               .                 # compare edx with esi
+ 180     73/jump-if-addr>=  $slice-equal?:true/disp8
+ 181     # c1 = *currp
+ 182     8a/copy-byte                    0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/AL    .               .                 # copy byte at *ebx to AL
+ 183     # c2 = *currs
+ 184     8a/copy-byte                    0/mod/indirect  2/rm32/edx    .           .             .           1/r32/CL    .               .                 # copy byte at *edx to CL
+ 185     # if (c1 != c2) return false
+ 186     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # compare eax and ecx
+ 187     75/jump-if-!=  $slice-equal?:false/disp8
+ 188     # ++currp
+ 189     43/increment-ebx
+ 190     # ++currs
+ 191     42/increment-edx
+ 192     eb/jump $slice-equal?:loop/disp8
+ 193 $slice-equal?:false:
+ 194     b8/copy-to-eax  0/imm32
+ 195     eb/jump  $slice-equal?:end/disp8
+ 196 $slice-equal?:true:
+ 197     b8/copy-to-eax  1/imm32
+ 198 $slice-equal?:end:
+ 199     # . restore registers
+ 200     5e/pop-to-esi
+ 201     5b/pop-to-ebx
+ 202     5a/pop-to-edx
+ 203     59/pop-to-ecx
+ 204     # . epilogue
+ 205     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 206     5d/pop-to-ebp
+ 207     c3/return
+ 208 
+ 209 test-slice-equal:
+ 210     # - slice-equal?(slice("Abc"), "Abc") == 1
+ 211     # . prologue
+ 212     55/push-ebp
+ 213     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 214     # (eax..ecx) = "Abc"
+ 215     b8/copy-to-eax  "Abc"/imm32
+ 216     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+ 217     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
+ 218     05/add-to-eax  4/imm32
+ 219     # var slice/ecx: slice = {eax, ecx}
+ 220     51/push-ecx
+ 221     50/push-eax
+ 222     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 223     # eax = slice-equal?(ecx, "Abc")
+ 224     # . . push args
+ 225     68/push  "Abc"/imm32
+ 226     51/push-ecx
+ 227     # . . call
+ 228     e8/call  slice-equal?/disp32
+ 229     # . . discard args
+ 230     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 231     # check-ints-equal(eax, 1, msg)
+ 232     # . . push args
+ 233     68/push  "F - test-slice-equal"/imm32
+ 234     68/push  1/imm32
+ 235     50/push-eax
+ 236     # . . call
+ 237     e8/call  check-ints-equal/disp32
+ 238     # . . discard args
+ 239     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 240     # . epilogue
+ 241     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 242     5d/pop-to-ebp
+ 243     c3/return
+ 244 
+ 245 test-slice-equal-false:
+ 246     # - slice-equal?(slice("bcd"), "Abc") == 0
+ 247     # . prologue
+ 248     55/push-ebp
+ 249     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 250     # (eax..ecx) = "bcd"
+ 251     b8/copy-to-eax  "bcd"/imm32
+ 252     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+ 253     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
+ 254     05/add-to-eax  4/imm32
+ 255     # var slice/ecx: slice = {eax, ecx}
+ 256     51/push-ecx
+ 257     50/push-eax
+ 258     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 259     # eax = slice-equal?(ecx, "Abc")
+ 260     # . . push args
+ 261     68/push  "Abc"/imm32
+ 262     51/push-ecx
+ 263     # . . call
+ 264     e8/call  slice-equal?/disp32
+ 265     # . . discard args
+ 266     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 267     # check-ints-equal(eax, 0, msg)
+ 268     # . . push args
+ 269     68/push  "F - test-slice-equal-false"/imm32
+ 270     68/push  0/imm32
+ 271     50/push-eax
+ 272     # . . call
+ 273     e8/call  check-ints-equal/disp32
+ 274     # . . discard args
+ 275     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 276     # . epilogue
+ 277     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 278     5d/pop-to-ebp
+ 279     c3/return
+ 280 
+ 281 test-slice-equal-too-long:
+ 282     # - slice-equal?(slice("Abcd"), "Abc") == 0
+ 283     # . prologue
+ 284     55/push-ebp
+ 285     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 286     # (eax..ecx) = "Abcd"
+ 287     b8/copy-to-eax  "Abcd"/imm32
+ 288     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+ 289     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
+ 290     05/add-to-eax  4/imm32
+ 291     # var slice/ecx: slice = {eax, ecx}
+ 292     51/push-ecx
+ 293     50/push-eax
+ 294     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 295     # eax = slice-equal?(ecx, "Abc")
+ 296     # . . push args
+ 297     68/push  "Abc"/imm32
+ 298     51/push-ecx
+ 299     # . . call
+ 300     e8/call  slice-equal?/disp32
+ 301     # . . discard args
+ 302     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 303     # check-ints-equal(eax, 0, msg)
+ 304     # . . push args
+ 305     68/push  "F - test-slice-equal-too-long"/imm32
+ 306     68/push  0/imm32
+ 307     50/push-eax
+ 308     # . . call
+ 309     e8/call  check-ints-equal/disp32
+ 310     # . . discard args
+ 311     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 312     # . epilogue
+ 313     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 314     5d/pop-to-ebp
+ 315     c3/return
+ 316 
+ 317 test-slice-equal-too-short:
+ 318     # - slice-equal?(slice("A"), "Abc") == 0
+ 319     # . prologue
+ 320     55/push-ebp
+ 321     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 322     # (eax..ecx) = "A"
+ 323     b8/copy-to-eax  "A"/imm32
+ 324     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+ 325     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
+ 326     05/add-to-eax  4/imm32
+ 327     # var slice/ecx: slice = {eax, ecx}
+ 328     51/push-ecx
+ 329     50/push-eax
+ 330     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 331     # eax = slice-equal?(ecx, "Abc")
+ 332     # . . push args
+ 333     68/push  "Abc"/imm32
+ 334     51/push-ecx
+ 335     # . . call
+ 336     e8/call  slice-equal?/disp32
+ 337     # . . discard args
+ 338     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 339     # check-ints-equal(eax, 0, msg)
+ 340     # . . push args
+ 341     68/push  "F - test-slice-equal-too-short"/imm32
+ 342     68/push  0/imm32
+ 343     50/push-eax
+ 344     # . . call
+ 345     e8/call  check-ints-equal/disp32
+ 346     # . . discard args
+ 347     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 348     # . epilogue
+ 349     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 350     5d/pop-to-ebp
+ 351     c3/return
+ 352 
+ 353 test-slice-equal-empty:
+ 354     # - slice-equal?(slice(""), "Abc") == 0
+ 355     # . prologue
+ 356     55/push-ebp
+ 357     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 358     # var slice/ecx: slice
+ 359     68/push  0/imm32/end
+ 360     68/push  0/imm32/start
+ 361     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 362     # eax = slice-equal?(ecx, "Abc")
+ 363     # . . push args
+ 364     68/push  "Abc"/imm32
+ 365     51/push-ecx
+ 366     # . . call
+ 367     e8/call  slice-equal?/disp32
+ 368     # . . discard args
+ 369     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 370     # check-ints-equal(eax, 0, msg)
+ 371     # . . push args
+ 372     68/push  "F - test-slice-equal-empty"/imm32
+ 373     68/push  0/imm32
+ 374     50/push-eax
+ 375     # . . call
+ 376     e8/call  check-ints-equal/disp32
+ 377     # . . discard args
+ 378     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 379     # . epilogue
+ 380     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 381     5d/pop-to-ebp
+ 382     c3/return
+ 383 
+ 384 test-slice-equal-with-empty:
+ 385     # - slice-equal?(slice("Ab"), "") == 0
+ 386     # . prologue
+ 387     55/push-ebp
+ 388     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 389     # (eax..ecx) = "Ab"
+ 390     b8/copy-to-eax  "Ab"/imm32
+ 391     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+ 392     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
+ 393     05/add-to-eax  4/imm32
+ 394     # var slice/ecx: slice = {eax, ecx}
+ 395     51/push-ecx
+ 396     50/push-eax
+ 397     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 398     # eax = slice-equal?(ecx, "")
+ 399     # . . push args
+ 400     68/push  ""/imm32
+ 401     51/push-ecx
+ 402     # . . call
+ 403     e8/call  slice-equal?/disp32
+ 404     # . . discard args
+ 405     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 406     # check-ints-equal(eax, 0, msg)
+ 407     # . . push args
+ 408     68/push  "F - test-slice-equal-with-empty"/imm32
+ 409     68/push  0/imm32
+ 410     50/push-eax
+ 411     # . . call
+ 412     e8/call  check-ints-equal/disp32
+ 413     # . . discard args
+ 414     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 415     # . epilogue
+ 416     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 417     5d/pop-to-ebp
+ 418     c3/return
+ 419 
+ 420 test-slice-equal-empty-with-empty:
+ 421     # - slice-equal?(slice(""), "") == 1
+ 422     # . prologue
+ 423     55/push-ebp
+ 424     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 425     # var slice/ecx: slice
+ 426     68/push  0/imm32/end
+ 427     68/push  0/imm32/start
+ 428     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 429     # eax = slice-equal?(ecx, "")
+ 430     # . . push args
+ 431     68/push  ""/imm32
+ 432     51/push-ecx
+ 433     # . . call
+ 434     e8/call  slice-equal?/disp32
+ 435     # . . discard args
+ 436     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 437     # check-ints-equal(eax, 1, msg)
+ 438     # . . push args
+ 439     68/push  "F - test-slice-equal-empty-with-empty"/imm32
+ 440     68/push  1/imm32
+ 441     50/push-eax
+ 442     # . . call
+ 443     e8/call  check-ints-equal/disp32
+ 444     # . . discard args
+ 445     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 446     # . epilogue
+ 447     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 448     5d/pop-to-ebp
+ 449     c3/return
+ 450 
+ 451 test-slice-equal-with-null:
+ 452     # - slice-equal?(slice("Ab"), null) == 0
+ 453     # . prologue
+ 454     55/push-ebp
+ 455     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 456     # (eax..ecx) = "Ab"
+ 457     b8/copy-to-eax  "Ab"/imm32
+ 458     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+ 459     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
+ 460     05/add-to-eax  4/imm32
+ 461     # var slice/ecx: slice = {eax, ecx}
+ 462     51/push-ecx
+ 463     50/push-eax
+ 464     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 465     # eax = slice-equal?(ecx, 0)
+ 466     # . . push args
+ 467     68/push  0/imm32
+ 468     51/push-ecx
+ 469     # . . call
+ 470     e8/call  slice-equal?/disp32
+ 471     # . . discard args
+ 472     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 473     # check-ints-equal(eax, 0, msg)
+ 474     # . . push args
+ 475     68/push  "F - test-slice-equal-with-null"/imm32
+ 476     68/push  0/imm32
+ 477     50/push-eax
+ 478     # . . call
+ 479     e8/call  check-ints-equal/disp32
+ 480     # . . discard args
+ 481     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 482     # . epilogue
+ 483     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 484     5d/pop-to-ebp
+ 485     c3/return
+ 486 
+ 487 slice-starts-with?:  # s: (addr slice), head: (addr array byte) -> result/eax: boolean
+ 488     # pseudocode
+ 489     #   hsize = head->size
+ 490     #   if (hsize > s->end - s->start) return false
+ 491     #   i = 0
+ 492     #   currs = s->start
+ 493     #   currp = head->data
+ 494     #   while i < hsize
+ 495     #     if (*currs != *currh) return false
+ 496     #     ++i
+ 497     #     ++currs
+ 498     #     ++currh
+ 499     #   return true
+ 500     #
+ 501     # registers:
+ 502     #   currs: esi
+ 503     #   currh: edi
+ 504     #   *currs: eax
+ 505     #   *currh: ebx
+ 506     #   i: ecx
+ 507     #   hsize: edx
+ 508     #
+ 509     # . prologue
+ 510     55/push-ebp
+ 511     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 512     # . save registers
+ 513     51/push-ecx
+ 514     52/push-edx
+ 515     53/push-ebx
+ 516     56/push-esi
+ 517     57/push-edi
+ 518     # esi = s
+ 519     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+ 520     # var lens/ecx: int = s->end - s->start
+ 521     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(esi+4) to ecx
+ 522     2b/subtract                     0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # subtract *esi from ecx
+ 523     # edi = head
+ 524     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
+ 525     # var hsize/edx: int = head->size
+ 526     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           2/r32/edx   .               .                 # copy *edi to edx
+ 527     # if (hsize > lens) return false
+ 528     39/compare                      3/mod/direct    2/rm32/edx    .           .             .           1/r32/ecx   .               .                 # compare edx with ecx
+ 529     7f/jump-if->  $slice-starts-with?:false/disp8
+ 530     # var currs/esi: (addr byte) = s->start
+ 531     8b/subtract                     0/mod/indirect  6/rm32/esi    .           .             .           6/r32/esi   .               .                 # copy *esi to esi
+ 532     # var currh/edi: (addr byte) = head->data
+ 533     81          0/subop/add         3/mod/direct    7/rm32/edi    .           .             .           .           .               4/imm32           # add to edi
+ 534     # var i/ecx: int = 0
+ 535     31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
+ 536     # var c1/eax: byte = 0
+ 537     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
+ 538     # var c2/ebx: byte = 0
+ 539     31/xor                          3/mod/direct    3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # clear ebx
+ 540 $slice-starts-with?:loop:
+ 541     # if (i >= hsize) return true
+ 542     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
+ 543     7d/jump-if->=  $slice-starts-with?:true/disp8
+ 544     # c1 = *currs
+ 545     8a/copy-byte                    0/mod/indirect  6/rm32/esi    .           .             .           0/r32/AL    .               .                 # copy byte at *esi to AL
+ 546     # c2 = *currh
+ 547     8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .             .           3/r32/BL    .               .                 # copy byte at *edi to BL
+ 548     # if (c1 != c2) return false
+ 549     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
+ 550     75/jump-if-!=  $slice-starts-with?:false/disp8
+ 551     # ++i
+ 552     41/increment-ecx
+ 553     # ++currs
+ 554     46/increment-esi
+ 555     # ++currh
+ 556     47/increment-edi
+ 557     eb/jump $slice-starts-with?:loop/disp8
+ 558 $slice-starts-with?:true:
+ 559     b8/copy-to-eax  1/imm32
+ 560     eb/jump  $slice-starts-with?:end/disp8
+ 561 $slice-starts-with?:false:
+ 562     b8/copy-to-eax  0/imm32
+ 563 $slice-starts-with?:end:
+ 564     # . restore registers
+ 565     5f/pop-to-edi
+ 566     5e/pop-to-esi
+ 567     5b/pop-to-ebx
+ 568     5a/pop-to-edx
+ 569     59/pop-to-ecx
+ 570     # . epilogue
+ 571     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 572     5d/pop-to-ebp
+ 573     c3/return
+ 574 
+ 575 test-slice-starts-with-single-character:
+ 576     # - slice-starts-with?(slice("Abc"), "A") == 1
+ 577     # . prologue
+ 578     55/push-ebp
+ 579     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 580     # (eax..ecx) = "Abc"
+ 581     b8/copy-to-eax  "Abc"/imm32
+ 582     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+ 583     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
+ 584     05/add-to-eax  4/imm32
+ 585     # var slice/ecx: slice = {eax, ecx}
+ 586     51/push-ecx
+ 587     50/push-eax
+ 588     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 589     # eax = slice-starts-with?(ecx, "A")
+ 590     # . . push args
+ 591     68/push  "A"/imm32
+ 592     51/push-ecx
+ 593     # . . call
+ 594     e8/call  slice-starts-with?/disp32
+ 595     # . . discard args
+ 596     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 597     # check-ints-equal(eax, 1, msg)
+ 598     # . . push args
+ 599     68/push  "F - test-slice-starts-with-single-character"/imm32
+ 600     68/push  1/imm32
+ 601     50/push-eax
+ 602     # . . call
+ 603     e8/call  check-ints-equal/disp32
+ 604     # . . discard args
+ 605     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 606     # . epilogue
+ 607     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 608     5d/pop-to-ebp
+ 609     c3/return
+ 610 
+ 611 test-slice-starts-with-empty-string:
+ 612     # - slice-starts-with?(slice("Abc"), "") == 1
+ 613     # . prologue
+ 614     55/push-ebp
+ 615     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 616     # (eax..ecx) = "Abc"
+ 617     b8/copy-to-eax  "Abc"/imm32
+ 618     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+ 619     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
+ 620     05/add-to-eax  4/imm32
+ 621     # var slice/ecx: slice = {eax, ecx}
+ 622     51/push-ecx
+ 623     50/push-eax
+ 624     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 625     # eax = slice-starts-with?(ecx, "")
+ 626     # . . push args
+ 627     68/push  ""/imm32
+ 628     51/push-ecx
+ 629     # . . call
+ 630     e8/call  slice-starts-with?/disp32
+ 631     # . . discard args
+ 632     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 633     # check-ints-equal(eax, 1, msg)
+ 634     # . . push args
+ 635     68/push  "F - test-slice-starts-with-empty-string"/imm32
+ 636     68/push  1/imm32
+ 637     50/push-eax
+ 638     # . . call
+ 639     e8/call  check-ints-equal/disp32
+ 640     # . . discard args
+ 641     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 642     # . epilogue
+ 643     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 644     5d/pop-to-ebp
+ 645     c3/return
+ 646 
+ 647 test-slice-starts-with-multiple-characters:
+ 648     # - slice-starts-with?(slice("Abc"), "Ab") == 1
+ 649     # . prologue
+ 650     55/push-ebp
+ 651     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 652     # (eax..ecx) = "Abc"
+ 653     b8/copy-to-eax  "Abc"/imm32
+ 654     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+ 655     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
+ 656     05/add-to-eax  4/imm32
+ 657     # var slice/ecx: slice = {eax, ecx}
+ 658     51/push-ecx
+ 659     50/push-eax
+ 660     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 661     # eax = slice-starts-with?(ecx, "Ab")
+ 662     # . . push args
+ 663     68/push  "Ab"/imm32
+ 664     51/push-ecx
+ 665     # . . call
+ 666     e8/call  slice-starts-with?/disp32
+ 667     # . . discard args
+ 668     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 669     # check-ints-equal(eax, 1, msg)
+ 670     # . . push args
+ 671     68/push  "F - test-slice-starts-with-multiple-characters"/imm32
+ 672     68/push  1/imm32
+ 673     50/push-eax
+ 674     # . . call
+ 675     e8/call  check-ints-equal/disp32
+ 676     # . . discard args
+ 677     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 678     # . epilogue
+ 679     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 680     5d/pop-to-ebp
+ 681     c3/return
+ 682 
+ 683 test-slice-starts-with-entire-string:
+ 684     # - slice-starts-with?(slice("Abc"), "Abc") == 1
+ 685     # . prologue
+ 686     55/push-ebp
+ 687     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 688     # (eax..ecx) = "Abc"
+ 689     b8/copy-to-eax  "Abc"/imm32
+ 690     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+ 691     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
+ 692     05/add-to-eax  4/imm32
+ 693     # var slice/ecx: slice = {eax, ecx}
+ 694     51/push-ecx
+ 695     50/push-eax
+ 696     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 697     # eax = slice-starts-with?(ecx, "Abc")
+ 698     # . . push args
+ 699     68/push  "Abc"/imm32
+ 700     51/push-ecx
+ 701     # . . call
+ 702     e8/call  slice-starts-with?/disp32
+ 703     # . . discard args
+ 704     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 705     # check-ints-equal(eax, 1, msg)
+ 706     # . . push args
+ 707     68/push  "F - test-slice-starts-with-entire-string"/imm32
+ 708     68/push  1/imm32
+ 709     50/push-eax
+ 710     # . . call
+ 711     e8/call  check-ints-equal/disp32
+ 712     # . . discard args
+ 713     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 714     # . epilogue
+ 715     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 716     5d/pop-to-ebp
+ 717     c3/return
+ 718 
+ 719 test-slice-starts-with-fails:
+ 720     # - slice-starts-with?(slice("Abc"), "Abd") == 1
+ 721     # . prologue
+ 722     55/push-ebp
+ 723     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 724     # (eax..ecx) = "Abc"
+ 725     b8/copy-to-eax  "Abc"/imm32
+ 726     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+ 727     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
+ 728     05/add-to-eax  4/imm32
+ 729     # var slice/ecx: slice = {eax, ecx}
+ 730     51/push-ecx
+ 731     50/push-eax
+ 732     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 733     # eax = slice-starts-with?(ecx, "Abd")
+ 734     # . . push args
+ 735     68/push  "Abd"/imm32
+ 736     51/push-ecx
+ 737     # . . call
+ 738     e8/call  slice-starts-with?/disp32
+ 739     # . . discard args
+ 740     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 741     # check-ints-equal(eax, 0, msg)
+ 742     # . . push args
+ 743     68/push  "F - test-slice-starts-with-fails"/imm32
+ 744     68/push  0/imm32
+ 745     50/push-eax
+ 746     # . . call
+ 747     e8/call  check-ints-equal/disp32
+ 748     # . . discard args
+ 749     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 750     # . epilogue
+ 751     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 752     5d/pop-to-ebp
+ 753     c3/return
+ 754 
+ 755 test-slice-starts-with-fails-2:
+ 756     # - slice-starts-with?(slice("Abc"), "Ac") == 1
+ 757     # . prologue
+ 758     55/push-ebp
+ 759     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 760     # (eax..ecx) = "Abc"
+ 761     b8/copy-to-eax  "Abc"/imm32
+ 762     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+ 763     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
+ 764     05/add-to-eax  4/imm32
+ 765     # var slice/ecx: slice = {eax, ecx}
+ 766     51/push-ecx
+ 767     50/push-eax
+ 768     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 769     # eax = slice-starts-with?(ecx, "Ac")
+ 770     # . . push args
+ 771     68/push  "Ac"/imm32
+ 772     51/push-ecx
+ 773     # . . call
+ 774     e8/call  slice-starts-with?/disp32
+ 775     # . . discard args
+ 776     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 777     # check-ints-equal(eax, 0, msg)
+ 778     # . . push args
+ 779     68/push  "F - test-slice-starts-with-fails-2"/imm32
+ 780     68/push  0/imm32
+ 781     50/push-eax
+ 782     # . . call
+ 783     e8/call  check-ints-equal/disp32
+ 784     # . . discard args
+ 785     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 786     # . epilogue
+ 787     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 788     5d/pop-to-ebp
+ 789     c3/return
+ 790 
+ 791 # write a slice to a stream
+ 792 # abort if the stream doesn't have enough space
+ 793 write-slice:  # out: (addr stream byte), s: (addr slice)
+ 794     # . prologue
+ 795     55/push-ebp
+ 796     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 797     # . save registers
+ 798     50/push-eax
+ 799     51/push-ecx
+ 800     52/push-edx
+ 801     53/push-ebx
+ 802     56/push-esi
+ 803     57/push-edi
+ 804     # esi = s
+ 805     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
+ 806     # var curr/ecx: (addr byte) = s->start
+ 807     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
+ 808     # var max/esi: (addr byte) = s->end
+ 809     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           6/r32/esi   4/disp8         .                 # copy *(esi+4) to esi
+ 810     # edi = out
+ 811     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
+ 812     # edx = out->size
+ 813     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           2/r32/edx   8/disp8         .                 # copy *(edi+8) to edx
+ 814     # ebx = out->write
+ 815     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           3/r32/ebx   .               .                 # copy *edi to ebx
+ 816 $write-slice:loop:
+ 817     # if (curr >= max) break
+ 818     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           6/r32/esi   .               .                 # compare ecx with esi
+ 819     73/jump-if-addr>=  $write-slice:loop-end/disp8
+ 820     # if (out->write >= out->size) abort
+ 821     39/compare                      3/mod/direct    3/rm32/ebx    .           .             .           2/r32/edx   .               .                 # compare ebx with edx
+ 822     7d/jump-if->=  $write-slice:abort/disp8
+ 823     # out->data[out->write] = *in
+ 824     # . AL = *in
+ 825     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
+ 826     8a/copy-byte                    0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/AL    .               .                 # copy byte at *ecx to AL
+ 827     # . out->data[out->write] = AL
+ 828     88/copy-byte                    1/mod/*+disp8   4/rm32/sib    7/base/edi  3/index/ebx   .           0/r32/AL    0xc/disp8       .                 # copy AL to *(edi+ebx+12)
+ 829     # ++out->write
+ 830     43/increment-ebx
+ 831     # ++in
+ 832     41/increment-ecx
+ 833     eb/jump  $write-slice:loop/disp8
+ 834 $write-slice:loop-end:
+ 835     # persist out->write
+ 836     89/copy                         0/mod/indirect  7/rm32/edi    .           .             .           3/r32/ebx   .               .                 # copy ebx to *edi
+ 837 $write-slice:end:
+ 838     # . restore registers
+ 839     5f/pop-to-edi
+ 840     5e/pop-to-esi
+ 841     5b/pop-to-ebx
+ 842     5a/pop-to-edx
+ 843     59/pop-to-ecx
+ 844     58/pop-to-eax
+ 845     # . epilogue
+ 846     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 847     5d/pop-to-ebp
+ 848     c3/return
+ 849 
+ 850 $write-slice:abort:
+ 851     # . _write(2/stderr, error)
+ 852     # . . push args
+ 853     68/push  "write-slice: out of space"/imm32
+ 854     68/push  2/imm32/stderr
+ 855     # . . call
+ 856     e8/call  _write/disp32
+ 857     # . . discard args
+ 858     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 859     # . syscall(exit, 1)
+ 860     bb/copy-to-ebx  1/imm32
+ 861     e8/call  syscall_exit/disp32
+ 862     # never gets here
+ 863 
+ 864 test-write-slice:
+ 865     # . prologue
+ 866     55/push-ebp
+ 867     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 868     # setup
+ 869     # . clear-stream(_test-stream)
+ 870     # . . push args
+ 871     68/push  _test-stream/imm32
+ 872     # . . call
+ 873     e8/call  clear-stream/disp32
+ 874     # . . discard args
+ 875     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 876     # (eax..ecx) = "Abc"
+ 877     b8/copy-to-eax  "Abc"/imm32
+ 878     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+ 879     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
+ 880     05/add-to-eax  4/imm32
+ 881     # var slice/ecx: slice = {eax, ecx}
+ 882     51/push-ecx
+ 883     50/push-eax
+ 884     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 885     # write-slice(_test-stream, slice)
+ 886     # . . push args
+ 887     51/push-ecx
+ 888     68/push  _test-stream/imm32
+ 889     # . . call
+ 890     e8/call  write-slice/disp32
+ 891     # . . discard args
+ 892     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 893     # check-stream-equal(_test-stream, "Abc", msg)
+ 894     # . . push args
+ 895     68/push  "F - test-write-slice"/imm32
+ 896     68/push  "Abc"/imm32
+ 897     68/push  _test-stream/imm32
+ 898     # . . call
+ 899     e8/call  check-stream-equal/disp32
+ 900     # . . discard args
+ 901     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 902     # . epilogue
+ 903     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 904     5d/pop-to-ebp
+ 905     c3/return
+ 906 
+ 907 # write a slice to a buffered-file
+ 908 write-slice-buffered:  # out: (addr buffered-file), s: (addr slice)
+ 909     # . prologue
+ 910     55/push-ebp
+ 911     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 912     # . save registers
+ 913     50/push-eax
+ 914     51/push-ecx
+ 915     52/push-edx
+ 916     53/push-ebx
+ 917     56/push-esi
+ 918     57/push-edi
+ 919     # esi = s
+ 920     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
+ 921     # var curr/ecx: (addr byte) = s->start
+ 922     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
+ 923     # var max/esi: (addr byte) = s->end
+ 924     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           6/r32/esi   4/disp8         .                 # copy *(esi+4) to esi
+ 925     # edi = out
+ 926     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
+ 927     # edx = out->size
+ 928     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(edi+12) to edx
+ 929     # ebx = out->write
+ 930     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           3/r32/ebx   4/disp8         .                 # copy *(edi+4) to ebx
+ 931 $write-slice-buffered:loop:
+ 932     # if (curr >= max) break
+ 933     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           6/r32/esi   .               .                 # compare ecx with esi
+ 934     73/jump-if-addr>=  $write-slice-buffered:loop-end/disp8
+ 935     # if (out->write >= out->size) flush and clear out's stream
+ 936     39/compare                      3/mod/direct    3/rm32/ebx    .           .             .           2/r32/edx   .               .                 # compare ebx with edx
+ 937     7c/jump-if-<  $write-slice-buffered:to-stream/disp8
+ 938     # . persist out->write
+ 939     89/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           3/r32/ebx   4/disp8         .                 # copy ebx to *(edi+4)
+ 940     # . flush(out)
+ 941     # . . push args
+ 942     57/push-edi
+ 943     # . . call
+ 944     e8/call  flush/disp32
+ 945     # . . discard args
+ 946     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 947     # . clear-stream(stream = out+4)
+ 948     # . . push args
+ 949     8d/copy-address                 1/mod/*+disp8   7/rm32/edi    .           .             .           0/r32/eax   4/disp8         .                 # copy edi+4 to eax
+ 950     50/push-eax
+ 951     # . . call
+ 952     e8/call  clear-stream/disp32
+ 953     # . . discard args
+ 954     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 955     # . out->write must now be 0; update its cache at ebx
+ 956     31/xor                          3/mod/direct    3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # clear ebx
+ 957 $write-slice-buffered:to-stream:
+ 958     # out->data[out->write] = *in
+ 959     # . AL = *in
+ 960     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
+ 961     8a/copy-byte                    0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/AL    .               .                 # copy byte at *ecx to AL
+ 962     # . out->data[out->write] = AL
+ 963     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)
+ 964     # ++out->write
+ 965     43/increment-ebx
+ 966     # ++in
+ 967     41/increment-ecx
+ 968     eb/jump  $write-slice-buffered:loop/disp8
+ 969 $write-slice-buffered:loop-end:
+ 970     # persist necessary variables from registers
+ 971     89/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           3/r32/ebx   4/disp8         .                 # copy ebx to *(edi+4)
+ 972 $write-slice-buffered:end:
+ 973     # . restore registers
+ 974     5f/pop-to-edi
+ 975     5e/pop-to-esi
+ 976     5b/pop-to-ebx
+ 977     5a/pop-to-edx
+ 978     59/pop-to-ecx
+ 979     58/pop-to-eax
+ 980     # . epilogue
+ 981     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 982     5d/pop-to-ebp
+ 983     c3/return
+ 984 
+ 985 test-write-slice-buffered:
+ 986     # . prologue
+ 987     55/push-ebp
+ 988     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 989     # setup
+ 990     # . clear-stream(_test-stream)
+ 991     # . . push args
+ 992     68/push  _test-stream/imm32
+ 993     # . . call
+ 994     e8/call  clear-stream/disp32
+ 995     # . . discard args
+ 996     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 997     # . clear-stream($_test-buffered-file->buffer)
+ 998     # . . push args
+ 999     68/push  $_test-buffered-file->buffer/imm32
+1000     # . . call
+1001     e8/call  clear-stream/disp32
+1002     # . . discard args
+1003     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1004     # (eax..ecx) = "Abc"
+1005     b8/copy-to-eax  "Abc"/imm32
+1006     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+1007     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
+1008     05/add-to-eax  4/imm32
+1009     # var slice/ecx: slice = {eax, ecx}
+1010     51/push-ecx
+1011     50/push-eax
+1012     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+1013     # write-slice-buffered(_test-buffered-file, slice)
+1014     # . . push args
+1015     51/push-ecx
+1016     68/push  _test-buffered-file/imm32
+1017     # . . call
+1018     e8/call  write-slice-buffered/disp32
+1019     # . . discard args
+1020     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1021     # flush(_test-buffered-file)
+1022     # . . push args
+1023     68/push  _test-buffered-file/imm32
+1024     # . . call
+1025     e8/call  flush/disp32
+1026     # . . discard args
+1027     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1028     # check-stream-equal(_test-stream, "Abc", msg)
+1029     # . . push args
+1030     68/push  "F - test-write-slice-buffered"/imm32
+1031     68/push  "Abc"/imm32
+1032     68/push  _test-stream/imm32
+1033     # . . call
+1034     e8/call  check-stream-equal/disp32
+1035     # . . discard args
+1036     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1037     # . epilogue
+1038     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1039     5d/pop-to-ebp
+1040     c3/return
+1041 
+1042 # copy a slice into a new (dynamically allocated) string
+1043 slice-to-string:  # ad: (addr allocation-descriptor), in: (addr slice), out: (addr handle array byte)
+1044     # . prologue
+1045     55/push-ebp
+1046     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1047     # . save registers
+1048     50/push-eax
+1049     51/push-ecx
+1050     52/push-edx
+1051     53/push-ebx
+1052     56/push-esi
+1053     # esi = in
+1054     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
+1055     # var curr/edx: (addr byte) = in->start
+1056     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
+1057     # var max/ebx: (addr byte) = in->end
+1058     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           3/r32/ebx   4/disp8         .                 # copy *(esi+4) to ebx
+1059     # var size/ecx: int = max - curr + 4  # total size of output string (including the initial 'size' field)
+1060     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           3/r32/ebx   .               .                 # copy ebx to ecx
+1061     29/subtract                     3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # subtract edx from ecx
+1062     81          0/subop/add         3/mod/direct    1/rm32/ecx    .           .             .           .           .               4/imm32           # add to ecx
+1063     # allocate(ad, size, out)
+1064     # . . push args
+1065     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+1066     51/push-ecx
+1067     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+1068     # . . call
+1069     e8/call  allocate/disp32
+1070     # . . discard args
+1071     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1072     # eax = out->payload
+1073     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0x10/disp8      .                 # copy *(ebp+16) to eax
+1074     8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           0/r32/eax   4/disp8         .                 # copy *(eax+4) to eax
+1075     # skip payload->allocid
+1076     05/add-to-eax  4/imm32
+1077     # if (eax == 0) abort
+1078     3d/compare-eax-and  0/imm32
+1079     74/jump-if-=  $slice-to-string:abort/disp8
+1080     # out->size = size-4
+1081     89/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy ecx to *eax
+1082     81          5/subop/subtract    0/mod/indirect  0/rm32/eax    .           .             .           .           .               4/imm32           # subtract 4 from *eax
+1083     # save out
+1084     50/push-eax
+1085 $slice-to-string:initialize:
+1086     # eax = _append-4(eax+4, eax+size, curr, max)  # clobbering ecx
+1087     # . . push args
+1088     53/push-ebx
+1089     52/push-edx
+1090     # . . push eax+size (clobbering ecx)
+1091     01/add                          3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # add eax to ecx
+1092     51/push-ecx
+1093     # . . push eax+4 (clobbering eax)
+1094     81          0/subop/add         3/mod/direct    0/rm32/eax    .           .             .           .           .               4/imm32           # add to eax
+1095     50/push-eax
+1096     # . . call
+1097     e8/call  _append-4/disp32
+1098     # . . discard args
+1099     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+1100     # restore out (assumes _append-4 can't error)
+1101     58/pop-to-eax
+1102 $slice-to-string:end:
+1103     # . restore registers
+1104     5e/pop-to-esi
+1105     5b/pop-to-ebx
+1106     5a/pop-to-edx
+1107     59/pop-to-ecx
+1108     58/pop-to-eax
+1109     # . epilogue
+1110     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1111     5d/pop-to-ebp
+1112     c3/return
+1113 
+1114 $slice-to-string:abort:
+1115     # . _write(2/stderr, error)
+1116     # . . push args
+1117     68/push  "slice-to-string: out of space\n"/imm32
+1118     68/push  2/imm32/stderr
+1119     # . . call
+1120     e8/call  _write/disp32
+1121     # . . discard args
+1122     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1123     # . syscall(exit, 1)
+1124     bb/copy-to-ebx  1/imm32
+1125     e8/call  syscall_exit/disp32
+1126     # never gets here
+1127 
+1128 test-slice-to-string:
+1129     # . prologue
+1130     55/push-ebp
+1131     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1132     # var heap/edx: allocation-descriptor
+1133     68/push  0/imm32/limit
+1134     68/push  0/imm32/curr
+1135     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
+1136     # heap = new-segment(512)
+1137     # . . push args
+1138     52/push-edx
+1139     68/push  0x200/imm32
+1140     # . . call
+1141     e8/call  new-segment/disp32
+1142     # . . discard args
+1143     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1144     # (eax..ecx) = "Abc"
+1145     b8/copy-to-eax  "Abc"/imm32
+1146     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+1147     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
+1148     05/add-to-eax  4/imm32
+1149     # var slice/ecx: slice = {eax, ecx}
+1150     51/push-ecx
+1151     50/push-eax
+1152     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+1153     # var h/ebx: (handle array byte)
+1154     68/push  0/imm32
+1155     68/push  0/imm32
+1156     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           4/r32/esp   .               .                 # copy esp to ebx
+1157     # slice-to-string(heap, slice, h)
+1158     # . . push args
+1159     53/push-ebx
+1160     51/push-ecx
+1161     52/push-edx
+1162     # . . call
+1163     e8/call  slice-to-string/disp32
+1164     # . . discard args
+1165     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1166     # eax = h->payload
+1167     8b/copy                         1/mod/*+disp8   3/rm32/ebx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(ebx+4) to eax
+1168     # skip payload->allocid
+1169     05/add-to-eax  4/imm32
+1170 +-- 26 lines: #?     # dump eax ---------------------------------------------------------------------------------------------------------------------------------------------------------
+1196     # eax = string-equal?(eax, "Abc")
+1197     # . . push args
+1198     68/push  "Abc"/imm32
+1199     50/push-eax
+1200     # . . call
+1201     e8/call  string-equal?/disp32
+1202     # . . discard args
+1203     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1204     # check-ints-equal(eax, 1, msg)
+1205     # . . push args
+1206     68/push  "F - test-slice-to-string"/imm32
+1207     68/push  1/imm32/true
+1208     50/push-eax
+1209     # . . call
+1210     e8/call  check-ints-equal/disp32
+1211     # . . discard args
+1212     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1213     # . reclaim locals
+1214     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x18/imm32        # add to esp
+1215     # . epilogue
+1216     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1217     5d/pop-to-ebp
+1218     c3/return
+1219 
+1220 # . . vim:nowrap:textwidth=0
+
+ + + -- cgit 1.4.1-2-gfad0