From f25f2e98f9a35a275b5dc31ea80cbbb26fe88c92 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sat, 30 Nov 2019 14:17:13 -0800 Subject: 5786 --- html/069allocate.subx.html | 415 ++++++++++++++++++++++----------------------- 1 file changed, 206 insertions(+), 209 deletions(-) (limited to 'html/069allocate.subx.html') diff --git a/html/069allocate.subx.html b/html/069allocate.subx.html index 1c5489ad..993274a9 100644 --- a/html/069allocate.subx.html +++ b/html/069allocate.subx.html @@ -19,7 +19,6 @@ a { color:inherit; } .subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } .subxS1Comment { color: #0000af; } -.CommentedCode { color: #8a8a8a; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .subxMinorFunction { color: #875f5f; } @@ -90,215 +89,213 @@ if ('onhashchange' in window) { 28 # a reasonable default 29 Heap-size: 30 0x200000/imm32/2MB - 31 #? # TODO: reclaim space allocated in tests. - 32 #? 0x2000000/imm32/32MB - 33 - 34 == code - 35 # instruction effective address register displacement immediate - 36 # . op subop mod rm32 base index scale r32 - 37 # . 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 + 31 + 32 == code + 33 # instruction effective address register displacement immediate + 34 # . op subop mod rm32 base index scale r32 + 35 # . 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 + 36 + 37 # Let's start initializing the default allocation descriptor. 38 - 39 # Let's start initializing the default allocation descriptor. - 40 - 41 Entry: - 42 # initialize heap - 43 # . Heap = new-segment(Heap-size) - 44 # . . push args - 45 68/push Heap/imm32 - 46 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Heap-size/disp32 # push *Heap-size - 47 # . . call - 48 e8/call new-segment/disp32 - 49 # . . discard args - 50 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - 51 - 52 e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'. - 53 $array-equal-main:end: - 54 # syscall(exit, Num-test-failures) - 55 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/ebx Num-test-failures/disp32 # copy *Num-test-failures to ebx - 56 b8/copy-to-eax 1/imm32/exit - 57 cd/syscall 0x80/imm8 - 58 - 59 # Claim the next 'n' bytes of memory starting at ad->curr and update ad->curr. - 60 # Abort if there isn't enough memory in 'ad'. - 61 allocate: # ad : (address allocation-descriptor), n : int -> address-or-null/eax - 62 # . prologue - 63 55/push-ebp - 64 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - 65 # . save registers - 66 51/push-ecx - 67 52/push-edx - 68 # ecx = ad - 69 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx - 70 # save ad->curr - 71 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax - 72 # check if there's enough space - 73 # . edx = ad->curr + n - 74 89/copy 3/mod/direct 2/rm32/edx . . . 0/r32/eax . . # copy eax to edx - 75 03/add 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0xc/disp8 . # add *(ebp+12) to edx - 76 3b/compare 1/mod/*+disp8 1/rm32/ecx . . . 2/r32/edx 4/disp8 . # compare edx with *(ecx+4) - 77 73/jump-if-greater-or-equal-signed $allocate:abort/disp8 - 78 $allocate:commit: - 79 # update ad->curr - 80 89/copy 0/mod/indirect 1/rm32/ecx . . . 2/r32/edx . . # copy edx to *ecx - 81 $allocate:end: - 82 # . restore registers - 83 5a/pop-to-edx - 84 59/pop-to-ecx - 85 # . epilogue - 86 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 87 5d/pop-to-ebp - 88 c3/return - 89 - 90 $allocate:abort: - 91 # . _write(2/stderr, error) - 92 # . . push args - 93 68/push "allocate: failed to allocate\n"/imm32 - 94 68/push 2/imm32/stderr - 95 # . . call - 96 e8/call _write/disp32 - 97 # . . discard args - 98 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - 99 # . syscall(exit, 1) -100 bb/copy-to-ebx 1/imm32 -101 b8/copy-to-eax 1/imm32/exit -102 cd/syscall 0x80/imm8 -103 # never gets here -104 -105 test-allocate-success: -106 # . prologue -107 55/push-ebp -108 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp -109 # var ad/ecx : (address allocation-descriptor) = {11, 15} -110 68/push 0xf/imm32/limit -111 68/push 0xb/imm32/curr -112 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx -113 # eax = allocate(ad, 3) -114 # . . push args -115 68/push 3/imm32 -116 51/push-ecx -117 # . . call -118 e8/call allocate/disp32 -119 # . . discard args -120 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -121 # check-ints-equal(eax, 11, msg) -122 # . . push args -123 68/push "F - test-allocate-success: returns current pointer of allocation descriptor"/imm32 -124 68/push 0xb/imm32 -125 50/push-eax -126 # . . call -127 e8/call check-ints-equal/disp32 -128 # . . discard args -129 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp -130 # check-ints-equal(ad->curr, 14, msg) -131 # . . push args -132 68/push "F - test-allocate-success: updates allocation descriptor"/imm32 -133 68/push 0xe/imm32 -134 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx -135 # . . call -136 e8/call check-ints-equal/disp32 -137 # . . discard args -138 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp -139 # . epilogue -140 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp -141 5d/pop-to-ebp -142 c3/return -143 -144 _pending-test-allocate-failure: -145 # . prologue -146 55/push-ebp -147 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp -148 # var ad/ecx : (address allocation-descriptor) = {11, 15} -149 68/push 0xf/imm32/limit -150 68/push 0xb/imm32/curr -151 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx -152 # eax = allocate(ad, 6) -153 # . . push args -154 68/push 6/imm32 -155 51/push-ecx -156 # . . call -157 e8/call allocate/disp32 -158 # . . discard args -159 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -160 # check-ints-equal(eax, 0, msg) -161 # . . push args -162 68/push "F - test-allocate-failure: returns null"/imm32 -163 68/push 0/imm32 -164 50/push-eax -165 # . . call -166 e8/call check-ints-equal/disp32 -167 # . . discard args -168 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp -169 # no change to ad->curr -170 # . check-ints-equal(ad->curr, 11) -171 # . . push args -172 68/push "F - test-allocate-failure: updates allocation descriptor"/imm32 -173 68/push 0xb/imm32 -174 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx -175 # . . call -176 e8/call check-ints-equal/disp32 -177 # . . discard args -178 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp -179 # . epilogue -180 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp -181 5d/pop-to-ebp -182 c3/return -183 -184 # helper: create a nested allocation descriptor (useful for tests) -185 allocate-region: # ad : (address allocation-descriptor), n : int -> new-ad : (address allocation-descriptor) -186 # . prologue -187 55/push-ebp -188 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp -189 # . save registers -190 51/push-ecx -191 # eax = allocate(ad, n) -192 # . . push args -193 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) -194 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) -195 # . . call -196 e8/call allocate/disp32 -197 # . . discard args -198 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -199 # if (eax == 0) abort -200 3d/compare-eax-and 0/imm32 -201 74/jump-if-equal $allocate-region:abort/disp8 -202 # earmark 8 bytes at the start for a new allocation descriptor -203 # . *eax = eax + 8 -204 89/copy 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # copy eax to ecx -205 81 0/subop/add 3/mod/direct 1/rm32/ecx . . . . . 8/imm32 # add to ecx -206 89/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy ecx to *eax -207 # . *(eax+4) = eax + n -208 89/copy 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # copy eax to ecx -209 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # add *(ebp+12) to ecx -210 89/copy 1/mod/*+disp8 0/rm32/eax . . . 1/r32/ecx 4/disp8 . # copy ecx to *(eax+4) -211 # . restore registers -212 59/pop-to-ecx -213 # . epilogue -214 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp -215 5d/pop-to-ebp -216 c3/return -217 -218 # We could create a more general '$abort' jump target, but then we'd need to do -219 # a conditional jump followed by loading the error message and an unconditional -220 # jump. Or we'd need to unconditionally load the error message before a -221 # conditional jump, even if it's unused the vast majority of the time. This way -222 # we bloat a potentially cold segment in RAM so we can abort with a single -223 # instruction. -224 $allocate-region:abort: -225 # . _write(2/stderr, error) -226 # . . push args -227 68/push "allocate-region: failed to allocate\n"/imm32 -228 68/push 2/imm32/stderr -229 # . . call -230 e8/call _write/disp32 -231 # . . discard args -232 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -233 # . syscall(exit, 1) -234 bb/copy-to-ebx 1/imm32 -235 b8/copy-to-eax 1/imm32/exit -236 cd/syscall 0x80/imm8 -237 # never gets here -238 -239 # . . vim:nowrap:textwidth=0 + 39 Entry: + 40 # initialize heap + 41 # . Heap = new-segment(Heap-size) + 42 # . . push args + 43 68/push Heap/imm32 + 44 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Heap-size/disp32 # push *Heap-size + 45 # . . call + 46 e8/call new-segment/disp32 + 47 # . . discard args + 48 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + 49 + 50 e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'. + 51 $array-equal-main:end: + 52 # syscall(exit, Num-test-failures) + 53 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/ebx Num-test-failures/disp32 # copy *Num-test-failures to ebx + 54 b8/copy-to-eax 1/imm32/exit + 55 cd/syscall 0x80/imm8 + 56 + 57 # Claim the next 'n' bytes of memory starting at ad->curr and update ad->curr. + 58 # Abort if there isn't enough memory in 'ad'. + 59 allocate: # ad : (address allocation-descriptor), n : int -> address-or-null/eax + 60 # . prologue + 61 55/push-ebp + 62 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp + 63 # . save registers + 64 51/push-ecx + 65 52/push-edx + 66 # ecx = ad + 67 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx + 68 # save ad->curr + 69 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax + 70 # check if there's enough space + 71 # . edx = ad->curr + n + 72 89/copy 3/mod/direct 2/rm32/edx . . . 0/r32/eax . . # copy eax to edx + 73 03/add 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0xc/disp8 . # add *(ebp+12) to edx + 74 3b/compare 1/mod/*+disp8 1/rm32/ecx . . . 2/r32/edx 4/disp8 . # compare edx with *(ecx+4) + 75 73/jump-if-greater-or-equal-signed $allocate:abort/disp8 + 76 $allocate:commit: + 77 # update ad->curr + 78 89/copy 0/mod/indirect 1/rm32/ecx . . . 2/r32/edx . . # copy edx to *ecx + 79 $allocate:end: + 80 # . restore registers + 81 5a/pop-to-edx + 82 59/pop-to-ecx + 83 # . epilogue + 84 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp + 85 5d/pop-to-ebp + 86 c3/return + 87 + 88 $allocate:abort: + 89 # . _write(2/stderr, error) + 90 # . . push args + 91 68/push "allocate: failed to allocate\n"/imm32 + 92 68/push 2/imm32/stderr + 93 # . . call + 94 e8/call _write/disp32 + 95 # . . discard args + 96 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + 97 # . syscall(exit, 1) + 98 bb/copy-to-ebx 1/imm32 + 99 b8/copy-to-eax 1/imm32/exit +100 cd/syscall 0x80/imm8 +101 # never gets here +102 +103 test-allocate-success: +104 # . prologue +105 55/push-ebp +106 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp +107 # var ad/ecx : (address allocation-descriptor) = {11, 15} +108 68/push 0xf/imm32/limit +109 68/push 0xb/imm32/curr +110 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx +111 # eax = allocate(ad, 3) +112 # . . push args +113 68/push 3/imm32 +114 51/push-ecx +115 # . . call +116 e8/call allocate/disp32 +117 # . . discard args +118 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +119 # check-ints-equal(eax, 11, msg) +120 # . . push args +121 68/push "F - test-allocate-success: returns current pointer of allocation descriptor"/imm32 +122 68/push 0xb/imm32 +123 50/push-eax +124 # . . call +125 e8/call check-ints-equal/disp32 +126 # . . discard args +127 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +128 # check-ints-equal(ad->curr, 14, msg) +129 # . . push args +130 68/push "F - test-allocate-success: updates allocation descriptor"/imm32 +131 68/push 0xe/imm32 +132 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx +133 # . . call +134 e8/call check-ints-equal/disp32 +135 # . . discard args +136 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +137 # . epilogue +138 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp +139 5d/pop-to-ebp +140 c3/return +141 +142 _pending-test-allocate-failure: +143 # . prologue +144 55/push-ebp +145 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp +146 # var ad/ecx : (address allocation-descriptor) = {11, 15} +147 68/push 0xf/imm32/limit +148 68/push 0xb/imm32/curr +149 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx +150 # eax = allocate(ad, 6) +151 # . . push args +152 68/push 6/imm32 +153 51/push-ecx +154 # . . call +155 e8/call allocate/disp32 +156 # . . discard args +157 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +158 # check-ints-equal(eax, 0, msg) +159 # . . push args +160 68/push "F - test-allocate-failure: returns null"/imm32 +161 68/push 0/imm32 +162 50/push-eax +163 # . . call +164 e8/call check-ints-equal/disp32 +165 # . . discard args +166 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +167 # no change to ad->curr +168 # . check-ints-equal(ad->curr, 11) +169 # . . push args +170 68/push "F - test-allocate-failure: updates allocation descriptor"/imm32 +171 68/push 0xb/imm32 +172 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx +173 # . . call +174 e8/call check-ints-equal/disp32 +175 # . . discard args +176 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +177 # . epilogue +178 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp +179 5d/pop-to-ebp +180 c3/return +181 +182 # helper: create a nested allocation descriptor (useful for tests) +183 allocate-region: # ad : (address allocation-descriptor), n : int -> new-ad : (address allocation-descriptor) +184 # . prologue +185 55/push-ebp +186 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp +187 # . save registers +188 51/push-ecx +189 # eax = allocate(ad, n) +190 # . . push args +191 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) +192 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) +193 # . . call +194 e8/call allocate/disp32 +195 # . . discard args +196 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +197 # if (eax == 0) abort +198 3d/compare-eax-and 0/imm32 +199 74/jump-if-equal $allocate-region:abort/disp8 +200 # earmark 8 bytes at the start for a new allocation descriptor +201 # . *eax = eax + 8 +202 89/copy 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # copy eax to ecx +203 81 0/subop/add 3/mod/direct 1/rm32/ecx . . . . . 8/imm32 # add to ecx +204 89/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy ecx to *eax +205 # . *(eax+4) = eax + n +206 89/copy 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # copy eax to ecx +207 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # add *(ebp+12) to ecx +208 89/copy 1/mod/*+disp8 0/rm32/eax . . . 1/r32/ecx 4/disp8 . # copy ecx to *(eax+4) +209 # . restore registers +210 59/pop-to-ecx +211 # . epilogue +212 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp +213 5d/pop-to-ebp +214 c3/return +215 +216 # We could create a more general '$abort' jump target, but then we'd need to do +217 # a conditional jump followed by loading the error message and an unconditional +218 # jump. Or we'd need to unconditionally load the error message before a +219 # conditional jump, even if it's unused the vast majority of the time. This way +220 # we bloat a potentially cold segment in RAM so we can abort with a single +221 # instruction. +222 $allocate-region:abort: +223 # . _write(2/stderr, error) +224 # . . push args +225 68/push "allocate-region: failed to allocate\n"/imm32 +226 68/push 2/imm32/stderr +227 # . . call +228 e8/call _write/disp32 +229 # . . discard args +230 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +231 # . syscall(exit, 1) +232 bb/copy-to-ebx 1/imm32 +233 b8/copy-to-eax 1/imm32/exit +234 cd/syscall 0x80/imm8 +235 # never gets here +236 +237 # . . vim:nowrap:textwidth=0 -- cgit 1.4.1-2-gfad0