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