7261 - mu.subx: array bounds-checking done

This commit is contained in:
Kartik Agaram 2020-11-17 18:14:43 -08:00
parent 83221b4e21
commit 1696ed831a
5 changed files with 333 additions and 107 deletions

View File

@ -0,0 +1,84 @@
# Helper to check an array's bounds, and to abort if they're violated.
# Really only intended to be called from code generated by mu.subx.
== code
__check-mu-array-bounds: # index: int, elem-size: int, arr-size: int, function-name: (addr array byte), array-name: (addr array byte)
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
51/push-ecx
52/push-edx
# . not bothering saving ebx; it's only clobbered if we're going to abort
# ecx = arr-size
8b/-> *(ebp+0x10) 1/r32/ecx
# var overflow/edx: int = 0
ba/copy-to-edx 0/imm32
# var offset/eax: int = index * elem-size
8b/-> *(ebp+8) 0/r32/eax
f7 4/subop/multiply-eax-with *(ebp+0xc)
# check for overflow
81 7/subop/compare %edx 0/imm32
0f 85/jump-if-!= __check-mu-array-bounds:overflow/disp32
# check bounds
39/compare %eax 1/r32/ecx
0f 82/jump-if-unsigned< $__check-mu-array-bounds:end/disp32 # negative index should always abort
# abort if necessary
(write-buffered Stderr "fn ")
(write-buffered Stderr *(ebp+0x14))
(write-buffered Stderr ": offset ")
(write-int32-hex-buffered Stderr %eax)
(write-buffered Stderr " is too large for array '")
(write-buffered Stderr *(ebp+0x18))
(write-buffered Stderr "'\n")
(flush Stderr)
# exit(1)
bb/copy-to-ebx 1/imm32
e8/call syscall_exit/disp32
$__check-mu-array-bounds:end:
# . restore registers
5a/pop-to-edx
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
__check-mu-array-bounds:overflow:
# "fn " function-name ": offset to array '" array-name "' overflowed 32 bits\n"
(write-buffered Stderr "fn ")
(write-buffered Stderr *(ebp+0x14))
(write-buffered Stderr ": offset to array '")
(write-buffered Stderr *(ebp+0x18))
(write-buffered Stderr "' overflowed 32 bits\n")
(flush Stderr)
# exit(1)
bb/copy-to-ebx 1/imm32
e8/call syscall_exit/disp32
# potential alternative
#? __bounds-check: # msg: (addr array byte)
#? (write-buffered Stderr "abort: array bounds exceeded in fn ")
#? 8b/-> *(esp+4) 0/r32/eax # we're going to abort, so just clobber away
#? (write-buffered Stderr %eax)
#? (write-buffered Stderr Newline)
#? # exit(1)
#? bb/copy-to-ebx 1/imm32
#? e8/call syscall_exit/disp32
# to be called as follows:
# var/reg <- index arr/rega: (addr array T), idx/regi: int
# | if size-of(T) is 1, 2, 4 or 8
# => # temporarily save array size to reg to check bounds
# "8b/-> *" rega " " reg "/r32"
# "c1/shift 5/subop/right %" reg " " log2(size-of(T)) "/imm32"
# "3b/compare " reg "/r32 *" rega
# "68/push \"" function "\"/imm32" # pass function name to error message
# "0f 8d/jump-if->= __bounds_check/disp32"
# "81 0/subop/add %esp 4/imm32" # drop function name
# # actually save the index addr in reg
# "8d/copy-address *(" rega "+" regi "<<" log2(size-of(T)) "+4) " reg "/r32"

BIN
apps/mu

Binary file not shown.

View File

