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