build `num-bytes`

This commit is contained in:
Kartik Agaram 2019-07-07 23:56:23 -07:00
parent 23bc3650e0
commit 195d62f167
3 changed files with 565 additions and 2 deletions

View File

@ -1136,7 +1136,7 @@ test-has-metadata-multiple-false:
5d/pop-to-EBP
c3/return
compute-width: # word : (address array byte)
compute-width: # word : (address array byte) -> EAX : int
# . prolog
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
@ -1198,7 +1198,7 @@ compute-width: # word : (address array byte)
# else: return 1
b8/copy-to-EAX 1/imm32
$compute-width:end:
# . discard locals
# . reclaim locals
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . restore registers
59/pop-to-ECX
@ -1322,6 +1322,66 @@ $test-compute-width:no-metadata:
5d/pop-to-EBP
c3/return
compute-width-of-slice: # s : (address slice) -> EAX : int
# . prolog
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# . save registers
51/push-ECX
# ECX = s
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX
# if has-metadata?(word, "imm32") or has-metadata?(word, "disp32"): return 4
# . EAX = has-metadata?(word, "imm32")
68/push "imm32"/imm32
51/push-ECX
e8/call has-metadata?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . if EAX: return 4
3d/compare-EAX-and 1/imm32
b8/copy-to-EAX 4/imm32 # ZF is set, so we can overwrite EAX now
74/jump-if-equal $compute-width-of-slice:end/disp8
# . has-metadata?(word, "disp32")
68/push "disp32"/imm32
51/push-ECX
e8/call has-metadata?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . if EAX: return 4
3d/compare-EAX-and 1/imm32
b8/copy-to-EAX 4/imm32 # ZF is set, so we can overwrite EAX now
74/jump-if-equal $compute-width-of-slice:end/disp8
# if has-metadata?(word, "imm16") or has-metadata?(word, "disp16"): return 2
# . has-metadata?(word, "imm16")
68/push "imm16"/imm32
51/push-ECX
e8/call has-metadata?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . if EAX: return 2
3d/compare-EAX-and 1/imm32
b8/copy-to-EAX 2/imm32 # ZF is set, so we can overwrite EAX now
74/jump-if-equal $compute-width-of-slice:end/disp8
# . has-metadata?(word, "disp16")
68/push "disp16"/imm32
51/push-ECX
e8/call has-metadata?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . if EAX: return 2
3d/compare-EAX-and 1/imm32
b8/copy-to-EAX 2/imm32 # ZF is set, so we can overwrite EAX now
74/jump-if-equal $compute-width-of-slice:end/disp8
# else: return 1
b8/copy-to-EAX 1/imm32
$compute-width-of-slice:end:
# . restore registers
59/pop-to-ECX
# . epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP
c3/return
is-label?: # word : (address slice) -> EAX : boolean
# . prolog
55/push-EBP

Binary file not shown.

View File