@ -5997,15 +5997,16 @@ test-convert-index-into-array:
(check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-index-into-array/7")
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array/8")
(check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-index-into-array/9")
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32" "F - test-convert-index-into-array/10")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array/11")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array/12")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array/13")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array/14")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array/15")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array/16")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array/17")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array/18")
(check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds %ecx 0x00000004 *eax \"foo\" \"arr\")" "F - test-convert-index-into-array/10")
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32" "F - test-convert-index-into-array/11")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array/12")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array/13")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array/14")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array/15")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array/16")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array/17")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array/18")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array/19")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
@ -6046,15 +6047,16 @@ test-convert-index-into-array-of-bytes:
(check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-index-into-array-of-bytes/7")
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array-of-bytes/8")
(check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-index-into-array-of-bytes/9")
(check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds %ecx 0x00000001 *eax \"foo\" \"arr\")" "F - test-convert-index-into-array-of-bytes/10")
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx<<0x00000000 + 4) 0x00000000/r32" "F - test-convert-index-into-array-of-bytes/11")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-of-bytes/13")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes/14")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes/15")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes/16")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes/17")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes/18")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes/19")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes/20")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-of-bytes/12")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes/13")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes/14")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes/15")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes/16")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes/17")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes/18")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes/19")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
@ -6092,15 +6094,16 @@ test-convert-index-into-array-with-literal:
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-with-literal/5")
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-with-literal/6")
(check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-index-into-array-with-literal/7")
(check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds 2 0x00000004 *eax \"foo\" \"arr\")" "F - test-convert-index-into-array-with-literal/8")
# 2 * 4 bytes/elem + 4 bytes for size = offset 12
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + 0x0000000c) 0x00000000/r32" "F - test-convert-index-into-array-with-literal/8")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-with-literal/9")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-with-literal/10")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-with-literal/11")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-with-literal/12")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-with-literal/13")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-with-literal/14")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-with-literal/15")
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + 0x0000000c) 0x00000000/r32" "F - test-convert-index-into-array-with-literal/9")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-with-literal/10")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-with-literal/11")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-with-literal/12")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-with-literal/13")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-with-literal/14")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-with-literal/15")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-with-literal/16")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
@ -6138,6 +6141,7 @@ test-convert-index-into-array-of-bytes-with-literal:
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-of-bytes-with-literal/5")
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-of-bytes-with-literal/6")
(check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-index-into-array-of-bytes-with-literal/7")
(check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds 2 0x00000001 *eax \"foo\" \"arr\")" "F - test-convert-index-into-array-of-bytes-with-literal/8")
# 2 * 1 byte/elem + 4 bytes for size = offset 6
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + 0x00000006) 0x00000000/r32" "F - test-convert-index-into-array-of-bytes-with-literal/8")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes-with-literal/9")
@ -6189,19 +6193,20 @@ test-convert-index-into-array-on-stack:
# var idx
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-on-stack/8")
(check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 2/imm32" "F - test-convert-index-into-array-on-stack/9")
(check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds %eax 0x00000004 *(ebp+0xfffffff0) \"foo\" \"arr\")" "F - test-convert-index-into-array-on-stack/10")
# var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp + eax<<0x00000002 + 0xfffffff4) 0x00000000/r32" "F - test-convert-index-into-array-on-stack/10")
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp + eax<<0x00000002 + 0xfffffff4) 0x00000000/r32" "F - test-convert-index-into-array-on-stack/11")
# reclaim idx
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-on-stack/11")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-on-stack/12")
# reclaim arr
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000010/imm32" "F - test-convert-index-into-array-on-stack/12")
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000010/imm32" "F - test-convert-index-into-array-on-stack/13")
#
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-on-stack/13")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-on-stack/14")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-on-stack/15")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-on-stack/16")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-on-stack/17")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-on-stack/18")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-on-stack/14")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-on-stack/15")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-on-stack/16")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-on-stack/17")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-on-stack/18")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-on-stack/19")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
@ -6242,19 +6247,20 @@ test-convert-index-into-array-on-stack-with-literal:
(check-next-stream-line-equal _test-output-stream " 68/push 0x0000000c/imm32" "F - test-convert-index-into-array-on-stack-with-literal/7")
# var x
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-on-stack-with-literal/8")
(check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds 2 0x00000004 *(ebp+0xfffffff0) \"foo\" \"arr\")" "F - test-convert-index-into-array-on-stack-with-literal/9")
# x is at (ebp-0x10) + 4 + 2*4 = ebp-4
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp + 0xfffffffc) 0x00000000/r32" "F - test-convert-index-into-array-on-stack-with-literal/9")
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp + 0xfffffffc) 0x00000000/r32" "F - test-convert-index-into-array-on-stack-with-literal/10")
# reclaim x
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-on-stack-with-literal/10")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-on-stack-with-literal/11")
# reclaim arr
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000010/imm32" "F - test-convert-index-into-array-on-stack-with-literal/11")
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000010/imm32" "F - test-convert-index-into-array-on-stack-with-literal/12")
#
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-on-stack-with-literal/12")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-on-stack-with-literal/13")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-on-stack-with-literal/14")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-on-stack-with-literal/15")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-on-stack-with-literal/16")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-on-stack-with-literal/17")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-on-stack-with-literal/13")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-on-stack-with-literal/14")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-on-stack-with-literal/15")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-on-stack-with-literal/16")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-on-stack-with-literal/17")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-on-stack-with-literal/18")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
@ -6295,19 +6301,20 @@ test-convert-index-into-array-of-bytes-on-stack-with-literal:
(check-next-stream-line-equal _test-output-stream " 68/push 0x00000003/imm32" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/7")
# var x
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/8")
(check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds 2 0x00000001 *(ebp+0xfffffff9) \"foo\" \"arr\")" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/9")
# x is at (ebp-7) + 4 + 2 = ebp-1
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp + 0xffffffff) 0x00000000/r32" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/9")
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp + 0xffffffff) 0x00000000/r32" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/10")
# reclaim x
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/10")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/11")
# reclaim arr
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000007/imm32" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/11")
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000007/imm32" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/12")
#
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/12")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/13")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/14")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/15")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/16")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/17")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/13")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/14")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/15")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/16")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/17")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/18")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
@ -6350,15 +6357,16 @@ test-convert-index-into-array-using-offset:
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array-using-offset/8")
(check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-index-into-array-using-offset/9")
(check-next-stream-line-equal _test-output-stream " 69/multiply %ecx 0x00000004/imm32 0x00000001/r32" "F - test-convert-index-into-array-using-offset/10")
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx + 4) 0x00000000/r32" "F - test-convert-index-into-array-using-offset/11")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-using-offset/12")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-using-offset/13")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-using-offset/14")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-using-offset/15")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-using-offset/16")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-using-offset/17")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-using-offset/18")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-using-offset/19")
(check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds %ecx 1 *eax \"foo\" \"arr\")" "F - test-convert-index-into-array-using-offset/11")
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx + 4) 0x00000000/r32" "F - test-convert-index-into-array-using-offset/12")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-using-offset/13")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-using-offset/14")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-using-offset/15")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-using-offset/16")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-using-offset/17")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-using-offset/18")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-using-offset/19")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-using-offset/20")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
@ -6401,15 +6409,16 @@ test-convert-index-into-array-of-bytes-using-offset:
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array-of-bytes-using-offset/8")
(check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-index-into-array-of-bytes-using-offset/9")
(check-next-stream-line-equal _test-output-stream " 69/multiply %ecx 0x00000001/imm32 0x00000001/r32" "F - test-convert-index-into-array-of-bytes-using-offset/10")
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx + 4) 0x00000000/r32" "F - test-convert-index-into-array-of-bytes-using-offset/11")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-of-bytes-using-offset/12")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes-using-offset/13")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes-using-offset/14")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes-using-offset/15")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes-using-offset/16")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes-using-offset/17")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes-using-offset/18")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes-using-offset/19")
(check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds %ecx 1 *eax \"foo\" \"arr\")" "F - test-convert-index-into-array-of-bytes-using-offset/11")
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx + 4) 0x00000000/r32" "F - test-convert-index-into-array-of-bytes-using-offset/12")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-of-bytes-using-offset/13")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes-using-offset/14")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes-using-offset/15")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes-using-offset/16")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes-using-offset/17")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes-using-offset/18")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes-using-offset/19")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes-using-offset/20")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
@ -6452,16 +6461,17 @@ test-convert-index-into-array-using-offset-on-stack:
(check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-index-into-array-using-offset-on-stack/8")
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array-using-offset-on-stack/9")
(check-next-stream-line-equal _test-output-stream " 69/multiply *(ebp+0xfffffff8) 0x00000004/imm32 0x00000001/r32" "F - test-convert-index-into-array-using-offset-on-stack/10")
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx + 4) 0x00000000/r32" "F - test-convert-index-into-array-using-offset-on-stack/11")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-using-offset-on-stack/12")
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-index-into-array-using-offset-on-stack/13")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-using-offset-on-stack/14")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-using-offset-on-stack/15")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-using-offset-on-stack/16")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-using-offset-on-stack/17")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-using-offset-on-stack/18")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-using-offset-on-stack/19")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-using-offset-on-stack/20")
(check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds %ecx 1 *eax \"foo\" \"arr\")" "F - test-convert-index-into-array-using-offset-on-stack/11")
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx + 4) 0x00000000/r32" "F - test-convert-index-into-array-using-offset-on-stack/12")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-using-offset-on-stack/13")
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-index-into-array-using-offset-on-stack/14")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-using-offset-on-stack/15")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-using-offset-on-stack/16")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-using-offset-on-stack/17")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-using-offset-on-stack/18")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-using-offset-on-stack/19")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-using-offset-on-stack/20")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-using-offset-on-stack/21")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
@ -6504,16 +6514,17 @@ test-convert-index-into-array-of-bytes-using-offset-on-stack:
(check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/8")
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/9")
(check-next-stream-line-equal _test-output-stream " 69/multiply *(ebp+0xfffffff8) 0x00000001/imm32 0x00000001/r32" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/10")
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx + 4) 0x00000000/r32" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/11")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/12")
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/13")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/14")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/15")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/16")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/17")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/18")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/19")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/20")
(check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds %ecx 1 *eax \"foo\" \"arr\")" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/11")
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx + 4) 0x00000000/r32" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/12")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/13")
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/14")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/15")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/16")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/17")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/18")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/19")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/20")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/21")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
@ -9534,15 +9545,16 @@ test-convert-array-of-user-defined-types:
(check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-array-of-user-defined-types/7")
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-array-of-user-defined-types/8")
(check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-array-of-user-defined-types/9")
(check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds %ecx 0x00000008 *eax \"foo\" \"arr\")" "F - test-convert-array-of-user-defined-types/10")
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx<<0x00000003 + 4) 0x00000000/r32" "F - test-convert-array-of-user-defined-types/11")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-array-of-user-defined-types/13")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-array-of-user-defined-types/14")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-array-of-user-defined-types/15")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-array-of-user-defined-types/16")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-array-of-user-defined-types/17")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-array-of-user-defined-types/18")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-array-of-user-defined-types/19")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-array-of-user-defined-types/20")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-array-of-user-defined-types/12")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-array-of-user-defined-types/13")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-array-of-user-defined-types/14")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-array-of-user-defined-types/15")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-array-of-user-defined-types/16")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-array-of-user-defined-types/17")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-array-of-user-defined-types/18")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-array-of-user-defined-types/19")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
@ -24774,6 +24786,11 @@ Curr-local-stack-offset: # (addr int)
== code
# We may not need to pass err/ed everywhere here. I think they're relics of Mu
# getting type checks later in life.
# But we do need them for runtime checks, particularly array index bounds checks.
# So perhaps it's not worth taking them out. They're a safety net.
emit-subx: # out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
# . prologue
55/push-ebp
@ -26844,6 +26861,8 @@ translate-mu-index-stmt: # out: (addr buffered-file), stmt: (addr stmt), fn: (a
(lookup *(ebx+0xc) *(ebx+0x10)) # Stmt1-inouts Stmt1-inouts => eax
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
89/<- %ebx 0/r32/eax
# emit bounds-check
(emit-mu-index-bounds-check *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))
# if (var->register) do one thing
{
81 7/subop/compare *(ebx+0x18) 0/imm32 # Var-register
@ -26880,6 +26899,125 @@ $translate-mu-index-stmt:error2:
(stop *(ebp+0x18) 1)
# never gets here
emit-mu-index-bounds-check: # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
51/push-ecx
52/push-edx
53/push-ebx
# ecx = stmt
8b/-> *(ebp+0xc) 1/r32/ecx
#
(emit-indent *(ebp+8) *Curr-block-depth)
(write-buffered *(ebp+8) "(__check-mu-array-bounds ")
$emit-mu-index-bounds-check:compute-base:
# var base/ebx: (addr var) = inouts[0]
(lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
89/<- %ebx 0/r32/eax
$emit-mu-index-bounds-check:emit-index:
# var index/edx: (addr var) = inouts[1]
(lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax
(lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
89/<- %edx 0/r32/eax
# if index->register, print its code
81 7/subop/compare *(edx+0x18) 0/imm32 # Var-register
{
0f 84/jump-if-= break/disp32
$emit-mu-index-bounds-check:emit-register-index:
(write-buffered *(ebp+8) "%")
(lookup *(edx+0x18) *(edx+0x1c)) # Var-register Var-register => eax
(write-buffered *(ebp+8) %eax)
eb/jump $emit-mu-index-bounds-check:index-done/disp8
}
# otherwise if index is a literal, print it
$emit-mu-index-bounds-check:emit-literal-index:
(lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax
(is-simple-mu-type? %eax 0) # => eax
3d/compare-eax-and 0/imm32/false
{
0f 84/jump-if-= break/disp32
(lookup *edx *(edx+4)) # Var-name Var-name => eax
(write-buffered *(ebp+8) %eax)
}
$emit-mu-index-bounds-check:index-done:
(write-buffered *(ebp+8) " ")
$emit-mu-index-bounds-check:emit-element-size:
# if index is a literal or int, print size of array element
{
{
(lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax
(is-simple-mu-type? %eax 0) # literal => eax
3d/compare-eax-and 0/imm32/false
75/jump-if-!= break/disp8
(lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax
(is-simple-mu-type? %eax 1) # int => eax
3d/compare-eax-and 0/imm32/false
75/jump-if-!= break/disp8
eb/jump $emit-mu-index-bounds-check:emit-element-size-offset/disp8
}
$emit-mu-index-bounds-check:emit-int-register-index:
(array-element-size %ebx *(ebp+0x14) *(ebp+0x18)) # => eax
(write-int32-hex-buffered *(ebp+8) %eax)
e9/jump $emit-mu-index-bounds-check:emit-base/disp32
}
$emit-mu-index-bounds-check:emit-element-size-offset:
# if index has type (offset ...), print "1"
(lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax
81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom
{
75/jump-if-!= break/disp8
(lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax
(is-simple-mu-type? %eax 7) # => eax
3d/compare-eax-and 0/imm32/false
{
0f 84/jump-if-= break/disp32
$emit-mu-index-bounds-check:emit-offset-register-index:
(write-buffered *(ebp+8) "1")
}
}
$emit-mu-index-bounds-check:emit-base:
# if base is in a register, print " *" base->register
81 7/subop/compare *(ebx+0x18) 0/imm32 # Var-register
{
74/jump-if-= break/disp8
(write-buffered *(ebp+8) " *")
(lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax
(write-buffered *(ebp+8) %eax)
e9/jump $emit-mu-index-bounds-check:emit-function-name/disp32
}
# otherwise print " *(ebp+" base->offset ")"
(write-buffered *(ebp+8) " *(ebp+")
(write-int32-hex-buffered *(ebp+8) *(ebx+0x14)) # Var-offset
(write-buffered *(ebp+8) ")")
$emit-mu-index-bounds-check:emit-function-name:
# " \"" function-name "\""
(write-buffered *(ebp+8) " \"")
8b/-> *(ebp+0x10) 1/r32/ecx
(lookup *ecx *(ecx+4)) # Function-name Function-name => eax
(write-buffered *(ebp+8) %eax)
(write-buffered *(ebp+8) "\"")
$emit-mu-index-bounds-check:emit-array-name:
# " \"" base->name "\""
(write-buffered *(ebp+8) " \"")
(lookup *ebx *(ebx+4)) # Var-name Var-name => eax
(write-buffered *(ebp+8) %eax)
(write-buffered *(ebp+8) "\")\n")
$emit-mu-index-bounds-check:end:
# . restore registers
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
translate-mu-index-stmt-with-array-in-register: # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
# . prologue
55/push-ebp

2
mu.md
View File

@ -681,7 +681,7 @@ populate x, 3 # array of 3 T's
I said at the start that most instructions map 1:1 to x86 machine code. To
enforce type- and memory-safety, I was forced to carve out a few exceptions:
* the `index` instruction on arrays, for bounds-checking (not yet implemented)
* the `index` instruction on arrays, for bounds-checking
* the `length` instruction on arrays, for translating the array size in bytes
into the number of elements.
* the `lookup` instruction on handles, for validating fat-pointer metadata

View File

@ -312,24 +312,28 @@ var/reg: (addr T) <- address var2: T
=> "8d/copy-address *(ebp+" var2.stack-offset ") " reg "/r32"
# Array operations
(TODO: bounds-checking)
var/reg <- index arr/rega: (addr array T), idx/regi: int
| if size-of(T) is 4 or 8
=> "8d/copy-address *(" rega "+" regi "<<" log2(size-of(T)) "+4) " reg "/r32"
| if size-of(T) is 1, 2, 4 or 8
=> "(__check-mu-array-bounds *" rega " %" regi " " size-of(T) ")"
"8d/copy-address *(" rega "+" regi "<<" log2(size-of(T)) "+4) " reg "/r32"
var/reg <- index arr: (array T len), idx/regi: int
=> "8d/copy-address *(ebp+" regi "<<" log2(size-of(T)) "+" (arr.stack-offset + 4) ") " reg "/r32"
=> "(__check-mu-array-bounds *(ebp+" arr.stack-offset ") %" regi " " size-of(T) ")"
"8d/copy-address *(ebp+" regi "<<" log2(size-of(T)) "+" (arr.stack-offset + 4) ") " reg "/r32"
var/reg <- index arr/rega: (addr array T), n
=> "8d/copy-address *(" rega "+" (n*size-of(T)+4) ") " reg "/r32"
=> "(__check-mu-array-bounds *" rega " " n " " size-of(T) ")"
"8d/copy-address *(" rega "+" (n*size-of(T)+4) ") " reg "/r32"
var/reg <- index arr: (array T len), n
=> "8d/copy-address *(ebp+" (arr.stack-offset+4+n*size-of(T)) ") " reg "/r32"
=> "(__check-mu-array-bounds *(ebp+" arr.stack-offset ") " n " " size-of(T) ")"
"8d/copy-address *(ebp+" (arr.stack-offset+4+n*size-of(T)) ") " reg "/r32"
var/reg: (offset T) <- compute-offset arr: (addr array T), idx/regi: int # arr can be in reg or mem
=> "69/multiply %" regi " " size-of(T) "/imm32 " reg "/r32"
var/reg: (offset T) <- compute-offset arr: (addr array T), idx: int # arr can be in reg or mem
=> "69/multiply *(ebp+" idx.stack-offset ") " size-of(T) "/imm32 " reg "/r32"
var/reg <- index arr/rega: (addr array T), o/rego: offset
=> "8d/copy-address *(" rega "+" rego "+4) " reg "/r32"
var/reg <- index arr/rega: (addr array T), o/rego: (offset T)
=> "(__check-mu-array-bounds %" rega " %" rego " 1 \"" function-name "\")"
"8d/copy-address *(" rega "+" rego "+4) " reg "/r32"
Computing the length of an array is complex.