# Some unsafe methods not intended to be used directly in SubX, only through
# Mu after proper type-checking.
== code
stream-empty?: # s: (addr stream _) -> result/eax: boolean
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
56/push-esi
# result = false
b8/copy-to-eax 0/imm32/false
# esi = s
8b/-> *(ebp+8) 6/r32/esi
# return s->read >= s->write
8b/-> *esi 1/r32/ecx
39/compare-with *(esi+4) 1/r32/ecx
0f 9d/set-if->= %al
$stream-empty?:end:
# . restore registers
5e/pop-to-esi
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
stream-full?: # s: (addr stream _) -> result/eax: boolean
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
56/push-esi
# result = false
b8/copy-to-eax 0/imm32/false
# esi = s
8b/-> *(ebp+8) 6/r32/esi
# return s->write >= s->size
8b/-> *(esi+8) 1/r32/ecx
39/compare-with *esi 1/r32/ecx
0f 9d/set-if->= %al
$stream-full?:end:
# . restore registers
5e/pop-to-esi
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
write-to-stream: # s: (addr stream _), in: (addr byte), n: int
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
51/push-ecx
52/push-edx
53/push-ebx
57/push-edi
# edi = s
8b/-> *(ebp+8) 7/r32/edi
# var swrite/edx: int = s->write
8b/-> *edi 2/r32/edx
# if (swrite + n > s->size) abort
8b/-> *(ebp+0x10) 1/r32/ecx
01/add-to %ecx 2/r32/edx
3b/compare 1/r32/ecx *(edi+8)
0f 8f/jump-if-> $write-to-stream:abort/disp32
# var out/edx: (addr byte) = s->data + s->write
8d/copy-address *(edi+edx+0xc) 2/r32/edx
# var outend/ebx: (addr byte) = out + n
8b/-> *(ebp+0x10) 3/r32/ebx
8d/copy-address *(edx+ebx) 3/r32/ebx
# eax = in
8b/-> *(ebp+0xc) 0/r32/eax
# var inend/ecx: (addr byte) = in + n
8b/-> *(ebp+0x10) 1/r32/ecx
8d/copy-address *(eax+ecx) 1/r32/ecx
#
(_append-4 %edx %ebx %eax %ecx) # => eax
# s->write += n
8b/-> *(ebp+0x10) 1/r32/ecx
01/add-to *edi 1/r32/ecx
$write-to-stream:end:
# . restore registers
5f/pop-to-edi
5b/pop-to-ebx
5a/pop-to-edx
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
$write-to-stream:abort:
(abort "write-to-stream: stream full")
# never gets here
read-from-stream: # s: (addr stream _), out: (addr byte), n: int
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
51/push-ecx
52/push-edx
53/push-ebx
56/push-esi
# esi = s
8b/-> *(ebp+8) 6/r32/esi
# var sread/edx: int = s->read
8b/-> *(esi+4) 2/r32/edx
# if (sread + n > s->write) abort
8b/-> *(ebp+0x10) 1/r32/ecx
01/add-to %ecx 2/r32/edx
3b/compare 1/r32/ecx *esi
0f 8f/jump-if-> $read-from-stream:abort/disp32
# var in/edx: (addr byte) = s->data + s->read
8d/copy-address *(esi+edx+0xc) 2/r32/edx
# var inend/ebx: (addr byte) = in + n
8b/-> *(ebp+0x10) 3/r32/ebx
8d/copy-address *(edx+ebx) 3/r32/ebx
# eax = out
8b/-> *(ebp+0xc) 0/r32/eax
# var outend/ecx: (addr byte) = out + n
8b/-> *(ebp+0x10) 1/r32/ecx
8d/copy-address *(eax+ecx) 1/r32/ecx
#
(_append-4 %eax %ecx %edx %ebx) # => eax
# s->read += n
8b/-> *(ebp+0x10) 1/r32/ecx
01/add-to *(esi+4) 1/r32/ecx
$read-from-stream:end:
# . restore registers
5e/pop-to-esi
5b/pop-to-ebx
5a/pop-to-edx
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
$read-from-stream:abort:
(abort "read-from-stream: stream empty")
# never gets here
stream-first: # s: (addr stream byte) -> result/eax: byte
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
56/push-esi
# result = false
b8/copy-to-eax 0/imm32
# esi = s
8b/-> *(ebp+8) 6/r32/esi
# var idx/ecx: int = s->read
8b/-> *(esi+4) 1/r32/ecx
# if idx >= s->write return 0
3b/compare-with 1/r32/ecx *esi
7d/jump-if->= $stream-first:end/disp8
# result = s->data[idx]
8a/byte-> *(esi+ecx+0xc) 0/r32/AL
$stream-first:end:
# . restore registers
5e/pop-to-esi
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
stream-final: # s: (addr stream byte) -> result/eax: byte
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
56/push-esi
# result = false
b8/copy-to-eax 0/imm32
# esi = s
8b/-> *(ebp+8) 6/r32/esi
# var max/ecx: int = s->write
8b/-> *esi 1/r32/ecx
# if s->read >= max return 0
39/compare-with *(esi+4) 1/r32/ecx
7d/jump-if->= $stream-final:end/disp8
# var idx/ecx: int = max - 1
49/decrement-ecx
# result = s->data[idx]
8a/byte-> *(esi+ecx+0xc) 0/r32/AL
$stream-final:end:
# . restore registers
5e/pop-to-esi
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
# compare all the data in two streams (ignoring the read pointer)
streams-data-equal?: # a: (addr stream byte), b: (addr array byte) -> result/eax: boolean
# pseudocode:
# awrite = a->write
# if (awrite != b->write) return false
# i = 0
# curra = a->data
# currb = b->data
# while i < awrite
# i1 = *curra
# i2 = *currb
# if (c1 != c2) return false
# i+=4, curra+=4, currb+=4
# return true
#
# registers:
# i: ecx
# awrite: edx
# curra: esi
# currb: edi
# i1: eax
# i2: ebx
#
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
52/push-edx
53/push-ebx
56/push-esi
57/push-edi
# esi = a
8b/-> *(ebp+8) 6/r32/esi
# edi = b
8b/-> *(ebp+0xc) 7/r32/edi
# var awrite/edx: int = a->write
8b/-> *esi 2/r32/edx
$streams-data-equal?:sizes:
# if (awrite != b->write) return false
39/compare *edi 2/r32/edx
75/jump-if-!= $streams-data-equal?:false/disp8
# var curra/esi: (addr byte) = a->data
81 0/subop/add %esi 0xc/imm32
# var currb/edi: (addr byte) = b->data
81 0/subop/add %edi 0xc/imm32
# var i/ecx: int = 0
31/xor-with %ecx 1/r32/ecx
# var vala/eax: int
31/xor-with %eax 0/r32/eax
# var valb/ebx: int
31/xor-with %ebx 3/r32/ebx
$streams-data-equal?:loop:
{
# if (i >= awrite) return true
39/compare %ecx 2/r32/edx
7d/jump-if->= $streams-data-equal?:true/disp8
# var vala/eax: int = *curra
8a/byte-> *esi 0/r32/eax
# var valb/ebx: int = *currb
8a/byte-> *edi 3/r32/ebx
# if (vala != valb) return false
39/compare %eax 3/r32/ebx
75/jump-if-!= $streams-data-equal?:false/disp8
# i++
41/increment-ecx
# curra++
46/increment-esi
# currb++
47/increment-edi
eb/jump loop/disp8
}
$streams-data-equal?:true:
b8/copy-to-eax 1/imm32
eb/jump $streams-data-equal?:end/disp8
$streams-data-equal?:false:
b8/copy-to-eax 0/imm32
$streams-data-equal?:end:
# . restore registers
5f/pop-to-edi
5e/pop-to-esi
5b/pop-to-ebx
5a/pop-to-edx
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
# helper for tests
check-streams-data-equal: # s: (addr stream _), expected: (addr array _), msg: (addr array byte)
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
#
(streams-data-equal? *(ebp+8) *(ebp+0xc)) # => eax
(check-ints-equal %eax 1 *(ebp+0x10))
$check-streams-data-equal:end:
# . restore registers
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return