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     # var out/ecx: (handle array byte)
106     68/push 0/imm32
107     68/push 0/imm32
108     89/<- %ecx 4/r32/esp
109     #
110     (stream-to-array _test-input-stream %ecx)
111     (lookup *ecx *(ecx+4))  # => eax
112     (check-strings-equal %eax "bc")
113     # . epilogue
114     89/<- %esp 5/r32/ebp
115     5d/pop-to-ebp
116     c3/return
117 
118 # like stream-to-array but ignore surrounding quotes
119 # we might do other stuff here later
120 unquote-stream-to-array:  # in: (addr stream _), out: (addr handle array _)
121     # . prologue
122     55/push-ebp
123     89/<- %ebp 4/r32/esp
124     # . save registers
125     50/push-eax
126     51/push-ecx
127     52/push-edx
128     56/push-esi
129     # esi = s
130     8b/-> *(ebp+8) 6/r32/esi
131     # var len/ecx: int = s->write - s->read - 2
132     8b/-> *esi 1/r32/ecx
133     2b/subtract *(esi+4) 1/r32/ecx
134     81 7/subop/compare %ecx 2/imm32
135     7c/jump-if-< $unquote-stream-to-array:end/disp8
136     81 5/subop/subtract %ecx 2/imm32
137     # allocate
138     (allocate-array Heap %ecx *(ebp+0xc))
139     # var in/edx: (addr byte) = s->data + s->read + 1
140     8b/-> *(esi+4) 2/r32/edx
141     8d/copy-address *(esi+edx+0xd) 2/r32/edx  # Stream-data + 1
142     # var dest/eax: (addr byte) = data for out
143     8b/-> *(ebp+0xc) 0/r32/eax
144     (lookup *eax *(eax+4))  # => eax
145     8d/copy-address *(eax+4) 0/r32/eax
146     #
147     (copy-bytes %edx %eax %ecx)
148 $unquote-stream-to-array:end:
149     # . restore registers
150     5e/pop-to-esi
151     5a/pop-to-edx
152     59/pop-to-ecx
153     58/pop-to-eax
154     # . epilogue
155     89/<- %esp 5/r32/ebp
156     5d/pop-to-ebp
157     c3/return