https://github.com/akkartik/mu/blob/main/306files.subx
  1 # Methods for constructing buffered-file objects.
  2 #
  3 # TODO: There are hard-coded parameters here for buffer sizes. When they
  4 # overflow, tracking down what's going on can get hairy.
  5 #
  6 # HACK: buffered-file stores naked addrs. This is safe because buffered-file
  7 # objects are opaque. But still sub-optimal; they'll be harder to reclaim when
  8 # we get around to that.
  9 
 10 == code
 11 
 12 open:  # filename: (addr array byte), write?: boolean, out: (addr handle buffered-file)
 13     # . prologue
 14     55/push-ebp
 15     89/<- %ebp 4/r32/esp
 16     # . save registers
 17     50/push-eax
 18     51/push-ecx
 19     # var new-fd/ecx: fd
 20     (open-fd *(ebp+8) *(ebp+0xc))  # => eax
 21     89/<- %ecx 0/r32/eax
 22     # if fd < 0 return
 23     3d/compare-eax-with 0/imm32
 24     7c/jump-if-< $open:end/disp8
 25     # allocate a buffered-file
 26     (allocate Heap 0x1010 *(ebp+0x10))  # file-buffer-size + 16 for other fields
 27     # var out-addr/eax: (addr buffered-file)
 28     8b/-> *(ebp+0x10) 0/r32/eax
 29     (lookup *eax *(eax+4))  # => eax
 30     # out-addr->size = 4KB
 31     c7 0/subop/copy *(eax+0xc) 0x1000/imm32/file-buffer-size  # Stream-size + 4 for fd
 32     # out-addr->fd = fd
 33     89/<- *eax 1/r32/ecx
 34 $open:end:
 35     # . restore registers
 36     59/pop-to-ecx
 37     58/pop-to-eax
 38     # . epilogue
 39     89/<- %esp 5/r32/ebp
 40     5d/pop-to-ebp
 41     c3/return
 42 
 43 open-fd:  # filename: (addr array byte), write?: boolean -> result/eax: fd
 44     # . prologue
 45     55/push-ebp
 46     89/<- %ebp 4/r32/esp
 47     # . save registers
 48     51/push-ecx
 49     52/push-edx
 50     53/push-ebx
 51     56/push-esi
 52     # ecx = filename
 53     8b/-> *(ebp+8) 1/r32/ecx
 54     # var size/edx: int = filename->length + 1 for the trailing null character
 55     8b/-> *ecx 2/r32/edx
 56     42/increment-edx
 57     # var s/esi: (stream size)
 58     29/subtract-from %esp 2/r32/edx
 59     52/push-edx  # size
 60     68/push 0/imm32/read
 61     68/push 0/imm32/write
 62     89/<- %esi 4/r32/esp
 63     # copy filename and a final null character
 64     (clear-stream %esi)
 65     (write %esi %ecx)
 66     # spill edx
 67     52/push-edx
 68     # var fd/eax: fd = open(filename)
 69     8d/copy-address *(esi+0xc) 3/r32/ebx
 70     8b/-> *(ebp+0xc) 1/r32/ecx/flags
 71     ba/copy-to-edx 0x180/imm32/permissions
 72     e8/call syscall_open/disp32
 73     # restore edx
 74     5a/pop-to-edx
 75 $open-fd:end:
 76     # . reclaim locals
 77     01/add-to %esp 2/r32/edx
 78     81 0/subop/add %esp 0xc/imm32
 79     # . restore registers
 80     5e/pop-to-esi
 81     5b/pop-to-ebx
 82     5a/pop-to-edx
 83     59/pop-to-ecx
 84     # . epilogue
 85     89/<- %esp 5/r32/ebp
 86     5d/pop-to-ebp
 87     c3/return
 88 
 89 populate-buffered-file-containing:  # contents: (addr array byte), out: (addr handle buffered-file)
 90     # . prologue
 91     55/push-ebp
 92     89/<- %ebp 4/r32/esp
 93     # . save registers
 94     50/push-eax
 95     51/push-ecx
 96     56/push-esi
 97     57/push-edi
 98     # esi = contents
 99     8b/-> *(ebp+8) 6/r32/esi
100     # var n/ecx: int = len(contents)
101     8b/-> *esi 1/r32/ecx
102     # var stream/edi: (handle stream byte)
103     68/push 0/imm32
104     68/push 0/imm32
105     89/<- %edi 4/r32/esp
106     # allocate stream
107     (new-stream Heap %ecx 1 %edi)
108     # var stream-addr/edi: (addr stream byte) = lookup(stream)
109     (lookup *edi *(edi+4))  # => eax
110     89/<- %edi 0/r32/eax
111     # write contents to stream
112     (write %edi %esi)
113     # allocate buffered-file
114     (allocate Heap 0x110 *(ebp+0xc))
115     # var out-addr/eax: (addr buffered-file)
116     8b/-> *(ebp+0xc) 0/r32/eax
117     (lookup *eax *(eax+4))  # => eax
118     # out-addr->size = 256 bytes
119     c7 0/subop/copy *(eax+0xc) 0x100/imm32/file-buffer-size
120     # out-addr->fd = stream
121     89/<- *eax 7/r32/edi
122 $populate-buffered-file-containing:end:
123     # . reclaim locals
124     81 0/subop/add %esp 8/imm32
125     # . restore registers
126     5f/pop-to-edi
127     5e/pop-to-esi
128     59/pop-to-ecx
129     58/pop-to-eax
130     # . epilogue
131     89/<- %esp 5/r32/ebp
132     5d/pop-to-ebp
133     c3/return
134 
135 new-buffered-file:  # out: (addr handle buffered-file)
136     # . prologue
137     55/push-ebp
138     89/<- %ebp 4/r32/esp
139     # . save registers
140     50/push-eax
141     51/push-ecx
142     # var stream/ecx: (handle stream byte)
143     68/push 0/imm32
144     68/push 0/imm32
145     89/<- %ecx 4/r32/esp
146     # allocate stream
147     (new-stream Heap 0x100 1 %ecx)
148     # var stream-addr/ecx: (addr stream byte) = lookup(stream)
149     (lookup *ecx *(ecx+4))  # => eax
150     89/<- %ecx 0/r32/eax
151     # allocate buffered-file
152     (allocate Heap 0x110 *(ebp+8))
153     # var out-addr/eax: (addr buffered-file)
154     8b/-> *(ebp+8) 0/r32/eax
155     (lookup *eax *(eax+4))  # => eax
156     # out-addr->size = 256 bytes
157     c7 0/subop/copy *(eax+0xc) 0x100/imm32/file-buffer-size
158     # out-addr->fd = stream
159     89/<- *eax 1/r32/ecx
160 $new-buffered-file:end:
161     # . reclaim locals
162     81 0/subop/add %esp 8/imm32
163     # . restore registers
164     59/pop-to-ecx
165     58/pop-to-eax
166     # . epilogue
167     89/<- %esp 5/r32/ebp
168     5d/pop-to-ebp
169     c3/return