@ -2118,9 +2118,512 @@ num-bytes: # line : (address stream) -> EAX : int
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
# var result/EAX = 0
31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX
# var word-slice/ECX = {0, 0}
68/push 0/imm32/end
68/push 0/imm32/start
89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX
#? # dump line {{{
#? # . write(2/stderr, "LL: ")
#? # . . push args
#? 68/push "LL: "/imm32
#? 68/push 2/imm32/stderr
#? # . . call
#? e8/call write/disp32
#? # . . discard args
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
#? # write-stream(2/stderr, line)
#? # . . push args
#? ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
#? 68/push 2/imm32/stderr
#? # . . call
#? e8/call write-stream/disp32
#? # . . discard args
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
#? # . write(2/stderr, "$\n")
#? # . . push args
#? 68/push "$\n"/imm32
#? 68/push 2/imm32/stderr
#? # . . call
#? e8/call write/disp32
#? # . . discard args
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
#? # }}}
$num-bytes:loop:
# next-word(line, word-slice)
# . . push args
51/push-ECX
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
# . . call
e8/call next-word/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
#? # dump word-slice {{{
#? # . write(2/stderr, "AA: ")
#? # . . push args
#? 68/push "AA: "/imm32
#? 68/push 2/imm32/stderr
#? # . . call
#? e8/call write/disp32
#? # . . discard args
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
#? # . clear-stream(Stderr+4)
#? # . . save EAX
#? 50/push-EAX
#? # . . push args
#? b8/copy-to-EAX Stderr/imm32
#? 05/add-to-EAX 4/imm32
#? 50/push-EAX
#? # . . call
#? e8/call clear-stream/disp32
#? # . . discard args
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
#? # . . restore EAX
#? 58/pop-to-EAX
#? # . write-slice-buffered(Stderr, word-slice)
#? # . . push args
#? 51/push-ECX
#? 68/push Stderr/imm32
#? # . . call
#? e8/call write-slice-buffered/disp32
#? # . . discard args
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
#? # . flush(Stderr)
#? # . . push args
#? 68/push Stderr/imm32
#? # . . call
#? e8/call flush/disp32
#? # . . discard args
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
#? # . write(2/stderr, "$\n")
#? # . . push args
#? 68/push "$\n"/imm32
#? 68/push 2/imm32/stderr
#? # . . call
#? e8/call write/disp32
#? # . . discard args
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
#? # }}}
$num-bytes:check0:
# if (slice-empty?(word-slice)) break
# . save result
50/push-EAX
# . EAX = slice-empty?(word-slice)
# . . push args
51/push-ECX
# . . call
e8/call slice-empty?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# . if (EAX != 0) break
3d/compare-EAX-and 0/imm32
# . restore result now that ZF is set
58/pop-into-EAX
75/jump-if-not-equal $num-bytes:end/disp8
$num-bytes:check-for-comment:
# if (slice-starts-with?(word-slice, "#")) break
# . start/EDX = word-slice->start
8b/copy 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # copy *ECX to EDX
# . c/EBX = *start
31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX
8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 3/r32/BL . . # copy byte at *EDX to BL
# . if (EBX == '#') break
81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0x23/imm32/hash # compare EBX
74/jump-if-equal $num-bytes:end/disp8
$num-bytes:check-for-label:
# if (slice-ends-with?(word-slice, ":")) break
# . end/EDX = word-slice->end
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 2/r32/EDX 4/disp8 . # copy *(ECX+4) to EDX
# . c/EBX = *(end-1)
31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX
8a/copy-byte 1/mod/*+disp8 2/rm32/EDX . . . 3/r32/BL -1/disp8 . # copy byte at *ECX to BL
# . if (EBX == ':') break
81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0x3a/imm32/colon # compare EBX
74/jump-if-equal $num-bytes:end/disp8
$num-bytes:check-for-segment-header:
# if (slice-equal?(word-slice, "==")) break
# . push result
50/push-EAX
# . EAX = slice-equal?(word-slice, "==")
# . . push args
68/push "=="/imm32
51/push-ECX
# . . call
e8/call slice-equal?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . if (EAX != 0) break
3d/compare-EAX-and 0/imm32
# . restore result now that ZF is set
58/pop-into-EAX
75/jump-if-not-equal $num-bytes:end/disp8
$num-bytes:loop-body:
# result += compute-width-of-slice(word-slice)
# . copy result to EDX
89/copy 3/mod/direct 2/rm32/EDX . . . 0/r32/EAX . . # copy EAX to EDX
# . EAX = compute-width-of-slice(word-slice)
# . . push args
51/push-ECX
# . . call
e8/call compute-width-of-slice/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# . EAX += result
01/add 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # add EDX to EAX
e9/jump $num-bytes:loop/disp32
$num-bytes:end:
# . reclaim locals
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . restore registers
5b/pop-into-EBX
5a/pop-into-EDX
59/pop-into-ECX
# . epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP
c3/return
test-num-bytes-handles-empty-string:
# if a line starts with '#', return 0
# . prolog
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# setup
# . clear-stream(_test-input-stream)
# . . push args
68/push _test-input-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
# . clear-stream(_test-output-stream)
# . . push args
68/push _test-output-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
# no contents in input
# EAX = num-bytes(_test-input-stream)
# . . push args
68/push _test-input-stream/imm32
# . . call
e8/call num-bytes/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# check-ints-equal(EAX, 0, msg)
# . . push args
68/push "F - test-num-bytes-handles-empty-string"/imm32
68/push 0/imm32/true
50/push-EAX
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# . epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP
c3/return
test-num-bytes-ignores-comments:
# if a line starts with '#', return 0
# . prolog
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# setup
# . clear-stream(_test-input-stream)
# . . push args
68/push _test-input-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
# . clear-stream(_test-output-stream)
# . . push args
68/push _test-output-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
# initialize input
# . write(_test-input-stream, "# abcd")
# . . push args
68/push "# abcd"/imm32
68/push _test-input-stream/imm32
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# EAX = num-bytes(_test-input-stream)
# . . push args
68/push _test-input-stream/imm32
# . . call
e8/call num-bytes/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# check-ints-equal(EAX, 0, msg)
# . . push args
68/push "F - test-num-bytes-ignores-comments"/imm32
68/push 0/imm32/true
50/push-EAX
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# . epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP
c3/return
test-num-bytes-ignores-labels:
# if the first word ends with ':', return 0
# . prolog
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# setup
# . clear-stream(_test-input-stream)
# . . push args
68/push _test-input-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
# . clear-stream(_test-output-stream)
# . . push args
68/push _test-output-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
# initialize input
# . write(_test-input-stream, "ab: # cd")
# . . push args
68/push "ab: # cd"/imm32
68/push _test-input-stream/imm32
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# EAX = num-bytes(_test-input-stream)
# . . push args
68/push _test-input-stream/imm32
# . . call
e8/call num-bytes/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# check-ints-equal(EAX, 0, msg)
# . . push args
68/push "F - test-num-bytes-ignores-labels"/imm32
68/push 0/imm32/true
50/push-EAX
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# . epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP
c3/return
test-num-bytes-ignores-segment-headers:
# if the first word is '==', return 0
# . prolog
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# setup
# . clear-stream(_test-input-stream)
# . . push args
68/push _test-input-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
# . clear-stream(_test-output-stream)
# . . push args
68/push _test-output-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
# initialize input
# . write(_test-input-stream, "== ab cd")
# . . push args
68/push "== ab cd"/imm32
68/push _test-input-stream/imm32
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# EAX = num-bytes(_test-input-stream)
# . . push args
68/push _test-input-stream/imm32
# . . call
e8/call num-bytes/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# check-ints-equal(EAX, 0, msg)
# . . push args
68/push "F - test-num-bytes-ignores-segment-headers"/imm32
68/push 0/imm32/true
50/push-EAX
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# . epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP
c3/return
test-num-bytes-counts-words-by-default:
# without metadata, count words
# . prolog
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# setup
# . clear-stream(_test-input-stream)
# . . push args
68/push _test-input-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
# . clear-stream(_test-output-stream)
# . . push args
68/push _test-output-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
# initialize input
# . write(_test-input-stream, "ab cd ef")
# . . push args
68/push "ab cd ef"/imm32
68/push _test-input-stream/imm32
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# EAX = num-bytes(_test-input-stream)
# . . push args
68/push _test-input-stream/imm32
# . . call
e8/call num-bytes/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# check-ints-equal(EAX, 3, msg)
# . . push args
68/push "F - test-num-bytes-counts-words-by-default"/imm32
68/push 3/imm32/true
50/push-EAX
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# . epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP
c3/return
test-num-bytes-ignores-trailing-comment:
# trailing comments appropriately ignored
# . prolog
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# setup
# . clear-stream(_test-input-stream)
# . . push args
68/push _test-input-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
# . clear-stream(_test-output-stream)
# . . push args
68/push _test-output-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
# initialize input
# . write(_test-input-stream, "ab cd # ef")
# . . push args
68/push "ab cd # ef"/imm32
68/push _test-input-stream/imm32
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# EAX = num-bytes(_test-input-stream)
# . . push args
68/push _test-input-stream/imm32
# . . call
e8/call num-bytes/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# check-ints-equal(EAX, 2, msg)
# . . push args
68/push "F - test-num-bytes-ignores-trailing-comment"/imm32
68/push 2/imm32/true
50/push-EAX
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# . epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP
c3/return
test-num-bytes-handles-imm32:
# if a word has the /imm32 metadata, count it as 4 bytes
# . prolog
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# setup
# . clear-stream(_test-input-stream)
# . . push args
68/push _test-input-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
# . clear-stream(_test-output-stream)
# . . push args
68/push _test-output-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
# initialize input
# . write(_test-input-stream, "ab cd/imm32 ef")
# . . push args
68/push "ab cd/imm32 ef"/imm32
68/push _test-input-stream/imm32
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# EAX = num-bytes(_test-input-stream)
# . . push args
68/push _test-input-stream/imm32
# . . call
e8/call num-bytes/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# check-ints-equal(EAX, 6, msg)
# . . push args
68/push "F - test-num-bytes-handles-imm32"/imm32
68/push 6/imm32/true
50/push-EAX
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# . epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP