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     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "write-to-stream: stream full" 3 0)  # 3=cyan
102     {
103       eb/jump loop/disp8
104     }
105     # never gets here
106 
107 read-from-stream:  # s: (addr stream _), out: (addr byte), n: int
108     # . prologue
109     55/push-ebp
110     89/<- %ebp 4/r32/esp
111     # . save registers
112     50/push-eax
113     51/push-ecx
114     52/push-edx
115     53/push-ebx
116     56/push-esi
117     # esi = s
118     8b/-> *(ebp+8) 6/r32/esi
119     # var sread/edx: int = s->read
120     8b/-> *(esi+4) 2/r32/edx
121     # if (sread + n > s->write) abort
122     8b/-> *(ebp+0x10) 1/r32/ecx
123     01/add-to %ecx 2/r32/edx
124     3b/compare 1/r32/ecx *esi
125     0f 8f/jump-if-> $read-from-stream:abort/disp32
126     # var in/edx: (addr byte) = s->data + s->read
127     8d/copy-address *(esi+edx+0xc) 2/r32/edx
128     # var inend/ebx: (addr byte) = in + n
129     8b/-> *(ebp+0x10) 3/r32/ebx
130     8d/copy-address *(edx+ebx) 3/r32/ebx
131     # eax = out
132     8b/-> *(ebp+0xc) 0/r32/eax
133     # var outend/ecx: (addr byte) = out + n
134     8b/-> *(ebp+0x10) 1/r32/ecx
135     8d/copy-address *(eax+ecx) 1/r32/ecx
136     #
137     (_append-4  %eax %ecx  %edx %ebx)  # => eax
138     # s->read += n
139     8b/-> *(ebp+0x10) 1/r32/ecx
140     01/add-to *(esi+4) 1/r32/ecx
141 $read-from-stream:end:
142     # . restore registers
143     5e/pop-to-esi
144     5b/pop-to-ebx
145     5a/pop-to-edx
146     59/pop-to-ecx
147     58/pop-to-eax
148     # . epilogue
149     89/<- %esp 5/r32/ebp
150     5d/pop-to-ebp
151     c3/return
152 
153 $read-from-stream:abort:
154     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "read-from-stream: stream empty" 3 0)  # 3=cyan
155     {
156       eb/jump loop/disp8
157     }
158     # never gets here
159 
160 stream-first:  # s: (addr stream byte) -> result/eax: byte
161     # . prologue
162     55/push-ebp
163     89/<- %ebp 4/r32/esp
164     # . save registers
165     51/push-ecx
166     56/push-esi
167     # result = false
168     b8/copy-to-eax 0/imm32
169     # esi = s
170     8b/-> *(ebp+8) 6/r32/esi
171     # var idx/ecx: int = s->read
172     8b/-> *(esi+4) 1/r32/ecx
173     # if idx >= s->write return 0
174     3b/compare-with 1/r32/ecx *esi
175     7d/jump-if->= $stream-first:end/disp8
176     # result = s->data[idx]
177     8a/byte-> *(esi+ecx+0xc) 0/r32/AL
178 $stream-first:end:
179     # . restore registers
180     5e/pop-to-esi
181     59/pop-to-ecx
182     # . epilogue
183     89/<- %esp 5/r32/ebp
184     5d/pop-to-ebp
185     c3/return
186 
187 stream-final:  # s: (addr stream byte) -> result/eax: byte
188     # . prologue
189     55/push-ebp
190     89/<- %ebp 4/r32/esp
191     # . save registers
192     51/push-ecx
193     56/push-esi
194     # result = false
195     b8/copy-to-eax 0/imm32
196     # esi = s
197     8b/-> *(ebp+8) 6/r32/esi
198     # var max/ecx: int = s->write
199     8b/-> *esi 1/r32/ecx
200     # if s->read >= max return 0
201     39/compare-with *(esi+4) 1/r32/ecx
202     7d/jump-if->= $stream-final:end/disp8
203     # var idx/ecx: int = max - 1
204     49/decrement-ecx
205     # result = s->data[idx]
206     8a/byte-> *(esi+ecx+0xc) 0/r32/AL
207 $stream-final:end:
208     # . restore registers
209     5e/pop-to-esi
210     59/pop-to-ecx
211     # . epilogue
212     89/<- %esp 5/r32/ebp
213     5d/pop-to-ebp
214     c3/return
215 
216 # compare all the data in two streams (ignoring the read pointer)
217 streams-data-equal?:  # f: (addr stream byte), s: (addr array byte) -> result/eax: boolean
218     # pseudocode:
219     #   awrite = a->write
220     #   if (awrite != b->write) return false
221     #   i = 0
222     #   curra = a->data
223     #   currb = b->data
224     #   while i < awrite
225     #     i1 = *curra
226     #     i2 = *currb
227     #     if (c1 != c2) return false
228     #     i+=4, curra+=4, currb+=4
229     #   return true
230     #
231     # registers:
232     #   i: ecx
233     #   awrite: edx
234     #   curra: esi
235     #   currb: edi
236     #   i1: eax
237     #   i2: ebx
238     #
239     # . prologue
240     55/push-ebp
241     89/<- %ebp 4/r32/esp
242     # . save registers
243     51/push-ecx
244     52/push-edx
245     53/push-ebx
246     56/push-esi
247     57/push-edi
248     # esi = a
249     8b/-> *(ebp+8) 6/r32/esi
250     # edi = b
251     8b/-> *(ebp+0xc) 7/r32/edi
252     # var awrite/edx: int = a->write
253     8b/-> *esi 2/r32/edx
254 $streams-data-equal?:sizes:
255     # if (awrite != b->write) return false
256     39/compare *edi 2/r32/edx
257     75/jump-if-!= $streams-data-equal?:false/disp8
258     # var curra/esi: (addr byte) = a->data
259     81 0/subop/add %esi 0xc/imm32
260     # var currb/edi: (addr byte) = b->data
261     81 0/subop/add %edi 0xc/imm32
262     # var i/ecx: int = 0
263     31/xor-with %ecx 1/r32/ecx
264     # var vala/eax: int
265     31/xor-with %eax 0/r32/eax
266     # var valb/ebx: int
267     31/xor-with %ebx 3/r32/ebx
268 $streams-data-equal?:loop:
269     {
270       # if (i >= awrite) return true
271       39/compare %ecx 2/r32/edx
272       7d/jump-if->= $streams-data-equal?:true/disp8
273       # var vala/eax: int = *curra
274       8a/byte-> *esi 0/r32/eax
275       # var valb/ebx: int = *currb
276       8a/byte-> *edi 3/r32/ebx
277       # if (vala != valb) return false
278       39/compare %eax 3/r32/ebx
279       75/jump-if-!= $streams-data-equal?:false/disp8
280       # i++
281       41/increment-ecx
282       # curra++
283       46/increment-esi
284       # currb++
285       47/increment-edi
286       eb/jump loop/disp8
287     }
288 $streams-data-equal?:true:
289     b8/copy-to-eax 1/imm32
290     eb/jump $streams-data-equal?:end/disp8
291 $streams-data-equal?:false:
292     b8/copy-to-eax 0/imm32
293 $streams-data-equal?:end:
294     # . restore registers
295     5f/pop-to-edi
296     5e/pop-to-esi
297     5b/pop-to-ebx
298     5a/pop-to-edx
299     59/pop-to-ecx
300     # . epilogue
301     89/<- %esp 5/r32/ebp
302     5d/pop-to-ebp
303     c3/return