https://github.com/akkartik/mu/blob/main/309stream.subx
  1 # Some unsafe methods not intended to be used directly in SubX, only through
  2 # Mu after proper type-checking.
  3 
  4 == code
  5 
  6 stream-empty?:  # s: (addr stream _) -> result/eax: boolean
  7     # . prologue
  8     55/push-ebp
  9     89/<- %ebp 4/r32/esp
 10     # . save registers
 11     51/push-ecx
 12     56/push-esi
 13     # result = false
 14     b8/copy-to-eax 0/imm32/false
 15     # esi = s
 16     8b/-> *(ebp+8) 6/r32/esi
 17     # return s->read >= s->write
 18     8b/-> *esi 1/r32/ecx
 19     39/compare-with *(esi+4) 1/r32/ecx
 20     0f 9d/set-if->= %al
 21 $stream-empty?:end:
 22     # . restore registers
 23     5e/pop-to-esi
 24     59/pop-to-ecx
 25     # . epilogue
 26     89/<- %esp 5/r32/ebp
 27     5d/pop-to-ebp
 28     c3/return
 29 
 30 stream-full?:  # s: (addr stream _) -> result/eax: boolean
 31     # . prologue
 32     55/push-ebp
 33     89/<- %ebp 4/r32/esp
 34     # . save registers
 35     51/push-ecx
 36     56/push-esi
 37     # result = false
 38     b8/copy-to-eax 0/imm32/false
 39     # esi = s
 40     8b/-> *(ebp+8) 6/r32/esi
 41     # return s->write >= s->size
 42     8b/-> *(esi+8) 1/r32/ecx
 43     39/compare-with *esi 1/r32/ecx
 44     0f 9d/set-if->= %al
 45 $stream-full?:end:
 46     # . restore registers
 47     5e/pop-to-esi
 48     59/pop-to-ecx
 49     # . epilogue
 50     89/<- %esp 5/r32/ebp
 51     5d/pop-to-ebp
 52     c3/return
 53 
 54 write-to-stream:  # s: (addr stream _), in: (addr byte), n: int
 55     # . prologue
 56     55/push-ebp
 57     89/<- %ebp 4/r32/esp
 58     # . save registers
 59     50/push-eax
 60     51/push-ecx
 61     52/push-edx
 62     53/push-ebx
 63     57/push-edi
 64     # edi = s
 65     8b/-> *(ebp+8) 7/r32/edi
 66     # var swrite/edx: int = s->write
 67     8b/-> *edi 2/r32/edx
 68     # if (swrite + n > s->size) abort
 69     8b/-> *(ebp+0x10) 1/r32/ecx
 70     01/add-to %ecx 2/r32/edx
 71     3b/compare 1/r32/ecx *(edi+8)
 72     0f 8f/jump-if-> $write-to-stream:abort/disp32
 73     # var out/edx: (addr byte) = s->data + s->write
 74     8d/copy-address *(edi+edx+0xc) 2/r32/edx
 75     # var outend/ebx: (addr byte) = out + n
 76     8b/-> *(ebp+0x10) 3/r32/ebx
 77     8d/copy-address *(edx+ebx) 3/r32/ebx
 78     # eax = in
 79     8b/-> *(ebp+0xc) 0/r32/eax
 80     # var inend/ecx: (addr byte) = in + n
 81     8b/-> *(ebp+0x10) 1/r32/ecx
 82     8d/copy-address *(eax+ecx) 1/r32/ecx
 83     #
 84     (_append-4  %edx %ebx  %eax %ecx)  # => eax
 85     # s->write += n
 86     8b/-> *(ebp+0x10) 1/r32/ecx
 87     01/add-to *edi 1/r32/ecx
 88 $write-to-stream:end:
 89     # . restore registers
 90     5f/pop-to-edi
 91     5b/pop-to-ebx
 92     5a/pop-to-edx
 93     59/pop-to-ecx
 94     58/pop-to-eax
 95     # . epilogue
 96     89/<- %esp 5/r32/ebp
 97     5d/pop-to-ebp
 98     c3/return
 99 
