https://github.com/akkartik/mu/blob/main/310copy-bytes.subx

      1 # Some helpers for copying non-overlapping regions of memory.
      2 # Really only intended to be called from code generated by mu.subx.
      3
      4 == code
      5
      6 copy-bytes:  # src: (addr byte), dest: (addr byte), size: int
      7     # pseudocode:
      8     #   curr-src/esi = src
      9     #   curr-dest/edi = dest
     10     #   i/ecx = 0
     11     #   while true
     12     #     if (i >= size) break
     13     #     *curr-dest = *curr-src
     14     #     ++curr-src
     15     #     ++curr-dest
     16     #     ++i
     17     #
     18     # . prologue
     19     55/push-ebp
     20     89/<- %ebp 4/r32/esp
     21     # . save registers
     22     50/push-eax
     23     51/push-ecx
     24     52/push-edx
     25     56/push-esi
     26     57/push-edi
     27     # curr-src/esi = src
     28     8b/-> *(ebp+8) 6/r32/esi
     29     # curr-dest/edi = dest
     30     8b/-> *(ebp+0xc) 7/r32/edi
     31     # var i/ecx: int = 0
     32     b9/copy-to-ecx 0/imm32
     33     # edx = size
     34     8b/-> *(ebp+0x10) 2/r32/edx
     35     {
     36       # if (i >= size) break
     37       39/compare %ecx 2/r32/edx
     38       7d/jump-if->=  break/disp8
     39       # *curr-dest = *curr-src
     40       8a/byte-> *esi 0/r32/AL
     41       88/byte<- *edi 0/r32/AL
     42       # update
     43       46/increment-esi
     44       47/increment-edi
     45       41/increment-ecx
     46       eb/jump loop/disp8
     47     }
     48 $copy-bytes:end:
     49     # . restore registers
     50     5f/pop-to-edi
     51     5e/pop-to-esi
     52     5a/pop-to-edx
     53     59/pop-to-ecx
     54     58/pop-to-eax
     55     # . epilogue
     56     89/<- %esp 5/r32/ebp
     57     5d/pop-to-ebp
     58     c3/return
     59
     60 stream-to-array:  # in: (addr stream _), out: (addr handle array _)
     61     # . prologue
     62     55/push-ebp
     63     89/<- %ebp 4/r32/esp
     64     # . save registers
     65     50/push-eax
     66     51/push-ecx
     67     52/push-edx
     68     56/push-esi
     69     # esi = s
     70     8b/-> *(ebp+8) 6/r32/esi
     71     # var len/ecx: int = s->write - s->read
     72     8b/-> *esi 1/r32/ecx
     73     2b/subtract *(esi+4) 1/r32/ecx
     74     # allocate
     75     (allocate-array Heap %ecx *(ebp+0xc))
     76     # var in/edx: (addr byte) = s->data + s->read
     77     8b/-> *(esi+4) 2/r32/edx
     78     8d/copy-address *(esi+edx+0xc) 2/r32/edx
     79     # var dest/eax: (addr byte) = data for out
     80     8b/-> *(ebp+0xc) 0/r32/eax
     81     (lookup *eax *(eax+4))  # => eax
     82     8d/copy-address *(eax+4) 0/r32/eax
     83     #
     84     (copy-bytes %edx %eax %ecx)
     85 $stream-to-array:end:
     86     # . restore registers
     87     5e/pop-to-esi
     88     5a/pop-to-edx
     89     59/pop-to-ecx
     90     58/pop-to-eax
     91     # . epilogue
     92     89/<- %esp 5/r32/ebp
     93     5d/pop-to-ebp
     94     c3/return
     95
     96 test-stream-to-array:
     97     # . prologue
     98     55/push-ebp
     99     89/<- %ebp 4/r32/esp
    100     # setup
    101     (clear-stream _test-input-stream)
    102     (write _test-input-stream "abc")
    103     # skip something
    104     (read-byte _test-input-stream)  # => eax
    105     8b/-> *$_test-input-stream->read 0/r32/eax
    106     (check-ints-equal %eax 1 "F - test-stream-to-array/pre")
    107     # var out/ecx: (handle array byte)
    108     68/push 0/imm32
    109     68/push 0/imm32
    110     89/<- %ecx 4/r32/esp
    111     #
    112     (stream-to-array _test-input-stream %ecx)
    113     (lookup *ecx *(ecx+4))  # => eax
    114     (check-strings-equal %eax "bc" "F - test-stream-to-array")
    115     8b/-> *$_test-input-stream->read 0/r32/eax
    116     (check-ints-equal %eax 1 "F - test-stream-to-array/read-pointer-not-perturbed")
    117     # . epilogue
    118     89/<- %esp 5/r32/ebp
    119     5d/pop-to-ebp
    120     c3/return
    121
    122 # like stream-to-array but ignore surrounding quotes
    123 # we might do other stuff here later
    124 unquote-stream-to-array:  # in: (addr stream _), out: (addr handle array _)
    125     # . prologue
    126     55/push-ebp
    127     89/<- %ebp 4/r32/esp
    128     # . save registers
    129     50/push-eax
    130     51/push-ecx
    131     52/push-edx
    132     56/push-esi
    133     # esi = s
    134     8b/-> *(ebp+8) 6/r32/esi
    135     # var len/ecx: int = s->write - s->read - 2
    136     8b/-> *esi 1/r32/ecx
    137     2b/subtract *(esi+4) 1/r32/ecx
    138     81 7/subop/compare %ecx 2/imm32
    139     7c/jump-if-< $unquote-stream-to-array:end/disp8
    140     81 5/subop/subtract %ecx 2/imm32
    141     # allocate
    142     (allocate-array Heap %ecx *(ebp+0xc))
    143     # var in/edx: (addr byte) = s->data + s->read + 1
    144     8b/-> *(esi+4) 2/r32/edx
    145     8d/copy-address *(esi+edx+0xd) 2/r32/edx  # Stream-data + 1
    146     # var dest/eax: (addr byte) = data for out
    147     8b/-> *(ebp+0xc) 0/r32/eax
    148     (lookup *eax *(eax+4))  # => eax
    149     8d/copy-address *(eax+4) 0/r32/eax
    150     #
    151     (copy-bytes %edx %eax %ecx)
    152 $unquote-stream-to-array:end:
    153     # . restore registers
    154     5e/pop-to-esi
    155     5a/pop-to-edx
    156     59/pop-to-ecx
    157     58/pop-to-eax
    158     # . epilogue
    159     89/<- %esp 5/r32/ebp
    160     5d/pop-to-ebp
    161     c3/return