49424b1933
There's a dependency cycle here: - draw-grapheme (Mu) uses read-grapheme (Mu) to be unicode-aware. - read-grapheme uses read-byte (SubX). Streams are a fundamental data structure in Mu. For the Mu compiler to be able to reason about the safety of stream operations, they need to be an opaque type. All stream primitives are written in SubX. To manipulate a stream's internals we force people to reach for SubX. That way if there's no SubX code there's confidence that things are safe. - read-byte and other stream operations have unit tests, like they should. The unit tests need to print data to screen when say a test fails. To do this they use various check- functions (SubX) that take a string argument. - Printing a string to screen uses draw-grapheme (Mu). Perhaps I should maintain variants of drawing primitives that operate only on ASCII.
221 lines
11 KiB
Plaintext
221 lines
11 KiB
Plaintext
# write: write to in-memory streams
|
|
#
|
|
# We need to do this in machine code because streams need to be opaque types,
|
|
# and we don't yet support opaque types in Mu.
|
|
|
|
== code
|
|
# instruction effective address register displacement immediate
|
|
# . op subop mod rm32 base index scale r32
|
|
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
|
|
|
|
write: # f: (addr stream byte), s: (addr array byte)
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# if (s == 0) return
|
|
81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 0/imm32 # compare *(ebp+12)
|
|
74/jump-if-= $write:end/disp8
|
|
# . save registers
|
|
50/push-eax
|
|
51/push-ecx
|
|
52/push-edx
|
|
53/push-ebx
|
|
# ecx = f
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx
|
|
# edx = f->write
|
|
8b/copy 0/mod/indirect 1/rm32/ecx . . . 2/r32/edx . . # copy *ecx to edx
|
|
# ebx = f->size
|
|
8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 3/r32/ebx 8/disp8 . # copy *(ecx+8) to ebx
|
|
# eax = _append-3(&f->data[f->write], &f->data[f->size], s)
|
|
# . . push s
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
|
# . . push &f->data[f->size]
|
|
8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ecx 3/index/ebx . 3/r32/ebx 0xc/disp8 . # copy ecx+ebx+12 to ebx
|
|
53/push-ebx
|
|
# . . push &f->data[f->write]
|
|
8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ecx 2/index/edx . 3/r32/ebx 0xc/disp8 . # copy ecx+edx+12 to ebx
|
|
53/push-ebx
|
|
# . . call
|
|
e8/call _append-3/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# f->write += eax
|
|
01/add 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # add eax to *ecx
|
|
# . restore registers
|
|
5b/pop-to-ebx
|
|
5a/pop-to-edx
|
|
59/pop-to-ecx
|
|
58/pop-to-eax
|
|
$write:end:
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-write-single:
|
|
# clear-stream(_test-stream)
|
|
# . . push args
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# write(_test-stream, "Ab")
|
|
# . . push args
|
|
68/push "Ab"/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# check-ints-equal(*_test-stream->data, 41/A 62/b 00 00, msg)
|
|
# . . push args
|
|
68/push "F - test-write-single"/imm32
|
|
68/push 0x006241/imm32/Ab
|
|
# . . push *_test-stream->data
|
|
b8/copy-to-eax _test-stream/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 0xc/disp8 . # push *(eax+12)
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# end
|
|
c3/return
|
|
|
|
test-write-appends:
|
|
# clear-stream(_test-stream)
|
|
# . . push args
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# write(_test-stream, "C")
|
|
# . . push args
|
|
68/push "C"/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# write(_test-stream, "D")
|
|
# . . push args
|
|
68/push "D"/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# check-ints-equal(*_test-stream->data, 43/C 44/D 00 00, msg)
|
|
# . . push args
|
|
68/push "F - test-write-appends"/imm32
|
|
68/push 0x00004443/imm32/C-D
|
|
# . . push *_test-stream->data
|
|
b8/copy-to-eax _test-stream/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 0xc/disp8 . # push *(eax+12)
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# end
|
|
c3/return
|
|
|
|
== data
|
|
|
|
_test-stream: # (stream byte)
|
|
# current write index
|
|
0/imm32
|
|
# current read index
|
|
0/imm32
|
|
# size
|
|
0x10/imm32
|
|
# data (2 lines x 8 bytes/line)
|
|
00 00 00 00 00 00 00 00
|
|
00 00 00 00 00 00 00 00
|
|
|
|
== code
|
|
|
|
# 3-argument variant of _append
|
|
_append-3: # out: (addr byte), outend: (addr byte), s: (addr array byte) -> num_bytes_appended/eax
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
51/push-ecx
|
|
# eax = _append-4(out, outend, &s->data[0], &s->data[s->size])
|
|
# . . push &s->data[s->size]
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax
|
|
8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
|
|
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx
|
|
51/push-ecx
|
|
# . . push &s->data[0]
|
|
8d/copy-address 1/mod/*+disp8 0/rm32/eax . . . 1/r32/ecx 4/disp8 . # copy eax+4 to ecx
|
|
51/push-ecx
|
|
# . . push outend
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
|
# . . push out
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
|
|
# . . call
|
|
e8/call _append-4/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
|
|
$_append-3:end:
|
|
# . restore registers
|
|
59/pop-to-ecx
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
# 4-argument variant of _append
|
|
_append-4: # out: (addr byte), outend: (addr byte), in: (addr byte), inend: (addr byte) -> num_bytes_appended/eax: int
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
51/push-ecx
|
|
52/push-edx
|
|
53/push-ebx
|
|
56/push-esi
|
|
57/push-edi
|
|
# num_bytes_appended = 0
|
|
b8/copy-to-eax 0/imm32
|
|
# edi = out
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 8/disp8 . # copy *(ebp+8) to edi
|
|
# edx = outend
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx
|
|
# esi = in
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0x10/disp8 . # copy *(ebp+16) to esi
|
|
# ecx = inend
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x14/disp8 . # copy *(ebp+20) to ecx
|
|
$_append-4:loop:
|
|
# if (in >= inend) break
|
|
39/compare 3/mod/direct 6/rm32/esi . . . 1/r32/ecx . . # compare esi with ecx
|
|
73/jump-if-addr>= $_append-4:end/disp8
|
|
# if (out >= outend) abort # just to catch test failures fast
|
|
39/compare 3/mod/direct 7/rm32/edi . . . 2/r32/edx . . # compare edi with edx
|
|
73/jump-if-addr>= $_append-4:end/disp8 # TODO: abort
|
|
# *out = *in
|
|
8a/copy-byte 0/mod/indirect 6/rm32/esi . . . 3/r32/BL . . # copy byte at *esi to BL
|
|
88/copy-byte 0/mod/indirect 7/rm32/edi . . . 3/r32/BL . . # copy byte at BL to *edi
|
|
# ++num_bytes_appended
|
|
40/increment-eax
|
|
# ++in
|
|
46/increment-esi
|
|
# ++out
|
|
47/increment-edi
|
|
eb/jump $_append-4:loop/disp8
|
|
$_append-4: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/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
# . . vim:nowrap:textwidth=0
|