100 $write-to-stream:abort:
101     (abort "write-to-stream: stream full")
102     # never gets here
103 
104 read-from-stream:  # s: (addr stream _), out: (addr byte), n: int
105     # . prologue
106     55/push-ebp
107     89/<- %ebp 4/r32/esp
108     # . save registers
109     50/push-eax
110     51/push-ecx
111     52/push-edx
112     53/push-ebx
113     56/push-esi
114     # esi = s
115     8b/-> *(ebp+8) 6/r32/esi
116     # var sread/edx: int = s->read
117     8b/-> *(esi+4) 2/r32/edx
118     # if (sread + n > s->write) abort
119     8b/-> *(ebp+0x10) 1/r32/ecx
120     01/add-to %ecx 2/r32/edx
121     3b/compare 1/r32/ecx *esi
122     0f 8f/jump-if-> $read-from-stream:abort/disp32
123     # var in/edx: (addr byte) = s->data + s->read
124     8d/copy-address *(esi+edx+0xc) 2/r32/edx
125     # var inend/ebx: (addr byte) = in + n
126     8b/-> *(ebp+0x10) 3/r32/ebx
127     8d/copy-address *(edx+ebx) 3/r32/ebx
128     # eax = out
129     8b/-> *(ebp+0xc) 0/r32/eax
130     # var outend/ecx: (addr byte) = out + n
131     8b/-> *(ebp+0x10) 1/r32/ecx
132     8d/copy-address *(eax+ecx) 1/r32/ecx
133     #
134     (_append-4  %eax %ecx  %edx %ebx)  # => eax
135     # s->read += n
136     8b/-> *(ebp+0x10) 1/r32/ecx
137     01/add-to *(esi+4) 1/r32/ecx
138 $read-from-stream:end:
139     # . restore registers
140     5e/pop-to-esi
141     5b/pop-to-ebx
142     5a/pop-to-edx
143     59/pop-to-ecx
144     58/pop-to-eax
145     # . epilogue
146     89/<- %esp 5/r32/ebp
147     5d/pop-to-ebp
148     c3/return
149 
150 $read-from-stream:abort:
151     (abort "read-from-stream: stream empty")
152     # never gets here
153 
154 stream-first:  # s: (addr stream byte) -> result/eax: byte
155     # . prologue
156     55/push-ebp
157     89/<- %ebp 4/r32/esp
158     # . save registers
159     51/push-ecx
160     56/push-esi
161     # result = false
162     b8/copy-to-eax 0/imm32
163     # esi = s
164     8b/-> *(ebp+8) 6/r32/esi
165     # var idx/ecx: int = s->read
166     8b/-> *(esi+4) 1/r32/ecx
167     # if idx >= s->write return 0
168     3b/compare-with 1/r32/ecx *esi
169     7d/jump-if->= $stream-first:end/disp8
170     # result = s->data[idx]
171     8a/byte-> *(esi+ecx+0xc) 0/r32/AL
172 $stream-first:end:
173     # . restore registers
174     5e/pop-to-esi
175     59/pop-to-ecx
176     # . epilogue
177     89/<- %esp 5/r32/ebp
178     5d/pop-to-ebp
179     c3/return
180 
181 stream-final:  # s: (addr stream byte) -> result/eax: byte
182     # . prologue
183     55/push-ebp
184     89/<- %ebp 4/r32/esp
185     # . save registers
186     51/push-ecx
187     56/push-esi
188     # result = false
189     b8/copy-to-eax 0/imm32
190     # esi = s
191     8b/-> *(ebp+8) 6/r32/esi
192     # var max/ecx: int = s->write
193     8b/-> *esi 1/r32/ecx
194     # if s->read >= max return 0
195     39/compare-with *(esi+4) 1/r32/ecx
196     7d/jump-if->= $stream-final:end/disp8
197     # var idx/ecx: int = max - 1
198     49/decrement-ecx
199     # result = s->data[idx]
200     8a/byte-> *(esi+ecx+0xc) 0/r32/AL
201 $stream-final:end:
202     # . restore registers
203     5e/pop-to-esi
204     59/pop-to-ecx
205     # . epilogue
206     89/<- %esp 5/r32/ebp
207     5d/pop-to-ebp
208     c3/return
209 
210 # compare all the data in two streams (ignoring the read pointer)
211 streams-data-equal?:  # a: (addr stream byte), b: (addr array byte) -> result/eax: boolean
212     # pseudocode:
213     #   awrite = a->write
214     #   if (awrite != b->write) return false
215     #   i = 0
216     #   curra = a->data
217     #   currb = b->data
218     #   while i < awrite
219     #     i1 = *curra
220     #     i2 = *currb
221     #     if (c1 != c2) return false
222     #     i+=4, curra+=4, currb+=4
223     #   return true
224     #
225     # registers:
226     #   i: ecx
227     #   awrite: edx
228     #   curra: esi
229     #   currb: edi
230     #   i1: eax
231     #   i2: ebx
232     #
233     # . prologue
234     55/push-ebp
235     89/<- %ebp 4/r32/esp
236     # . save registers
237     51/push-ecx
238     52/push-edx
239     53/push-ebx
240     56/push-esi
241     57/push-edi
242     # esi = a
243     8b/-> *(ebp+8) 6/r32/esi
244     # edi = b
245     8b/-> *(ebp+0xc) 7/r32/edi
246     # var awrite/edx: int = a->write
247     8b/-> *esi 2/r32/edx
248 $streams-data-equal?:sizes:
249     # if (awrite != b->write) return false
250     39/compare *edi 2/r32/edx
251     75/jump-if-!= $streams-data-equal?:false/disp8
252     # var curra/esi: (addr byte) = a->data
253     81 0/subop/add %esi 0xc/imm32
254     # var currb/edi: (addr byte) = b->data
255     81 0/subop/add %edi 0xc/imm32
256     # var i/ecx: int = 0
257     31/xor-with %ecx 1/r32/ecx
258     # var vala/eax: int
259     31/xor-with %eax 0/r32/eax
260     # var valb/ebx: int
261     31/xor-with %ebx 3/r32/ebx
262 $streams-data-equal?:loop:
263     {
264       # if (i >= awrite) return true
265       39/compare %ecx 2/r32/edx
266       7d/jump-if->= $streams-data-equal?:true/disp8
267       # var vala/eax: int = *curra
268       8a/byte-> *esi 0/r32/eax
269       # var valb/ebx: int = *currb
270       8a/byte-> *edi 3/r32/ebx
271       # if (vala != valb) return false
272       39/compare %eax 3/r32/ebx
273       75/jump-if-!= $streams-data-equal?:false/disp8
274       # i++
275       41/increment-ecx
276       # curra++
277       46/increment-esi
278       # currb++
279       47/increment-edi
280       eb/jump loop/disp8
281     }
282 $streams-data-equal?:true:
283     b8/copy-to-eax 1/imm32
284     eb/jump $streams-data-equal?:end/disp8
285 $streams-data-equal?:false:
286     b8/copy-to-eax 0/imm32
287 $streams-data-equal?:end:
288     # . restore registers
289     5f/pop-to-edi
290     5e/pop-to-esi
291     5b/pop-to-ebx
292     5a/pop-to-edx
293     59/pop-to-ecx
294     # . epilogue
295     89/<- %esp 5/r32/ebp
296     5d/pop-to-ebp
297     c3/return
298 
299 # helper for tests
300 check-streams-data-equal:  # s: (addr stream _), expected: (addr array _), msg: (addr array byte)
301     # . prologue
302     55/push-ebp
303     89/<- %ebp 4/r32/esp
304     # . save registers
305     50/push-eax
306     #
307     (streams-data-equal? *(ebp+8) *(ebp+0xc))  # => eax
308     (check-ints-equal %eax 1 *(ebp+0x10))
309 $check-streams-data-equal:end:
310     # . restore registers
311     58/pop-to-eax
312     # . epilogue
313     89/<- %esp 5/r32/ebp
314     5d/pop-to-ebp
315     c3/return