diff --git a/html/050_write.subx.html b/html/050_write.subx.html index 967cf9d8..7d0d3ac4 100644 --- a/html/050_write.subx.html +++ b/html/050_write.subx.html @@ -20,8 +20,8 @@ a { color:inherit; } .subxS1Comment { color: #0000af; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxMinorFunction { color: #875f5f; } .Constant { color: #008787; } +.subxMinorFunction { color: #875f5f; } --> diff --git a/html/052kernel-string-equal.subx.html b/html/052kernel-string-equal.subx.html index 9215365d..52d84bfa 100644 --- a/html/052kernel-string-equal.subx.html +++ b/html/052kernel-string-equal.subx.html @@ -15,15 +15,15 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } +.subxS2Comment { color: #8a8a8a; } +.subxTest { color: #5f8700; } .subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } .subxS1Comment { color: #0000af; } -.subxTest { color: #5f8700; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .subxMinorFunction { color: #875f5f; } .Constant { color: #008787; } -.subxS2Comment { color: #8a8a8a; } .subxH1Comment { color: #005faf; text-decoration: underline; } --> @@ -60,277 +60,276 @@ if ('onhashchange' in window) { https://github.com/akkartik/mu/blob/master/052kernel-string-equal.subx
-  1 # Checking null-terminated ascii strings.
+  1 # Checking null-terminated strings.
   2 #
   3 # By default we create strings as arrays of bytes, and all arrays have a 4-byte
-  4 # length prefix.
+  4 # size prefix.
   5 #
-  6 # However, we sometimes need to deal with null-prefixed strings when interacting
-  7 # with the Linux kernel. This layer implements a function for comparing a
-  8 # null-terminated 'kernel string' with a length-prefixed 'SubX string'.
-  9 #
- 10 # To run (from the subx directory):
- 11 #   $ ./bootstrap translate 05[0-2]*.subx -o /tmp/tmp52
- 12 #   $ ./bootstrap run /tmp/tmp52  # runs a series of tests
- 13 #   ......  # all tests pass
- 14 #
- 15 # (We can't yet run the tests when given a "test" commandline argument,
- 16 # because checking for it would require the function being tested! Breakage
- 17 # would cause tests to not run, rather than to fail as we'd like.)
- 18 
- 19 == code
- 20 #   instruction                     effective address                                                   register    displacement    immediate
- 21 # . op          subop               mod             rm32          base        index         scale       r32
- 22 # . 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
- 23 
- 24 Entry:  # run all tests
- 25     e8/call  run-tests/disp32  # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
- 26     # syscall(exit, Num-test-failures)
- 27     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/ebx   Num-test-failures/disp32          # copy *Num-test-failures to ebx
- 28     b8/copy-to-eax  1/imm32/exit
- 29     cd/syscall  0x80/imm8
- 30 
- 31 # compare a null-terminated ascii string with a more idiomatic length-prefixed byte array
- 32 # reason for the name: the only place we should have null-terminated ascii strings is from commandline args
- 33 kernel-string-equal?:  # s: (addr kernel-string), benchmark: (addr array byte) -> eax: boolean
- 34     # pseudocode:
- 35     #   n = benchmark->length
- 36     #   s1 = s
- 37     #   s2 = benchmark->data
- 38     #   i = 0
- 39     #   while (i < n)
- 40     #     c1 = *s1
- 41     #     c2 = *s2
- 42     #     if (c1 == 0) return false
- 43     #     if (c1 != c2) return false
- 44     #     ++s1, ++s2, ++i
- 45     #   return *s1 == 0
- 46     #
- 47     # registers:
- 48     #   i: ecx
- 49     #   n: edx
- 50     #   s1: edi
- 51     #   s2: esi
- 52     #   c1: eax
- 53     #   c2: ebx
- 54     #
- 55     # . prologue
- 56     55/push-ebp
- 57     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 58     # . save registers
- 59     51/push-ecx
- 60     52/push-edx
- 61     53/push-ebx
- 62     56/push-esi
- 63     57/push-edi
- 64     # var s1/edi: (addr byte) = s
- 65     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
- 66     # var n/edx: int = benchmark->length
- 67     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
- 68     8b/copy                         0/mod/indirect  2/rm32/edx    .           .             .           2/r32/edx   .               .                 # copy *edx to edx
- 69     # var s2/esi: (addr byte) = benchmark->data
- 70     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
- 71     81          0/subop/add         3/mod/direct    6/rm32/esi    .           .             .           .           .               4/imm32           # add to esi
- 72     # var i/ecx: int = 0
- 73     b9/copy-to-ecx  0/imm32/exit
- 74     # var c1/eax: byte = 0
- 75     b8/copy-to-eax  0/imm32
- 76     # var c2/ebx: byte = 0
- 77     bb/copy-to-ebx  0/imm32
- 78 $kernel-string-equal?:loop:
- 79     # if (i >= n) break
- 80     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
- 81     7d/jump-if->=  $kernel-string-equal?:break/disp8
- 82     # c1 = *s1
- 83     8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .             .           0/r32/AL    .               .                 # copy byte at *edi to AL
- 84     # c2 = *s2
- 85     8a/copy-byte                    0/mod/indirect  6/rm32/esi    .           .             .           3/r32/BL    .               .                 # copy byte at *esi to BL
- 86     # if (c1 == 0) return false
- 87     3d/compare-eax-and  0/imm32/null
- 88     74/jump-if-=  $kernel-string-equal?:false/disp8
- 89     # if (c1 != c2) return false
- 90     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
- 91     75/jump-if-!=  $kernel-string-equal?:false/disp8
- 92     # ++i
- 93     41/increment-ecx
- 94     # ++s1
- 95     47/increment-edi
- 96     # ++s2
- 97     46/increment-esi
- 98     eb/jump  $kernel-string-equal?:loop/disp8
- 99 $kernel-string-equal?:break:
-100     # return *s1 == 0
-101     8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .             .           0/r32/AL    .               .                 # copy byte at *edi to AL
-102     3d/compare-eax-and  0/imm32/null
-103     75/jump-if-!=  $kernel-string-equal?:false/disp8
-104 $kernel-string-equal?:true:
-105     b8/copy-to-eax  1/imm32
-106     eb/jump  $kernel-string-equal?:end/disp8
-107 $kernel-string-equal?:false:
-108     b8/copy-to-eax  0/imm32
-109 $kernel-string-equal?:end:
-110     # . restore registers
-111     5f/pop-to-edi
-112     5e/pop-to-esi
-113     5b/pop-to-ebx
-114     5a/pop-to-edx
-115     59/pop-to-ecx
-116     # . epilogue
-117     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-118     5d/pop-to-ebp
-119     c3/return
-120 
-121 # - tests
-122 
-123 test-compare-null-kernel-string-with-empty-array:
-124     # eax = kernel-string-equal?(Null-kernel-string, "")
-125     # . . push args
-126     68/push  ""/imm32
-127     68/push  Null-kernel-string/imm32
-128     # . . call
-129     e8/call  kernel-string-equal?/disp32
-130     # . . discard args
-131     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-132     # check-ints-equal(eax, 1, msg)
-133     # . . push args
-134     68/push  "F - test-compare-null-kernel-string-with-empty-array"/imm32
-135     68/push  1/imm32/true
-136     50/push-eax
-137     # . . call
-138     e8/call  check-ints-equal/disp32
-139     # . . discard args
-140     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-141     c3/return
-142 
-143 test-compare-null-kernel-string-with-non-empty-array:
-144     # eax = kernel-string-equal?(Null-kernel-string, "Abc")
-145     # . . push args
-146     68/push  "Abc"/imm32
-147     68/push  Null-kernel-string/imm32
-148     # . . call
-149     e8/call  kernel-string-equal?/disp32
-150     # . . discard args
-151     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-152     # check-ints-equal(eax, 0, msg)
-153     # . . push args
-154     68/push  "F - test-compare-null-kernel-string-with-non-empty-array"/imm32
-155     68/push  0/imm32/false
-156     50/push-eax
-157     # . . call
-158     e8/call  check-ints-equal/disp32
-159     # . . discard args
-160     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-161     c3/return
-162 
-163 test-compare-kernel-string-with-equal-array:
-164     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Abc")
-165     # . . push args
-166     68/push  "Abc"/imm32
-167     68/push  _test-Abc-kernel-string/imm32
-168     # . . call
-169     e8/call  kernel-string-equal?/disp32
-170     # . . discard args
-171     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-172     # check-ints-equal(eax, 1, msg)
-173     # . . push args
-174     68/push  "F - test-compare-kernel-string-with-equal-array"/imm32
-175     68/push  1/imm32/true
-176     50/push-eax
-177     # . . call
-178     e8/call  check-ints-equal/disp32
-179     # . . discard args
-180     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-181     c3/return
-182 
-183 test-compare-kernel-string-with-inequal-array:
-184     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Adc")
-185     # . . push args
-186     68/push  "Adc"/imm32
-187     68/push  _test-Abc-kernel-string/imm32
-188     # . . call
-189     e8/call  kernel-string-equal?/disp32
-190     # . . discard args
-191     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-192     # check-ints-equal(eax, 0, msg)
-193     # . . push args
-194     68/push  "F - test-compare-kernel-string-with-equal-array"/imm32
-195     68/push  0/imm32/false
-196     50/push-eax
-197     # . . call
-198     e8/call  check-ints-equal/disp32
-199     # . . discard args
-200     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-201     c3/return
-202 
-203 test-compare-kernel-string-with-empty-array:
-204     # eax = kernel-string-equal?(_test-Abc-kernel-string, "")
-205     # . . push args
-206     68/push  ""/imm32
-207     68/push  _test-Abc-kernel-string/imm32
-208     # . . call
-209     e8/call  kernel-string-equal?/disp32
-210     # . . discard args
-211     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-212     # check-ints-equal(eax, 0, msg)
-213     # . . push args
-214     68/push  "F - test-compare-kernel-string-with-equal-array"/imm32
-215     68/push  0/imm32/false
-216     50/push-eax
-217     # . . call
-218     e8/call  check-ints-equal/disp32
-219     # . . discard args
-220     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-221     c3/return
-222 
-223 test-compare-kernel-string-with-shorter-array:
-224     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Ab")
-225     # . . push args
-226     68/push  "Ab"/imm32
-227     68/push  _test-Abc-kernel-string/imm32
-228     # . . call
-229     e8/call  kernel-string-equal?/disp32
-230     # . . discard args
-231     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-232     # check-ints-equal(eax, 0, msg)
-233     # . . push args
-234     68/push  "F - test-compare-kernel-string-with-shorter-array"/imm32
-235     68/push  0/imm32/false
-236     50/push-eax
-237     # . . call
-238     e8/call  check-ints-equal/disp32
-239     # . . discard args
-240     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-241     c3/return
-242 
-243 test-compare-kernel-string-with-longer-array:
-244     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Abcd")
-245     # . . push args
-246     68/push  "Abcd"/imm32
-247     68/push  _test-Abc-kernel-string/imm32
-248     # . . call
-249     e8/call  kernel-string-equal?/disp32
-250     # . . discard args
-251     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-252     # check-ints-equal(eax, 0, msg)
-253     # . . push args
-254     68/push  "F - test-compare-kernel-string-with-longer-array"/imm32
-255     68/push  0/imm32/false
-256     50/push-eax
-257     # . . call
-258     e8/call  check-ints-equal/disp32
-259     # . . discard args
-260     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-261     c3/return
-262 
-263 == data
-264 
-265 Null-kernel-string:  # (addr kernel-string)
-266     00/null
-267 
-268 _test-Abc-kernel-string:  # (addr kernel-string)
-269     41/A 62/b 63/c 00/null
-270 
-271 # . . vim:nowrap:textwidth=0
+  6 # However, we sometimes need to deal with null-terminated strings when
+  7 # interacting with the Linux kernel. This layer implements a function for
+  8 # comparing a null-terminated 'kernel string' with a size-prefixed 'SubX
+  9 # string'.
+ 10 #
+ 11 # To run (from the subx directory):
+ 12 #   $ ./bootstrap translate 05[0-2]*.subx -o /tmp/tmp52
+ 13 #   $ ./bootstrap run /tmp/tmp52  # runs a series of tests
+ 14 #   ......  # all tests pass
+ 15 #
+ 16 # (We can't yet run the tests when given a "test" commandline argument,
+ 17 # because checking for it would require the function being tested! Breakage
+ 18 # would cause tests to not run, rather than to fail as we'd like.)
+ 19 
+ 20 == code
+ 21 #   instruction                     effective address                                                   register    displacement    immediate
+ 22 # . op          subop               mod             rm32          base        index         scale       r32
+ 23 # . 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
+ 24 
+ 25 Entry:  # run all tests
+ 26     e8/call  run-tests/disp32  # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
+ 27     # syscall(exit, Num-test-failures)
+ 28     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/ebx   Num-test-failures/disp32          # copy *Num-test-failures to ebx
+ 29     b8/copy-to-eax  1/imm32/exit
+ 30     cd/syscall  0x80/imm8
+ 31 
+ 32 kernel-string-equal?:  # s: (addr kernel-string), benchmark: (addr array byte) -> eax: boolean
+ 33     # pseudocode:
+ 34     #   n = benchmark->size
+ 35     #   s1 = s
+ 36     #   s2 = benchmark->data
+ 37     #   i = 0
+ 38     #   while (i < n)
+ 39     #     c1 = *s1
+ 40     #     c2 = *s2
+ 41     #     if (c1 == 0) return false
+ 42     #     if (c1 != c2) return false
+ 43     #     ++s1, ++s2, ++i
+ 44     #   return *s1 == 0
+ 45     #
+ 46     # registers:
+ 47     #   i: ecx
+ 48     #   n: edx
+ 49     #   s1: edi
+ 50     #   s2: esi
+ 51     #   c1: eax
+ 52     #   c2: ebx
+ 53     #
+ 54     # . prologue
+ 55     55/push-ebp
+ 56     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 57     # . save registers
+ 58     51/push-ecx
+ 59     52/push-edx
+ 60     53/push-ebx
+ 61     56/push-esi
+ 62     57/push-edi
+ 63     # var s1/edi: (addr byte) = s
+ 64     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
+ 65     # var n/edx: int = benchmark->size
+ 66     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
+ 67     8b/copy                         0/mod/indirect  2/rm32/edx    .           .             .           2/r32/edx   .               .                 # copy *edx to edx
+ 68     # var s2/esi: (addr byte) = benchmark->data
+ 69     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
+ 70     81          0/subop/add         3/mod/direct    6/rm32/esi    .           .             .           .           .               4/imm32           # add to esi
+ 71     # var i/ecx: int = 0
+ 72     b9/copy-to-ecx  0/imm32/exit
+ 73     # var c1/eax: byte = 0
+ 74     b8/copy-to-eax  0/imm32
+ 75     # var c2/ebx: byte = 0
+ 76     bb/copy-to-ebx  0/imm32
+ 77 $kernel-string-equal?:loop:
+ 78     # if (i >= n) break
+ 79     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
+ 80     7d/jump-if->=  $kernel-string-equal?:break/disp8
+ 81     # c1 = *s1
+ 82     8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .             .           0/r32/AL    .               .                 # copy byte at *edi to AL
+ 83     # c2 = *s2
+ 84     8a/copy-byte                    0/mod/indirect  6/rm32/esi    .           .             .           3/r32/BL    .               .                 # copy byte at *esi to BL
+ 85     # if (c1 == 0) return false
+ 86     3d/compare-eax-and  0/imm32/null
+ 87     74/jump-if-=  $kernel-string-equal?:false/disp8
+ 88     # if (c1 != c2) return false
+ 89     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
+ 90     75/jump-if-!=  $kernel-string-equal?:false/disp8
+ 91     # ++i
+ 92     41/increment-ecx
+ 93     # ++s1
+ 94     47/increment-edi
+ 95     # ++s2
+ 96     46/increment-esi
+ 97     eb/jump  $kernel-string-equal?:loop/disp8
+ 98 $kernel-string-equal?:break:
+ 99     # return *s1 == 0
+100     8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .             .           0/r32/AL    .               .                 # copy byte at *edi to AL
+101     3d/compare-eax-and  0/imm32/null
+102     75/jump-if-!=  $kernel-string-equal?:false/disp8
+103 $kernel-string-equal?:true:
+104     b8/copy-to-eax  1/imm32
+105     eb/jump  $kernel-string-equal?:end/disp8
+106 $kernel-string-equal?:false:
+107     b8/copy-to-eax  0/imm32
+108 $kernel-string-equal?:end:
+109     # . restore registers
+110     5f/pop-to-edi
+111     5e/pop-to-esi
+112     5b/pop-to-ebx
+113     5a/pop-to-edx
+114     59/pop-to-ecx
+115     # . epilogue
+116     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+117     5d/pop-to-ebp
+118     c3/return
+119 
+120 # - tests
+121 
+122 test-compare-null-kernel-string-with-empty-array:
+123     # eax = kernel-string-equal?(Null-kernel-string, "")
+124     # . . push args
+125     68/push  ""/imm32
+126     68/push  Null-kernel-string/imm32
+127     # . . call
+128     e8/call  kernel-string-equal?/disp32
+129     # . . discard args
+130     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+131     # check-ints-equal(eax, 1, msg)
+132     # . . push args
+133     68/push  "F - test-compare-null-kernel-string-with-empty-array"/imm32
+134     68/push  1/imm32/true
+135     50/push-eax
+136     # . . call
+137     e8/call  check-ints-equal/disp32
+138     # . . discard args
+139     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+140     c3/return
+141 
+142 test-compare-null-kernel-string-with-non-empty-array:
+143     # eax = kernel-string-equal?(Null-kernel-string, "Abc")
+144     # . . push args
+145     68/push  "Abc"/imm32
+146     68/push  Null-kernel-string/imm32
+147     # . . call
+148     e8/call  kernel-string-equal?/disp32
+149     # . . discard args
+150     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+151     # check-ints-equal(eax, 0, msg)
+152     # . . push args
+153     68/push  "F - test-compare-null-kernel-string-with-non-empty-array"/imm32
+154     68/push  0/imm32/false
+155     50/push-eax
+156     # . . call
+157     e8/call  check-ints-equal/disp32
+158     # . . discard args
+159     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+160     c3/return
+161 
+162 test-compare-kernel-string-with-equal-array:
+163     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Abc")
+164     # . . push args
+165     68/push  "Abc"/imm32
+166     68/push  _test-Abc-kernel-string/imm32
+167     # . . call
+168     e8/call  kernel-string-equal?/disp32
+169     # . . discard args
+170     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+171     # check-ints-equal(eax, 1, msg)
+172     # . . push args
+173     68/push  "F - test-compare-kernel-string-with-equal-array"/imm32
+174     68/push  1/imm32/true
+175     50/push-eax
+176     # . . call
+177     e8/call  check-ints-equal/disp32
+178     # . . discard args
+179     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+180     c3/return
+181 
+182 test-compare-kernel-string-with-inequal-array:
+183     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Adc")
+184     # . . push args
+185     68/push  "Adc"/imm32
+186     68/push  _test-Abc-kernel-string/imm32
+187     # . . call
+188     e8/call  kernel-string-equal?/disp32
+189     # . . discard args
+190     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+191     # check-ints-equal(eax, 0, msg)
+192     # . . push args
+193     68/push  "F - test-compare-kernel-string-with-equal-array"/imm32
+194     68/push  0/imm32/false
+195     50/push-eax
+196     # . . call
+197     e8/call  check-ints-equal/disp32
+198     # . . discard args
+199     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+200     c3/return
+201 
+202 test-compare-kernel-string-with-empty-array:
+203     # eax = kernel-string-equal?(_test-Abc-kernel-string, "")
+204     # . . push args
+205     68/push  ""/imm32
+206     68/push  _test-Abc-kernel-string/imm32
+207     # . . call
+208     e8/call  kernel-string-equal?/disp32
+209     # . . discard args
+210     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+211     # check-ints-equal(eax, 0, msg)
+212     # . . push args
+213     68/push  "F - test-compare-kernel-string-with-equal-array"/imm32
+214     68/push  0/imm32/false
+215     50/push-eax
+216     # . . call
+217     e8/call  check-ints-equal/disp32
+218     # . . discard args
+219     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+220     c3/return
+221 
+222 test-compare-kernel-string-with-shorter-array:
+223     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Ab")
+224     # . . push args
+225     68/push  "Ab"/imm32
+226     68/push  _test-Abc-kernel-string/imm32
+227     # . . call
+228     e8/call  kernel-string-equal?/disp32
+229     # . . discard args
+230     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+231     # check-ints-equal(eax, 0, msg)
+232     # . . push args
+233     68/push  "F - test-compare-kernel-string-with-shorter-array"/imm32
+234     68/push  0/imm32/false
+235     50/push-eax
+236     # . . call
+237     e8/call  check-ints-equal/disp32
+238     # . . discard args
+239     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+240     c3/return
+241 
+242 test-compare-kernel-string-with-longer-array:
+243     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Abcd")
+244     # . . push args
+245     68/push  "Abcd"/imm32
+246     68/push  _test-Abc-kernel-string/imm32
+247     # . . call
+248     e8/call  kernel-string-equal?/disp32
+249     # . . discard args
+250     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+251     # check-ints-equal(eax, 0, msg)
+252     # . . push args
+253     68/push  "F - test-compare-kernel-string-with-longer-array"/imm32
+254     68/push  0/imm32/false
+255     50/push-eax
+256     # . . call
+257     e8/call  check-ints-equal/disp32
+258     # . . discard args
+259     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+260     c3/return
+261 
+262 == data
+263 
+264 Null-kernel-string:  # (addr kernel-string)
+265     00/null
+266 
+267 _test-Abc-kernel-string:  # (addr kernel-string)
+268     41/A 62/b 63/c 00/null
+269 
+270 # . . vim:nowrap:textwidth=0
 
diff --git a/html/053new-segment.subx.html b/html/053new-segment.subx.html index fac198a7..29f3a2dd 100644 --- a/html/053new-segment.subx.html +++ b/html/053new-segment.subx.html @@ -21,8 +21,8 @@ a { color:inherit; } .subxS1Comment { color: #0000af; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxMinorFunction { color: #875f5f; } .Constant { color: #008787; } +.subxMinorFunction { color: #875f5f; } --> diff --git a/html/054string-equal.subx.html b/html/054string-equal.subx.html index 87480b2a..4fe3c4cc 100644 --- a/html/054string-equal.subx.html +++ b/html/054string-equal.subx.html @@ -15,15 +15,15 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } -.subxFunction { color: #af5f00; text-decoration: underline; } +.subxS2Comment { color: #8a8a8a; } .subxTest { color: #5f8700; } +.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; } .Constant { color: #008787; } -.subxS2Comment { color: #8a8a8a; } .subxH1Comment { color: #005faf; text-decoration: underline; } --> @@ -60,7 +60,7 @@ if ('onhashchange' in window) { https://github.com/akkartik/mu/blob/master/054string-equal.subx
-  1 # Comparing 'regular' length-prefixed strings.
+  1 # Comparing 'regular' size-prefixed strings.
   2 
   3 == code
   4 #   instruction                     effective address                                                   register    displacement    immediate
@@ -77,7 +77,7 @@ if ('onhashchange' in window) {
  15 
  16 string-equal?:  # s: (addr array byte), benchmark: (addr array byte) -> eax: boolean
  17     # pseudocode:
- 18     #   if (s->length != benchmark->length) return false
+ 18     #   if (s->size != benchmark->size) return false
  19     #   return string-starts-with?(s, benchmark)
  20     #
  21     # . prologue
@@ -91,10 +91,10 @@ if ('onhashchange' in window) {
  29     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
  30     # edi = benchmark
  31     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
- 32     # ecx = s->length
+ 32     # ecx = s->size
  33     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
- 34 $string-equal?:lengths:
- 35     # if (ecx != benchmark->length) return false
+ 34 $string-equal?:sizes:
+ 35     # if (ecx != benchmark->size) return false
  36     39/compare                      0/mod/indirect  7/rm32/edi    .           .             .           1/r32/ecx   .               .                 # compare *edi and ecx
  37     b8/copy-to-eax  0/imm32/false
  38     75/jump-if-!=  $string-equal?:end/disp8
@@ -119,10 +119,10 @@ if ('onhashchange' in window) {
  57 
  58 string-starts-with?:  # s: (addr array byte), benchmark: (addr array byte) -> eax: boolean
  59     # pseudocode:
- 60     #   if (s->length < benchmark->length) return false
+ 60     #   if (s->size < benchmark->size) return false
  61     #   currs = s->data
  62     #   currb = benchmark->data
- 63     #   maxb = &benchmark->data[benchmark->length]
+ 63     #   maxb = &benchmark->data[benchmark->size]
  64     #   while currb < maxb
  65     #     c1 = *currs
  66     #     c2 = *currb
@@ -149,17 +149,17 @@ if ('onhashchange' in window) {
  87     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
  88     # edi = benchmark
  89     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
- 90     # var blen/ecx: int = benchmark->length
+ 90     # var bsize/ecx: int = benchmark->size
  91     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           1/r32/ecx   .               .                 # copy *edi to ecx
- 92 $string-starts-with?:lengths:
- 93     # if (s->length < blen) return false
+ 92 $string-starts-with?:sizes:
+ 93     # if (s->size < bsize) return false
  94     39/compare                      0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # compare *esi with ecx
  95     7c/jump-if-<  $string-starts-with?:false/disp8
  96     # var currs/esi: (addr byte) = s->data
  97     81          0/subop/add         3/mod/direct    6/rm32/esi    .           .             .           .           .               4/imm32           # add to esi
  98     # var currb/edi: (addr byte) = benchmark->data
  99     81          0/subop/add         3/mod/direct    7/rm32/edi    .           .             .           .           .               4/imm32           # add to edi
-100     # var maxb/ecx: (addr byte) = &benchmark->data[benchmark->length]
+100     # var maxb/ecx: (addr byte) = &benchmark->data[benchmark->size]
 101     01/add                          3/mod/direct    1/rm32/ecx    .           .             .           7/r32/edi   .               .                 # add edi to ecx
 102     # var c1/eax: byte = 0
 103     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
@@ -219,7 +219,7 @@ if ('onhashchange' in window) {
 157     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
 158     c3/return
 159 
-160 test-compare-empty-with-non-empty-string:  # also checks length-mismatch code path
+160 test-compare-empty-with-non-empty-string:  # also checks size-mismatch code path
 161     # eax = string-equal?("", "Abc")
 162     # . . push args
 163     68/push  "Abc"/imm32
@@ -259,7 +259,7 @@ if ('onhashchange' in window) {
 197     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
 198     c3/return
 199 
-200 test-compare-inequal-strings-equal-lengths:
+200 test-compare-inequal-strings-equal-sizes:
 201     # eax = string-equal?("Abc", "Adc")
 202     # . . push args
 203     68/push  "Adc"/imm32
@@ -270,7 +270,7 @@ if ('onhashchange' in window) {
 208     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 209     # check-ints-equal(eax, 0, msg)
 210     # . . push args
-211     68/push  "F - test-compare-inequal-strings-equal-lengths"/imm32
+211     68/push  "F - test-compare-inequal-strings-equal-sizes"/imm32
 212     68/push  0/imm32/false
 213     50/push-eax
 214     # . . call
diff --git a/html/055stream.subx.html b/html/055stream.subx.html
index c66e74fe..50f3253d 100644
--- a/html/055stream.subx.html
+++ b/html/055stream.subx.html
@@ -16,9 +16,9 @@ a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
 .subxS2Comment { color: #8a8a8a; }
+.subxFunction { color: #af5f00; text-decoration: underline; }
 .LineNr { }
 .subxS1Comment { color: #0000af; }
-.subxFunction { color: #af5f00; text-decoration: underline; }
 .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
 .Constant { color: #008787; }
 .subxH1Comment { color: #005faf; text-decoration: underline; }
@@ -62,10 +62,10 @@ if ('onhashchange' in window) {
  3 # A stream looks like this:
  4 #   write: int  # index at which writes go
  5 #   read: int  # index that we've read until
- 6 #   data: (array byte)  # prefixed by length as usual
+ 6 #   data: (array byte)  # prefixed by size as usual
  7 #
  8 # some primitives for operating on streams:
- 9 #   - clear-stream (clears everything but the data length)
+ 9 #   - clear-stream (clears everything but the data size)
 10 #   - rewind-stream (resets read pointer)
 11 
 12 == code
@@ -82,9 +82,9 @@ if ('onhashchange' in window) {
 23     51/push-ecx
 24     # eax = f
 25     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         0/r32/eax   8/disp8         .                 # copy *(ebp+8) to eax
-26     # var count/ecx: int = f->length
+26     # var count/ecx: int = f->size
 27     8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(eax+8) to ecx
-28     # var max/ecx: (addr byte) = &f->data[f->length]
+28     # var max/ecx: (addr byte) = &f->data[f->size]
 29     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   0xc/disp8       .                 # copy eax+ecx+12 to ecx
 30     # f->write = 0
 31     c7          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0/imm32           # copy to *eax
diff --git a/html/056trace.subx.html b/html/056trace.subx.html
index 79c4d40b..8897bbf4 100644
--- a/html/056trace.subx.html
+++ b/html/056trace.subx.html
@@ -15,17 +15,17 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color:
 a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
+.subxS2Comment { color: #8a8a8a; }
+.subxTest { color: #5f8700; }
 .subxFunction { color: #af5f00; text-decoration: underline; }
-.subxH1Comment { color: #005faf; 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; }
-.subxS2Comment { color: #8a8a8a; }
+.subxH1Comment { color: #005faf; text-decoration: underline; }
 .Constant { color: #008787; }
-.subxTest { color: #5f8700; }
+.subxMinorFunction { color: #875f5f; }
 -->
 
 
@@ -66,7 +66,7 @@ if ('onhashchange' in window) {
   3 # A trace stream looks like a regular stream:
   4 #   write: int  # index at which writes go
   5 #   read: int  # index that we've read until
-  6 #   data: (array byte)  # prefixed by length as usual
+  6 #   data: (array byte)  # prefixed by size as usual
   7 # Usually the trace stream will be in a separate segment set aside for the purpose.
   8 #
   9 # primitives for operating on traces (arguments in quotes):
@@ -96,7 +96,7 @@ if ('onhashchange' in window) {
  33     0/imm32
  34     # current read index
  35     0/imm32
- 36     # length
+ 36     # size
  37     8/imm32
  38     # data
  39     00 00 00 00 00 00 00 00  # 8 bytes
@@ -106,7 +106,7 @@ if ('onhashchange' in window) {
  43 # . op          subop               mod             rm32          base        index         scale       r32
  44 # . 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
  45 
- 46 # Allocate a new segment for the trace stream, initialize its length, and save its address to Trace-stream.
+ 46 # Allocate a new segment for the trace stream, initialize its size, and save its address to Trace-stream.
  47 # The Trace-stream segment will consist of variable-length lines separated by newlines (0x0a)
  48 initialize-trace-stream:  # n: int
  49     # . prologue
@@ -130,10 +130,10 @@ if ('onhashchange' in window) {
  67 #?     # watch point to catch Trace-stream leaks
  68 #? $watch-1:
  69     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy eax to *Trace-stream
- 70     # Trace-stream->length = n - 12
+ 70     # Trace-stream->size = n - 12
  71     # . ecx -= 12
  72     81          5/subop/subtract    3/mod/direct    1/rm32/ecx    .           .             .           .           .               0xc/imm32         # subtract from ecx
- 73     # . Trace-stream->length = ecx
+ 73     # . Trace-stream->size = ecx
  74     89/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           1/r32/ecx   8/disp8         .                 # copy ecx to *(eax+8)
  75 $initialize-trace-stream:end:
  76     # . restore registers
@@ -163,12 +163,12 @@ if ('onhashchange' in window) {
 100     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
 101     # var ecx: int = t->write
 102     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           1/r32/ecx   .               .                 # copy *edi to ecx
-103     # var edx: int = t->length
+103     # var edx: int = t->size
 104     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           2/r32/edx   8/disp8         .                 # copy *(edi+8) to edx
-105     # eax = _append-3(&t->data[t->write], &t->data[t->length], line)
+105     # eax = _append-3(&t->data[t->write], &t->data[t->size], line)
 106     # . . push line
 107     56/push-esi
-108     # . . push &t->data[t->length]
+108     # . . push &t->data[t->size]
 109     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    7/base/edi  2/index/edx   .           3/r32/ebx   0xc/disp8       .                 # copy edi+edx+12 to ebx
 110     53/push-ebx
 111     # . . push &t->data[t->write]
@@ -185,10 +185,10 @@ if ('onhashchange' in window) {
 122     01/add                          0/mod/indirect  7/rm32/edi    .           .             .           0/r32/eax   .               .                 # add eax to *edi
 123     # refresh ecx = t->write
 124     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           1/r32/ecx   .               .                 # copy *edi to ecx
-125     # eax = _append-3(&t->data[t->write], &t->data[t->length], line)
+125     # eax = _append-3(&t->data[t->write], &t->data[t->size], line)
 126     # . . push line
 127     68/push  Newline/imm32
-128     # . . push &t->data[t->length]
+128     # . . push &t->data[t->size]
 129     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    7/base/edi  2/index/edx   .           3/r32/ebx   0xc/disp8       .                 # copy edi+edx+12 to ebx
 130     53/push-ebx
 131     # . . push &t->data[t->write]
@@ -931,8 +931,8 @@ if ('onhashchange' in window) {
 868     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
 869     # . save registers
 870     51/push-ecx
-871     # eax = _append-4(out, outend, &s->data[0], &s->data[s->length])
-872     # . . push &s->data[s->length]
+871     # eax = _append-4(out, outend, &s->data[0], &s->data[s->size])
+872     # . . push &s->data[s->size]
 873     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         0/r32/eax   0x10/disp8      .                 # copy *(ebp+16) to eax
 874     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
 875     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
@@ -1028,7 +1028,7 @@ if ('onhashchange' in window) {
 965     8/imm32
 966     # read
 967     0/imm32
-968     # length
+968     # size
 969     8/imm32
 970     # data
 971     41 42 41 42 41 0a 00 00  # 8 bytes
@@ -1038,7 +1038,7 @@ if ('onhashchange' in window) {
 975     0/imm32
 976     # read
 977     0/imm32
-978     # length
+978     # size
 979     8/imm32
 980     # data
 981     00 00 00 00 00 00 00 00  # 8 bytes
@@ -1048,7 +1048,7 @@ if ('onhashchange' in window) {
 985     8/imm32
 986     # read
 987     0/imm32
-988     # length
+988     # size
 989     8/imm32
 990     # data
 991     41 41 41 41 0a 41 41 41  # 8 bytes
diff --git a/html/057write.subx.html b/html/057write.subx.html
index 0cfc4ac4..3dfceffa 100644
--- a/html/057write.subx.html
+++ b/html/057write.subx.html
@@ -16,13 +16,13 @@ a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
 .subxS2Comment { color: #8a8a8a; }
+.subxTest { color: #5f8700; }
+.subxFunction { color: #af5f00; text-decoration: underline; }
 .LineNr { }
 .subxS1Comment { color: #0000af; }
-.subxFunction { color: #af5f00; text-decoration: underline; }
 .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
-.subxMinorFunction { color: #875f5f; }
 .Constant { color: #008787; }
-.subxTest { color: #5f8700; }
+.subxMinorFunction { color: #875f5f; }
 -->
 
 
@@ -73,7 +73,7 @@ if ('onhashchange' in window) {
  13 # A stream looks like this:
  14 #   read: int  # index at which to read next
  15 #   write: int  # index at which writes go
- 16 #   data: (array byte)  # prefixed by length as usual
+ 16 #   data: (array byte)  # prefixed by size as usual
  17 
  18 == code
  19 #   instruction                     effective address                                                   register    displacement    immediate
@@ -107,12 +107,12 @@ if ('onhashchange' in window) {
  47     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
  48     # edx = f->write
  49     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # copy *ecx to edx
- 50     # ebx = f->length
+ 50     # ebx = f->size
  51     8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           3/r32/ebx   8/disp8         .                 # copy *(ecx+8) to ebx
- 52     # eax = _append-3(&f->data[f->write], &f->data[f->length], s)
+ 52     # eax = _append-3(&f->data[f->write], &f->data[f->size], s)
  53     # . . push s
  54     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
- 55     # . . push &f->data[f->length]
+ 55     # . . push &f->data[f->size]
  56     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
  57     53/push-ebx
  58     # . . push &f->data[f->write]
@@ -210,7 +210,7 @@ if ('onhashchange' in window) {
 150     0/imm32
 151     # current read index
 152     0/imm32
-153     # length
+153     # size
 154     0x10/imm32
 155     # data (2 lines x 8 bytes/line)
 156     00 00 00 00 00 00 00 00
diff --git a/html/058stream-equal.subx.html b/html/058stream-equal.subx.html
index 2d38ddef..9e737216 100644
--- a/html/058stream-equal.subx.html
+++ b/html/058stream-equal.subx.html
@@ -16,12 +16,12 @@ a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
 .subxS2Comment { color: #8a8a8a; }
+.subxTest { color: #5f8700; }
+.subxFunction { color: #af5f00; text-decoration: underline; }
 .LineNr { }
 .subxS1Comment { color: #0000af; }
-.subxFunction { color: #af5f00; text-decoration: underline; }
 .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
 .Constant { color: #008787; }
-.subxTest { color: #5f8700; }
 -->
 
 
@@ -84,8 +84,8 @@ if ('onhashchange' in window) {
  25     81          0/subop/add         3/mod/direct    6/rm32/esi    .           .             .           .           .               0xc/imm32         # add to esi
  26     # edi = s
  27     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
- 28 $stream-data-equal?:compare-lengths:
- 29     # if (f->write != s->length) return false
+ 28 $stream-data-equal?:compare-sizes:
+ 29     # if (f->write != s->size) return false
  30     39/compare                      0/mod/indirect  7/rm32/edi    .           .             .           0/r32/eax   .               .                 # compare *edi and eax
  31     75/jump-if-!=  $stream-data-equal?:false/disp8
  32     # var currs/edi: (addr byte) = s->data
@@ -208,7 +208,7 @@ if ('onhashchange' in window) {
 149     5d/pop-to-ebp
 150     c3/return
 151 
-152 test-stream-data-equal-length-check:
+152 test-stream-data-equal-size-check:
 153     # . prologue
 154     55/push-ebp
 155     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
@@ -237,7 +237,7 @@ if ('onhashchange' in window) {
 178     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 179     # check-ints-equal(eax, 0, msg)
 180     # . . push args
-181     68/push  "F - test-stream-data-equal-length-check"/imm32
+181     68/push  "F - test-stream-data-equal-size-check"/imm32
 182     68/push  0/imm32
 183     50/push-eax
 184     # . . call
@@ -289,30 +289,30 @@ if ('onhashchange' in window) {
 230 next-stream-line-equal?:  # f: (addr stream byte), s: (addr array byte) -> eax: boolean
 231     # pseudocode:
 232     #   currf = f->read  # bound: f->write
-233     #   currs = 0  # bound: s->length
+233     #   currs = 0  # bound: s->size
 234     #   while true
 235     #     if currf >= f->write
-236     #       return currs >= s->length
+236     #       return currs >= s->size
 237     #     if f[currf] == '\n'
 238     #       ++currf
-239     #       return currs >= s->length
-240     #     if (currs >= s->length) return false  # the current line of f still has data to match
+239     #       return currs >= s->size
+240     #     if (currs >= s->size) return false  # the current line of f still has data to match
 241     #     if (f[currf] != s[currs]) return false
 242     #     ++currf
 243     #     ++currs
 244     #
 245     # collapsing the two branches that can return true:
 246     #   currf = f->read  # bound: f->write
-247     #   currs = 0  # bound: s->length
+247     #   currs = 0  # bound: s->size
 248     #   while true
 249     #     if (currf >= f->write) break
 250     #     if (f[currf] == '\n') break
-251     #     if (currs >= s->length) return false  # the current line of f still has data to match
+251     #     if (currs >= s->size) return false  # the current line of f still has data to match
 252     #     if (f[currf] != s[currs]) return false
 253     #     ++currf
 254     #     ++currs
 255     #   ++currf  # skip '\n'
-256     #   return currs >= s->length
+256     #   return currs >= s->size
 257     # Here the final `++currf` is sometimes unnecessary (if we're already at the end of the stream)
 258     #
 259     # registers:
@@ -352,7 +352,7 @@ if ('onhashchange' in window) {
 293     # if (c1 == '\n') break
 294     3d/compare-eax-and  0xa/imm32/newline
 295     74/jump-if-=  $next-stream-line-equal?:break/disp8
-296     # if (currs >= s->length) return false
+296     # if (currs >= s->size) return false
 297     3b/compare                      0/mod/indirect  7/rm32/edi    .           .             .           2/r32/edx   .               .                 # compare edx with *edi
 298     7d/jump-if->=  $next-stream-line-equal?:false/disp8
 299     # c2 = s->data[currs]
@@ -368,7 +368,7 @@ if ('onhashchange' in window) {
 309 $next-stream-line-equal?:break:
 310     # ++currf
 311     41/increment-ecx
-312     # if (currs >= s->length) return true
+312     # if (currs >= s->size) return true
 313     3b/compare                      0/mod/indirect  7/rm32/edi    .           .             .           2/r32/edx   .               .                 # compare edx with *edi
 314     7c/jump-if-<  $next-stream-line-equal?:false/disp8
 315 $next-stream-line-equal?:true:
diff --git a/html/059stop.subx.html b/html/059stop.subx.html
index c94eda2d..8cf368fc 100644
--- a/html/059stop.subx.html
+++ b/html/059stop.subx.html
@@ -16,14 +16,14 @@ a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
 .subxS2Comment { color: #8a8a8a; }
+.subxTest { color: #5f8700; }
+.subxFunction { color: #af5f00; text-decoration: underline; }
 .LineNr { }
 .subxS1Comment { color: #0000af; }
 .CommentedCode { color: #8a8a8a; }
-.subxFunction { color: #af5f00; text-decoration: underline; }
 .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
-.subxMinorFunction { color: #875f5f; }
 .Constant { color: #008787; }
-.subxTest { color: #5f8700; }
+.subxMinorFunction { color: #875f5f; }
 -->
 
 
diff --git a/html/060read.subx.html b/html/060read.subx.html
index 140a0e95..dee513d3 100644
--- a/html/060read.subx.html
+++ b/html/060read.subx.html
@@ -16,10 +16,10 @@ a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
 .subxS2Comment { color: #8a8a8a; }
-.LineNr { }
-.subxS1Comment { color: #0000af; }
 .subxTest { color: #5f8700; }
 .subxFunction { color: #af5f00; text-decoration: underline; }
+.LineNr { }
+.subxS1Comment { color: #0000af; }
 .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
 .subxMinorFunction { color: #875f5f; }
 .Constant { color: #008787; }
@@ -99,7 +99,7 @@ if ('onhashchange' in window) {
  38 # As a reminder, a stream looks like this:
  39 #   write: int  # index at which to write to next
  40 #   read: int  # index at which to read next
- 41 #   data: (array byte)  # prefixed by length as usual
+ 41 #   data: (array byte)  # prefixed by size as usual
  42 
  43 == code
  44 #   instruction                     effective address                                                   register    displacement    immediate
@@ -131,7 +131,7 @@ if ('onhashchange' in window) {
  70     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
  71     # edi = s
  72     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to esi
- 73     # eax = _buffer-4(out = &s->data[s->write], outend = &s->data[s->length],
+ 73     # eax = _buffer-4(out = &s->data[s->write], outend = &s->data[s->size],
  74     #                 in  = &f->data[f->read],  inend  = &f->data[f->write])
  75     # . . push &f->data[f->write]
  76     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy *esi to eax
@@ -141,7 +141,7 @@ if ('onhashchange' in window) {
  80     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   4/disp8         .                 # copy *(esi+4) to eax
  81     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  0/index/eax   .           0/r32/eax   0xc/disp8       .                 # copy esi+eax+12 to eax
  82     50/push-eax
- 83     # . . push &s->data[s->length]
+ 83     # . . push &s->data[s->size]
  84     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           0/r32/eax   8/disp8         .                 # copy *(edi+8) to eax
  85     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    7/base/edi  0/index/eax   .           0/r32/eax   0xc/disp8       .                 # copy edi+eax+12 to eax
  86     50/push-eax
@@ -177,8 +177,8 @@ if ('onhashchange' in window) {
 116     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
 117     # . save registers
 118     51/push-ecx
-119     # eax = _buffer-4(out, outend, &s->data[0], &s->data[s->length])
-120     # . . push &s->data[s->length]
+119     # eax = _buffer-4(out, outend, &s->data[0], &s->data[s->size])
+120     # . . push &s->data[s->size]
 121     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         0/r32/eax   0x10/disp8      .                 # copy *(ebp+16) to eax
 122     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
 123     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
@@ -269,14 +269,14 @@ if ('onhashchange' in window) {
 208     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
 209     # eax = s->write
 210     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy *esi to eax
-211     # edx = s->length
+211     # edx = s->size
 212     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           2/r32/edx   8/disp8         .                 # copy *(esi+8) to edx
-213     # syscall(read, fd, &s->data[s->write], s->length - s->write)
+213     # syscall(read, fd, &s->data[s->write], s->size - s->write)
 214     # . . fd: ebx
 215     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           3/r32/ebx   8/disp8         .                 # copy *(ebp+8) to ebx
 216     # . . data: ecx = &s->data[s->write]
 217     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  0/index/eax   .           1/r32/ecx   0xc/disp8       .                 # copy esi+eax+12 to ecx
-218     # . . size: edx = s->length - s->write
+218     # . . size: edx = s->size - s->write
 219     29/subtract                     3/mod/direct    2/rm32/edx    .           .             .           0/r32/eax   .               .                 # subtract eax from edx
 220     # . . syscall
 221     b8/copy-to-eax  3/imm32/read
@@ -298,14 +298,14 @@ if ('onhashchange' in window) {
 237     #   1 (what we have above):
 238     #     ecx = s
 239     #     eax = s->write
-240     #     edx = s->length
+240     #     edx = s->size
 241     #     # syscall
 242     #     ecx = lea ecx+eax+12
 243     #     edx = sub edx eax
 244     #
 245     #   2:
 246     #     ecx = s
-247     #     edx = s->length
+247     #     edx = s->size
 248     #     ecx = &s->data
 249     #     # syscall
 250     #     ecx = add ecx, s->write
@@ -492,7 +492,7 @@ if ('onhashchange' in window) {
 431     0/imm32
 432     # current read index
 433     0/imm32
-434     # length
+434     # size
 435     8/imm32
 436     # data
 437     00 00 00 00 00 00 00 00  # 8 bytes
diff --git a/html/061read-byte.subx.html b/html/061read-byte.subx.html
index 8ffe504e..94d61894 100644
--- a/html/061read-byte.subx.html
+++ b/html/061read-byte.subx.html
@@ -15,15 +15,15 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color:
 a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
+.subxS2Comment { color: #8a8a8a; }
+.subxTest { color: #5f8700; }
 .subxFunction { color: #af5f00; text-decoration: underline; }
 .LineNr { }
 .subxS1Comment { color: #0000af; }
-.subxTest { color: #5f8700; }
 .SpecialChar { color: #d70000; }
 .Constant { color: #008787; }
 .subxMinorFunction { color: #875f5f; }
 .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
-.subxS2Comment { color: #8a8a8a; }
 .subxH1Comment { color: #005faf; text-decoration: underline; }
 -->
 
@@ -82,7 +82,7 @@ if ('onhashchange' in window) {
  20     0/imm32
  21     #   current read index
  22     0/imm32
- 23     #   length
+ 23     #   size
  24     8/imm32
  25     #   data
  26     00 00 00 00 00 00 00 00  # 8 bytes
@@ -308,7 +308,7 @@ if ('onhashchange' in window) {
 246     # . . discard args
 247     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 248     # pretend buffer is full
-249     # . _test-buffered-file->read = 6  # >= _test-buffered-file->length
+249     # . _test-buffered-file->read = 6  # >= _test-buffered-file->size
 250     b8/copy-to-eax  _test-buffered-file/imm32
 251     c7          0/subop/copy        1/mod/*+disp8   0/rm32/eax    .           .             .           .           8/disp8         6/imm32           # copy to *(eax+8)
 252     # read-byte-buffered(_test-buffered-file)
@@ -341,7 +341,7 @@ if ('onhashchange' in window) {
 279     0/imm32
 280     # current read index
 281     0/imm32
-282     # length
+282     # size
 283     6/imm32
 284     # data
 285     00 00 00 00 00 00  # 6 bytes
@@ -351,7 +351,7 @@ if ('onhashchange' in window) {
 289     0/imm32
 290     # current read index
 291     0/imm32
-292     # length
+292     # size
 293     0x100/imm32  # 256 bytes
 294     # data (16 lines x 16 bytes/line)
 295     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
@@ -380,7 +380,7 @@ if ('onhashchange' in window) {
 318     0/imm32
 319     # current read index
 320     0/imm32
-321     # length
+321     # size
 322     6/imm32
 323     # data
 324     00 00 00 00 00 00  # 6 bytes
diff --git a/html/062write-stream.subx.html b/html/062write-stream.subx.html
index 9bc2c29f..cf1d726f 100644
--- a/html/062write-stream.subx.html
+++ b/html/062write-stream.subx.html
@@ -16,14 +16,14 @@ a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
 .subxS2Comment { color: #8a8a8a; }
+.subxTest { color: #5f8700; }
+.subxFunction { color: #af5f00; text-decoration: underline; }
 .LineNr { }
 .subxS1Comment { color: #0000af; }
 .CommentedCode { color: #8a8a8a; }
-.subxFunction { color: #af5f00; text-decoration: underline; }
 .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
-.subxMinorFunction { color: #875f5f; }
 .Constant { color: #008787; }
-.subxTest { color: #5f8700; }
+.subxMinorFunction { color: #875f5f; }
 -->
 
 
@@ -101,7 +101,7 @@ if ('onhashchange' in window) {
  40     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
  41     # esi = s
  42     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
- 43     # eax = _append-4(&f->data[f->write], &f->data[f->length], &s->data[s->read], &s->data[s->write])
+ 43     # eax = _append-4(&f->data[f->write], &f->data[f->size], &s->data[s->read], &s->data[s->write])
  44     # . . push &s->data[s->write]
  45     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy *esi to eax
  46     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  0/index/eax   .           0/r32/eax   0xc/disp8       .                 # copy esi+eax+12 to eax
@@ -110,7 +110,7 @@ if ('onhashchange' in window) {
  49     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   4/disp8         .                 # copy *(esi+4) to eax
  50     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  0/index/eax   .           0/r32/eax   0xc/disp8       .                 # copy esi+eax+12 to eax
  51     50/push-eax
- 52     # . . push &f->data[f->length]
+ 52     # . . push &f->data[f->size]
  53     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           0/r32/eax   8/disp8         .                 # copy *(edi+8) to eax
  54     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    7/base/edi  0/index/eax   .           0/r32/eax   0xc/disp8       .                 # copy edi+eax+12 to eax
  55     50/push-eax
@@ -308,7 +308,7 @@ if ('onhashchange' in window) {
 247     4/imm32
 248     # current read index
 249     1/imm32
-250     # length
+250     # size
 251     8/imm32
 252     # data
 253     41/A 42/B 43/C 44/D 00 00 00 00  # 8 bytes
diff --git a/html/063error.subx.html b/html/063error.subx.html
index e9f1dea4..008e59d5 100644
--- a/html/063error.subx.html
+++ b/html/063error.subx.html
@@ -16,10 +16,10 @@ a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
 .subxS2Comment { color: #8a8a8a; }
-.LineNr { }
-.SpecialChar { color: #d70000; }
-.subxS1Comment { color: #0000af; }
 .subxFunction { color: #af5f00; text-decoration: underline; }
+.LineNr { }
+.subxS1Comment { color: #0000af; }
+.SpecialChar { color: #d70000; }
 .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
 .Constant { color: #008787; }
 -->
diff --git a/html/064write-byte.subx.html b/html/064write-byte.subx.html
index 06ba099c..4aebe3e0 100644
--- a/html/064write-byte.subx.html
+++ b/html/064write-byte.subx.html
@@ -15,16 +15,16 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color:
 a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
+.subxS2Comment { color: #8a8a8a; }
+.subxTest { color: #5f8700; }
 .subxFunction { color: #af5f00; text-decoration: underline; }
-.subxMinorFunction { color: #875f5f; }
 .LineNr { }
 .subxS1Comment { color: #0000af; }
 .SpecialChar { color: #d70000; }
 .Constant { color: #008787; }
-.subxH1Comment { color: #005faf; text-decoration: underline; }
+.subxMinorFunction { color: #875f5f; }
 .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
-.subxS2Comment { color: #8a8a8a; }
-.subxTest { color: #5f8700; }
+.subxH1Comment { color: #005faf; text-decoration: underline; }
 -->
 
 
@@ -78,7 +78,7 @@ if ('onhashchange' in window) {
  16     0/imm32
  17     #   current read index
  18     0/imm32
- 19     #   length
+ 19     #   size
  20     8/imm32
  21     #   data
  22     00 00 00 00 00 00 00 00  # 8 bytes
@@ -103,7 +103,7 @@ if ('onhashchange' in window) {
  41     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
  42     # ecx = f->write
  43     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(edi+4) to ecx
- 44     # if (f->write >= f->length) flush and clear f's stream
+ 44     # if (f->write >= f->size) flush and clear f's stream
  45     3b/compare                      1/mod/*+disp8   7/rm32/edi    .           .             .           1/r32/ecx   0xc/disp8       .                 # compare ecx with *(edi+12)
  46     7c/jump-if-<  $write-byte-buffered:to-stream/disp8
  47     # . flush(f)
@@ -278,7 +278,7 @@ if ('onhashchange' in window) {
 216     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
 217     # ecx = f->write
 218     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           1/r32/ecx   .               .                 # copy *edi to ecx
-219     # if (f->write >= f->length) abort
+219     # if (f->write >= f->size) abort
 220     3b/compare                      1/mod/*+disp8   7/rm32/edi    .           .             .           1/r32/ecx   8/disp8         .                 # compare ecx with *(edi+8)
 221     7d/jump-if->=  $append-byte:abort/disp8
 222 $append-byte:to-stream:
@@ -350,7 +350,7 @@ if ('onhashchange' in window) {
 288     0/imm32
 289     # current read index
 290     0/imm32
-291     # length
+291     # size
 292     0x400/imm32  # 1024 bytes
 293     # data (64 lines x 16 bytes/line)
 294     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
@@ -427,7 +427,7 @@ if ('onhashchange' in window) {
 365     0/imm32
 366     # current read index
 367     0/imm32
-368     # length
+368     # size
 369     6/imm32
 370     # data
 371     00 00 00 00 00 00  # 6 bytes
@@ -458,7 +458,7 @@ if ('onhashchange' in window) {
 396     0/imm32
 397     # current read index
 398     0/imm32
-399     # length
+399     # size
 400     6/imm32
 401     # data
 402     00 00 00 00 00 00  # 6 bytes
diff --git a/html/065write-buffered.subx.html b/html/065write-buffered.subx.html
index 755994e9..840b92c9 100644
--- a/html/065write-buffered.subx.html
+++ b/html/065write-buffered.subx.html
@@ -16,14 +16,14 @@ a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
 .subxS2Comment { color: #8a8a8a; }
-.LineNr { }
-.SpecialChar { color: #d70000; }
-.subxS1Comment { color: #0000af; }
-.subxFunction { color: #af5f00; text-decoration: underline; }
-.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
-.subxH1Comment { color: #005faf; text-decoration: underline; }
-.Constant { color: #008787; }
 .subxTest { color: #5f8700; }
+.subxFunction { color: #af5f00; text-decoration: underline; }
+.LineNr { }
+.subxS1Comment { color: #0000af; }
+.SpecialChar { color: #d70000; }
+.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
+.Constant { color: #008787; }
+.subxH1Comment { color: #005faf; text-decoration: underline; }
 -->
 
 
@@ -69,9 +69,9 @@ if ('onhashchange' in window) {
   8 write-buffered:  # f: (addr buffered-file), msg: (addr array byte)
   9     # pseudocode:
  10     #   in = msg->data
- 11     #   inend = &msg->data[msg->length]
+ 11     #   inend = &msg->data[msg->size]
  12     #   while (in < inend)
- 13     #     if f->write >= f->length
+ 13     #     if f->write >= f->size
  14     #       flush(f)
  15     #       clear-stream(f)
  16     #     c = *in
@@ -83,7 +83,7 @@ if ('onhashchange' in window) {
  22     #   in: esi
  23     #   inend: ecx
  24     #   f: edi
- 25     #   f->length: edx
+ 25     #   f->size: edx
  26     #   f->write: ebx (cached; need to keep in sync)
  27     #   c: eax
  28     #
@@ -101,12 +101,12 @@ if ('onhashchange' in window) {
  40     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         0/r32/eax   0xc/disp8       .                 # copy *(ebp+12) to eax
  41     # var in/esi: (addr byte) = msg->data
  42     8d/copy-address                 1/mod/*+disp8   0/rm32/eax    .           .             .           6/r32/esi   4/disp8         .                 # copy eax+4 to esi
- 43     # var inend/ecx: (addr byte) = &msg->data[msg->length]
+ 43     # var inend/ecx: (addr byte) = &msg->data[msg->size]
  44     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
  45     8d/copy-address                 0/mod/indirect  4/rm32/sib    6/base/esi  1/index/ecx   .           1/r32/ecx   .               .                 # copy esi+ecx to ecx
  46     # edi = f
  47     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
- 48     # edx = f->length
+ 48     # edx = f->size
  49     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(edi+12) to edx
  50     # ebx = f->write
  51     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           3/r32/ebx   4/disp8         .                 # copy *(edi+4) to ebx
@@ -114,7 +114,7 @@ if ('onhashchange' in window) {
  53     # if (in >= inend) break
  54     39/compare                      3/mod/direct    6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # compare esi with ecx
  55     73/jump-if-addr>=  $write-buffered:loop-end/disp8
- 56     # if (f->write >= f->length) flush and clear f's stream
+ 56     # if (f->write >= f->size) flush and clear f's stream
  57     39/compare                      3/mod/direct    3/rm32/ebx    .           .             .           2/r32/edx   .               .                 # compare ebx with edx
  58     7c/jump-if-<  $write-buffered:to-stream/disp8
  59     # . persist f->write
@@ -276,7 +276,7 @@ if ('onhashchange' in window) {
 215     0/imm32
 216     #   current read index
 217     0/imm32
-218     #   length
+218     #   size
 219     8/imm32
 220     #   data
 221     00 00 00 00 00 00 00 00  # 8 bytes
diff --git a/html/066print-int.subx.html b/html/066print-int.subx.html
index c2b71a84..dac46129 100644
--- a/html/066print-int.subx.html
+++ b/html/066print-int.subx.html
@@ -16,14 +16,14 @@ a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
 .subxS2Comment { color: #8a8a8a; }
-.Folded { color: #080808; background-color: #949494; }
+.subxTest { color: #5f8700; }
+.subxFunction { color: #af5f00; text-decoration: underline; }
 .LineNr { }
 .subxS1Comment { color: #0000af; }
-.subxFunction { color: #af5f00; text-decoration: underline; }
 .Constant { color: #008787; }
-.subxH1Comment { color: #005faf; text-decoration: underline; }
+.Folded { color: #080808; background-color: #949494; }
 .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
-.subxTest { color: #5f8700; }
+.subxH1Comment { color: #005faf; text-decoration: underline; }
 -->
 
 
diff --git a/html/067parse-hex.subx.html b/html/067parse-hex.subx.html
index 371ebaca..3ae7b0a8 100644
--- a/html/067parse-hex.subx.html
+++ b/html/067parse-hex.subx.html
@@ -16,13 +16,13 @@ a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
 .subxS2Comment { color: #8a8a8a; }
-.LineNr { }
-.SpecialChar { color: #d70000; }
-.subxS1Comment { color: #0000af; }
+.subxTest { color: #5f8700; }
 .subxFunction { color: #af5f00; text-decoration: underline; }
+.LineNr { }
+.subxS1Comment { color: #0000af; }
+.SpecialChar { color: #d70000; }
 .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
 .Constant { color: #008787; }
-.subxTest { color: #5f8700; }
 -->
 
 
@@ -422,10 +422,10 @@ if ('onhashchange' in window) {
 362     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   8/disp8         .                 # copy *(ebp+8) to eax
 363     # var curr/ecx: (addr byte) = &in->data
 364     8d/copy-address                 1/mod/*+disp8   0/rm32/eax    .           .             .           1/r32/ecx   4/disp8         .                 # copy eax+4 to ecx
-365     # var max/edx: (addr byte) = &in->data[in->length]
-366     # . edx = in->length
+365     # var max/edx: (addr byte) = &in->data[in->size]
+366     # . edx = in->size
 367     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           2/r32/edx   .               .                 # copy *eax to edx
-368     # . edx = in->data + in->length
+368     # . edx = in->data + in->size
 369     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  2/index/edx   .           2/r32/edx   4/disp8         .                 # copy eax+edx+4 to edx
 370     # return parse-hex-int-helper(curr, max)
 371     # . . push args
diff --git a/html/068error-byte.subx.html b/html/068error-byte.subx.html
index 4ef793ac..bfc11d1d 100644
--- a/html/068error-byte.subx.html
+++ b/html/068error-byte.subx.html
@@ -16,11 +16,11 @@ a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
 .subxS2Comment { color: #8a8a8a; }
+.subxFunction { color: #af5f00; text-decoration: underline; }
 .LineNr { }
-.SpecialChar { color: #d70000; }
 .subxS1Comment { color: #0000af; }
 .CommentedCode { color: #8a8a8a; }
-.subxFunction { color: #af5f00; text-decoration: underline; }
+.SpecialChar { color: #d70000; }
 .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
 .Constant { color: #008787; }
 -->
diff --git a/html/069allocate.subx.html b/html/069allocate.subx.html
index 21ef578c..6f5ee389 100644
--- a/html/069allocate.subx.html
+++ b/html/069allocate.subx.html
@@ -16,14 +16,14 @@ a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
 .subxS2Comment { color: #8a8a8a; }
+.subxTest { color: #5f8700; }
 .subxFunction { color: #af5f00; text-decoration: underline; }
 .LineNr { }
 .subxS1Comment { color: #0000af; }
 .SpecialChar { color: #d70000; }
 .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
-.subxMinorFunction { color: #875f5f; }
 .Constant { color: #008787; }
-.subxTest { color: #5f8700; }
+.subxMinorFunction { color: #875f5f; }
 -->
 
 
@@ -79,255 +79,920 @@ if ('onhashchange' in window) {
  18 
  19 == data
  20 
- 21 # A default allocation descriptor for programs to use.
- 22 Heap:  # allocation-descriptor
- 23   # curr
- 24   0/imm32
- 25   # limit
- 26   0/imm32
- 27 
- 28 # a reasonable default
- 29 Heap-size:  # int
- 30   0x400000/imm32/4MB
- 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
+ 21 # Allocations are returned in a handle, which consists of an alloc-id and a payload.
+ 22 # The alloc-id helps detect use-after-free errors.
+ 23 Handle-size:  # (addr int)
+ 24   8/imm32
+ 25 
+ 26 # A default allocation descriptor for programs to use.
+ 27 Heap:  # allocation-descriptor
+ 28   # curr
+ 29   0/imm32
+ 30   # limit
+ 31   0/imm32
+ 32 
+ 33 # a reasonable default
+ 34 Heap-size:  # int
+ 35   0x600000/imm32/6MB
  36 
- 37 # Let's start initializing the default allocation descriptor.
- 38 
- 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: (addr allocation-descriptor), n: int -> address-or-null/eax: (addr _)
- 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->=-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: 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     # var eax: (handle byte) = 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: 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     # var eax: (handle byte) = 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: (addr allocation-descriptor), n: int -> new-ad: (handle 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-=  $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
+ 37 Next-alloc-id:  # int
+ 38   0x100/imm32  # save a few alloc ids for fake handles
+ 39 
+ 40 == code
+ 41 #   instruction                     effective address                                                   register    displacement    immediate
+ 42 # . op          subop               mod             rm32          base        index         scale       r32
+ 43 # . 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
+ 44 
+ 45 # Let's start initializing the default allocation descriptor.
+ 46 
+ 47 Entry:
+ 48     # initialize heap
+ 49     # . Heap = new-segment(Heap-size)
+ 50     # . . push args
+ 51     68/push  Heap/imm32
+ 52     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Heap-size/disp32                  # push *Heap-size
+ 53     # . . call
+ 54     e8/call  new-segment/disp32
+ 55     # . . discard args
+ 56     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 57 
+ 58     e8/call  run-tests/disp32  # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
+ 59 $array-equal-main:end:
+ 60     # syscall(exit, Num-test-failures)
+ 61     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/ebx   Num-test-failures/disp32          # copy *Num-test-failures to ebx
+ 62     b8/copy-to-eax  1/imm32/exit
+ 63     cd/syscall  0x80/imm8
+ 64 
+ 65 # Allocate and clear 'n' bytes of memory from an allocation-descriptor 'ad'.
+ 66 # Abort if there isn't enough memory in 'ad'.
+ 67 allocate:  # ad: (addr allocation-descriptor), n: int, out: (addr handle)
+ 68     # . prologue
+ 69     55/push-ebp
+ 70     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 71     # . save registers
+ 72     50/push-eax
+ 73     # allocate-raw(ad, n, out)
+ 74     # . . push args
+ 75     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+ 76     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+ 77     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+ 78     # . . call
+ 79     e8/call  allocate-raw/disp32
+ 80     # . . discard args
+ 81     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 82     # eax = out->payload + 4
+ 83     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0x10/disp8      .                 # copy *(ebp+16) to eax
+ 84     8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           0/r32/eax   4/disp8         .                 # copy *(eax+4) to eax
+ 85     05/add-to-eax  4/imm32
+ 86     # zero-out(eax, n)
+ 87     # . . push args
+ 88     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+ 89     50/push-eax
+ 90     # . . call
+ 91     e8/call  zero-out/disp32
+ 92     # . . discard args
+ 93     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 94 $allocate:end:
+ 95     # . restore registers
+ 96     58/pop-to-eax
+ 97     # . epilogue
+ 98     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 99     5d/pop-to-ebp
+100     c3/return
+101 
+102 # Claim the next 'n' bytes of memory starting at ad->curr and update ad->curr.
+103 # Abort if there isn't enough memory in 'ad'.
+104 allocate-raw:  # ad: (addr allocation-descriptor), n: int, out: (addr handle)
+105     # . prologue
+106     55/push-ebp
+107     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+108     # . save registers
+109     50/push-eax
+110     51/push-ecx
+111     52/push-edx
+112     53/push-ebx
+113     56/push-esi
+114     57/push-edi
+115     # ecx = ad
+116     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
+117     # edx = out
+118     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0x10/disp8      .                 # copy *(ebp+16) to edx
+119     # ebx = n
+120     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           3/r32/ebx   0xc/disp8       .                 # copy *(ebp+12) to ebx
+121     # out->alloc-id = Next-alloc-id
+122     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Next-alloc-id/disp32              # copy *Next-alloc-id to eax
+123     89/copy                         0/mod/indirect  2/rm32/edx    .           .             .           0/r32/eax   .               .                 # copy eax to *edx
+124     # out->payload = ad->curr
+125     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
+126 $allocate-raw:save-payload-in-eax:
+127     89/copy                         1/mod/*+disp8   2/rm32/edx    .           .             .           0/r32/eax   4/disp8         .                 # copy eax to *(edx+4)
+128     # *out->payload = Next-alloc-id
+129     8b/copy                         1/mod/*+disp8   2/rm32/edx    .           .             .           7/r32/edi   4/disp8         .                 # copy *(edx+4) to edi
+130     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           6/r32/esi   Next-alloc-id/disp32              # copy *Next-alloc-id to esi
+131     89/copy                         0/mod/indirect  7/rm32/edi    .           .             .           6/r32/esi   .               .                 # copy esi to *edi
+132 $allocate-raw:increment-next-alloc-id:
+133     # increment *Next-alloc-id
+134     ff          0/subop/increment   0/mod/indirect  5/rm32/.disp32            .             .           .           Next-alloc-id/disp32              # increment *Next-alloc-id
+135     # check if there's enough space
+136     # TODO: move this check up before any state updates when we support error recovery
+137     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  3/index/ebx   .           0/r32/eax   4/disp8         .                 # copy eax+ebx+4 to eax
+138     3b/compare                      1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # compare eax with *(ecx+4)
+139     73/jump-if->=-signed  $allocate-raw:abort/disp8
+140 $allocate-raw:commit:
+141     # ad->curr += n+4
+142     89/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy eax to *ecx
+143 $allocate-raw:end:
+144     # . restore registers
+145     5f/pop-to-edi
+146     5e/pop-to-esi
+147     5b/pop-to-ebx
+148     5a/pop-to-edx
+149     59/pop-to-ecx
+150     58/pop-to-eax
+151     # . epilogue
+152     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+153     5d/pop-to-ebp
+154     c3/return
+155 
+156 $allocate-raw:abort:
+157     # . _write(2/stderr, error)
+158     # . . push args
+159     68/push  "allocate: failed\n"/imm32
+160     68/push  2/imm32/stderr
+161     # . . call
+162     e8/call  _write/disp32
+163     # . . discard args
+164     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+165     # . syscall(exit, 1)
+166     bb/copy-to-ebx  1/imm32
+167     b8/copy-to-eax  1/imm32/exit
+168     cd/syscall  0x80/imm8
+169     # never gets here
+170 
+171 test-allocate-raw-success:
+172     # . prologue
+173     55/push-ebp
+174     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+175     # var ad/ecx: allocation-descriptor
+176     68/push  0/imm32/limit
+177     68/push  0/imm32/curr
+178     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+179     # ad = new-segment(512)
+180     # . . push args
+181     51/push-ecx
+182     68/push  0x200/imm32
+183     # . . call
+184     e8/call  new-segment/disp32
+185     # . . discard args
+186     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+187     # var expected-payload/ebx = ad->curr
+188     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           3/r32/ebx   .               .                 # copy *ecx to ebx
+189     # var h/edx: handle = {0, 0}
+190     68/push  0/imm32
+191     68/push  0/imm32
+192     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
+193     # *Next-alloc-id = 0x34
+194     c7          0/subop/copy        0/mod/indirect  5/rm32/.disp32            .             .           .           Next-alloc-id/disp32  0x34/imm32  # copy to *Next-alloc-id
+195     # allocate-raw(ad, 3, h)
+196     # . . push args
+197     52/push-edx
+198     68/push  3/imm32
+199     51/push-ecx
+200     # . . call
+201     e8/call  allocate-raw/disp32
+202     # . . discard args
+203     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+204     # check-ints-equal(h->alloc-id, 0x34, msg)
+205     # . . push args
+206     68/push  "F - test-allocate-raw-success: sets alloc-id in handle"/imm32
+207     68/push  0x34/imm32
+208     ff          6/subop/push        0/mod/indirect  2/rm32/edx    .           .             .           .           .               .                 # push *edx
+209     # . . call
+210     e8/call  check-ints-equal/disp32
+211     # . . discard args
+212     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+213     # check-ints-equal(h->payload, expected-payload, msg)
+214     # . . push args
+215     68/push  "F - test-allocate-raw-success: sets payload in handle"/imm32
+216     53/push-ebx
+217     ff          6/subop/push        1/mod/*+disp8   2/rm32/edx    .           .             .           .           4/disp8         .                 # push *(edx+4)
+218     # . . call
+219     e8/call  check-ints-equal/disp32
+220     # . . discard args
+221     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+222     # check-ints-equal(h->payload->alloc-id, 0x34, msg)
+223     # . . push args
+224     68/push  "F - test-allocate-raw-success: sets alloc-id in payload"/imm32
+225     68/push  0x34/imm32
+226     ff          6/subop/push        0/mod/indirect  3/rm32/ebx    .           .             .           .           .               .                 # push *ebx
 227     # . . call
-228     e8/call  _write/disp32
+228     e8/call  check-ints-equal/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 # Claim the next 'n+4' bytes of memory and initialize the first 4 to n.
-238 # Abort if there isn't enough memory in 'ad'.
-239 allocate-array:  # ad: (addr allocation-descriptor), n: int -> result/eax: (addr _)
-240     # . prologue
-241     55/push-ebp
-242     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-243     # . save registers
-244     51/push-ecx
-245     52/push-edx
-246     # ecx = n
-247     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy *(ebp+12) to ecx
-248     # var size/edx: int = n+4
-249     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           2/r32/edx   4/disp8         .                 # copy ecx+4 to edx
-250     # result = allocate(ad, size)
-251     # . . push args
-252     52/push-edx
-253     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
-254     # . . call
-255     e8/call  allocate/disp32
-256     # . . discard args
-257     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-258     # *result = n
-259     89/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy ecx to *eax
-260 $allocate-array:end:
-261     # . restore registers
-262     5a/pop-to-edx
-263     59/pop-to-ecx
-264     # . epilogue
-265     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-266     5d/pop-to-ebp
-267     c3/return
-268 
-269 # . . vim:nowrap:textwidth=0
+230     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+231     # check-ints-equal(*Next-alloc-id, 0x35, msg)
+232     # . . push args
+233     68/push  "F - test-allocate-raw-success: increments Next-alloc-id"/imm32
+234     68/push  0x35/imm32
+235     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Next-alloc-id/disp32              # push *Next-alloc-id
+236     # . . call
+237     e8/call  check-ints-equal/disp32
+238     # . . discard args
+239     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+240     # check-ints-equal(ad->curr - expected-payload, 3 + 4 for alloc-id, msg)
+241     # . . push args
+242     68/push  "F - test-allocate-raw-success: updates allocation descriptor"/imm32
+243     68/push  7/imm32
+244     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
+245     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # subtract ebx from eax
+246     50/push-eax
+247     # . . call
+248     e8/call  check-ints-equal/disp32
+249     # . . discard args
+250     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+251     # clean up
+252     c7          0/subop/copy        0/mod/indirect  5/rm32/.disp32            .             .           .           Next-alloc-id/disp32  0x100/imm32 # copy to *Next-alloc-id
+253     # . epilogue
+254     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+255     5d/pop-to-ebp
+256     c3/return
+257 
+258 lookup:  # h: (handle T) -> eax: (addr T)
+259     # . prologue
+260     55/push-ebp
+261     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+262     # . save registers
+263     51/push-ecx
+264     # eax = 0
+265     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
+266     # ecx = handle->alloc_id
+267     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
+268     # if (ecx == 0) return 0
+269     81          7/subop/compare     3/mod/direct    1/rm32/ecx    .           .             .           .           .               0/imm32           # compare ecx
+270     74/jump-if-=  $lookup:end/disp8
+271     # eax = handle->address (payload)
+272     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0xc/disp8       .                 # copy *(ebp+12) to eax
+273     # if (ecx != *eax) abort
+274     39/compare                      0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # compare *eax and ecx
+275     75/jump-if-!=  $lookup:abort/disp8
+276     # add 4 to eax
+277     05/add-to-eax  4/imm32
+278 $lookup:end:
+279     # . restore registers
+280     59/pop-to-ecx
+281     # . epilogue
+282     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+283     5d/pop-to-ebp
+284     c3/return
+285 
+286 $lookup:abort:
+287     # . _write(2/stderr, msg)
+288     # . . push args
+289     68/push  "lookup failed\n"/imm32
+290     68/push  2/imm32/stderr
+291     # . . call
+292     e8/call  _write/disp32
+293     # . . discard args
+294     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+295     # . syscall(exit, 1)
+296     bb/copy-to-ebx  1/imm32/exit-status
+297     b8/copy-to-eax  1/imm32/exit
+298     cd/syscall  0x80/imm8
+299 
+300 test-lookup-success:
+301     # . prologue
+302     55/push-ebp
+303     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+304     # var ad/ebx: allocation-descriptor
+305     68/push  0/imm32/limit
+306     68/push  0/imm32/curr
+307     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           4/r32/esp   .               .                 # copy esp to ebx
+308     # ad = new-segment(512)
+309     # . . push args
+310     53/push-ebx
+311     68/push  0x200/imm32
+312     # . . call
+313     e8/call  new-segment/disp32
+314     # . . discard args
+315     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+316     # var handle/ecx: handle
+317     68/push  0/imm32/address
+318     68/push  0/imm32/alloc-id
+319     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+320     # var old-top/edx = ad->curr
+321     8b/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           2/r32/edx   .               .                 # copy *ebx to edx
+322     # allocate-raw(ad, 2, handle)
+323     # . . push args
+324     51/push-ecx
+325     68/push  2/imm32/size
+326     53/push-ebx
+327     # . . call
+328     e8/call  allocate-raw/disp32
+329     # . . discard args
+330     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+331     # eax = lookup(handle)
+332     # . . push args
+333     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+334     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+335     # . . call
+336     e8/call  lookup/disp32
+337     # . . discard args
+338     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+339     # eax contains old top of heap, except skipping the alloc-id in the payload
+340     # . check-ints-equal(eax, old-top+4, msg)
+341     # . . push args
+342     68/push  "F - test-lookup-success"/imm32
+343     81          0/subop/add         3/mod/direct    2/rm32/edx    .           .             .           .           .               4/imm32           # add to edx
+344     52/push-edx
+345     50/push-eax
+346     # . . call
+347     e8/call  check-ints-equal/disp32
+348     # . . discard args
+349     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+350     # clean up
+351     c7          0/subop/copy        0/mod/indirect  5/rm32/.disp32            .             .           .           Next-alloc-id/disp32  0x100/imm32 # copy to *Next-alloc-id
+352     # . epilogue
+353     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+354     5d/pop-to-ebp
+355     c3/return
+356 
+357 test-lookup-null-returns-null:
+358     # . prologue
+359     55/push-ebp
+360     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+361     # var handle/ecx: handle
+362     68/push  0/imm32/address
+363     68/push  0/imm32/alloc-id
+364     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+365     # eax = lookup(handle)
+366     # . . push args
+367     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+368     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+369     # . . call
+370     e8/call  lookup/disp32
+371     # . . discard args
+372     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+373     # check-ints-equal(eax, 0, msg)
+374     # . . push args
+375     68/push  "F - test-lookup-null-returns-null"/imm32
+376     68/push  0/imm32
+377     50/push-eax
+378     # . . call
+379     e8/call  check-ints-equal/disp32
+380     # . . discard args
+381     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+382     # . epilogue
+383     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+384     5d/pop-to-ebp
+385     c3/return
+386 
+387 _pending-test-lookup-failure:
+388     # . prologue
+389     55/push-ebp
+390     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+391     # var heap/esi: allocation-descriptor
+392     68/push  0/imm32/limit
+393     68/push  0/imm32/curr
+394     89/copy                         3/mod/direct    6/rm32/esi    .           .             .           4/r32/esp   .               .                 # copy esp to esi
+395     # heap = new-segment(512)
+396     # . . push args
+397     56/push-esi
+398     68/push  0x200/imm32
+399     # . . call
+400     e8/call  new-segment/disp32
+401     # . . discard args
+402     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+403     # var h1/ecx: handle
+404     68/push  0/imm32/address
+405     68/push  0/imm32/alloc-id
+406     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+407     # var old_top/ebx = heap->curr
+408     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           3/r32/ebx   .               .                 # copy *esi to ebx
+409     # first allocation, to h1
+410     # . allocate(heap, 2, h1)
+411     # . . push args
+412     51/push-ecx
+413     68/push  2/imm32/size
+414     56/push-esi
+415     # . . call
+416     e8/call  allocate/disp32
+417     # . . discard args
+418     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+419     # reset heap->curr to mimic reclamation
+420     89/copy                         0/mod/indirect  6/rm32/esi    .           .             .           3/r32/ebx   .               .                 # copy ebx to *esi
+421     # second allocation that returns the same address as the first
+422     # var h2/edx: handle
+423     68/push  0/imm32/address
+424     68/push  0/imm32/alloc-id
+425     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
+426     # . allocate(heap, 2, h2)
+427     # . . push args
+428     52/push-edx
+429     68/push  2/imm32/size
+430     56/push-esi
+431     # . . call
+432     e8/call  allocate/disp32
+433     # . . discard args
+434     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+435     # check-ints-equal(h1->address, h2->address, msg)
+436     # . . push args
+437     68/push  "F - test-lookup-failure"/imm32
+438     ff          6/subop/push        1/mod/*+disp8   2/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(edx+4)
+439     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+440     # . . call
+441     e8/call  check-ints-equal/disp32
+442     # . . discard args
+443     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+444     # lookup(h1) should crash
+445     # . . push args
+446     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+447     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+448     # . . call
+449     e8/call  lookup/disp32
+450     # should never get past this point
+451     # . . discard args
+452     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+453     # clean up
+454     c7          0/subop/copy        0/mod/indirect  5/rm32/.disp32            .             .           .           Next-alloc-id/disp32  0x100/imm32 # copy to *Next-alloc-id
+455     # . epilogue
+456     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+457     5d/pop-to-ebp
+458     c3/return
+459 
+460 # when comparing handles, just treat them as pure values
+461 handle-equal?:  # a: handle, b: handle -> eax: boolean
+462     # . prologue
+463     55/push-ebp
+464     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+465     # . save registers
+466     51/push-ecx
+467     # eax = false
+468     b8/copy-to-eax  0/imm32/false
+469 $handle-equal?:compare-alloc-id:
+470     # ecx = a->alloc_id
+471     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
+472     # if (ecx != b->alloc_id) return false
+473     39/compare                      1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8      .                 # compare ecx and *(ebp+16)
+474     75/jump-if-!=  $handle-equal?:end/disp8
+475 $handle-equal?:compare-address:
+476     # ecx = handle->address
+477     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy *(ebp+12) to ecx
+478     # if (ecx != b->address) return false
+479     39/compare                      1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x14/disp8      .                 # compare ecx and *(ebp+20)
+480     75/jump-if-!=  $handle-equal?:end/disp8
+481 $handle-equal?:return-true:
+482     # return true
+483     b8/copy-to-eax  1/imm32/true
+484 $handle-equal?:end:
+485     # . restore registers
+486     59/pop-to-ecx
+487     # . epilogue
+488     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+489     5d/pop-to-ebp
+490     c3/return
+491 
+492 # helper: create a nested allocation descriptor (useful for tests)
+493 allocate-region:  # ad: (addr allocation-descriptor), n: int, out: (addr handle allocation-descriptor)
+494     # . prologue
+495     55/push-ebp
+496     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+497     # . save registers
+498     50/push-eax
+499     51/push-ecx
+500     # allocate(ad, n, out)
+501     # . . push args
+502     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+503     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+504     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+505     # . . call
+506     e8/call  allocate/disp32
+507     # . . discard args
+508     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+509     # eax = out->payload
+510     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0x10/disp8      .                 # copy *(ebp+16) to eax
+511     8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           0/r32/eax   4/disp8         .                 # copy *(eax+4) to eax
+512     # skip payload->allocid
+513     05/add-to-eax  4/imm32
+514     # if (eax == 0) abort
+515     3d/compare-eax-and  0/imm32
+516     74/jump-if-=  $allocate-region:abort/disp8
+517     # earmark 8 bytes at the start for a new allocation descriptor
+518     # . *eax = eax + 8
+519     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy eax to ecx
+520     81          0/subop/add         3/mod/direct    1/rm32/ecx    .           .             .           .           .               8/imm32           # add to ecx
+521     89/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy ecx to *eax
+522     # . *(eax+4) = eax + n
+523     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy eax to ecx
+524     03/add                          1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0xc/disp8       .                 # add *(ebp+12) to ecx
+525     89/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           1/r32/ecx   4/disp8         .                 # copy ecx to *(eax+4)
+526     # . restore registers
+527     59/pop-to-ecx
+528     58/pop-to-eax
+529     # . epilogue
+530     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+531     5d/pop-to-ebp
+532     c3/return
+533 
+534 # We could create a more general '$abort' jump target, but then we'd need to do
+535 # a conditional jump followed by loading the error message and an unconditional
+536 # jump. Or we'd need to unconditionally load the error message before a
+537 # conditional jump, even if it's unused the vast majority of the time. This way
+538 # we bloat a potentially cold segment in RAM so we can abort with a single
+539 # instruction.
+540 $allocate-region:abort:
+541     # . _write(2/stderr, error)
+542     # . . push args
+543     68/push  "allocate-region: failed to allocate\n"/imm32
+544     68/push  2/imm32/stderr
+545     # . . call
+546     e8/call  _write/disp32
+547     # . . discard args
+548     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+549     # . syscall(exit, 1)
+550     bb/copy-to-ebx  1/imm32
+551     b8/copy-to-eax  1/imm32/exit
+552     cd/syscall  0x80/imm8
+553     # never gets here
+554 
+555 # Claim the next 'n+4' bytes of memory and initialize the first 4 to n.
+556 # Abort if there isn't enough memory in 'ad'.
+557 allocate-array:  # ad: (addr allocation-descriptor), n: int, out: (addr handle)
+558     # . prologue
+559     55/push-ebp
+560     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+561     # . save registers
+562     50/push-eax
+563     51/push-ecx
+564     52/push-edx
+565     # ecx = n
+566     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy *(ebp+12) to ecx
+567     # var size/edx: int = n+4
+568     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           2/r32/edx   4/disp8         .                 # copy ecx+4 to edx
+569     # allocate(ad, size, out)
+570     # . . push args
+571     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+572     52/push-edx
+573     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+574     # . . call
+575     e8/call  allocate/disp32
+576     # . . discard args
+577     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+578     # *out->payload = n
+579     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0x10/disp8      .                 # copy *(ebp+16) to eax
+580     8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           0/r32/eax   4/disp8         .                 # copy *(eax+4) to eax
+581     # . skip payload->allocid
+582     05/add-to-eax  4/imm32
+583     # .
+584     89/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy ecx to *eax
+585 $allocate-array:end:
+586     # . restore registers
+587     5a/pop-to-edx
+588     59/pop-to-ecx
+589     58/pop-to-eax
+590     # . epilogue
+591     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+592     5d/pop-to-ebp
+593     c3/return
+594 
+595 test-allocate-array:
+596     # . prologue
+597     55/push-ebp
+598     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+599     # var ad/ecx: allocation-descriptor
+600     68/push  0/imm32/limit
+601     68/push  0/imm32/curr
+602     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+603     # ad = new-segment(512)
+604     # . . push args
+605     51/push-ecx
+606     68/push  0x200/imm32
+607     # . . call
+608     e8/call  new-segment/disp32
+609     # . . discard args
+610     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+611     # var expected-payload/ebx = ad->curr
+612     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           3/r32/ebx   .               .                 # copy *ecx to ebx
+613     # var h/edx: handle = {0, 0}
+614     68/push  0/imm32
+615     68/push  0/imm32
+616     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
+617     # *Next-alloc-id = 0x34
+618     c7          0/subop/copy        0/mod/indirect  5/rm32/.disp32            .             .           .           Next-alloc-id/disp32  0x34/imm32  # copy to *Next-alloc-id
+619     # allocate-array(ad, 3, h)
+620     # . . push args
+621     52/push-edx
+622     68/push  3/imm32
+623     51/push-ecx
+624     # . . call
+625     e8/call  allocate-array/disp32
+626     # . . discard args
+627     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+628     # check-ints-equal(h->alloc-id, 0x34, msg)
+629     # . . push args
+630     68/push  "F - test-allocate-array: sets alloc-id in handle"/imm32
+631     68/push  0x34/imm32
+632     ff          6/subop/push        0/mod/indirect  2/rm32/edx    .           .             .           .           .               .                 # push *edx
+633     # . . call
+634     e8/call  check-ints-equal/disp32
+635     # . . discard args
+636     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+637     # check-ints-equal(h->payload, expected-payload, msg)
+638     # . . push args
+639     68/push  "F - test-allocate-array: sets payload in handle"/imm32
+640     53/push-ebx
+641     ff          6/subop/push        1/mod/*+disp8   2/rm32/edx    .           .             .           .           4/disp8         .                 # push *(edx+4)
+642     # . . call
+643     e8/call  check-ints-equal/disp32
+644     # . . discard args
+645     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+646     # check-ints-equal(h->payload->alloc-id, 0x34, msg)
+647     # . . push args
+648     68/push  "F - test-allocate-array: sets alloc-id in payload"/imm32
+649     68/push  0x34/imm32
+650     ff          6/subop/push        0/mod/indirect  3/rm32/ebx    .           .             .           .           .               .                 # push *ebx
+651     # . . call
+652     e8/call  check-ints-equal/disp32
+653     # . . discard args
+654     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+655     # check-ints-equal(h->payload->size, 3, msg)
+656     # . . push args
+657     68/push  "F - test-allocate-array: sets array size in payload"/imm32
+658     68/push  3/imm32
+659     ff          6/subop/push        1/mod/*+disp8   3/rm32/ebx    .           .             .           .           4/disp8         .                 # push *(ebx+4)
+660     # . . call
+661     e8/call  check-ints-equal/disp32
+662     # . . discard args
+663     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+664     # check-ints-equal(*Next-alloc-id, 0x35, msg)
+665     # . . push args
+666     68/push  "F - test-allocate-array: increments Next-alloc-id"/imm32
+667     68/push  0x35/imm32
+668     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Next-alloc-id/disp32              # push *Next-alloc-id
+669     # . . call
+670     e8/call  check-ints-equal/disp32
+671     # . . discard args
+672     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+673     # check-ints-equal(ad->curr - expected-payload, 3 + 4 for alloc-id + 4 for array size, msg)
+674     # . . push args
+675     68/push  "F - test-allocate-array: updates allocation descriptor"/imm32
+676     68/push  0xb/imm32
+677     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
+678     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # subtract ebx from eax
+679     50/push-eax
+680     # . . call
+681     e8/call  check-ints-equal/disp32
+682     # . . discard args
+683     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+684     # clean up
+685     c7          0/subop/copy        0/mod/indirect  5/rm32/.disp32            .             .           .           Next-alloc-id/disp32  1/imm32     # copy to *Next-alloc-id
+686     # . epilogue
+687     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+688     5d/pop-to-ebp
+689     c3/return
+690 
+691 copy-array:  # ad: (addr allocation-descriptor), src: (addr array), out: (addr handle)
+692     # . prologue
+693     55/push-ebp
+694     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+695     # . save registers
+696     50/push-eax
+697     51/push-ecx
+698     52/push-edx
+699     56/push-esi
+700     # esi = src
+701     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
+702     # var size/ecx: int = src->size+4
+703     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
+704     81          0/subop/add         3/mod/direct    1/rm32/ecx    .           .             .           .           .               4/imm32           # add to ecx
+705     # allocate(ad, size, out)
+706     # . . push args
+707     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+708     51/push-ecx
+709     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+710     # . . call
+711     e8/call  allocate/disp32
+712     # . . discard args
+713     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+714     # var payload/eax: (addr byte) = out->payload
+715     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0x10/disp8      .                 # copy *(ebp+16) to eax
+716     8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           0/r32/eax   4/disp8         .                 # copy *(eax+4) to eax
+717     # . skip payload->allocid
+718     05/add-to-eax  4/imm32
+719     # var max/ecx: (addr byte) = payload + size
+720     01/add                          3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # add eax to ecx
+721     # _append-4(payload, max, src, &src->data[src->size])
+722     # . . push &src->data[src->size]
+723     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
+724     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  2/index/edx   .           2/r32/edx   4/disp8         .                 # copy esi+edx+4 to edx
+725     52/push-edx
+726     # . . push src
+727     56/push-esi
+728     # . . push max
+729     51/push-ecx
+730     # . . push payload
+731     50/push-eax
+732     # . . call
+733     e8/call  _append-4/disp32
+734     # . . discard args
+735     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+736 $copy-array:end:
+737     # . restore registers
+738     5e/pop-to-esi
+739     5a/pop-to-edx
+740     59/pop-to-ecx
+741     58/pop-to-eax
+742     # . epilogue
+743     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+744     5d/pop-to-ebp
+745     c3/return
+746 
+747 test-copy-array:
+748     # . prologue
+749     55/push-ebp
+750     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+751     # var src/esi: (addr array int) = [3, 4, 5]
+752     68/push  5/imm32
+753     68/push  4/imm32
+754     68/push  3/imm32
+755     68/push  0xc/imm32/size
+756     89/copy                         3/mod/direct    6/rm32/esi    .           .             .           4/r32/esp   .               .                 # copy esp to esi
+757     # var ad/ecx: allocation-descriptor
+758     68/push  0/imm32/limit
+759     68/push  0/imm32/curr
+760     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+761     # ad = new-segment(512)
+762     # . . push args
+763     51/push-ecx
+764     68/push  0x200/imm32
+765     # . . call
+766     e8/call  new-segment/disp32
+767     # . . discard args
+768     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+769     # var expected-payload/ebx = ad->curr
+770     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           3/r32/ebx   .               .                 # copy *ecx to ebx
+771     # var h/edx: handle = {0, 0}
+772     68/push  0/imm32
+773     68/push  0/imm32
+774     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
+775     # *Next-alloc-id = 0x34
+776     c7          0/subop/copy        0/mod/indirect  5/rm32/.disp32            .             .           .           Next-alloc-id/disp32  0x34/imm32  # copy to *Next-alloc-id
+777     # copy-array(ad, src, h)
+778     # . . push args
+779     52/push-edx
+780     56/push-esi
+781     51/push-ecx
+782     # . . call
+783     e8/call  copy-array/disp32
+784     # . . discard args
+785     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+786     # check-ints-equal(h->alloc-id, 0x34, msg)
+787     # . . push args
+788     68/push  "F - test-copy-array: sets alloc-id in handle"/imm32
+789     68/push  0x34/imm32
+790     ff          6/subop/push        0/mod/indirect  2/rm32/edx    .           .             .           .           .               .                 # push *edx
+791     # . . call
+792     e8/call  check-ints-equal/disp32
+793     # . . discard args
+794     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+795     # check-ints-equal(h->payload, expected-payload, msg)
+796     # . . push args
+797     68/push  "F - test-copy-array: sets payload in handle"/imm32
+798     53/push-ebx
+799     ff          6/subop/push        1/mod/*+disp8   2/rm32/edx    .           .             .           .           4/disp8         .                 # push *(edx+4)
+800     # . . call
+801     e8/call  check-ints-equal/disp32
+802     # . . discard args
+803     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+804     # check-ints-equal(h->payload->alloc-id, 0x34, msg)
+805     # . . push args
+806     68/push  "F - test-copy-array: sets alloc-id in payload"/imm32
+807     68/push  0x34/imm32
+808     ff          6/subop/push        0/mod/indirect  2/rm32/edx    .           .             .           .           .               .                 # push *edx
+809     # . . call
+810     e8/call  check-ints-equal/disp32
+811     # . . discard args
+812     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+813     # var payload/eax: (addr int) = lookup(h)
+814     # . . push args
+815     ff          6/subop/push        1/mod/*+disp8   2/rm32/edx    .           .             .           .           4/disp8         .                 # push *(edx+4)
+816     ff          6/subop/push        0/mod/indirect  2/rm32/edx    .           .             .           .           .               .                 # push *edx
+817     # . . call
+818     e8/call  lookup/disp32
+819     # . . discard args
+820     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+821     # check-ints-equal(payload->size, 0xc, msg)
+822     # . . push args
+823     68/push  "F - test-copy-array: sets array size in payload"/imm32
+824     68/push  0xc/imm32
+825     ff          6/subop/push        0/mod/indirect  0/rm32/eax    .           .             .           .           .               .                 # push *eax
+826     # . . call
+827     e8/call  check-ints-equal/disp32
+828     # . . discard args
+829     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+830     # check-ints-equal(*Next-alloc-id, 0x35, msg)
+831     # . . push args
+832     68/push  "F - test-copy-array: increments Next-alloc-id"/imm32
+833     68/push  0x35/imm32
+834     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Next-alloc-id/disp32              # push *Next-alloc-id
+835     # . . call
+836     e8/call  check-ints-equal/disp32
+837     # . . discard args
+838     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+839     # check-ints-equal(ad->curr - expected-payload, 12 + 4 for alloc-id + 4 for length, msg)
+840     # . . push args
+841     68/push  "F - test-copy-array: updates allocation descriptor"/imm32
+842     68/push  0x14/imm32
+843     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
+844     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # subtract ebx from eax
+845     50/push-eax
+846     # . . call
+847     e8/call  check-ints-equal/disp32
+848     # . . discard args
+849     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+850     # clean up
+851     c7          0/subop/copy        0/mod/indirect  5/rm32/.disp32            .             .           .           Next-alloc-id/disp32  1/imm32     # copy to *Next-alloc-id
+852     # . epilogue
+853     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+854     5d/pop-to-ebp
+855     c3/return
+856 
+857 # Fill a region of memory with zeroes.
+858 zero-out:  # start: (addr byte), len: int
+859     # pseudocode:
+860     #   curr/esi = start
+861     #   i/ecx = 0
+862     #   while true
+863     #     if (i >= len) break
+864     #     *curr = 0
+865     #     ++curr
+866     #     ++i
+867     #
+868     # . prologue
+869     55/push-ebp
+870     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+871     # . save registers
+872     50/push-eax
+873     51/push-ecx
+874     52/push-edx
+875     56/push-esi
+876     # curr/esi = start
+877     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+878     # var i/ecx: int = 0
+879     31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
+880     # edx = len
+881     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
+882 $zero-out:loop:
+883     # if (i >= len) break
+884     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
+885     7d/jump-if->=  $zero-out:end/disp8
+886     # *curr = 0
+887     c6          0/subop/copy        0/mod/direct    6/rm32/esi    .           .             .           .           .               0/imm8            # copy byte to *esi
+888     # ++curr
+889     46/increment-esi
+890     # ++i
+891     41/increment-ecx
+892     eb/jump  $zero-out:loop/disp8
+893 $zero-out:end:
+894     # . restore registers
+895     5e/pop-to-esi
+896     5a/pop-to-edx
+897     59/pop-to-ecx
+898     58/pop-to-eax
+899     # . epilogue
+900     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+901     5d/pop-to-ebp
+902     c3/return
+903 
+904 test-zero-out:
+905     # . prologue
+906     55/push-ebp
+907     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+908     # region/ecx = 34, 35, 36, 37
+909     68/push  0x37363534/imm32
+910     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+911     # zero-out(ecx, 3)
+912     # . . push args
+913     68/push  3/imm32/len
+914     51/push-ecx
+915     # . . call
+916     e8/call  zero-out/disp32
+917     # . . discard args
+918     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+919     # first 3 bytes cleared, fourth left alone
+920     # . check-ints-equal(*ecx, 0x37000000, msg)
+921     # . . push args
+922     68/push  "F - test-zero-out"/imm32
+923     68/push  0x37000000/imm32
+924     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+925     # . . call
+926     e8/call  check-ints-equal/disp32
+927     # . . discard args
+928     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+929     # . epilogue
+930     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+931     5d/pop-to-ebp
+932     c3/return
+933 
+934 # . . vim:nowrap:textwidth=0
 
diff --git a/html/070new-stream.subx.html b/html/070new-stream.subx.html index 1275b225..2eb35066 100644 --- a/html/070new-stream.subx.html +++ b/html/070new-stream.subx.html @@ -16,12 +16,12 @@ a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } .subxS2Comment { color: #8a8a8a; } +.subxTest { color: #5f8700; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } .subxS1Comment { color: #0000af; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .Constant { color: #008787; } -.subxTest { color: #5f8700; } --> @@ -64,117 +64,136 @@ if ('onhashchange' in window) { 5 # . op subop mod rm32 base index scale r32 6 # . 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 7 - 8 new-stream: # ad: (addr allocation-descriptor), length: int, elemsize: int -> address/eax: (handle stream _) + 8 new-stream: # ad: (addr allocation-descriptor), length: int, elemsize: int, out: (addr handle stream _) 9 # . prologue 10 55/push-ebp 11 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 12 # . save registers - 13 52/push-edx - 14 # var n/eax: int = elemsize * length + 12 (for read, write and length) - 15 # . eax = elemsize - 16 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax - 17 # . eax *= length - 18 31/xor 3/mod/direct 2/rm32/edx . . . 2/r32/edx . . # clear edx - 19 f7 4/subop/multiply 1/mod/*+disp8 5/rm32/ebp . . 0xc/disp8 . # multiply *(ebp+12) into eax - 20 # . if overflow abort - 21 81 7/subop/compare 3/mod/direct 2/rm32/edx . . . . . 0/imm32 # compare edx - 22 75/jump-if-!= $new-stream:abort/disp8 - 23 # . edx = elemsize*length - 24 89/copy 3/mod/direct 2/rm32/edx . . . 0/r32/eax . . # copy eax to edx - 25 # . eax += 12 - 26 05/add-to-eax 0xc/imm32 - 27 # var eax: (handle stream _) = allocate(ad, n) - 28 # . . push args - 29 50/push-eax - 30 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - 31 # . . call - 32 e8/call allocate/disp32 - 33 # . . discard args - 34 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - 35 # eax->length = elemsize*length - 36 89/copy 1/mod/*+disp8 0/rm32/eax . . . 2/r32/edx 8/disp8 . # copy edx to *(eax+8) - 37 # clear-stream(eax) - 38 # . . push args - 39 50/push-eax - 40 # . . call - 41 e8/call clear-stream/disp32 - 42 # . . discard args - 43 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - 44 $new-stream:end: - 45 # . restore registers - 46 5a/pop-to-edx - 47 # . epilogue - 48 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 49 5d/pop-to-ebp - 50 c3/return - 51 - 52 $new-stream:abort: - 53 # . _write(2/stderr, error) - 54 # . . push args - 55 68/push "new-stream: size too large\n"/imm32 - 56 68/push 2/imm32/stderr - 57 # . . call - 58 e8/call _write/disp32 - 59 # . . discard args - 60 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - 61 # . syscall(exit, 1) - 62 bb/copy-to-ebx 1/imm32 - 63 b8/copy-to-eax 1/imm32/exit - 64 cd/syscall 0x80/imm8 - 65 # never gets here - 66 - 67 test-new-stream: - 68 # . prologue - 69 55/push-ebp - 70 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - 71 # var heap/ecx: allocation-descriptor - 72 68/push 0/imm32/limit - 73 68/push 0/imm32/curr - 74 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - 75 # heap = new-segment(512) - 76 # . . push args - 77 51/push-ecx - 78 68/push 0x200/imm32 - 79 # . . call - 80 e8/call new-segment/disp32 - 81 # . . discard args - 82 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - 83 # var start/edx = ad->curr - 84 8b/copy 0/mod/indirect 1/rm32/ecx . . . 2/r32/edx . . # copy *ecx to edx - 85 # var eax: (handle stream byte) = new-stream(heap, 3, 2) - 86 # . . push args - 87 68/push 2/imm32 - 88 68/push 3/imm32 - 89 51/push-ecx - 90 # . . call - 91 e8/call new-stream/disp32 - 92 # . . discard args - 93 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - 94 # check-ints-equal(eax, edx, msg) - 95 # . . push args - 96 68/push "F - test-new-stream: returns current pointer of allocation descriptor"/imm32 - 97 52/push-edx - 98 50/push-eax - 99 # . . call -100 e8/call check-ints-equal/disp32 -101 # . . discard args -102 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp -103 # check-ints-equal(eax->length, 6, msg) -104 # . . push args -105 68/push "F - test-new-stream: sets length correctly"/imm32 -106 68/push 6/imm32 -107 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . . 8/disp8 # push *(eax+8) -108 # . . call -109 e8/call check-ints-equal/disp32 -110 # . . discard args -111 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp -112 # the rest is delegated to clear-stream() so we won't bother checking it -113 # . epilogue -114 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp -115 5d/pop-to-ebp -116 c3/return -117 -118 # . . vim:nowrap:textwidth=0 + 13 50/push-eax + 14 52/push-edx + 15 # var size/edx: int = elemsize*length (clobbering eax) + 16 # . eax = elemsize + 17 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax + 18 # . eax *= length + 19 31/xor 3/mod/direct 2/rm32/edx . . . 2/r32/edx . . # clear edx + 20 f7 4/subop/multiply 1/mod/*+disp8 5/rm32/ebp . . 0xc/disp8 . # multiply *(ebp+12) into eax + 21 # . if overflow abort + 22 81 7/subop/compare 3/mod/direct 2/rm32/edx . . . . . 0/imm32 # compare edx + 23 75/jump-if-!= $new-stream:abort/disp8 + 24 # . edx = elemsize*length + 25 89/copy 3/mod/direct 2/rm32/edx . . . 0/r32/eax . . # copy eax to edx + 26 # var n/eax: int = size + 12 (for read, write and size) + 27 05/add-to-eax 0xc/imm32 + 28 # allocate(ad, n, out) + 29 # . . push args + 30 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 . # push *(ebp+20) + 31 50/push-eax + 32 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) + 33 # . . call + 34 e8/call allocate/disp32 + 35 # . . discard args + 36 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp + 37 # eax = out->payload + 38 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x14/disp8 . # copy *(ebp+20) to eax + 39 8b/copy 1/mod/*+disp8 0/rm32/eax . . . 0/r32/eax 4/disp8 . # copy *(eax+4) to eax + 40 # skip payload->allocid + 41 05/add-to-eax 4/imm32 + 42 # eax->size = size + 43 89/copy 1/mod/*+disp8 0/rm32/eax . . . 2/r32/edx 8/disp8 . # copy edx to *(eax+8) + 44 # clear-stream(eax) + 45 # . . push args + 46 50/push-eax + 47 # . . call + 48 e8/call clear-stream/disp32 + 49 # . . discard args + 50 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp + 51 $new-stream:end: + 52 # . restore registers + 53 5a/pop-to-edx + 54 58/pop-to-eax + 55 # . epilogue + 56 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp + 57 5d/pop-to-ebp + 58 c3/return + 59 + 60 $new-stream:abort: + 61 # . _write(2/stderr, error) + 62 # . . push args + 63 68/push "new-stream: size too large\n"/imm32 + 64 68/push 2/imm32/stderr + 65 # . . call + 66 e8/call _write/disp32 + 67 # . . discard args + 68 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + 69 # . syscall(exit, 1) + 70 bb/copy-to-ebx 1/imm32 + 71 b8/copy-to-eax 1/imm32/exit + 72 cd/syscall 0x80/imm8 + 73 # never gets here + 74 + 75 test-new-stream: + 76 # . prologue + 77 55/push-ebp + 78 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp + 79 # var heap/ecx: allocation-descriptor + 80 68/push 0/imm32/limit + 81 68/push 0/imm32/curr + 82 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx + 83 # heap = new-segment(512) + 84 # . . push args + 85 51/push-ecx + 86 68/push 0x200/imm32 + 87 # . . call + 88 e8/call new-segment/disp32 + 89 # . . discard args + 90 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + 91 # var start/edx = ad->curr + 92 8b/copy 0/mod/indirect 1/rm32/ecx . . . 2/r32/edx . . # copy *ecx to edx + 93 # var h/ebx: (handle stream byte) + 94 68/push 0/imm32 + 95 68/push 0/imm32 + 96 89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx + 97 # new-stream(heap, 3, 2, h) + 98 # . . push args + 99 53/push-ebx +100 68/push 2/imm32 +101 68/push 3/imm32 +102 51/push-ecx +103 # . . call +104 e8/call new-stream/disp32 +105 # . . discard args +106 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp +107 # eax = out->payload +108 8b/copy 1/mod/*+disp8 3/rm32/ebx . . . 0/r32/eax 4/disp8 . # copy *(ebx+4) to eax +109 # check-ints-equal(eax, edx, msg) +110 # . . push args +111 68/push "F - test-new-stream: returns current pointer of allocation descriptor"/imm32 +112 52/push-edx +113 50/push-eax +114 # . . call +115 e8/call check-ints-equal/disp32 +116 # . . discard args +117 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +118 # skip payload->allocid +119 05/add-to-eax 4/imm32 +120 # check-ints-equal(eax->size, 6, msg) +121 # . . push args +122 68/push "F - test-new-stream: sets size correctly"/imm32 +123 68/push 6/imm32 +124 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . . 8/disp8 # push *(eax+8) +125 # . . call +126 e8/call check-ints-equal/disp32 +127 # . . discard args +128 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +129 # the rest is delegated to clear-stream() so we won't bother checking it +130 # . reclaim locals +131 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp +132 # . epilogue +133 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp +134 5d/pop-to-ebp +135 c3/return +136 +137 # . . vim:nowrap:textwidth=0 diff --git a/html/071read-line.subx.html b/html/071read-line.subx.html index 1dd7df47..e8070be6 100644 --- a/html/071read-line.subx.html +++ b/html/071read-line.subx.html @@ -16,13 +16,13 @@ a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } .subxS2Comment { color: #8a8a8a; } +.subxTest { color: #5f8700; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } .subxS1Comment { color: #0000af; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxH1Comment { color: #005faf; text-decoration: underline; } .Constant { color: #008787; } -.subxTest { color: #5f8700; } +.subxH1Comment { color: #005faf; text-decoration: underline; } --> @@ -69,7 +69,7 @@ if ('onhashchange' in window) { 9 read-line-buffered: # f: (addr buffered-file), s: (addr stream byte) 10 # pseudocode: 11 # while true - 12 # if (s->write >= s->length) abort + 12 # if (s->write >= s->size) abort 13 # if (f->read >= f->write) populate stream from file 14 # if (f->write == 0) break 15 # AL = f->data[f->read] @@ -95,7 +95,7 @@ if ('onhashchange' in window) { 35 # edx = s->write 36 8b/copy 0/mod/indirect 7/rm32/edi . . . 2/r32/edx . . # copy *edi to edx 37 $read-line-buffered:loop: - 38 # if (s->write >= s->length) abort + 38 # if (s->write >= s->size) abort 39 3b/compare 1/mod/*+disp8 7/rm32/edi . . . 2/r32/edx 8/disp8 . # compare edx with *(edi+8) 40 7d/jump-if->= $read-line-buffered:abort/disp8 41 # if (f->read >= f->write) populate stream from file @@ -279,7 +279,7 @@ if ('onhashchange' in window) { 219 read-line: # f: (addr stream byte), s: (addr stream byte) 220 # pseudocode: 221 # while true -222 # if (s->write >= s->length) abort +222 # if (s->write >= s->size) abort 223 # if (f->read >= f->write) break 224 # AL = f->data[f->read] 225 # s->data[s->write] = AL @@ -304,7 +304,7 @@ if ('onhashchange' in window) { 244 # edx = s->write 245 8b/copy 0/mod/indirect 7/rm32/edi . . . 2/r32/edx . . # copy *edi to edx 246 $read-line:loop: -247 # if (s->write >= s->length) abort +247 # if (s->write >= s->size) abort 248 3b/compare 1/mod/*+disp8 7/rm32/edi . . . 2/r32/edx 8/disp8 . # compare edx with *(edi+8) 249 0f 8d/jump-if->= $read-line:abort/disp32 250 # if (f->read >= f->write) break diff --git a/html/072slice.subx.html b/html/072slice.subx.html index 77105894..214a8ea6 100644 --- a/html/072slice.subx.html +++ b/html/072slice.subx.html @@ -16,14 +16,14 @@ a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } .subxS2Comment { color: #8a8a8a; } -.Folded { color: #080808; background-color: #949494; } +.subxTest { color: #5f8700; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } .subxS1Comment { color: #0000af; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxH1Comment { color: #005faf; text-decoration: underline; } +.Folded { color: #080808; background-color: #949494; } .Constant { color: #008787; } -.subxTest { color: #5f8700; } +.subxH1Comment { color: #005faf; text-decoration: underline; } --> @@ -183,7 +183,7 @@ if ('onhashchange' in window) { 122 # if (p == 0) return (s == 0) 123 # currs = s->start 124 # maxs = s->end - 125 # if (maxs - currs != p->length) return false + 125 # if (maxs - currs != p->size) return false 126 # currp = p->data 127 # while currs < maxs 128 # if (*currs != *currp) return false @@ -212,7 +212,7 @@ if ('onhashchange' in window) { 151 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 152 # var maxs/esi: (addr byte) = s->end 153 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 6/r32/esi 4/disp8 . # copy *(esi+4) to esi - 154 # var slen/eax: int = maxs - currs + 154 # var ssize/eax: int = maxs - currs 155 89/copy 3/mod/direct 0/rm32/eax . . . 6/r32/esi . . # copy esi to eax 156 29/subtract 3/mod/direct 0/rm32/eax . . . 2/r32/edx . . # subtract edx from eax 157 # ebx = p @@ -226,7 +226,7 @@ if ('onhashchange' in window) { 165 74/jump-if-= $slice-equal?:true/disp8 166 eb/jump $slice-equal?:false/disp8 167 $slice-equal?:nonnull-string: - 168 # if (slen != p->length) return false + 168 # if (ssize != p->size) return false 169 39/compare 0/mod/indirect 3/rm32/ebx . . . 0/r32/eax . . # compare *ebx and eax 170 75/jump-if-!= $slice-equal?:false/disp8 171 # var currp/ebx: (addr byte) = p->data @@ -547,12 +547,12 @@ if ('onhashchange' in window) { 486 487 slice-starts-with?: # s: (addr slice), head: (addr array byte) -> eax: boolean 488 # pseudocode - 489 # lenh = head->length - 490 # if (lenh > s->end - s->start) return false + 489 # hsize = head->size + 490 # if (hsize > s->end - s->start) return false 491 # i = 0 492 # currs = s->start 493 # currp = head->data - 494 # while i < lenh + 494 # while i < hsize 495 # if (*currs != *currh) return false 496 # ++i 497 # ++currs @@ -565,7 +565,7 @@ if ('onhashchange' in window) { 504 # *currs: eax 505 # *currh: ebx 506 # i: ecx - 507 # lenh: edx + 507 # hsize: edx 508 # 509 # . prologue 510 55/push-ebp @@ -583,9 +583,9 @@ if ('onhashchange' in window) { 522 2b/subtract 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # subtract *esi from ecx 523 # edi = head 524 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 0xc/disp8 . # copy *(ebp+12) to edi - 525 # var lenh/edx: int = head->length + 525 # var hsize/edx: int = head->size 526 8b/copy 0/mod/indirect 7/rm32/edi . . . 2/r32/edx . . # copy *edi to edx - 527 # if (lenh > lens) return false + 527 # if (hsize > lens) return false 528 39/compare 3/mod/direct 2/rm32/edx . . . 1/r32/ecx . . # compare edx with ecx 529 7f/jump-if-> $slice-starts-with?:false/disp8 530 # var currs/esi: (addr byte) = s->start @@ -599,7 +599,7 @@ if ('onhashchange' in window) { 538 # var c2/ebx: byte = 0 539 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx 540 $slice-starts-with?:loop: - 541 # if (i >= lenh) return true + 541 # if (i >= hsize) return true 542 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 543 7d/jump-if->= $slice-starts-with?:true/disp8 544 # c1 = *currs @@ -870,7 +870,7 @@ if ('onhashchange' in window) { 809 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 6/r32/esi 4/disp8 . # copy *(esi+4) to esi 810 # edi = out 811 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 7/r32/edi 8/disp8 . # copy *(ebp+8) to edi - 812 # edx = out->length + 812 # edx = out->size 813 8b/copy 1/mod/*+disp8 7/rm32/edi . . . 2/r32/edx 8/disp8 . # copy *(edi+8) to edx 814 # ebx = out->write 815 8b/copy 0/mod/indirect 7/rm32/edi . . . 3/r32/ebx . . # copy *edi to ebx @@ -878,7 +878,7 @@ if ('onhashchange' in window) { 817 # if (curr >= max) break 818 39/compare 3/mod/direct 1/rm32/ecx . . . 6/r32/esi . . # compare ecx with esi 819 73/jump-if-addr>= $write-slice:loop-end/disp8 - 820 # if (out->write >= out->length) abort + 820 # if (out->write >= out->size) abort 821 39/compare 3/mod/direct 3/rm32/ebx . . . 2/r32/edx . . # compare ebx with edx 822 7d/jump-if->= $write-slice:abort/disp8 823 # out->data[out->write] = *in @@ -986,7 +986,7 @@ if ('onhashchange' in window) { 925 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 6/r32/esi 4/disp8 . # copy *(esi+4) to esi 926 # edi = out 927 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 7/r32/edi 8/disp8 . # copy *(ebp+8) to edi - 928 # edx = out->length + 928 # edx = out->size 929 8b/copy 1/mod/*+disp8 7/rm32/edi . . . 2/r32/edx 0xc/disp8 . # copy *(edi+12) to edx 930 # ebx = out->write 931 8b/copy 1/mod/*+disp8 7/rm32/edi . . . 3/r32/ebx 4/disp8 . # copy *(edi+4) to ebx @@ -994,7 +994,7 @@ if ('onhashchange' in window) { 933 # if (curr >= max) break 934 39/compare 3/mod/direct 1/rm32/ecx . . . 6/r32/esi . . # compare ecx with esi 935 73/jump-if-addr>= $write-slice-buffered:loop-end/disp8 - 936 # if (out->write >= out->length) flush and clear out's stream + 936 # if (out->write >= out->size) flush and clear out's stream 937 39/compare 3/mod/direct 3/rm32/ebx . . . 2/r32/edx . . # compare ebx with edx 938 7c/jump-if-< $write-slice-buffered:to-stream/disp8 939 # . persist out->write @@ -1102,141 +1102,160 @@ if ('onhashchange' in window) { 1041 c3/return 1042 1043 # copy a slice into a new (dynamically allocated) string -1044 slice-to-string: # ad: (addr allocation-descriptor), in: (addr slice) -> out/eax: (addr array byte) +1044 slice-to-string: # ad: (addr allocation-descriptor), in: (addr slice), out: (addr handle array byte) 1045 # . prologue 1046 55/push-ebp 1047 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1048 # . save registers -1049 51/push-ecx -1050 52/push-edx -1051 53/push-ebx -1052 56/push-esi -1053 # esi = in -1054 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi -1055 # var curr/edx: (addr byte) = in->start -1056 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx -1057 # var max/ebx: (addr byte) = in->end -1058 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 3/r32/ebx 4/disp8 . # copy *(esi+4) to ebx -1059 # var size/ecx: int = max - curr + 4 # total size of output string (including the initial length) -1060 89/copy 3/mod/direct 1/rm32/ecx . . . 3/r32/ebx . . # copy ebx to ecx -1061 29/subtract 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # subtract edx from ecx -1062 81 0/subop/add 3/mod/direct 1/rm32/ecx . . . . . 4/imm32 # add to ecx -1063 # var out/eax: (handle array byte) = allocate(ad, size) -1064 # . . push args -1065 51/push-ecx -1066 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) -1067 # . . call -1068 e8/call allocate/disp32 -1069 # . . discard args -1070 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -1071 # if (eax == 0) abort -1072 3d/compare-eax-and 0/imm32 -1073 74/jump-if-= $slice-to-string:abort/disp8 -1074 # out->length = size-4 -1075 89/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy ecx to *eax -1076 81 5/subop/subtract 0/mod/indirect 0/rm32/eax . . . . . 4/imm32 # subtract 4 from *eax -1077 # save out -1078 50/push-eax -1079 $slice-to-string:initialize: -1080 # eax = _append-4(eax+4, eax+size, curr, max) # clobbering ecx -1081 # . . push args -1082 53/push-ebx -1083 52/push-edx -1084 # . . push eax+size (clobbering ecx) -1085 01/add 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # add eax to ecx -1086 51/push-ecx -1087 # . . push eax+4 (clobbering eax) -1088 81 0/subop/add 3/mod/direct 0/rm32/eax . . . . . 4/imm32 # add to eax -1089 50/push-eax -1090 # . . call -1091 e8/call _append-4/disp32 -1092 # . . discard args -1093 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp -1094 # restore out (assumes _append-4 can't error) -1095 58/pop-to-eax -1096 $slice-to-string:end: -1097 # . restore registers -1098 5e/pop-to-esi -1099 5b/pop-to-ebx -1100 5a/pop-to-edx -1101 59/pop-to-ecx -1102 # . epilogue -1103 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp -1104 5d/pop-to-ebp -1105 c3/return -1106 -1107 $slice-to-string:abort: -1108 # . _write(2/stderr, error) -1109 # . . push args -1110 68/push "slice-to-string: out of space\n"/imm32 -1111 68/push 2/imm32/stderr -1112 # . . call -1113 e8/call _write/disp32 -1114 # . . discard args -1115 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -1116 # . syscall(exit, 1) -1117 bb/copy-to-ebx 1/imm32 -1118 b8/copy-to-eax 1/imm32/exit -1119 cd/syscall 0x80/imm8 -1120 # never gets here -1121 -1122 test-slice-to-string: -1123 # . prologue -1124 55/push-ebp -1125 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp -1126 # var heap/edx: allocation-descriptor -1127 68/push 0/imm32/limit -1128 68/push 0/imm32/curr -1129 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx -1130 # heap = new-segment(512) -1131 # . . push args -1132 52/push-edx -1133 68/push 0x200/imm32 -1134 # . . call -1135 e8/call new-segment/disp32 -1136 # . . discard args -1137 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -1138 # (eax..ecx) = "Abc" -1139 b8/copy-to-eax "Abc"/imm32 -1140 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx -1141 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 -1142 05/add-to-eax 4/imm32 -1143 # var slice/ecx: slice = {eax, ecx} -1144 51/push-ecx -1145 50/push-eax -1146 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx -1147 # eax = slice-to-string(heap, slice) -1148 # . . push args -1149 51/push-ecx -1150 52/push-edx -1151 # . . call -1152 e8/call slice-to-string/disp32 -1153 # . . discard args -1154 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -1155 +-- 26 lines: #? # dump word-slice -------------------------------------------------------------------------------------------------------------------------------------------------- -1181 # eax = string-equal?(eax, "Abc") -1182 # . . push args -1183 68/push "Abc"/imm32 -1184 50/push-eax -1185 # . . call -1186 e8/call string-equal?/disp32 -1187 # . . discard args -1188 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -1189 # check-ints-equal(eax, 1, msg) -1190 # . . push args -1191 68/push "F - test-slice-to-string"/imm32 -1192 68/push 1/imm32/true -1193 50/push-eax -1194 # . . call -1195 e8/call check-ints-equal/disp32 -1196 # . . discard args -1197 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp -1198 # . epilogue -1199 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp -1200 5d/pop-to-ebp -1201 c3/return -1202 -1203 # . . vim:nowrap:textwidth=0 +1049 50/push-eax +1050 51/push-ecx +1051 52/push-edx +1052 53/push-ebx +1053 56/push-esi +1054 # esi = in +1055 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi +1056 # var curr/edx: (addr byte) = in->start +1057 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx +1058 # var max/ebx: (addr byte) = in->end +1059 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 3/r32/ebx 4/disp8 . # copy *(esi+4) to ebx +1060 # var size/ecx: int = max - curr + 4 # total size of output string (including the initial 'size' field) +1061 89/copy 3/mod/direct 1/rm32/ecx . . . 3/r32/ebx . . # copy ebx to ecx +1062 29/subtract 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # subtract edx from ecx +1063 81 0/subop/add 3/mod/direct 1/rm32/ecx . . . . . 4/imm32 # add to ecx +1064 # allocate(ad, size, out) +1065 # . . push args +1066 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) +1067 51/push-ecx +1068 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) +1069 # . . call +1070 e8/call allocate/disp32 +1071 # . . discard args +1072 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +1073 # eax = out->payload +1074 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax +1075 8b/copy 1/mod/*+disp8 0/rm32/eax . . . 0/r32/eax 4/disp8 . # copy *(eax+4) to eax +1076 # skip payload->allocid +1077 05/add-to-eax 4/imm32 +1078 # if (eax == 0) abort +1079 3d/compare-eax-and 0/imm32 +1080 74/jump-if-= $slice-to-string:abort/disp8 +1081 # out->size = size-4 +1082 89/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy ecx to *eax +1083 81 5/subop/subtract 0/mod/indirect 0/rm32/eax . . . . . 4/imm32 # subtract 4 from *eax +1084 # save out +1085 50/push-eax +1086 $slice-to-string:initialize: +1087 # eax = _append-4(eax+4, eax+size, curr, max) # clobbering ecx +1088 # . . push args +1089 53/push-ebx +1090 52/push-edx +1091 # . . push eax+size (clobbering ecx) +1092 01/add 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # add eax to ecx +1093 51/push-ecx +1094 # . . push eax+4 (clobbering eax) +1095 81 0/subop/add 3/mod/direct 0/rm32/eax . . . . . 4/imm32 # add to eax +1096 50/push-eax +1097 # . . call +1098 e8/call _append-4/disp32 +1099 # . . discard args +1100 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp +1101 # restore out (assumes _append-4 can't error) +1102 58/pop-to-eax +1103 $slice-to-string:end: +1104 # . restore registers +1105 5e/pop-to-esi +1106 5b/pop-to-ebx +1107 5a/pop-to-edx +1108 59/pop-to-ecx +1109 58/pop-to-eax +1110 # . epilogue +1111 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp +1112 5d/pop-to-ebp +1113 c3/return +1114 +1115 $slice-to-string:abort: +1116 # . _write(2/stderr, error) +1117 # . . push args +1118 68/push "slice-to-string: out of space\n"/imm32 +1119 68/push 2/imm32/stderr +1120 # . . call +1121 e8/call _write/disp32 +1122 # . . discard args +1123 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +1124 # . syscall(exit, 1) +1125 bb/copy-to-ebx 1/imm32 +1126 b8/copy-to-eax 1/imm32/exit +1127 cd/syscall 0x80/imm8 +1128 # never gets here +1129 +1130 test-slice-to-string: +1131 # . prologue +1132 55/push-ebp +1133 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp +1134 # var heap/edx: allocation-descriptor +1135 68/push 0/imm32/limit +1136 68/push 0/imm32/curr +1137 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx +1138 # heap = new-segment(512) +1139 # . . push args +1140 52/push-edx +1141 68/push 0x200/imm32 +1142 # . . call +1143 e8/call new-segment/disp32 +1144 # . . discard args +1145 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +1146 # (eax..ecx) = "Abc" +1147 b8/copy-to-eax "Abc"/imm32 +1148 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx +1149 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 +1150 05/add-to-eax 4/imm32 +1151 # var slice/ecx: slice = {eax, ecx} +1152 51/push-ecx +1153 50/push-eax +1154 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx +1155 # var h/ebx: (handle array byte) +1156 68/push 0/imm32 +1157 68/push 0/imm32 +1158 89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx +1159 # slice-to-string(heap, slice, h) +1160 # . . push args +1161 53/push-ebx +1162 51/push-ecx +1163 52/push-edx +1164 # . . call +1165 e8/call slice-to-string/disp32 +1166 # . . discard args +1167 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +1168 # eax = h->payload +1169 8b/copy 1/mod/*+disp8 3/rm32/ebx . . . 0/r32/eax 4/disp8 . # copy *(ebx+4) to eax +1170 # skip payload->allocid +1171 05/add-to-eax 4/imm32 +1172 +-- 26 lines: #? # dump eax --------------------------------------------------------------------------------------------------------------------------------------------------------- +1198 # eax = string-equal?(eax, "Abc") +1199 # . . push args +1200 68/push "Abc"/imm32 +1201 50/push-eax +1202 # . . call +1203 e8/call string-equal?/disp32 +1204 # . . discard args +1205 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +1206 # check-ints-equal(eax, 1, msg) +1207 # . . push args +1208 68/push "F - test-slice-to-string"/imm32 +1209 68/push 1/imm32/true +1210 50/push-eax +1211 # . . call +1212 e8/call check-ints-equal/disp32 +1213 # . . discard args +1214 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp +1215 # . reclaim locals +1216 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # add to esp +1217 # . epilogue +1218 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp +1219 5d/pop-to-ebp +1220 c3/return +1221 +1222 # . . vim:nowrap:textwidth=0 diff --git a/html/073next-token.subx.html b/html/073next-token.subx.html index d4a7c4fb..15421795 100644 --- a/html/073next-token.subx.html +++ b/html/073next-token.subx.html @@ -16,12 +16,12 @@ a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } .subxS2Comment { color: #8a8a8a; } +.subxTest { color: #5f8700; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } .subxS1Comment { color: #0000af; } -.Constant { color: #008787; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxTest { color: #5f8700; } +.Constant { color: #008787; } --> diff --git a/html/074write-stream-data.subx.html b/html/074write-stream-data.subx.html index 7e906849..9955a876 100644 --- a/html/074write-stream-data.subx.html +++ b/html/074write-stream-data.subx.html @@ -16,12 +16,12 @@ a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } .subxS2Comment { color: #8a8a8a; } +.subxTest { color: #5f8700; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } .subxS1Comment { color: #0000af; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .Constant { color: #008787; } -.subxTest { color: #5f8700; } --> diff --git a/html/075print-int-decimal.subx.html b/html/075print-int-decimal.subx.html index a9753eea..9720b310 100644 --- a/html/075print-int-decimal.subx.html +++ b/html/075print-int-decimal.subx.html @@ -16,14 +16,14 @@ a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } .subxS2Comment { color: #8a8a8a; } -.Folded { color: #080808; background-color: #949494; } +.subxTest { color: #5f8700; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } .subxS1Comment { color: #0000af; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxH1Comment { color: #005faf; text-decoration: underline; } +.Folded { color: #080808; background-color: #949494; } .Constant { color: #008787; } -.subxTest { color: #5f8700; } +.subxH1Comment { color: #005faf; text-decoration: underline; } --> @@ -83,7 +83,7 @@ if ('onhashchange' in window) { 22 # push '-' 23 # w = out->write 24 # curr = &out->data[out->write] - 25 # max = &out->data[out->length] + 25 # max = &out->data[out->size] 26 # while true 27 # pop into eax 28 # if (eax == sentinel) break @@ -139,7 +139,7 @@ if ('onhashchange' in window) { 78 8b/copy 0/mod/indirect 7/rm32/edi . . . 2/r32/edx . . # copy *edi to edx 79 # var curr/ecx: (addr byte) = &out->data[out->write] 80 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/edi 2/index/edx . 1/r32/ecx 0xc/disp8 . # copy ebx+edx+12 to ecx - 81 # var max/ebx: (addr byte) = &out->data[out->length] + 81 # var max/ebx: (addr byte) = &out->data[out->size] 82 8b/copy 1/mod/*+disp8 7/rm32/edi . . . 3/r32/ebx 8/disp8 . # copy *(edi+8) to ebx 83 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/edi 3/index/ebx . 3/r32/ebx 0xc/disp8 . # copy edi+ebx+12 to ebx 84 $print-int32-decimal:write-loop: diff --git a/html/076next-word.subx.html b/html/076next-word.subx.html index 7d573edb..3c5104c3 100644 --- a/html/076next-word.subx.html +++ b/html/076next-word.subx.html @@ -16,12 +16,12 @@ a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } .subxS2Comment { color: #8a8a8a; } +.subxTest { color: #5f8700; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } .subxS1Comment { color: #0000af; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .Constant { color: #008787; } -.subxTest { color: #5f8700; } --> diff --git a/html/077subx-words.subx.html b/html/077subx-words.subx.html index 39970cd9..401520c3 100644 --- a/html/077subx-words.subx.html +++ b/html/077subx-words.subx.html @@ -16,12 +16,12 @@ a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } .subxS2Comment { color: #8a8a8a; } +.subxTest { color: #5f8700; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } .subxS1Comment { color: #0000af; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .Constant { color: #008787; } -.subxTest { color: #5f8700; } --> diff --git a/html/078emit-hex.subx.html b/html/078emit-hex.subx.html index d080510f..295875a8 100644 --- a/html/078emit-hex.subx.html +++ b/html/078emit-hex.subx.html @@ -16,12 +16,12 @@ a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } .subxS2Comment { color: #8a8a8a; } +.subxTest { color: #5f8700; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } .subxS1Comment { color: #0000af; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .Constant { color: #008787; } -.subxTest { color: #5f8700; } --> diff --git a/html/079emit.subx.html b/html/079emit.subx.html index 57b6d11c..b98b146c 100644 --- a/html/079emit.subx.html +++ b/html/079emit.subx.html @@ -16,14 +16,14 @@ a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } .subxS2Comment { color: #8a8a8a; } -.LineNr { } -.SpecialChar { color: #d70000; } -.subxS1Comment { color: #0000af; } +.subxTest { color: #5f8700; } .subxFunction { color: #af5f00; text-decoration: underline; } +.LineNr { } +.subxS1Comment { color: #0000af; } +.SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .Folded { color: #080808; background-color: #949494; } .Constant { color: #008787; } -.subxTest { color: #5f8700; } --> diff --git a/html/081table.subx.html b/html/081table.subx.html index 0051739b..5478ad79 100644 --- a/html/081table.subx.html +++ b/html/081table.subx.html @@ -16,14 +16,14 @@ a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } .subxS2Comment { color: #8a8a8a; } -.LineNr { } -.SpecialChar { color: #d70000; } -.subxS1Comment { color: #0000af; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxH1Comment { color: #005faf; text-decoration: underline; } -.Constant { color: #008787; } .subxTest { color: #5f8700; } +.subxFunction { color: #af5f00; text-decoration: underline; } +.LineNr { } +.subxS1Comment { color: #0000af; } +.SpecialChar { color: #d70000; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.Constant { color: #008787; } +.subxH1Comment { color: #005faf; text-decoration: underline; } --> @@ -61,19 +61,19 @@ if ('onhashchange' in window) {
    1 # A table is a stream of (key, value) rows.
    2 #
-   3 # Each row consists of a 4-byte key -- a 'string_key' which is (addr array
-   4 # byte) -- and a variable-size value.
-   5 #
-   6 # Accessing the table performs a linear scan for a key string, and always
-   7 # requires passing in the row size.
-   8 #
-   9 # Table primitives have the form <variant>(stream, <arg>, row-size, ...) -> address/eax
-  10 #
-  11 # The following table shows available options for <variant>:
-  12 #   if not found:           | arg=string              arg=slice
-  13 #   ------------------------+---------------------------------------------------
-  14 #   abort                   | get                     get-slice
-  15 #   insert key              | get-or-insert           leaky-get-or-insert-slice
+   3 # Each row consists of an 8-byte key -- a (handle array byte) -- and a variable-size value.
+   4 #
+   5 # Accessing the table performs a linear scan for a key string, and always
+   6 # requires passing in the row size.
+   7 #
+   8 # Table primitives have the form <variant>(stream, <arg>, row-size, ...) -> address/eax
+   9 #
+  10 # The following table shows available options for <variant>:
+  11 #   if not found:           | arg=string              arg=slice
+  12 #   ------------------------+---------------------------------------------------
+  13 #   abort                   | get                     get-slice
+  14 #   insert key              | get-or-insert           get-or-insert-slice
+  15 #                           | get-or-insert-handle
   16 #   stop                    | get-or-stop             get-slice-or-stop
   17 #   return null             | maybe-get               maybe-get-slice
   18 # Some variants may take extra args.
@@ -84,14 +84,14 @@ if ('onhashchange' in window) {
   23 # . 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
   24 
   25 # if no row is found, abort
-  26 # type string_key = (addr array byte)
-  27 get:  # table: (addr stream {string_key, T}), key: string_key, row-size: int, abort-message-prefix: (addr array byte) -> eax: (addr T)
-  28     # pseudocode:
-  29     #   curr = table->data
-  30     #   max = &table->data[table->write]
-  31     #   while curr < max
-  32     #     if string-equal?(key, *curr)
-  33     #       return curr+4
+  26 get:  # table: (addr stream {(handle array byte), T}), key: (addr array byte), row-size: int, abort-message-prefix: (addr array byte) -> eax: (addr T)
+  27     # pseudocode:
+  28     #   curr = table->data
+  29     #   max = &table->data[table->write]
+  30     #   while curr < max
+  31     #     var c: (addr array byte) = lookup(*curr)
+  32     #     if string-equal?(key, c)
+  33     #       return curr+8
   34     #     curr += row-size
   35     #   abort
   36     #
@@ -104,7 +104,7 @@ if ('onhashchange' in window) {
   43     56/push-esi
   44     # esi = table
   45     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
-  46     # var curr/ecx: (addr string_key) = table->data
+  46     # var curr/ecx: (addr handle array byte) = table->data
   47     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy esi+12 to ecx
   48     # var max/edx: (addr byte) = &table->data[table->write]
   49     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
@@ -113,1645 +113,2104 @@ if ('onhashchange' in window) {
   52     # if (curr >= max) abort
   53     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
   54     73/jump-if-addr>=  $get:abort/disp8
-  55     # if (string-equal?(key, *curr)) return curr+4
-  56     # . eax = string-equal?(key, *curr)
-  57     # . . push args
+  55     # var c/eax: (addr array byte) = lookup(*curr)
+  56     # . . push args
+  57     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
   58     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
-  59     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
-  60     # . . call
-  61     e8/call  string-equal?/disp32
-  62     # . . discard args
-  63     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-  64     # . if (eax != false) return eax = curr+4
-  65     3d/compare-eax-and  0/imm32/false
-  66     74/jump-if-=  $get:mismatch/disp8
-  67     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy ecx+4 to eax
-  68     eb/jump  $get:end/disp8
-  69 $get:mismatch:
-  70     # curr += row-size
-  71     03/add                          1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8      .                 # add *(ebp+16) to ecx
-  72     # loop
-  73     eb/jump  $get:search-loop/disp8
-  74 $get:end:
-  75     # . restore registers
-  76     5e/pop-to-esi
-  77     5a/pop-to-edx
-  78     59/pop-to-ecx
-  79     # . epilogue
-  80     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-  81     5d/pop-to-ebp
-  82     c3/return
-  83 
-  84 $get:abort:
-  85     # . _write(2/stderr, abort-message-prefix)
-  86     # . . push args
-  87     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
-  88     68/push  2/imm32/stderr
-  89     # . . call
-  90     e8/call  _write/disp32
-  91     # . . discard args
-  92     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-  93     # . _write(2/stderr, error)
+  59     # . . call
+  60     e8/call  lookup/disp32
+  61     # . . discard args
+  62     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+  63     # if (string-equal?(key, c)) return curr+8
+  64     # . eax = string-equal?(key, c)
+  65     # . . push args
+  66     50/push-eax
+  67     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+  68     # . . call
+  69     e8/call  string-equal?/disp32
+  70     # . . discard args
+  71     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+  72     # . if (eax != false) return eax = curr+8
+  73     3d/compare-eax-and  0/imm32/false
+  74     74/jump-if-=  $get:mismatch/disp8
+  75     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   8/disp8         .                 # copy ecx+8 to eax
+  76     eb/jump  $get:end/disp8
+  77 $get:mismatch:
+  78     # curr += row-size
+  79     03/add                          1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8      .                 # add *(ebp+16) to ecx
+  80     # loop
+  81     eb/jump  $get:search-loop/disp8
+  82 $get:end:
+  83     # . restore registers
+  84     5e/pop-to-esi
+  85     5a/pop-to-edx
+  86     59/pop-to-ecx
+  87     # . epilogue
+  88     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+  89     5d/pop-to-ebp
+  90     c3/return
+  91 
+  92 $get:abort:
+  93     # . _write(2/stderr, abort-message-prefix)
   94     # . . push args
-  95     68/push  ": get: key not found: "/imm32
+  95     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
   96     68/push  2/imm32/stderr
   97     # . . call
   98     e8/call  _write/disp32
   99     # . . discard args
  100     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 101     # . _write(2/stderr, key)
+ 101     # . _write(2/stderr, error)
  102     # . . push args
- 103     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+ 103     68/push  ": get: key not found: "/imm32
  104     68/push  2/imm32/stderr
  105     # . . call
  106     e8/call  _write/disp32
  107     # . . discard args
  108     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 109     # . _write(2/stderr, "\n")
+ 109     # . _write(2/stderr, key)
  110     # . . push args
- 111     68/push  Newline/imm32
+ 111     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
  112     68/push  2/imm32/stderr
  113     # . . call
  114     e8/call  _write/disp32
  115     # . . discard args
  116     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 117     # . syscall(exit, 1)
- 118     bb/copy-to-ebx  1/imm32
- 119     b8/copy-to-eax  1/imm32/exit
- 120     cd/syscall  0x80/imm8
- 121     # never gets here
- 122 
- 123 test-get:
- 124     # . prologue
- 125     55/push-ebp
- 126     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 127     # - setup: create a table with a couple of keys
- 128     # var table/ecx: (stream {string, number} 16)  # 2 rows * 8 bytes/row
- 129     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # subtract from esp
- 130     68/push  0x10/imm32/length
- 131     68/push  0/imm32/read
- 132     68/push  0/imm32/write
- 133     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
- 134     # insert(table, "code", 8 bytes per row)
- 135     # . . push args
- 136     68/push  8/imm32/row-size
- 137     68/push  "code"/imm32
- 138     51/push-ecx
- 139     # . . call
- 140     e8/call  get-or-insert/disp32
- 141     # . . discard args
- 142     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 143     # insert(table, "data", 8 bytes per row)
- 144     # . . push args
- 145     68/push  8/imm32/row-size
- 146     68/push  "data"/imm32
+ 117     # . _write(2/stderr, "\n")
+ 118     # . . push args
+ 119     68/push  Newline/imm32
+ 120     68/push  2/imm32/stderr
+ 121     # . . call
+ 122     e8/call  _write/disp32
+ 123     # . . discard args
+ 124     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 125     # . syscall(exit, 1)
+ 126     bb/copy-to-ebx  1/imm32
+ 127     b8/copy-to-eax  1/imm32/exit
+ 128     cd/syscall  0x80/imm8
+ 129     # never gets here
+ 130 
+ 131 test-get:
+ 132     # . prologue
+ 133     55/push-ebp
+ 134     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 135     # - setup: create a table with a couple of keys
+ 136     # var table/ecx: (stream {(handle array byte), number} 24)  # 2 rows * 12 bytes/row
+ 137     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x18/imm32        # subtract from esp
+ 138     68/push  0x18/imm32/size
+ 139     68/push  0/imm32/read
+ 140     68/push  0/imm32/write
+ 141     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 142     # insert(table, "code", 12 bytes/row, Heap)
+ 143     # . . push args
+ 144     68/push  Heap/imm32
+ 145     68/push  0xc/imm32/row-size
+ 146     68/push  "code"/imm32
  147     51/push-ecx
  148     # . . call
- 149     e8/call  get-or-insert/disp32
+ 149     e8/call  get-or-insert/disp32
  150     # . . discard args
- 151     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 152 $test-get:check1:
- 153     # eax = get(table, "code", 8 bytes per row)
- 154     # . . push args
- 155     68/push  8/imm32/row-size
- 156     68/push  "code"/imm32
+ 151     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+ 152     # insert(table, "data", 12 bytes/row, Heap)
+ 153     # . . push args
+ 154     68/push  Heap/imm32
+ 155     68/push  0xc/imm32/row-size
+ 156     68/push  "data"/imm32
  157     51/push-ecx
  158     # . . call
- 159     e8/call  get/disp32
+ 159     e8/call  get-or-insert/disp32
  160     # . . discard args
- 161     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 162     # check-ints-equal(eax - table->data, 4, msg)
- 163     # . check-ints-equal(eax - table, 16, msg)
+ 161     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+ 162 $test-get:check1:
+ 163     # eax = get(table, "code", 12 bytes/row)
  164     # . . push args
- 165     68/push  "F - test-get/0"/imm32
- 166     68/push  0x10/imm32
- 167     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
- 168     50/push-eax
- 169     # . . call
- 170     e8/call  check-ints-equal/disp32
- 171     # . . discard args
- 172     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 173 $test-get:check2:
- 174     # eax = get(table, "data", 8 bytes per row)
- 175     # . . push args
- 176     68/push  8/imm32/row-size
- 177     68/push  "data"/imm32
- 178     51/push-ecx
+ 165     68/push  0xc/imm32/row-size
+ 166     68/push  "code"/imm32
+ 167     51/push-ecx
+ 168     # . . call
+ 169     e8/call  get/disp32
+ 170     # . . discard args
+ 171     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 172     # check-ints-equal(eax - table->data, 8, msg)
+ 173     # . check-ints-equal(eax - table, 20, msg)
+ 174     # . . push args
+ 175     68/push  "F - test-get/0"/imm32
+ 176     68/push  0x14/imm32
+ 177     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+ 178     50/push-eax
  179     # . . call
- 180     e8/call  get/disp32
+ 180     e8/call  check-ints-equal/disp32
  181     # . . discard args
  182     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 183     # check-ints-equal(eax - table->data, 12, msg)
- 184     # . check-ints-equal(eax - table, 24, msg)
+ 183 $test-get:check2:
+ 184     # eax = get(table, "data", 12 bytes/row)
  185     # . . push args
- 186     68/push  "F - test-get/1"/imm32
- 187     68/push  0x18/imm32
- 188     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
- 189     50/push-eax
- 190     # . . call
- 191     e8/call  check-ints-equal/disp32
- 192     # . . discard args
- 193     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 194 $test-get:end:
- 195     # . epilogue
- 196     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
- 197     5d/pop-to-ebp
- 198     c3/return
- 199 
- 200 # if no row is found, abort
- 201 get-slice:  # table: (addr stream {string_key, T}), key: (addr slice), row-size: int, abort-message-prefix: (addr array byte) -> eax: (addr T)
- 202     # pseudocode:
- 203     #   curr = table->data
- 204     #   max = &table->data[table->write]
- 205     #   while curr < max
- 206     #     if slice-equal?(key, *curr)
- 207     #       return curr+4
- 208     #     curr += row-size
- 209     #   abort
- 210     #
- 211     # . prologue
- 212     55/push-ebp
- 213     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 214     # . save registers
- 215     51/push-ecx
- 216     52/push-edx
- 217     56/push-esi
- 218     # esi = table
- 219     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
- 220     # var curr/ecx: (addr string_key) = table->data
- 221     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy esi+12 to ecx
- 222     # var max/edx: (addr byte) = &table->data[table->write]
- 223     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
- 224     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ecx  2/index/edx   .           2/r32/edx   .               .                 # copy ecx+edx to edx
- 225 $get-slice:search-loop:
- 226     # if (curr >= max) abort
- 227     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
- 228     73/jump-if-addr>=  $get-slice:abort/disp8
- 229     # if (slice-equal?(key, *curr)) return curr+4
- 230     # . eax = slice-equal?(key, *curr)
- 231     # . . push args
- 232     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
- 233     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
- 234     # . . call
- 235     e8/call  slice-equal?/disp32
- 236     # . . discard args
- 237     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 238     # . if (eax != false) return eax = curr+4
- 239     3d/compare-eax-and  0/imm32/false
- 240     74/jump-if-=  $get-slice:mismatch/disp8
- 241     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy ecx+4 to eax
- 242     eb/jump  $get-slice:end/disp8
- 243 $get-slice:mismatch:
- 244     # curr += row-size
- 245     03/add                          1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8      .                 # add *(ebp+16) to ecx
- 246     # loop
- 247     eb/jump  $get-slice:search-loop/disp8
- 248 $get-slice:end:
- 249     # . restore registers
- 250     5e/pop-to-esi
- 251     5a/pop-to-edx
- 252     59/pop-to-ecx
- 253     # . epilogue
- 254     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
- 255     5d/pop-to-ebp
- 256     c3/return
- 257 
- 258 $get-slice:abort:
- 259     # . _write(2/stderr, abort-message-prefix)
- 260     # . . push args
- 261     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
- 262     68/push  2/imm32/stderr
- 263     # . . call
- 264     e8/call  _write/disp32
- 265     # . . discard args
- 266     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 267     # . _write(2/stderr, error)
- 268     # . . push args
- 269     68/push  ": get-slice: key not found: "/imm32
- 270     68/push  2/imm32/stderr
- 271     # . . call
- 272     e8/call  _write/disp32
- 273     # . . discard args
- 274     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 275     # . write-slice-buffered(Stderr, key)
- 276     # . . push args
- 277     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
- 278     68/push  Stderr/imm32
- 279     # . . call
- 280     e8/call  write-slice-buffered/disp32
- 281     # . . discard args
- 282     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 283     # . flush(Stderr)
- 284     # . . push args
- 285     68/push  Stderr/imm32
- 286     # . . call
- 287     e8/call  flush/disp32
- 288     # . . discard args
- 289     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 290     # . _write(2/stderr, "\n")
- 291     # . . push args
- 292     68/push  Newline/imm32
- 293     68/push  2/imm32/stderr
- 294     # . . call
- 295     e8/call  _write/disp32
- 296     # . . discard args
- 297     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 298     # . syscall(exit, 1)
- 299     bb/copy-to-ebx  1/imm32
- 300     b8/copy-to-eax  1/imm32/exit
- 301     cd/syscall  0x80/imm8
- 302     # never gets here
- 303 
- 304 test-get-slice:
- 305     # . prologue
- 306     55/push-ebp
- 307     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 308     # - setup: create a table with a couple of keys
- 309     # var table/ecx: (stream {string, number} 16)  # 2 rows * 8 bytes/row
- 310     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # subtract from esp
- 311     68/push  0x10/imm32/length
- 312     68/push  0/imm32/read
- 313     68/push  0/imm32/write
- 314     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
- 315     # insert(table, "code", 8 bytes per row)
- 316     # . . push args
- 317     68/push  8/imm32/row-size
- 318     68/push  "code"/imm32
- 319     51/push-ecx
- 320     # . . call
- 321     e8/call  get-or-insert/disp32
- 322     # . . discard args
- 323     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 324     # insert(table, "data", 8 bytes per row)
- 325     # . . push args
- 326     68/push  8/imm32/row-size
- 327     68/push  "data"/imm32
- 328     51/push-ecx
- 329     # . . call
- 330     e8/call  get-or-insert/disp32
- 331     # . . discard args
- 332     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 333 $test-get-slice:check1:
- 334     # (eax..edx) = "code"
- 335     b8/copy-to-eax  "code"/imm32
- 336     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           2/r32/edx   .               .                 # copy *eax to edx
- 337     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  2/index/edx   .           2/r32/edx   4/disp8         .                 # copy eax+edx+4 to edx
- 338     05/add-to-eax  4/imm32
- 339     # var slice/edx: slice = {eax, edx}
- 340     52/push-edx
- 341     50/push-eax
- 342     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
- 343     # eax = get-slice(table, "code", 8 bytes per row)
- 344     # . . push args
- 345     68/push  8/imm32/row-size
- 346     52/push-edx
- 347     51/push-ecx
- 348     # . . call
- 349     e8/call  get-slice/disp32
- 350     # . . discard args
- 351     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 352     # check-ints-equal(eax - table->data, 4, msg)  # first row's value slot returned
- 353     # . check-ints-equal(eax - table, 16, msg)
- 354     # . . push args
- 355     68/push  "F - test-get-slice/0"/imm32
- 356     68/push  0x10/imm32
- 357     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
- 358     50/push-eax
- 359     # . . call
- 360     e8/call  check-ints-equal/disp32
- 361     # . . discard args
- 362     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 363 $test-get-slice:check2:
- 364     # (eax..edx) = "data"
- 365     b8/copy-to-eax  "data"/imm32
- 366     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           2/r32/edx   .               .                 # copy *eax to edx
- 367     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  2/index/edx   .           2/r32/edx   4/disp8         .                 # copy eax+edx+4 to edx
- 368     05/add-to-eax  4/imm32
- 369     # var slice/edx: slice = {eax, edx}
- 370     52/push-edx
- 371     50/push-eax
- 372     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
- 373     # eax = get-slice(table, "data" slice, 8 bytes per row)
- 374     # . . push args
- 375     68/push  8/imm32/row-size
- 376     52/push-edx
- 377     51/push-ecx
- 378     # . . call
- 379     e8/call  get-slice/disp32
- 380     # . . discard args
- 381     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 382     # check-ints-equal(eax - table->data, 12, msg)
- 383     # . check-ints-equal(eax - table, 24, msg)
- 384     # . . push args
- 385     68/push  "F - test-get-slice/1"/imm32
- 386     68/push  0x18/imm32
- 387     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
- 388     50/push-eax
- 389     # . . call
- 390     e8/call  check-ints-equal/disp32
- 391     # . . discard args
- 392     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 393 $test-get-slice:end:
- 394     # . epilogue
- 395     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
- 396     5d/pop-to-ebp
- 397     c3/return
- 398 
- 399 # if no row is found, save 'key' to the next available row
- 400 # if there are no rows free, abort
- 401 # return the address of the value
- 402 # Beware: assume keys are immutable; they're inserted by reference
- 403 # TODO: pass in an allocation descriptor
- 404 get-or-insert:  # table: (addr stream {string_key, T}), key: string_key, row-size: int -> eax: (addr T)
- 405     # pseudocode:
- 406     #   curr = table->data
- 407     #   max = &table->data[table->write]
- 408     #   while curr < max
- 409     #     if string-equal?(key, *curr)
- 410     #       return curr+4
- 411     #     curr += row-size
- 412     #   if table->write >= table->length
- 413     #     abort
- 414     #   zero-out(max, row-size)
- 415     #   *max = key
- 416     #   table->write += row-size
- 417     #   return max+4
- 418     #
- 419     # . prologue
- 420     55/push-ebp
- 421     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 422     # . save registers
- 423     51/push-ecx
- 424     52/push-edx
- 425     56/push-esi
- 426     # esi = table
- 427     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
- 428     # var curr/ecx: (addr string_key) = table->data
- 429     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy esi+12 to ecx
- 430     # var max/edx: (addr string_key) = &table->data[table->write]
- 431     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
- 432     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ecx  2/index/edx   .           2/r32/edx   .               .                 # copy ecx+edx to edx
- 433 $get-or-insert:search-loop:
- 434     # if (curr >= max) break
- 435     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
- 436     73/jump-if-addr>=  $get-or-insert:not-found/disp8
- 437     # if (string-equal?(key, *curr)) return curr+4
- 438     # . eax = string-equal?(key, *curr)
- 439     # . . push args
- 440     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
- 441     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
- 442     # . . call
- 443     e8/call  string-equal?/disp32
- 444     # . . discard args
- 445     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 446     # . if (eax != false) return eax = curr+4
- 447     3d/compare-eax-and  0/imm32/false
- 448     74/jump-if-=  $get-or-insert:mismatch/disp8
- 449     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy ecx+4 to eax
- 450     eb/jump  $get-or-insert:end/disp8
- 451 $get-or-insert:mismatch:
- 452     # curr += row-size
- 453     03/add                          1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8      .                 # add *(ebp+16) to ecx
- 454     # loop
- 455     eb/jump  $get-or-insert:search-loop/disp8
- 456 $get-or-insert:not-found:
- 457     # result/eax = 0
- 458     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
- 459     # if (table->write >= table->length) abort
- 460     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
- 461     3b/compare                      1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   8/disp8         .                 # compare ecx with *(esi+8)
- 462     73/jump-if-addr>=  $get-or-insert:abort/disp8
- 463     # zero-out(max, row-size)
- 464     # . . push args
- 465     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
- 466     52/push-edx
- 467     # . . call
- 468     e8/call  zero-out/disp32
- 469     # . . discard args
- 470     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 471     # *max = key
- 472     # . eax = key
- 473     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0xc/disp8       .                 # copy *(ebp+12) to eax
- 474     # . *max = eax
- 475     89/copy                         0/mod/indirect  2/rm32/edx    .           .             .           0/r32/eax   .               .                 # copy eax to *edx
- 476     # table->write += row-size
- 477     # . eax = row-size
- 478     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0x10/disp8      .                 # copy *(ebp+16) to eax
- 479     # . table->write += eax
- 480     01/add                          0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # add eax to *esi
- 481     # return max+4
- 482     # . eax = max
- 483     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           2/r32/edx   .               .                 # copy edx to eax
- 484     # . eax += 4
- 485     05/add-to-eax  4/imm32
- 486 $get-or-insert:end:
- 487     # . restore registers
- 488     5e/pop-to-esi
- 489     5a/pop-to-edx
- 490     59/pop-to-ecx
- 491     # . epilogue
- 492     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
- 493     5d/pop-to-ebp
- 494     c3/return
- 495 
- 496 $get-or-insert:abort:
- 497     # . _write(2/stderr, error)
+ 186     68/push  0xc/imm32/row-size
+ 187     68/push  "data"/imm32
+ 188     51/push-ecx
+ 189     # . . call
+ 190     e8/call  get/disp32
+ 191     # . . discard args
+ 192     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 193     # check-ints-equal(eax - table->data, 20, msg)
+ 194     # . check-ints-equal(eax - table, 32, msg)
+ 195     # . . push args
+ 196     68/push  "F - test-get/1"/imm32
+ 197     68/push  0x20/imm32
+ 198     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+ 199     50/push-eax
+ 200     # . . call
+ 201     e8/call  check-ints-equal/disp32
+ 202     # . . discard args
+ 203     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 204 $test-get:end:
+ 205     # . epilogue
+ 206     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 207     5d/pop-to-ebp
+ 208     c3/return
+ 209 
+ 210 # if no row is found, abort
+ 211 get-slice:  # table: (addr stream {(handle array byte), T}), key: (addr slice), row-size: int, abort-message-prefix: (addr array byte) -> eax: (addr T)
+ 212     # pseudocode:
+ 213     #   curr = table->data
+ 214     #   max = &table->data[table->write]
+ 215     #   while curr < max
+ 216     #     var c: (addr array byte) = lookup(*curr)
+ 217     #     if slice-equal?(key, c)
+ 218     #       return curr+8
+ 219     #     curr += row-size
+ 220     #   abort
+ 221     #
+ 222     # . prologue
+ 223     55/push-ebp
+ 224     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 225     # . save registers
+ 226     51/push-ecx
+ 227     52/push-edx
+ 228     56/push-esi
+ 229     # esi = table
+ 230     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+ 231     # var curr/ecx: (addr handle array byte) = table->data
+ 232     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy esi+12 to ecx
+ 233     # var max/edx: (addr byte) = &table->data[table->write]
+ 234     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
+ 235     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ecx  2/index/edx   .           2/r32/edx   .               .                 # copy ecx+edx to edx
+ 236 $get-slice:search-loop:
+ 237     # if (curr >= max) abort
+ 238     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
+ 239     73/jump-if-addr>=  $get-slice:abort/disp8
+ 240     # var c/eax: (addr array byte) = lookup(*curr)
+ 241     # . . push args
+ 242     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+ 243     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+ 244     # . . call
+ 245     e8/call  lookup/disp32
+ 246     # . . discard args
+ 247     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 248     # if (slice-equal?(key, c)) return curr+8
+ 249     # . eax = slice-equal?(key, c)
+ 250     # . . push args
+ 251     50/push-eax
+ 252     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+ 253     # . . call
+ 254     e8/call  slice-equal?/disp32
+ 255     # . . discard args
+ 256     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 257     # . if (eax != false) return eax = curr+8
+ 258     3d/compare-eax-and  0/imm32/false
+ 259     74/jump-if-=  $get-slice:mismatch/disp8
+ 260     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   8/disp8         .                 # copy ecx+8 to eax
+ 261     eb/jump  $get-slice:end/disp8
+ 262 $get-slice:mismatch:
+ 263     # curr += row-size
+ 264     03/add                          1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8      .                 # add *(ebp+16) to ecx
+ 265     # loop
+ 266     eb/jump  $get-slice:search-loop/disp8
+ 267 $get-slice:end:
+ 268     # . restore registers
+ 269     5e/pop-to-esi
+ 270     5a/pop-to-edx
+ 271     59/pop-to-ecx
+ 272     # . epilogue
+ 273     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 274     5d/pop-to-ebp
+ 275     c3/return
+ 276 
+ 277 $get-slice:abort:
+ 278     # . _write(2/stderr, abort-message-prefix)
+ 279     # . . push args
+ 280     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
+ 281     68/push  2/imm32/stderr
+ 282     # . . call
+ 283     e8/call  _write/disp32
+ 284     # . . discard args
+ 285     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 286     # . _write(2/stderr, error)
+ 287     # . . push args
+ 288     68/push  ": get-slice: key not found: "/imm32
+ 289     68/push  2/imm32/stderr
+ 290     # . . call
+ 291     e8/call  _write/disp32
+ 292     # . . discard args
+ 293     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 294     # . write-slice-buffered(Stderr, key)
+ 295     # . . push args
+ 296     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+ 297     68/push  Stderr/imm32
+ 298     # . . call
+ 299     e8/call  write-slice-buffered/disp32
+ 300     # . . discard args
+ 301     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 302     # . flush(Stderr)
+ 303     # . . push args
+ 304     68/push  Stderr/imm32
+ 305     # . . call
+ 306     e8/call  flush/disp32
+ 307     # . . discard args
+ 308     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 309     # . _write(2/stderr, "\n")
+ 310     # . . push args
+ 311     68/push  Newline/imm32
+ 312     68/push  2/imm32/stderr
+ 313     # . . call
+ 314     e8/call  _write/disp32
+ 315     # . . discard args
+ 316     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 317     # . syscall(exit, 1)
+ 318     bb/copy-to-ebx  1/imm32
+ 319     b8/copy-to-eax  1/imm32/exit
+ 320     cd/syscall  0x80/imm8
+ 321     # never gets here
+ 322 
+ 323 test-get-slice:
+ 324     # . prologue
+ 325     55/push-ebp
+ 326     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 327     # - setup: create a table with a couple of keys
+ 328     # var table/ecx: (stream {string, number} 24)  # 2 rows * 12 bytes/row
+ 329     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x18/imm32        # subtract from esp
+ 330     68/push  0x18/imm32/size
+ 331     68/push  0/imm32/read
+ 332     68/push  0/imm32/write
+ 333     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 334     # insert(table, "code", 12 bytes/row, Heap)
+ 335     # . . push args
+ 336     68/push  Heap/imm32
+ 337     68/push  0xc/imm32/row-size
+ 338     68/push  "code"/imm32
+ 339     51/push-ecx
+ 340     # . . call
+ 341     e8/call  get-or-insert/disp32
+ 342     # . . discard args
+ 343     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+ 344     # insert(table, "data", 12 bytes/row, Heap)
+ 345     # . . push args
+ 346     68/push  Heap/imm32
+ 347     68/push  0xc/imm32/row-size
+ 348     68/push  "data"/imm32
+ 349     51/push-ecx
+ 350     # . . call
+ 351     e8/call  get-or-insert/disp32
+ 352     # . . discard args
+ 353     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+ 354 $test-get-slice:check1:
+ 355     # (eax..edx) = "code"
+ 356     b8/copy-to-eax  "code"/imm32
+ 357     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           2/r32/edx   .               .                 # copy *eax to edx
+ 358     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  2/index/edx   .           2/r32/edx   4/disp8         .                 # copy eax+edx+4 to edx
+ 359     05/add-to-eax  4/imm32
+ 360     # var slice/edx: slice = {eax, edx}
+ 361     52/push-edx
+ 362     50/push-eax
+ 363     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
+ 364     # eax = get-slice(table, "code", 12 bytes/row)
+ 365     # . . push args
+ 366     68/push  0xc/imm32/row-size
+ 367     52/push-edx
+ 368     51/push-ecx
+ 369     # . . call
+ 370     e8/call  get-slice/disp32
+ 371     # . . discard args
+ 372     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 373     # check-ints-equal(eax - table->data, 8, msg)  # first row's value slot returned
+ 374     # . check-ints-equal(eax - table, 20, msg)
+ 375     # . . push args
+ 376     68/push  "F - test-get-slice/0"/imm32
+ 377     68/push  0x14/imm32
+ 378     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+ 379     50/push-eax
+ 380     # . . call
+ 381     e8/call  check-ints-equal/disp32
+ 382     # . . discard args
+ 383     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 384 $test-get-slice:check2:
+ 385     # (eax..edx) = "data"
+ 386     b8/copy-to-eax  "data"/imm32
+ 387     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           2/r32/edx   .               .                 # copy *eax to edx
+ 388     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  2/index/edx   .           2/r32/edx   4/disp8         .                 # copy eax+edx+4 to edx
+ 389     05/add-to-eax  4/imm32
+ 390     # var slice/edx: slice = {eax, edx}
+ 391     52/push-edx
+ 392     50/push-eax
+ 393     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
+ 394     # eax = get-slice(table, "data" slice, 12 bytes/row)
+ 395     # . . push args
+ 396     68/push  0xc/imm32/row-size
+ 397     52/push-edx
+ 398     51/push-ecx
+ 399     # . . call
+ 400     e8/call  get-slice/disp32
+ 401     # . . discard args
+ 402     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 403     # check-ints-equal(eax - table->data, 20, msg)
+ 404     # . check-ints-equal(eax - table, 32, msg)
+ 405     # . . push args
+ 406     68/push  "F - test-get-slice/1"/imm32
+ 407     68/push  0x20/imm32
+ 408     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+ 409     50/push-eax
+ 410     # . . call
+ 411     e8/call  check-ints-equal/disp32
+ 412     # . . discard args
+ 413     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 414 $test-get-slice:end:
+ 415     # . epilogue
+ 416     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 417     5d/pop-to-ebp
+ 418     c3/return
+ 419 
+ 420 # if no row is found, save 'key' to the next available row
+ 421 # if there are no rows free, abort
+ 422 # return the address of the value
+ 423 get-or-insert:  # table: (addr stream {(handle array byte), T}), key: (addr array byte), row-size: int, ad: (addr allocation-descriptor) -> eax: (addr T)
+ 424     # pseudocode:
+ 425     #   curr = table->data
+ 426     #   max = &table->data[table->write]
+ 427     #   while curr < max
+ 428     #     var c: (addr array byte) = lookup(*curr)
+ 429     #     if string-equal?(key, c)
+ 430     #       return curr+8
+ 431     #     curr += row-size
+ 432     #   if table->write >= table->size
+ 433     #     abort
+ 434     #   zero-out(max, row-size)
+ 435     #   copy-array(ad, key, max)
+ 436     #   table->write += row-size
+ 437     #   return max+8
+ 438     #
+ 439     # . prologue
+ 440     55/push-ebp
+ 441     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 442     # . save registers
+ 443     51/push-ecx
+ 444     52/push-edx
+ 445     56/push-esi
+ 446     # esi = table
+ 447     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+ 448     # var curr/ecx: (addr handle array byte) = table->data
+ 449     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy esi+12 to ecx
+ 450     # var max/edx: (addr byte) = &table->data[table->write]
+ 451     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
+ 452     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ecx  2/index/edx   .           2/r32/edx   .               .                 # copy ecx+edx to edx
+ 453 $get-or-insert:search-loop:
+ 454     # if (curr >= max) break
+ 455     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
+ 456     73/jump-if-addr>=  $get-or-insert:not-found/disp8
+ 457     # var c/eax: (addr array byte) = lookup(*curr)
+ 458     # . . push args
+ 459     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+ 460     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+ 461     # . . call
+ 462     e8/call  lookup/disp32
+ 463     # . . discard args
+ 464     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 465     # if (string-equal?(key, c)) return curr+8
+ 466     # . eax = string-equal?(key, c)
+ 467     # . . push args
+ 468     50/push-eax
+ 469     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+ 470     # . . call
+ 471     e8/call  string-equal?/disp32
+ 472     # . . discard args
+ 473     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 474     # . if (eax != false) return eax = curr+8
+ 475     3d/compare-eax-and  0/imm32/false
+ 476     74/jump-if-=  $get-or-insert:mismatch/disp8
+ 477     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   8/disp8         .                 # copy ecx+8 to eax
+ 478     eb/jump  $get-or-insert:end/disp8
+ 479 $get-or-insert:mismatch:
+ 480     # curr += row-size
+ 481     03/add                          1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8      .                 # add *(ebp+16) to ecx
+ 482     # loop
+ 483     eb/jump  $get-or-insert:search-loop/disp8
+ 484 $get-or-insert:not-found:
+ 485     # if (table->write >= table->size) abort
+ 486     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
+ 487     3b/compare                      1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   8/disp8         .                 # compare ecx with *(esi+8)
+ 488     73/jump-if-addr>=  $get-or-insert:abort/disp8
+ 489     # zero-out(max, row-size)
+ 490     # . . push args
+ 491     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+ 492     52/push-edx
+ 493     # . . call
+ 494     e8/call  zero-out/disp32
+ 495     # . . discard args
+ 496     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 497     # copy-array(ad, key, max)
  498     # . . push args
- 499     68/push  "get-or-insert: table is full\n"/imm32
- 500     68/push  2/imm32/stderr
- 501     # . . call
- 502     e8/call  _write/disp32
- 503     # . . discard args
- 504     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 505     # . syscall(exit, 1)
- 506     bb/copy-to-ebx  1/imm32
- 507     b8/copy-to-eax  1/imm32/exit
- 508     cd/syscall  0x80/imm8
- 509     # never gets here
- 510 
- 511 test-get-or-insert:
- 512     # . prologue
- 513     55/push-ebp
- 514     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 515     # var table/ecx: (stream {string, number} 16)  # 2 rows * 8 bytes/row
- 516     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # subtract from esp
- 517     68/push  0x10/imm32/length
- 518     68/push  0/imm32/read
- 519     68/push  0/imm32/write
- 520     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
- 521 $test-get-or-insert:first-call:
- 522     # - start with an empty table, insert one key, verify that it was inserted
- 523     # eax = get-or-insert(table, "code", 8 bytes per row)
- 524     # . . push args
- 525     68/push  8/imm32/row-size
- 526     68/push  "code"/imm32
- 527     51/push-ecx
- 528     # . . call
- 529     e8/call  get-or-insert/disp32
- 530     # . . discard args
- 531     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 532     # check-ints-equal(eax - table->data, 4, msg)  # first row's value slot returned
- 533     # . check-ints-equal(eax - table, 16, msg)
- 534     # . . push args
- 535     68/push  "F - test-get-or-insert/0"/imm32
- 536     68/push  0x10/imm32
- 537     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
- 538     50/push-eax
- 539     # . . call
- 540     e8/call  check-ints-equal/disp32
- 541     # . . discard args
- 542     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 543 $test-get-or-insert:check2:
- 544     # check-ints-equal(table->write, row-size = 8, msg)
- 545     # . . push args
- 546     68/push  "F - test-get-or-insert/1"/imm32
- 547     68/push  8/imm32/row-size
- 548     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
- 549     # . . call
- 550     e8/call  check-ints-equal/disp32
- 551     # . . discard args
- 552     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 553     # check-strings-equal(*table->data, "code", msg)
+ 499     52/push-edx
+ 500     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+ 501     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
+ 502     # . . call
+ 503     e8/call  copy-array/disp32
+ 504     # . . discard args
+ 505     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 506     # table->write += row-size
+ 507     # . eax = row-size
+ 508     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0x10/disp8      .                 # copy *(ebp+16) to eax
+ 509     # . table->write += eax
+ 510     01/add                          0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # add eax to *esi
+ 511     # return max+8
+ 512     # . eax = max
+ 513     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           2/r32/edx   .               .                 # copy edx to eax
+ 514     # . eax += 8
+ 515     05/add-to-eax  8/imm32
+ 516 $get-or-insert:end:
+ 517     # . restore registers
+ 518     5e/pop-to-esi
+ 519     5a/pop-to-edx
+ 520     59/pop-to-ecx
+ 521     # . epilogue
+ 522     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 523     5d/pop-to-ebp
+ 524     c3/return
+ 525 
+ 526 $get-or-insert:abort:
+ 527     # . _write(2/stderr, error)
+ 528     # . . push args
+ 529     68/push  "get-or-insert: table is full\n"/imm32
+ 530     68/push  2/imm32/stderr
+ 531     # . . call
+ 532     e8/call  _write/disp32
+ 533     # . . discard args
+ 534     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 535     # . syscall(exit, 1)
+ 536     bb/copy-to-ebx  1/imm32
+ 537     b8/copy-to-eax  1/imm32/exit
+ 538     cd/syscall  0x80/imm8
+ 539     # never gets here
+ 540 
+ 541 test-get-or-insert:
+ 542     # . prologue
+ 543     55/push-ebp
+ 544     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 545     # var table/ecx: (stream {(handle array byte), number} 24)  # 2 rows * 12 bytes/row
+ 546     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x18/imm32        # subtract from esp
+ 547     68/push  0x18/imm32/size
+ 548     68/push  0/imm32/read
+ 549     68/push  0/imm32/write
+ 550     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 551 $test-get-or-insert:first-call:
+ 552     # - start with an empty table, insert one key, verify that it was inserted
+ 553     # eax = get-or-insert(table, "code", 12 bytes/row, Heap)
  554     # . . push args
- 555     68/push  "F - test-get-or-insert/2"/imm32
- 556     68/push  "code"/imm32
- 557     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0xc/disp8       .                 # push *(ecx+12)
- 558     # . . call
- 559     e8/call  check-strings-equal/disp32
- 560     # . . discard args
- 561     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 562 $test-get-or-insert:second-call:
- 563     # - insert the same key again, verify that it was reused
- 564     # eax = get-or-insert(table, "code", 8 bytes per row)
+ 555     68/push  Heap/imm32
+ 556     68/push  0xc/imm32/row-size
+ 557     68/push  "code"/imm32
+ 558     51/push-ecx
+ 559     # . . call
+ 560     e8/call  get-or-insert/disp32
+ 561     # . . discard args
+ 562     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+ 563     # check-ints-equal(eax - table->data, 8, msg)  # first row's value slot returned
+ 564     # . check-ints-equal(eax - table, 20, msg)
  565     # . . push args
- 566     68/push  8/imm32/row-size
- 567     68/push  "code"/imm32
- 568     51/push-ecx
- 569     # . . call
- 570     e8/call  get-or-insert/disp32
- 571     # . . discard args
- 572     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 573     # check-ints-equal(eax - table->data, 4, msg)
- 574     # . check-ints-equal(eax - table, 16, msg)
+ 566     68/push  "F - test-get-or-insert/0"/imm32
+ 567     68/push  0x14/imm32
+ 568     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+ 569     50/push-eax
+ 570     # . . call
+ 571     e8/call  check-ints-equal/disp32
+ 572     # . . discard args
+ 573     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 574     # check-ints-equal(table->write, row-size = 12, msg)
  575     # . . push args
- 576     68/push  "F - test-get-or-insert/3"/imm32
- 577     68/push  0x10/imm32
- 578     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
- 579     50/push-eax
- 580     # . . call
- 581     e8/call  check-ints-equal/disp32
- 582     # . . discard args
- 583     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 584     # no new row inserted
- 585     # . check-ints-equal(table->write, row-size = 8, msg)
- 586     # . . push args
- 587     68/push  "F - test-get-or-insert/4"/imm32
- 588     68/push  8/imm32/row-size
- 589     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
- 590     # . . call
- 591     e8/call  check-ints-equal/disp32
- 592     # . . discard args
- 593     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 594     # check-strings-equal(*table->data, "code", msg)
- 595     # . . push args
- 596     68/push  "F - test-get-or-insert/5"/imm32
- 597     68/push  "code"/imm32
- 598     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0xc/disp8       .                 # push *(ecx+12)
- 599     # . . call
- 600     e8/call  check-strings-equal/disp32
- 601     # . . discard args
- 602     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 603 $test-get-or-insert:third-call:
- 604     # - insert a new key, verify that it was inserted
- 605     # eax = get-or-insert(table, "data", 8 bytes per row)
- 606     # . . push args
- 607     68/push  8/imm32/row-size
- 608     68/push  "data"/imm32
- 609     51/push-ecx
- 610     # . . call
- 611     e8/call  get-or-insert/disp32
- 612     # . . discard args
- 613     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 614     # table gets a new row
- 615     # check-ints-equal(eax - table->data, 12, msg)  # second row's value slot returned
- 616     # . check-ints-equal(eax - table, 24, msg)
- 617     # . . push args
- 618     68/push  "F - test-get-or-insert/6"/imm32
- 619     68/push  0x18/imm32
- 620     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
- 621     50/push-eax
- 622     # . . call
- 623     e8/call  check-ints-equal/disp32
- 624     # . . discard args
- 625     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 626     # check-ints-equal(table->write, 2 rows = 16, msg)
- 627     # . . push args
- 628     68/push  "F - test-get-or-insert/7"/imm32
- 629     68/push  0x10/imm32/two-rows
- 630     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
- 631     # . . call
- 632     e8/call  check-ints-equal/disp32
- 633     # . . discard args
- 634     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 635     # check-strings-equal(*table->data+8, "data", msg)
- 636     # check-strings-equal(*(table+20), "data", msg)
- 637     # . . push args
- 638     68/push  "F - test-get-or-insert/8"/imm32
- 639     68/push  "data"/imm32
- 640     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0x14/disp8      .                 # push *(ecx+20)
- 641     # . . call
- 642     e8/call  check-strings-equal/disp32
- 643     # . . discard args
- 644     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 645 $test-get-or-insert:end:
- 646     # . epilogue
- 647     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
- 648     5d/pop-to-ebp
- 649     c3/return
- 650 
- 651 # if no row is found, save 'key' in the next available row
- 652 # if there are no rows free, abort
- 653 # WARNING: leaks memory
- 654 # TODO: pass in an allocation descriptor
- 655 leaky-get-or-insert-slice:  # table: (addr stream {string_key, T}), key: (addr slice), row-size: int -> eax: (addr T)
- 656     # pseudocode:
- 657     #   curr = table->data
- 658     #   max = &table->data[table->write]
- 659     #   while curr < max
- 660     #     if slice-equal?(key, *curr)
- 661     #       return curr+4
- 662     #     curr += row-size
- 663     #   if table->write >= table->length
- 664     #     abort
- 665     #   zero-out(max, row-size)
- 666     #   *max = slice-to-string(Heap, key)
- 667     #   table->write += row-size
- 668     #   return max+4
- 669     #
- 670     # . prologue
- 671     55/push-ebp
- 672     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 673     # . save registers
- 674     51/push-ecx
- 675     52/push-edx
- 676     56/push-esi
- 677     # esi = table
- 678     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
- 679     # var curr/ecx: (addr string_key) = table->data
- 680     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy esi+12 to ecx
- 681     # var max/edx: (addr string_key) = &table->data[table->write]
- 682     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
- 683     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ecx  2/index/edx   .           2/r32/edx   .               .                 # copy ecx+edx to edx
- 684 $leaky-get-or-insert-slice:search-loop:
- 685     # if (curr >= max) break
- 686     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
- 687     73/jump-if-addr>=  $leaky-get-or-insert-slice:not-found/disp8
- 688     # if (slice-equal?(key, *curr)) return curr+4
- 689     # . eax = slice-equal?(key, *curr)
- 690     # . . push args
- 691     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
- 692     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
- 693     # . . call
- 694     e8/call  slice-equal?/disp32
- 695     # . . discard args
- 696     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 697     # . if (eax != false) return eax = curr+4
- 698     3d/compare-eax-and  0/imm32/false
- 699     74/jump-if-=  $leaky-get-or-insert-slice:mismatch/disp8
- 700     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy ecx+4 to eax
- 701     eb/jump  $leaky-get-or-insert-slice:end/disp8
- 702 $leaky-get-or-insert-slice:mismatch:
- 703     # curr += row-size
- 704     03/add                          1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8      .                 # add *(ebp+16) to ecx
- 705     # loop
- 706     eb/jump  $leaky-get-or-insert-slice:search-loop/disp8
- 707 $leaky-get-or-insert-slice:not-found:
- 708     # result/eax = 0
- 709     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
- 710     # if (table->write >= table->length) abort
- 711     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
- 712     3b/compare                      1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   8/disp8         .                 # compare ecx with *(esi+8)
- 713     7d/jump-if->=  $leaky-get-or-insert-slice:abort/disp8
- 714     # zero-out(max, row-size)
- 715     # . . push args
- 716     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
- 717     52/push-edx
- 718     # . . call
- 719     e8/call  zero-out/disp32
- 720     # . . discard args
- 721     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 722     # *max = slice-to-string(Heap, key)
- 723     # . eax = slice-to-string(Heap, key)
- 724     # . . push args
- 725     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
- 726     68/push  Heap/imm32
- 727     # . . call
- 728     e8/call  slice-to-string/disp32
- 729     # . . discard args
- 730     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 731     # . *max = eax
- 732     89/copy                         0/mod/indirect  2/rm32/edx    .           .             .           0/r32/eax   .               .                 # copy eax to *edx
- 733     # table->write += row-size
- 734     # . eax = row-size
- 735     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0x10/disp8      .                 # copy *(ebp+16) to eax
- 736     # . table->write += eax
- 737     01/add                          0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # add eax to *esi
- 738     # return max+4
- 739     # . eax = max
- 740     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           2/r32/edx   .               .                 # copy edx to eax
- 741     # . eax += 4
- 742     05/add-to-eax  4/imm32
- 743 $leaky-get-or-insert-slice:end:
- 744     # . restore registers
- 745     5e/pop-to-esi
- 746     5a/pop-to-edx
- 747     59/pop-to-ecx
- 748     # . epilogue
- 749     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
- 750     5d/pop-to-ebp
- 751     c3/return
- 752 
- 753 $leaky-get-or-insert-slice:abort:
- 754     # . _write(2/stderr, error)
- 755     # . . push args
- 756     68/push  "leaky-get-or-insert-slice: table is full\n"/imm32
- 757     68/push  2/imm32/stderr
- 758     # . . call
- 759     e8/call  _write/disp32
- 760     # . . discard args
- 761     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 762     # . syscall(exit, 1)
- 763     bb/copy-to-ebx  1/imm32
- 764     b8/copy-to-eax  1/imm32/exit
- 765     cd/syscall  0x80/imm8
- 766     # never gets here
- 767 
- 768 test-leaky-get-or-insert-slice:
- 769     # . prologue
- 770     55/push-ebp
- 771     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 772     # var table/ecx: (stream {string, number} 16)  # 2 rows * 8 bytes/row
- 773     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # subtract from esp
- 774     68/push  0x10/imm32/length
- 775     68/push  0/imm32/read
- 776     68/push  0/imm32/write
- 777     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
- 778     # (eax..edx) = "code"
- 779     b8/copy-to-eax  "code"/imm32
- 780     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           2/r32/edx   .               .                 # copy *eax to edx
- 781     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  2/index/edx   .           2/r32/edx   4/disp8         .                 # copy eax+edx+4 to edx
- 782     05/add-to-eax  4/imm32
- 783     # var slice/edx: slice = {eax, edx}
- 784     52/push-edx
- 785     50/push-eax
- 786     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
- 787 $test-leaky-get-or-insert-slice:first-call:
- 788     # - start with an empty table, insert one key, verify that it was inserted
- 789     # eax = leaky-get-or-insert-slice(table, "code" slice, 8 bytes per row)
- 790     # . . push args
- 791     68/push  8/imm32/row-size
- 792     52/push-edx
- 793     51/push-ecx
- 794     # . . call
- 795     e8/call  leaky-get-or-insert-slice/disp32
- 796     # . . discard args
- 797     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 798     # check-ints-equal(eax - table->data, 4, msg)  # first row's value slot returned
- 799     # . check-ints-equal(eax - table, 16, msg)
- 800     # . . push args
- 801     68/push  "F - test-leaky-get-or-insert-slice/0"/imm32
- 802     68/push  0x10/imm32
- 803     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
- 804     50/push-eax
- 805     # . . call
- 806     e8/call  check-ints-equal/disp32
- 807     # . . discard args
- 808     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 809 $test-leaky-get-or-insert-slice:check2:
- 810     # check-ints-equal(table->write, row-size = 8, msg)
- 811     # . . push args
- 812     68/push  "F - test-leaky-get-or-insert-slice/1"/imm32
- 813     68/push  8/imm32/row-size
- 814     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
- 815     # . . call
- 816     e8/call  check-ints-equal/disp32
- 817     # . . discard args
- 818     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 819     # check-strings-equal(*table->data, "code", msg)
- 820     # . . push args
- 821     68/push  "F - test-leaky-get-or-insert-slice/2"/imm32
- 822     68/push  "code"/imm32
- 823     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0xc/disp8       .                 # push *(ecx+12)
- 824     # . . call
- 825     e8/call  check-strings-equal/disp32
- 826     # . . discard args
- 827     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 828 $test-leaky-get-or-insert-slice:second-call:
- 829     # - insert the same key again, verify that it was reused
- 830     # eax = leaky-get-or-insert-slice(table, "code" slice, 8 bytes per row)
- 831     # . . push args
- 832     68/push  8/imm32/row-size
- 833     52/push-edx
- 834     51/push-ecx
- 835     # . . call
- 836     e8/call  leaky-get-or-insert-slice/disp32
- 837     # . . discard args
- 838     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 839     # check-ints-equal(eax - table->data, 4, msg)
- 840     # . check-ints-equal(eax - table, 16, msg)
- 841     # . . push args
- 842     68/push  "F - test-leaky-get-or-insert-slice/3"/imm32
- 843     68/push  0x10/imm32
- 844     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
- 845     50/push-eax
- 846     # . . call
- 847     e8/call  check-ints-equal/disp32
- 848     # . . discard args
- 849     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 850     # no new row inserted
- 851     # . check-ints-equal(table->write, row-size = 8, msg)
- 852     # . . push args
- 853     68/push  "F - test-leaky-get-or-insert-slice/4"/imm32
- 854     68/push  8/imm32/row-size
- 855     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
- 856     # . . call
- 857     e8/call  check-ints-equal/disp32
- 858     # . . discard args
- 859     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 860     # check-strings-equal(*table->data, "code", msg)
- 861     # . . push args
- 862     68/push  "F - test-leaky-get-or-insert-slice/5"/imm32
- 863     68/push  "code"/imm32
- 864     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0xc/disp8       .                 # push *(ecx+12)
- 865     # . . call
- 866     e8/call  check-strings-equal/disp32
- 867     # . . discard args
- 868     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 869 $test-leaky-get-or-insert-slice:third-call:
- 870     # - insert a new key, verify that it was inserted
- 871     # (eax..edx) = "data"
- 872     b8/copy-to-eax  "data"/imm32
- 873     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           2/r32/edx   .               .                 # copy *eax to edx
- 874     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  2/index/edx   .           2/r32/edx   4/disp8         .                 # copy eax+edx+4 to edx
- 875     05/add-to-eax  4/imm32
- 876     # var slice/edx: slice = {eax, edx}
- 877     52/push-edx
- 878     50/push-eax
- 879     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
- 880     # eax = leaky-get-or-insert-slice(table, "data" slice, 8 bytes per row)
- 881     # . . push args
- 882     68/push  8/imm32/row-size
- 883     52/push-edx
- 884     51/push-ecx
- 885     # . . call
- 886     e8/call  leaky-get-or-insert-slice/disp32
- 887     # . . discard args
- 888     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 889     # table gets a new row
- 890     # check-ints-equal(eax - table->data, 12, msg)  # second row's value slot returned
- 891     # . check-ints-equal(eax - table, 24, msg)
+ 576     68/push  "F - test-get-or-insert/1"/imm32
+ 577     68/push  0xc/imm32/row-size
+ 578     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+ 579     # . . call
+ 580     e8/call  check-ints-equal/disp32
+ 581     # . . discard args
+ 582     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 583     # var curr-addr/eax: (addr array byte) = lookup(table->data)
+ 584     # . . push args
+ 585     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0x10/disp8      .                 # push *(ecx+16)
+ 586     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0xc/disp8       .                 # push *(ecx+12)
+ 587     # . . call
+ 588     e8/call  lookup/disp32
+ 589     # . . discard args
+ 590     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 591     # check-strings-equal(curr-addr, "code", msg)
+ 592     # . . push args
+ 593     68/push  "F - test-get-or-insert/2"/imm32
+ 594     68/push  "code"/imm32
+ 595     50/push-eax
+ 596     # . . call
+ 597     e8/call  check-strings-equal/disp32
+ 598     # . . discard args
+ 599     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 600 $test-get-or-insert:second-call:
+ 601     # - insert the same key again, verify that it was reused
+ 602     # eax = get-or-insert(table, "code", 12 bytes/row, Heap)
+ 603     # . . push args
+ 604     68/push  Heap/imm32
+ 605     68/push  0xc/imm32/row-size
+ 606     68/push  "code"/imm32
+ 607     51/push-ecx
+ 608     # . . call
+ 609     e8/call  get-or-insert/disp32
+ 610     # . . discard args
+ 611     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+ 612     # check-ints-equal(eax - table->data, 8, msg)
+ 613     # . check-ints-equal(eax - table, 20, msg)
+ 614     # . . push args
+ 615     68/push  "F - test-get-or-insert/3"/imm32
+ 616     68/push  0x14/imm32
+ 617     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+ 618     50/push-eax
+ 619     # . . call
+ 620     e8/call  check-ints-equal/disp32
+ 621     # . . discard args
+ 622     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 623     # no new row inserted
+ 624     # . check-ints-equal(table->write, row-size = 12, msg)
+ 625     # . . push args
+ 626     68/push  "F - test-get-or-insert/4"/imm32
+ 627     68/push  0xc/imm32/row-size
+ 628     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+ 629     # . . call
+ 630     e8/call  check-ints-equal/disp32
+ 631     # . . discard args
+ 632     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 633     # curr-addr = lookup(table->data)
+ 634     # . . push args
+ 635     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0x10/disp8      .                 # push *(ecx+16)
+ 636     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0xc/disp8       .                 # push *(ecx+12)
+ 637     # . . call
+ 638     e8/call  lookup/disp32
+ 639     # . . discard args
+ 640     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 641     # check-strings-equal(curr-addr, "code", msg)
+ 642     # . . push args
+ 643     68/push  "F - test-get-or-insert/5"/imm32
+ 644     68/push  "code"/imm32
+ 645     50/push-eax
+ 646     # . . call
+ 647     e8/call  check-strings-equal/disp32
+ 648     # . . discard args
+ 649     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 650 $test-get-or-insert:third-call:
+ 651     # - insert a new key, verify that it was inserted
+ 652     # eax = get-or-insert(table, "data", 12 bytes/row, Heap)
+ 653     # . . push args
+ 654     68/push  Heap/imm32
+ 655     68/push  0xc/imm32/row-size
+ 656     68/push  "data"/imm32
+ 657     51/push-ecx
+ 658     # . . call
+ 659     e8/call  get-or-insert/disp32
+ 660     # . . discard args
+ 661     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+ 662     # table gets a new row
+ 663     # check-ints-equal(eax - table->data, 20, msg)  # second row's value slot returned
+ 664     # . check-ints-equal(eax - table, 32, msg)
+ 665     # . . push args
+ 666     68/push  "F - test-get-or-insert/6"/imm32
+ 667     68/push  0x20/imm32
+ 668     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+ 669     50/push-eax
+ 670     # . . call
+ 671     e8/call  check-ints-equal/disp32
+ 672     # . . discard args
+ 673     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 674     # check-ints-equal(table->write, 2 rows = 24, msg)
+ 675     # . . push args
+ 676     68/push  "F - test-get-or-insert/7"/imm32
+ 677     68/push  0x18/imm32/two-rows
+ 678     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+ 679     # . . call
+ 680     e8/call  check-ints-equal/disp32
+ 681     # . . discard args
+ 682     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 683     # curr-addr = lookup(table->data+12)
+ 684     # . . push args
+ 685     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0x1c/disp8      .                 # push *(ecx+28)
+ 686     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0x18/disp8      .                 # push *(ecx+24)
+ 687     # . . call
+ 688     e8/call  lookup/disp32
+ 689     # . . discard args
+ 690     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 691     # check-strings-equal(curr-addr, "data", msg)
+ 692     # . . push args
+ 693     68/push  "F - test-get-or-insert/8"/imm32
+ 694     68/push  "data"/imm32
+ 695     50/push-eax
+ 696     # . . call
+ 697     e8/call  check-strings-equal/disp32
+ 698     # . . discard args
+ 699     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 700 $test-get-or-insert:end:
+ 701     # . epilogue
+ 702     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 703     5d/pop-to-ebp
+ 704     c3/return
+ 705 
+ 706 # if no row is found, save 'key' to the next available row
+ 707 # if there are no rows free, abort
+ 708 # return the address of the value
+ 709 get-or-insert-handle:  # table: (addr stream {(handle array byte), T}), key: (handle array byte), row-size: int -> eax: (addr T)
+ 710     # pseudocode:
+ 711     #   var curr: (addr handle stream) = table->data
+ 712     #   var max: (addr byte) = &table->data[table->write]
+ 713     #   var k: (addr array byte) = lookup(key)
+ 714     #   while curr < max
+ 715     #     var c: (addr array byte) = lookup(*curr)
+ 716     #     if string-equal?(k, c)
+ 717     #       return curr+8
+ 718     #     curr += row-size
+ 719     #   if table->write >= table->size
+ 720     #     abort
+ 721     #   *max = key
+ 722     #   table->write += row-size
+ 723     #   return max+8
+ 724     #
+ 725     # . prologue
+ 726     55/push-ebp
+ 727     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 728     # . save registers
+ 729     51/push-ecx
+ 730     52/push-edx
+ 731     53/push-ebx
+ 732     56/push-esi
+ 733     # esi = table
+ 734     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+ 735     # var k/ebx: (addr array byte) = lookup(key)
+ 736     # . eax = lookup(key)
+ 737     # . . push args
+ 738     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+ 739     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+ 740     # . . call
+ 741     e8/call  lookup/disp32
+ 742     # . . discard args
+ 743     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 744     # . ebx = eax
+ 745     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
+ 746     # var curr/ecx: (addr handle array byte) = table->data
+ 747     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy esi+12 to ecx
+ 748     # var max/edx: (addr byte) = &table->data[table->write]
+ 749     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
+ 750     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ecx  2/index/edx   .           2/r32/edx   .               .                 # copy ecx+edx to edx
+ 751 $get-or-insert-handle:search-loop:
+ 752     # if (curr >= max) break
+ 753     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
+ 754     73/jump-if-addr>=  $get-or-insert-handle:not-found/disp8
+ 755     # var c/eax: (addr array byte) = lookup(*curr)
+ 756     # . . push args
+ 757     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+ 758     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+ 759     # . . call
+ 760     e8/call  lookup/disp32
+ 761     # . . discard args
+ 762     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 763     # if (string-equal?(k, c)) return curr+8
+ 764     # . eax = string-equal?(k, c)
+ 765     # . . push args
+ 766     50/push-eax
+ 767     53/push-ebx
+ 768     # . . call
+ 769     e8/call  string-equal?/disp32
+ 770     # . . discard args
+ 771     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 772     # . if (eax != false) return eax = curr+8
+ 773     3d/compare-eax-and  0/imm32/false
+ 774     74/jump-if-=  $get-or-insert-handle:mismatch/disp8
+ 775     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   8/disp8         .                 # copy ecx+8 to eax
+ 776     eb/jump  $get-or-insert-handle:end/disp8
+ 777 $get-or-insert-handle:mismatch:
+ 778     # curr += row-size
+ 779     03/add                          1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x14/disp8      .                 # add *(ebp+20) to ecx
+ 780     # loop
+ 781     eb/jump  $get-or-insert-handle:search-loop/disp8
+ 782 $get-or-insert-handle:not-found:
+ 783     # if (table->write >= table->size) abort
+ 784     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
+ 785     3b/compare                      1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   8/disp8         .                 # compare ecx with *(esi+8)
+ 786     73/jump-if-addr>=  $get-or-insert-handle:abort/disp8
+ 787     # table->write += row-size
+ 788     # . eax = row-size
+ 789     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0x14/disp8      .                 # copy *(ebp+20) to eax
+ 790     # . table->write += eax
+ 791     01/add                          0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # add eax to *esi
+ 792     # *max = key
+ 793     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0xc/disp8       .                 # copy *(ebp+12) to eax
+ 794     89/copy                         0/mod/indirect  2/rm32/edx    .           .             .           0/r32/eax   .               .                 # copy eax to *edx
+ 795     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0x10/disp8      .                 # copy *(ebp+16) to eax
+ 796     89/copy                         1/mod/*+disp8   2/rm32/edx    .           .             .           0/r32/eax   4/disp8         .                 # copy eax to *(edx+4)
+ 797     # return max+8
+ 798     # . eax = max
+ 799     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           2/r32/edx   .               .                 # copy edx to eax
+ 800     # . eax += 8
+ 801     05/add-to-eax  8/imm32
+ 802 $get-or-insert-handle:end:
+ 803     # . restore registers
+ 804     5e/pop-to-esi
+ 805     5b/pop-to-ebx
+ 806     5a/pop-to-edx
+ 807     59/pop-to-ecx
+ 808     # . epilogue
+ 809     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 810     5d/pop-to-ebp
+ 811     c3/return
+ 812 
+ 813 $get-or-insert-handle:abort:
+ 814     # . _write(2/stderr, error)
+ 815     # . . push args
+ 816     68/push  "get-or-insert-handle: table is full\n"/imm32
+ 817     68/push  2/imm32/stderr
+ 818     # . . call
+ 819     e8/call  _write/disp32
+ 820     # . . discard args
+ 821     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 822     # . syscall(exit, 1)
+ 823     bb/copy-to-ebx  1/imm32
+ 824     b8/copy-to-eax  1/imm32/exit
+ 825     cd/syscall  0x80/imm8
+ 826     # never gets here
+ 827 
+ 828 test-get-or-insert-handle:
+ 829     # . prologue
+ 830     55/push-ebp
+ 831     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 832     # var table/ecx: (stream {(handle array byte), number} 24)  # 2 rows * 12 bytes/row
+ 833     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x18/imm32        # subtract from esp
+ 834     68/push  0x18/imm32/size
+ 835     68/push  0/imm32/read
+ 836     68/push  0/imm32/write
+ 837     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 838     # var h/edx: (handle array byte)
+ 839     68/push  0/imm32
+ 840     68/push  0/imm32
+ 841     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
+ 842 $test-get-or-insert-handle:first-call:
+ 843     # - start with an empty table, insert one key, verify that it was inserted
+ 844     # copy-array(Heap, "code", h)
+ 845     # . . push args
+ 846     52/push-edx
+ 847     68/push  "code"/imm32
+ 848     68/push  Heap/imm32
+ 849     # . . call
+ 850     e8/call  copy-array/disp32
+ 851     # . . discard args
+ 852     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 853     # eax = get-or-insert-handle(table, h, 12 bytes/row)
+ 854     # . . push args
+ 855     68/push  0xc/imm32/row-size
+ 856     ff          6/subop/push        1/mod/*+disp8   2/rm32/edx    .           .             .           .           4/disp8         .                 # push *(edx+4)
+ 857     ff          6/subop/push        0/mod/indirect  2/rm32/edx    .           .             .           .           .               .                 # push *edx
+ 858     51/push-ecx
+ 859     # . . call
+ 860     e8/call  get-or-insert-handle/disp32
+ 861     # . . discard args
+ 862     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+ 863     # check-ints-equal(eax - table->data, 8, msg)  # first row's value slot returned
+ 864     # . check-ints-equal(eax - table, 20, msg)
+ 865     # . . push args
+ 866     68/push  "F - test-get-or-insert-handle/0"/imm32
+ 867     68/push  0x14/imm32
+ 868     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+ 869     50/push-eax
+ 870     # . . call
+ 871     e8/call  check-ints-equal/disp32
+ 872     # . . discard args
+ 873     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 874     # check-ints-equal(table->write, row-size = 12, msg)
+ 875     # . . push args
+ 876     68/push  "F - test-get-or-insert-handle/1"/imm32
+ 877     68/push  0xc/imm32/row-size
+ 878     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+ 879     # . . call
+ 880     e8/call  check-ints-equal/disp32
+ 881     # . . discard args
+ 882     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 883     # var curr-addr/eax: (addr array byte) = lookup(table->data)
+ 884     # . . push args
+ 885     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0x10/disp8      .                 # push *(ecx+16)
+ 886     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0xc/disp8       .                 # push *(ecx+12)
+ 887     # . . call
+ 888     e8/call  lookup/disp32
+ 889     # . . discard args
+ 890     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 891     # check-strings-equal(curr-addr, "code", msg)
  892     # . . push args
- 893     68/push  "F - test-leaky-get-or-insert-slice/6"/imm32
- 894     68/push  0x18/imm32
- 895     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
- 896     50/push-eax
- 897     # . . call
- 898     e8/call  check-ints-equal/disp32
- 899     # . . discard args
- 900     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 901     # check-ints-equal(table->write, 2 rows = 16, msg)
- 902     # . . push args
- 903     68/push  "F - test-leaky-get-or-insert-slice/7"/imm32
- 904     68/push  0x10/imm32/two-rows
- 905     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
- 906     # . . call
- 907     e8/call  check-ints-equal/disp32
- 908     # . . discard args
- 909     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 910     # check-strings-equal(*table->data+8, "data", msg)
- 911     # check-strings-equal(*(table+20), "data", msg)
+ 893     68/push  "F - test-get-or-insert-handle/2"/imm32
+ 894     68/push  "code"/imm32
+ 895     50/push-eax
+ 896     # . . call
+ 897     e8/call  check-strings-equal/disp32
+ 898     # . . discard args
+ 899     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 900 $test-get-or-insert-handle:second-call:
+ 901     # - insert the same key again, verify that it was reused
+ 902     # copy-array(Heap, "code", h)
+ 903     # . . push args
+ 904     52/push-edx
+ 905     68/push  "code"/imm32
+ 906     68/push  Heap/imm32
+ 907     # . . call
+ 908     e8/call  copy-array/disp32
+ 909     # . . discard args
+ 910     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 911     # eax = get-or-insert-handle(table, h, 12 bytes/row)
  912     # . . push args
- 913     68/push  "F - test-leaky-get-or-insert-slice/8"/imm32
- 914     68/push  "data"/imm32
- 915     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0x14/disp8      .                 # push *(ecx+20)
- 916     # . . call
- 917     e8/call  check-strings-equal/disp32
- 918     # . . discard args
- 919     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 920 $test-leaky-get-or-insert-slice:end:
- 921     # . epilogue
- 922     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
- 923     5d/pop-to-ebp
- 924     c3/return
- 925 
- 926 # if no row is found, stop(ed)
- 927 get-or-stop:  # table: (addr stream {string_key, T}), key: string_key, row-size: int,
- 928               # abort-message-prefix: (addr array byte), err: (addr buffered-file), ed: (addr exit-descriptor)
- 929               # -> eax: (addr T)
- 930     # pseudocode:
- 931     #   curr = table->data
- 932     #   max = &table->data[table->write]
- 933     #   while curr < max
- 934     #     if string-equal?(key, *curr)
- 935     #       return curr+4
- 936     #     curr += row-size
- 937     #   write-buffered(err, msg)
- 938     #   stop(ed)
- 939     #
- 940     # . prologue
- 941     55/push-ebp
- 942     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 943     # . save registers
- 944     51/push-ecx
- 945     52/push-edx
- 946     56/push-esi
- 947     # esi = table
- 948     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
- 949     # var curr/ecx: (addr string_key) = table->data
- 950     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy esi+12 to ecx
- 951     # var max/edx: (addr byte) = &table->data[table->write]
- 952     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
- 953     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ecx  2/index/edx   .           2/r32/edx   .               .                 # copy ecx+edx to edx
- 954 $get-or-stop:search-loop:
- 955     # if (curr >= max) stop(ed)
- 956     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
- 957     73/jump-if-addr>=  $get-or-stop:stop/disp8
- 958     # if (string-equal?(key, *curr)) return curr+4
- 959     # . eax = string-equal?(key, *curr)
- 960     # . . push args
- 961     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
- 962     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
- 963     # . . call
- 964     e8/call  string-equal?/disp32
- 965     # . . discard args
- 966     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 967     # . if (eax != false) return eax = curr+4
- 968     3d/compare-eax-and  0/imm32/false
- 969     74/jump-if-=  $get-or-stop:mismatch/disp8
- 970     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy ecx+4 to eax
- 971     eb/jump  $get-or-stop:end/disp8
- 972 $get-or-stop:mismatch:
- 973     # curr += row-size
- 974     03/add                          1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8      .                 # add *(ebp+16) to ecx
- 975     # loop
- 976     eb/jump  $get-or-stop:search-loop/disp8
- 977 $get-or-stop:end:
- 978     # . restore registers
- 979     5e/pop-to-esi
- 980     5a/pop-to-edx
- 981     59/pop-to-ecx
- 982     # . epilogue
- 983     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
- 984     5d/pop-to-ebp
- 985     c3/return
- 986 
- 987 $get-or-stop:stop:
- 988     # . write-buffered(err, abort-message-prefix)
- 989     # . . push args
- 990     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
- 991     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
- 992     # . . call
- 993     e8/call  write-buffered/disp32
- 994     # . . discard args
- 995     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
- 996     # . write-buffered(err, error)
- 997     # . . push args
- 998     68/push  ": get-or-stop: key not found: "/imm32
- 999     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
-1000     # . . call
-1001     e8/call  write-buffered/disp32
-1002     # . . discard args
-1003     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-1004     # . write-buffered(err, key)
-1005     # . . push args
-1006     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
-1007     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
-1008     # . . call
-1009     e8/call  write-buffered/disp32
-1010     # . . discard args
-1011     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-1012     # . write-buffered(err, "\n")
-1013     # . . push args
-1014     68/push  Newline/imm32
-1015     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
-1016     # . . call
-1017     e8/call  write-buffered/disp32
-1018     # . . discard args
-1019     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-1020     # . stop(ed, 1)
-1021     # . . push args
-1022     68/push  1/imm32
-1023     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x1c/disp8      .                 # push *(ebp+28)
-1024     # . . call
-1025     e8/call  stop/disp32
-1026     # never gets here
-1027 $get-or-stop:terminus:
-1028     # . . discard args
-1029     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-1030     # syscall(exit, 1)
-1031     b8/copy-to-eax  1/imm32/exit
-1032     cd/syscall  0x80/imm8
-1033 
-1034 test-get-or-stop:
-1035     # This test uses exit-descriptors. Use ebp for setting up local variables.
-1036     # . prologue
-1037     55/push-ebp
-1038     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-1039     # setup
-1040     # . clear-stream(_test-error-stream)
-1041     # . . push args
-1042     68/push  _test-error-stream/imm32
-1043     # . . call
-1044     e8/call  clear-stream/disp32
-1045     # . . discard args
-1046     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-1047     # . clear-stream($_test-error-buffered-file->buffer)
-1048     # . . push args
-1049     68/push  $_test-error-buffered-file->buffer/imm32
-1050     # . . call
-1051     e8/call  clear-stream/disp32
-1052     # . . discard args
-1053     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-1054     # var table/ecx: (stream {string, number} 16)  # 2 rows * 8 bytes/row
-1055     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # subtract from esp
-1056     68/push  0x10/imm32/length
-1057     68/push  0/imm32/read
-1058     68/push  0/imm32/write
-1059     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
-1060     # var ed/edx: exit-descriptor
-1061     68/push  0/imm32
-1062     68/push  0/imm32
-1063     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
-1064     # size 'ed' for the calls to 'get-or-stop'
-1065     # . tailor-exit-descriptor(ed, 24)
-1066     # . . push args
-1067     68/push  0x18/imm32/nbytes-of-args-for-get-or-stop
-1068     52/push-edx
-1069     # . . call
-1070     e8/call  tailor-exit-descriptor/disp32
-1071     # . . discard args
-1072     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-1073     # insert(table, "code", 8 bytes per row)
-1074     # . . push args
-1075     68/push  8/imm32/row-size
-1076     68/push  "code"/imm32
-1077     51/push-ecx
-1078     # . . call
-1079     e8/call  get-or-insert/disp32
-1080     # . . discard args
-1081     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1082 $test-get-or-stop:success:
-1083     # eax = get-or-stop(table, "code", row-size=8, msg, _test-error-buffered-file, ed)
-1084     # . . push args
-1085     52/push-edx/ed
-1086     68/push  _test-error-buffered-file/imm32
-1087     68/push  "foo"/imm32/abort-prefix
-1088     68/push  8/imm32/row-size
-1089     68/push  "code"/imm32
-1090     51/push-ecx
-1091     # . . call
-1092     e8/call  get-or-stop/disp32
-1093     # . . discard args
-1094     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x18/imm32        # add to esp
-1095 $test-get-or-stop:success-assertion:
-1096     # check-ints-equal(eax - table->data, 4, msg)
-1097     # . check-ints-equal(eax - table, 16, msg)
-1098     # . . push args
-1099     68/push  "F - test-get-or-stop/0"/imm32
-1100     68/push  0x10/imm32
-1101     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
-1102     50/push-eax
-1103     # . . call
-1104     e8/call  check-ints-equal/disp32
-1105     # . . discard args
-1106     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1107 $test-get-or-stop:failure:
-1108     # eax = get-or-stop(table, "data", row-size=8, msg, _test-error-buffered-file, ed)
-1109     # . . push args
-1110     52/push-edx/ed
-1111     68/push  _test-error-buffered-file/imm32
-1112     68/push  "foo"/imm32/abort-prefix
-1113     68/push  8/imm32/row-size
-1114     68/push  "data"/imm32
-1115     51/push-ecx
-1116     # . . call
-1117     e8/call  get-or-stop/disp32
-1118     # registers except esp may be clobbered at this point
-1119     # restore register args, discard others
-1120     59/pop-to-ecx
-1121     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
-1122     5a/pop-to-edx
-1123 $test-get-or-stop:failure-assertion:
-1124     # check that get-or-stop tried to call stop(1)
-1125     # . check-ints-equal(ed->value, 2, msg)
-1126     # . . push args
-1127     68/push  "F - test-get-or-stop/1"/imm32
-1128     68/push  2/imm32
-1129     # . . push ed->value
-1130     ff          6/subop/push        1/mod/*+disp8   2/rm32/edx    .           .             .           .           4/disp8         .                 # push *(edx+4)
-1131     # . . call
-1132     e8/call  check-ints-equal/disp32
-1133     # . . discard args
-1134     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1135 $test-get-or-stop:end:
-1136     # . epilogue
-1137     # don't restore esp from ebp; manually reclaim locals
-1138     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x24/imm32        # add to esp
-1139     5d/pop-to-ebp
-1140     c3/return
-1141 
-1142 # if no row is found, stop(ed)
-1143 get-slice-or-stop:  # table: (addr stream {string_key, _}), key: (addr slice), row-size: int,
-1144                     # abort-message-prefix: (addr string), err: (addr buffered-file), ed: (addr exit-descriptor)
-1145                     # -> eax: (addr _)
-1146     # pseudocode:
-1147     #   curr = table->data
-1148     #   max = &table->data[table->write]
-1149     #   while curr < max
-1150     #     if slice-equal?(key, *curr)
-1151     #       return curr+4
-1152     #     curr += row-size
-1153     #   write-buffered(err, msg)
-1154     #   stop(ed)
-1155     #
-1156     # . prologue
-1157     55/push-ebp
-1158     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-1159     # . save registers
-1160     51/push-ecx
-1161     52/push-edx
-1162     56/push-esi
-1163     # esi = table
-1164     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
-1165     # var curr/ecx: (addr string_key) = table->data
-1166     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy esi+12 to ecx
-1167     # var max/edx: (addr byte) = &table->data[table->write]
-1168     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
-1169     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ecx  2/index/edx   .           2/r32/edx   .               .                 # copy ecx+edx to edx
-1170 $get-slice-or-stop:search-loop:
-1171     # if (curr >= max) stop(ed)
-1172     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
-1173     73/jump-if-addr>=  $get-slice-or-stop:stop/disp8
-1174     # if (slice-equal?(key, *curr)) return curr+4
-1175     # . eax = slice-equal?(key, *curr)
-1176     # . . push args
-1177     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
-1178     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
-1179     # . . call
-1180     e8/call  slice-equal?/disp32
-1181     # . . discard args
-1182     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-1183     # . if (eax != false) return eax = curr+4
-1184     3d/compare-eax-and  0/imm32/false
-1185     74/jump-if-=  $get-slice-or-stop:mismatch/disp8
-1186     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy ecx+4 to eax
-1187     eb/jump  $get-slice-or-stop:end/disp8
-1188 $get-slice-or-stop:mismatch:
-1189     # curr += row-size
-1190     03/add                          1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8      .                 # add *(ebp+16) to ecx
-1191     # loop
-1192     eb/jump  $get-slice-or-stop:search-loop/disp8
-1193 $get-slice-or-stop:end:
-1194     # . restore registers
-1195     5e/pop-to-esi
-1196     5a/pop-to-edx
-1197     59/pop-to-ecx
-1198     # . epilogue
-1199     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-1200     5d/pop-to-ebp
-1201     c3/return
-1202 
-1203 $get-slice-or-stop:stop:
-1204     # . write-buffered(err, abort-message-prefix)
-1205     # . . push args
-1206     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
-1207     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
-1208     # . . call
-1209     e8/call  write-buffered/disp32
-1210     # . . discard args
-1211     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-1212     # . write-buffered(err, error)
-1213     # . . push args
-1214     68/push  ": get-slice-or-stop: key not found: "/imm32
-1215     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
-1216     # . . call
-1217     e8/call  write-buffered/disp32
-1218     # . . discard args
-1219     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-1220     # . write-slice-buffered(err, key)
-1221     # . . push args
-1222     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
-1223     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
-1224     # . . call
-1225     e8/call  write-slice-buffered/disp32
-1226     # . . discard args
-1227     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-1228     # . write-buffered(err, "\n")
-1229     # . . push args
-1230     68/push  Newline/imm32
-1231     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
-1232     # . . call
-1233     e8/call  write-buffered/disp32
-1234     # . . discard args
-1235     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-1236     # . stop(ed, 1)
-1237     # . . push args
-1238     68/push  1/imm32
-1239     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x1c/disp8      .                 # push *(ebp+28)
-1240     # . . call
-1241     e8/call  stop/disp32
-1242     # never gets here
-1243 $get-slice-or-stop:terminus:
-1244     # . . discard args
-1245     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-1246     # syscall(exit, 1)
-1247     b8/copy-to-eax  1/imm32/exit
-1248     cd/syscall  0x80/imm8
-1249 
-1250 test-get-slice-or-stop:
-1251     # This test uses exit-descriptors. Use ebp for setting up local variables.
-1252     # . prologue
-1253     55/push-ebp
-1254     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-1255     # setup
-1256     # . clear-stream(_test-error-stream)
-1257     # . . push args
-1258     68/push  _test-error-stream/imm32
-1259     # . . call
-1260     e8/call  clear-stream/disp32
-1261     # . . discard args
-1262     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-1263     # . clear-stream($_test-error-buffered-file->buffer)
-1264     # . . push args
-1265     68/push  $_test-error-buffered-file->buffer/imm32
-1266     # . . call
-1267     e8/call  clear-stream/disp32
-1268     # . . discard args
-1269     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-1270     # var table/ecx: (stream {string, number} 16)  # 2 rows * 8 bytes/row
-1271     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # subtract from esp
-1272     68/push  0x10/imm32/length
-1273     68/push  0/imm32/read
-1274     68/push  0/imm32/write
-1275     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
-1276     # var ed/edx: exit-descriptor
-1277     68/push  0/imm32
-1278     68/push  0/imm32
-1279     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
-1280     # var slice/ebx: slice = "code"
-1281     # . (eax..ebx) = "code"
-1282     b8/copy-to-eax  "code"/imm32
-1283     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # copy *eax to ebx
-1284     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  3/index/ebx   .           3/r32/ebx   4/disp8         .                 # copy eax+ebx+4 to ebx
-1285     05/add-to-eax  4/imm32
-1286     # . ebx = {eax, ebx}
-1287     53/push-ebx
-1288     50/push-eax
-1289     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           4/r32/esp   .               .                 # copy esp to ebx
-1290     # size 'ed' for the calls to 'get-or-stop' (define no locals past this point)
-1291     # . tailor-exit-descriptor(ed, 24)
-1292     # . . push args
-1293     68/push  0x18/imm32/nbytes-of-args-for-get-or-stop
-1294     52/push-edx
-1295     # . . call
-1296     e8/call  tailor-exit-descriptor/disp32
-1297     # . . discard args
-1298     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-1299     # insert(table, "code", 8 bytes per row)
-1300     # . . push args
-1301     68/push  8/imm32/row-size
-1302     68/push  "code"/imm32
-1303     51/push-ecx
-1304     # . . call
-1305     e8/call  get-or-insert/disp32
-1306     # . . discard args
-1307     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1308 $test-get-slice-or-stop:success:
-1309     # eax = get-slice-or-stop(table, slice, row-size=8, msg, _test-error-buffered-file, ed)
-1310     # . . push args
-1311     52/push-edx/ed
-1312     68/push  _test-error-buffered-file/imm32
-1313     68/push  "foo"/imm32/abort-prefix
-1314     68/push  8/imm32/row-size
-1315     53/push-ebx/slice
-1316     51/push-ecx
-1317     # . . call
-1318     e8/call  get-slice-or-stop/disp32
-1319     # registers except esp may be clobbered at this point
-1320     # restore register args, discard others
-1321     59/pop-to-ecx
-1322     5b/pop-to-ebx
-1323     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1324     5a/pop-to-edx
-1325 $test-get-slice-or-stop:success-assertion:
-1326     # check-ints-equal(eax - table->data, 4, msg)  # first row's value slot returned
-1327     # . check-ints-equal(eax - table, 16, msg)
-1328     # . . push args
-1329     68/push  "F - test-get-slice-or-stop/0"/imm32
-1330     68/push  0x10/imm32
-1331     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
-1332     50/push-eax
-1333     # . . call
-1334     e8/call  check-ints-equal/disp32
-1335     # . . discard args
-1336     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1337 $test-get-slice-or-stop:failure:
-1338     # slice = "segment2"
-1339     # . *ebx = "segment2"->data
-1340     b8/copy-to-eax  "segment2"/imm32
-1341     05/add-to-eax  4/imm32
-1342     89/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to *ebx
-1343     # . *(ebx+4) = "segment2"->data + len("segment2")
-1344     05/add-to-eax  8/imm32/strlen
-1345     89/copy                         1/mod/*+disp8   3/rm32/ebx    .           .             .           0/r32/eax   4/disp8         .                 # copy eax to *(ebx+4)
-1346     # eax = get-slice-or-stop(table, slice, row-size=8, msg, _test-error-buffered-file, ed)
-1347     # . . push args
-1348     52/push-edx/ed
-1349     68/push  _test-error-buffered-file/imm32
-1350     68/push  "foo"/imm32/abort-prefix
-1351     68/push  8/imm32/row-size
-1352     53/push-ebx/slice
-1353     51/push-ecx
-1354     # . . call
-1355     e8/call  get-slice-or-stop/disp32
-1356     # registers except esp may be clobbered at this point
-1357     # restore register args, discard others
-1358     59/pop-to-ecx
-1359     5b/pop-to-ebx
-1360     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1361     5a/pop-to-edx
-1362 $test-get-slice-or-stop:failure-assertion:
-1363     # check that get-or-stop tried to call stop(1)
-1364     # . check-ints-equal(ed->value, 2, msg)
-1365     # . . push args
-1366     68/push  "F - test-get-or-stop/1"/imm32
-1367     68/push  2/imm32
-1368     # . . push ed->value
-1369     ff          6/subop/push        1/mod/*+disp8   2/rm32/edx    .           .             .           .           4/disp8         .                 # push *(edx+4)
-1370     # . . call
-1371     e8/call  check-ints-equal/disp32
-1372     # . . discard args
-1373     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1374 $test-get-slice-or-stop:end:
-1375     # . epilogue
-1376     # don't restore esp from ebp; manually reclaim locals
-1377     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x2c/imm32        # add to esp
-1378     5d/pop-to-ebp
-1379     c3/return
-1380 
-1381 # if no row is found, return null (0)
-1382 maybe-get:  # table: (addr stream {string_key, T}), key: string_key, row-size: int -> eax: (addr T)
-1383     # pseudocode:
-1384     #   curr = table->data
-1385     #   max = &table->data[table->write]
-1386     #   while curr < max
-1387     #     if string-equal?(key, *curr)
-1388     #       return curr+4
-1389     #     curr += row-size
-1390     #   return 0
-1391     #
-1392     # . prologue
-1393     55/push-ebp
-1394     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-1395     # . save registers
-1396     51/push-ecx
-1397     52/push-edx
-1398     56/push-esi
-1399     # esi = table
-1400     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
-1401     # var curr/ecx: (addr string_key) = table->data
-1402     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy esi+12 to ecx
-1403     # var max/edx: (addr byte) = &table->data[table->write]
-1404     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
-1405     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ecx  2/index/edx   .           2/r32/edx   .               .                 # copy ecx+edx to edx
-1406 $maybe-get:search-loop:
-1407     # if (curr >= max) return null
-1408     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
-1409     73/jump-if-addr>=  $maybe-get:null/disp8
-1410     # if (string-equal?(key, *curr)) return curr+4
-1411     # . eax = string-equal?(key, *curr)
-1412     # . . push args
-1413     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
-1414     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
-1415     # . . call
-1416     e8/call  string-equal?/disp32
-1417     # . . discard args
-1418     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-1419     # . if (eax != false) return eax = curr+4
-1420     3d/compare-eax-and  0/imm32/false
-1421     74/jump-if-=  $maybe-get:mismatch/disp8
-1422     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy ecx+4 to eax
-1423     eb/jump  $maybe-get:end/disp8
-1424 $maybe-get:mismatch:
-1425     # curr += row-size
-1426     03/add                          1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8      .                 # add *(ebp+16) to ecx
-1427     # loop
-1428     eb/jump  $maybe-get:search-loop/disp8
-1429 $maybe-get:null:
-1430     b8/copy-to-eax  0/imm32
-1431 $maybe-get:end:
-1432     # . restore registers
-1433     5e/pop-to-esi
-1434     5a/pop-to-edx
-1435     59/pop-to-ecx
-1436     # . epilogue
-1437     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-1438     5d/pop-to-ebp
-1439     c3/return
-1440 
-1441 test-maybe-get:
-1442     # . prologue
-1443     55/push-ebp
-1444     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-1445     # - setup: create a table with one row
-1446     # var table/ecx: (stream {string, number} 16)   # 2 rows * 8 bytes/row
-1447     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # subtract from esp
-1448     68/push  0x10/imm32/length
-1449     68/push  0/imm32/read
-1450     68/push  0/imm32/write
-1451     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
-1452     # eax = get-or-insert(table, "code", 8 bytes per row)
+ 913     68/push  0xc/imm32/row-size
+ 914     ff          6/subop/push        1/mod/*+disp8   2/rm32/edx    .           .             .           .           4/disp8         .                 # push *(edx+4)
+ 915     ff          6/subop/push        0/mod/indirect  2/rm32/edx    .           .             .           .           .               .                 # push *edx
+ 916     51/push-ecx
+ 917     # . . call
+ 918     e8/call  get-or-insert-handle/disp32
+ 919     # . . discard args
+ 920     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+ 921     # check-ints-equal(eax - table->data, 8, msg)
+ 922     # . check-ints-equal(eax - table, 20, msg)
+ 923     # . . push args
+ 924     68/push  "F - test-get-or-insert-handle/3"/imm32
+ 925     68/push  0x14/imm32
+ 926     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+ 927     50/push-eax
+ 928     # . . call
+ 929     e8/call  check-ints-equal/disp32
+ 930     # . . discard args
+ 931     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 932     # no new row inserted
+ 933     # . check-ints-equal(table->write, row-size = 12, msg)
+ 934     # . . push args
+ 935     68/push  "F - test-get-or-insert-handle/4"/imm32
+ 936     68/push  0xc/imm32/row-size
+ 937     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+ 938     # . . call
+ 939     e8/call  check-ints-equal/disp32
+ 940     # . . discard args
+ 941     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 942     # curr-addr = lookup(table->data)
+ 943     # . . push args
+ 944     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0x10/disp8      .                 # push *(ecx+16)
+ 945     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0xc/disp8       .                 # push *(ecx+12)
+ 946     # . . call
+ 947     e8/call  lookup/disp32
+ 948     # . . discard args
+ 949     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 950     # check-strings-equal(curr-addr, "code", msg)
+ 951     # . . push args
+ 952     68/push  "F - test-get-or-insert-handle/5"/imm32
+ 953     68/push  "code"/imm32
+ 954     50/push-eax
+ 955     # . . call
+ 956     e8/call  check-strings-equal/disp32
+ 957     # . . discard args
+ 958     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 959 $test-get-or-insert-handle:third-call:
+ 960     # - insert a new key, verify that it was inserted
+ 961     # copy-array(Heap, "data", h)
+ 962     # . . push args
+ 963     52/push-edx
+ 964     68/push  "data"/imm32
+ 965     68/push  Heap/imm32
+ 966     # . . call
+ 967     e8/call  copy-array/disp32
+ 968     # . . discard args
+ 969     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 970     # eax = get-or-insert-handle(table, h, 12 bytes/row)
+ 971     # . . push args
+ 972     68/push  0xc/imm32/row-size
+ 973     ff          6/subop/push        1/mod/*+disp8   2/rm32/edx    .           .             .           .           4/disp8         .                 # push *(edx+4)
+ 974     ff          6/subop/push        0/mod/indirect  2/rm32/edx    .           .             .           .           .               .                 # push *edx
+ 975     51/push-ecx
+ 976     # . . call
+ 977     e8/call  get-or-insert-handle/disp32
+ 978     # . . discard args
+ 979     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+ 980     # table gets a new row
+ 981     # check-ints-equal(eax - table->data, 20, msg)  # second row's value slot returned
+ 982     # . check-ints-equal(eax - table, 32, msg)
+ 983     # . . push args
+ 984     68/push  "F - test-get-or-insert-handle/6"/imm32
+ 985     68/push  0x20/imm32
+ 986     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+ 987     50/push-eax
+ 988     # . . call
+ 989     e8/call  check-ints-equal/disp32
+ 990     # . . discard args
+ 991     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 992     # check-ints-equal(table->write, 2 rows = 24, msg)
+ 993     # . . push args
+ 994     68/push  "F - test-get-or-insert-handle/7"/imm32
+ 995     68/push  0x18/imm32/two-rows
+ 996     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+ 997     # . . call
+ 998     e8/call  check-ints-equal/disp32
+ 999     # . . discard args
+1000     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1001     # curr-addr = lookup(table->data+12)
+1002     # . . push args
+1003     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0x1c/disp8      .                 # push *(ecx+28)
+1004     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0x18/disp8      .                 # push *(ecx+24)
+1005     # . . call
+1006     e8/call  lookup/disp32
+1007     # . . discard args
+1008     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1009     # check-strings-equal(curr-addr, "data", msg)
+1010     # . . push args
+1011     68/push  "F - test-get-or-insert-handle/8"/imm32
+1012     68/push  "data"/imm32
+1013     50/push-eax
+1014     # . . call
+1015     e8/call  check-strings-equal/disp32
+1016     # . . discard args
+1017     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1018 $test-get-or-insert-handle:end:
+1019     # . epilogue
+1020     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1021     5d/pop-to-ebp
+1022     c3/return
+1023 
+1024 # if no row is found, save 'key' in the next available row
+1025 # if there are no rows free, abort
+1026 get-or-insert-slice:  # table: (addr stream {(handle array byte), T}), key: (addr slice), row-size: int, ad: (addr allocation-descriptor) -> eax: (addr T)
+1027     # pseudocode:
+1028     #   curr = table->data
+1029     #   max = &table->data[table->write]
+1030     #   while curr < max
+1031     #     var c: (addr array byte) = lookup(*curr)
+1032     #     if slice-equal?(key, *curr)
+1033     #       return curr+8
+1034     #     curr += row-size
+1035     #   if table->write >= table->size
+1036     #     abort
+1037     #   zero-out(max, row-size)
+1038     #   slice-to-string(ad, key, max)
+1039     #   table->write += row-size
+1040     #   return max+8
+1041     #
+1042     # . prologue
+1043     55/push-ebp
+1044     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1045     # . save registers
+1046     51/push-ecx
+1047     52/push-edx
+1048     56/push-esi
+1049     # esi = table
+1050     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+1051     # var curr/ecx: (addr handle array byte) = table->data
+1052     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy esi+12 to ecx
+1053     # var max/edx: (addr byte) = &table->data[table->write]
+1054     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
+1055     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ecx  2/index/edx   .           2/r32/edx   .               .                 # copy ecx+edx to edx
+1056 $get-or-insert-slice:search-loop:
+1057     # if (curr >= max) break
+1058     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
+1059     73/jump-if-addr>=  $get-or-insert-slice:not-found/disp8
+1060     # var c/eax: (addr array byte) = lookup(*curr)
+1061     # . . push args
+1062     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+1063     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+1064     # . . call
+1065     e8/call  lookup/disp32
+1066     # . . discard args
+1067     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1068     # if (slice-equal?(key, c)) return curr+4
+1069     # . eax = slice-equal?(key, c)
+1070     # . . push args
+1071     50/push-eax
+1072     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+1073     # . . call
+1074     e8/call  slice-equal?/disp32
+1075     # . . discard args
+1076     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1077     # . if (eax != false) return eax = curr+8
+1078     3d/compare-eax-and  0/imm32/false
+1079     74/jump-if-=  $get-or-insert-slice:mismatch/disp8
+1080     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   8/disp8         .                 # copy ecx+8 to eax
+1081     eb/jump  $get-or-insert-slice:end/disp8
+1082 $get-or-insert-slice:mismatch:
+1083     # curr += row-size
+1084     03/add                          1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8      .                 # add *(ebp+16) to ecx
+1085     # loop
+1086     eb/jump  $get-or-insert-slice:search-loop/disp8
+1087 $get-or-insert-slice:not-found:
+1088     # result/eax = 0
+1089     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
+1090     # if (table->write >= table->size) abort
+1091     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
+1092     3b/compare                      1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   8/disp8         .                 # compare ecx with *(esi+8)
+1093     7d/jump-if->=  $get-or-insert-slice:abort/disp8
+1094     # zero-out(max, row-size)
+1095     # . . push args
+1096     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+1097     52/push-edx
+1098     # . . call
+1099     e8/call  zero-out/disp32
+1100     # . . discard args
+1101     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1102     # slice-to-string(ad, key, max)
+1103     # . . push args
+1104     52/push-edx
+1105     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+1106     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
+1107     # . . call
+1108     e8/call  slice-to-string/disp32
+1109     # . . discard args
+1110     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1111     # table->write += row-size
+1112     # . eax = row-size
+1113     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0x10/disp8      .                 # copy *(ebp+16) to eax
+1114     # . table->write += eax
+1115     01/add                          0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # add eax to *esi
+1116     # return max+8
+1117     # . eax = max
+1118     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           2/r32/edx   .               .                 # copy edx to eax
+1119     # . eax += 8
+1120     05/add-to-eax  8/imm32
+1121 $get-or-insert-slice:end:
+1122     # . restore registers
+1123     5e/pop-to-esi
+1124     5a/pop-to-edx
+1125     59/pop-to-ecx
+1126     # . epilogue
+1127     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1128     5d/pop-to-ebp
+1129     c3/return
+1130 
+1131 $get-or-insert-slice:abort:
+1132     # . _write(2/stderr, error)
+1133     # . . push args
+1134     68/push  "get-or-insert-slice: table is full\n"/imm32
+1135     68/push  2/imm32/stderr
+1136     # . . call
+1137     e8/call  _write/disp32
+1138     # . . discard args
+1139     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1140     # . syscall(exit, 1)
+1141     bb/copy-to-ebx  1/imm32
+1142     b8/copy-to-eax  1/imm32/exit
+1143     cd/syscall  0x80/imm8
+1144     # never gets here
+1145 
+1146 test-get-or-insert-slice:
+1147     # . prologue
+1148     55/push-ebp
+1149     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1150     # var table/ecx: (stream {string, number} 24)  # 2 rows * 12 bytes/row
+1151     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x18/imm32        # subtract from esp
+1152     68/push  0x18/imm32/size
+1153     68/push  0/imm32/read
+1154     68/push  0/imm32/write
+1155     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+1156     # (eax..edx) = "code"
+1157     b8/copy-to-eax  "code"/imm32
+1158     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           2/r32/edx   .               .                 # copy *eax to edx
+1159     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  2/index/edx   .           2/r32/edx   4/disp8         .                 # copy eax+edx+4 to edx
+1160     05/add-to-eax  4/imm32
+1161     # var slice/edx: slice = {eax, edx}
+1162     52/push-edx
+1163     50/push-eax
+1164     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
+1165 $test-get-or-insert-slice:first-call:
+1166     # - start with an empty table, insert one key, verify that it was inserted
+1167     # eax = get-or-insert-slice(table, "code" slice, 12 bytes/row, Heap)
+1168     # . . push args
+1169     68/push  Heap/imm32
+1170     68/push  0xc/imm32/row-size
+1171     52/push-edx
+1172     51/push-ecx
+1173     # . . call
+1174     e8/call  get-or-insert-slice/disp32
+1175     # . . discard args
+1176     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+1177     # check-ints-equal(eax - table->data, 8, msg)  # first row's value slot returned
+1178     # . check-ints-equal(eax - table, 20, msg)
+1179     # . . push args
+1180     68/push  "F - test-get-or-insert-slice/0"/imm32
+1181     68/push  0x14/imm32
+1182     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+1183     50/push-eax
+1184     # . . call
+1185     e8/call  check-ints-equal/disp32
+1186     # . . discard args
+1187     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1188     # check-ints-equal(table->write, row-size = 12, msg)
+1189     # . . push args
+1190     68/push  "F - test-get-or-insert-slice/1"/imm32
+1191     68/push  0xc/imm32/row-size
+1192     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+1193     # . . call
+1194     e8/call  check-ints-equal/disp32
+1195     # . . discard args
+1196     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1197     # var curr-addr/eax: (addr array byte) = lookup(table->data)
+1198     # . . push args
+1199     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0x10/disp8      .                 # push *(ecx+16)
+1200     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0xc/disp8       .                 # push *(ecx+12)
+1201     # . . call
+1202     e8/call  lookup/disp32
+1203     # . . discard args
+1204     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1205     # check-strings-equal(curr-addr, "code", msg)
+1206     # . . push args
+1207     68/push  "F - test-get-or-insert-slice/2"/imm32
+1208     68/push  "code"/imm32
+1209     50/push-eax
+1210     # . . call
+1211     e8/call  check-strings-equal/disp32
+1212     # . . discard args
+1213     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1214 $test-get-or-insert-slice:second-call:
+1215     # - insert the same key again, verify that it was reused
+1216     # eax = get-or-insert-slice(table, "code" slice, 12 bytes/row)
+1217     # . . push args
+1218     68/push  Heap/imm32
+1219     68/push  0xc/imm32/row-size
+1220     52/push-edx
+1221     51/push-ecx
+1222     # . . call
+1223     e8/call  get-or-insert-slice/disp32
+1224     # . . discard args
+1225     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+1226     # check-ints-equal(eax - table->data, 8, msg)
+1227     # . check-ints-equal(eax - table, 20, msg)
+1228     # . . push args
+1229     68/push  "F - test-get-or-insert-slice/3"/imm32
+1230     68/push  0x14/imm32
+1231     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+1232     50/push-eax
+1233     # . . call
+1234     e8/call  check-ints-equal/disp32
+1235     # . . discard args
+1236     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1237     # no new row inserted
+1238     # . check-ints-equal(table->write, row-size = 12, msg)
+1239     # . . push args
+1240     68/push  "F - test-get-or-insert-slice/4"/imm32
+1241     68/push  0xc/imm32/row-size
+1242     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+1243     # . . call
+1244     e8/call  check-ints-equal/disp32
+1245     # . . discard args
+1246     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1247     # curr-addr = lookup(table->data)
+1248     # . . push args
+1249     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0x10/disp8      .                 # push *(ecx+16)
+1250     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0xc/disp8       .                 # push *(ecx+12)
+1251     # . . call
+1252     e8/call  lookup/disp32
+1253     # . . discard args
+1254     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1255     # check-strings-equal(curr-addr, "code", msg)
+1256     # . . push args
+1257     68/push  "F - test-get-or-insert-slice/5"/imm32
+1258     68/push  "code"/imm32
+1259     50/push-eax
+1260     # . . call
+1261     e8/call  check-strings-equal/disp32
+1262     # . . discard args
+1263     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1264 $test-get-or-insert-slice:third-call:
+1265     # - insert a new key, verify that it was inserted
+1266     # (eax..edx) = "data"
+1267     b8/copy-to-eax  "data"/imm32
+1268     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           2/r32/edx   .               .                 # copy *eax to edx
+1269     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  2/index/edx   .           2/r32/edx   4/disp8         .                 # copy eax+edx+4 to edx
+1270     05/add-to-eax  4/imm32
+1271     # var slice/edx: slice = {eax, edx}
+1272     52/push-edx
+1273     50/push-eax
+1274     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
+1275     # eax = get-or-insert-slice(table, "data" slice, 12 bytes/row)
+1276     # . . push args
+1277     68/push  Heap/imm32
+1278     68/push  0xc/imm32/row-size
+1279     52/push-edx
+1280     51/push-ecx
+1281     # . . call
+1282     e8/call  get-or-insert-slice/disp32
+1283     # . . discard args
+1284     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+1285     # table gets a new row
+1286     # check-ints-equal(eax - table->data, 20, msg)  # second row's value slot returned
+1287     # . check-ints-equal(eax - table, 32, msg)
+1288     # . . push args
+1289     68/push  "F - test-get-or-insert-slice/6"/imm32
+1290     68/push  0x20/imm32
+1291     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+1292     50/push-eax
+1293     # . . call
+1294     e8/call  check-ints-equal/disp32
+1295     # . . discard args
+1296     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1297     # check-ints-equal(table->write, 2 rows = 24, msg)
+1298     # . . push args
+1299     68/push  "F - test-get-or-insert-slice/7"/imm32
+1300     68/push  0x18/imm32/two-rows
+1301     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+1302     # . . call
+1303     e8/call  check-ints-equal/disp32
+1304     # . . discard args
+1305     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1306     # curr-addr = lookup(table->data+12)
+1307     # . . push args
+1308     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0x1c/disp8      .                 # push *(ecx+28)
+1309     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0x18/disp8      .                 # push *(ecx+24)
+1310     # . . call
+1311     e8/call  lookup/disp32
+1312     # . . discard args
+1313     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1314     # check-strings-equal(curr-addr, "data", msg)
+1315     # . . push args
+1316     68/push  "F - test-get-or-insert-slice/8"/imm32
+1317     68/push  "data"/imm32
+1318     50/push-eax
+1319     # . . call
+1320     e8/call  check-strings-equal/disp32
+1321     # . . discard args
+1322     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1323 $test-get-or-insert-slice:end:
+1324     # . epilogue
+1325     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1326     5d/pop-to-ebp
+1327     c3/return
+1328 
+1329 # if no row is found, stop(ed)
+1330 get-or-stop:  # table: (addr stream {(handle array byte), T}), key: (addr array byte), row-size: int,
+1331               # abort-message-prefix: (addr array byte), err: (addr buffered-file), ed: (addr exit-descriptor)
+1332               # -> eax: (addr T)
+1333     # pseudocode:
+1334     #   curr = table->data
+1335     #   max = &table->data[table->write]
+1336     #   while curr < max
+1337     #     var c: (addr array byte) = lookup(*curr)
+1338     #     if string-equal?(key, c)
+1339     #       return curr+8
+1340     #     curr += row-size
+1341     #   write-buffered(err, msg)
+1342     #   stop(ed)
+1343     #
+1344     # . prologue
+1345     55/push-ebp
+1346     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1347     # . save registers
+1348     51/push-ecx
+1349     52/push-edx
+1350     56/push-esi
+1351     # esi = table
+1352     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+1353     # var curr/ecx: (addr handle array byte) = table->data
+1354     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy esi+12 to ecx
+1355     # var max/edx: (addr byte) = &table->data[table->write]
+1356     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
+1357     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ecx  2/index/edx   .           2/r32/edx   .               .                 # copy ecx+edx to edx
+1358 $get-or-stop:search-loop:
+1359     # if (curr >= max) stop(ed)
+1360     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
+1361     73/jump-if-addr>=  $get-or-stop:stop/disp8
+1362     # var c/eax: (addr array byte) = lookup(*curr)
+1363     # . . push args
+1364     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+1365     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+1366     # . . call
+1367     e8/call  lookup/disp32
+1368     # . . discard args
+1369     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1370     # if (string-equal?(key, c)) return curr+8
+1371     # . eax = string-equal?(key, c)
+1372     # . . push args
+1373     50/push-eax
+1374     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+1375     # . . call
+1376     e8/call  string-equal?/disp32
+1377     # . . discard args
+1378     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1379     # . if (eax != false) return eax = curr+8
+1380     3d/compare-eax-and  0/imm32/false
+1381     74/jump-if-=  $get-or-stop:mismatch/disp8
+1382     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   8/disp8         .                 # copy ecx+8 to eax
+1383     eb/jump  $get-or-stop:end/disp8
+1384 $get-or-stop:mismatch:
+1385     # curr += row-size
+1386     03/add                          1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8      .                 # add *(ebp+16) to ecx
+1387     # loop
+1388     eb/jump  $get-or-stop:search-loop/disp8
+1389 $get-or-stop:end:
+1390     # . restore registers
+1391     5e/pop-to-esi
+1392     5a/pop-to-edx
+1393     59/pop-to-ecx
+1394     # . epilogue
+1395     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1396     5d/pop-to-ebp
+1397     c3/return
+1398 
+1399 $get-or-stop:stop:
+1400     # . write-buffered(err, abort-message-prefix)
+1401     # . . push args
+1402     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
+1403     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
+1404     # . . call
+1405     e8/call  write-buffered/disp32
+1406     # . . discard args
+1407     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1408     # . write-buffered(err, error)
+1409     # . . push args
+1410     68/push  ": get-or-stop: key not found: "/imm32
+1411     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
+1412     # . . call
+1413     e8/call  write-buffered/disp32
+1414     # . . discard args
+1415     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1416     # . write-buffered(err, key)
+1417     # . . push args
+1418     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+1419     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
+1420     # . . call
+1421     e8/call  write-buffered/disp32
+1422     # . . discard args
+1423     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1424     # . write-buffered(err, "\n")
+1425     # . . push args
+1426     68/push  Newline/imm32
+1427     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
+1428     # . . call
+1429     e8/call  write-buffered/disp32
+1430     # . . discard args
+1431     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1432     # . stop(ed, 1)
+1433     # . . push args
+1434     68/push  1/imm32
+1435     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x1c/disp8      .                 # push *(ebp+28)
+1436     # . . call
+1437     e8/call  stop/disp32
+1438     # never gets here
+1439 $get-or-stop:terminus:
+1440     # . . discard args
+1441     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1442     # syscall(exit, 1)
+1443     b8/copy-to-eax  1/imm32/exit
+1444     cd/syscall  0x80/imm8
+1445 
+1446 test-get-or-stop:
+1447     # This test uses exit-descriptors. Use ebp for setting up local variables.
+1448     # . prologue
+1449     55/push-ebp
+1450     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1451     # setup
+1452     # . clear-stream(_test-error-stream)
 1453     # . . push args
-1454     68/push  8/imm32/row-size
-1455     68/push  "code"/imm32
-1456     51/push-ecx
-1457     # . . call
-1458     e8/call  get-or-insert/disp32
-1459     # . . discard args
-1460     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1461 $test-maybe-get:success:
-1462     # - check for the same key, verify that it was reused
-1463     # eax = maybe-get(table, "code", 8 bytes per row)
-1464     # . . push args
-1465     68/push  8/imm32/row-size
-1466     68/push  "code"/imm32
-1467     51/push-ecx
-1468     # . . call
-1469     e8/call  maybe-get/disp32
-1470     # . . discard args
-1471     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1472     # check-ints-equal(eax - table->data, 4, msg)
-1473     # . check-ints-equal(eax - table, 16, msg)
-1474     # . . push args
-1475     68/push  "F - test-maybe-get/0"/imm32
-1476     68/push  0x10/imm32
-1477     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
-1478     50/push-eax
-1479     # . . call
-1480     e8/call  check-ints-equal/disp32
-1481     # . . discard args
-1482     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1483     # no new row inserted
-1484     # . check-ints-equal(table->write, row-size = 8, msg)
-1485     # . . push args
-1486     68/push  "F - test-maybe-get/1"/imm32
-1487     68/push  8/imm32/row-size
-1488     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
-1489     # . . call
-1490     e8/call  check-ints-equal/disp32
-1491     # . . discard args
-1492     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1493     # check-strings-equal(*table->data, "code", msg)
-1494     # . . push args
-1495     68/push  "F - test-maybe-get/2"/imm32
-1496     68/push  "code"/imm32
-1497     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0xc/disp8       .                 # push *(ecx+12)
-1498     # . . call
-1499     e8/call  check-strings-equal/disp32
-1500     # . . discard args
-1501     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1502 $test-maybe-get:failure:
-1503     # - search for a new key
-1504     # eax = maybe-get(table, "data", 8 bytes per row)
-1505     # . . push args
-1506     68/push  8/imm32/row-size
-1507     68/push  "data"/imm32
-1508     51/push-ecx
-1509     # . . call
-1510     e8/call  maybe-get/disp32
-1511     # . . discard args
-1512     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1513     # check-ints-equal(eax, 0, msg)
-1514     # . . push args
-1515     68/push  "F - test-maybe-get/3"/imm32
-1516     68/push  0/imm32
-1517     50/push-eax
-1518     # . . call
-1519     e8/call  check-ints-equal/disp32
-1520     # . . discard args
-1521     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1522 $test-maybe-get:end:
-1523     # . epilogue
-1524     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-1525     5d/pop-to-ebp
-1526     c3/return
-1527 
-1528 # if no row is found, return null (0)
-1529 maybe-get-slice:  # table: (addr stream {string_key, T}), key: (addr slice), row-size: int -> eax: (addr T)
-1530     # pseudocode:
-1531     #   curr = table->data
-1532     #   max = &table->data[table->write]
-1533     #   while curr < max
-1534     #     if slice-equal?(key, *curr)
-1535     #       return curr+4
-1536     #     curr += row-size
-1537     #   return 0
-1538     #
-1539     # . prologue
-1540     55/push-ebp
-1541     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-1542     # . save registers
-1543     51/push-ecx
-1544     52/push-edx
-1545     56/push-esi
-1546     # esi = table
-1547     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
-1548     # var curr/ecx: (addr string_key) = table->data
-1549     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy esi+12 to ecx
-1550     # var max/edx: (addr byte) = &table->data[table->write]
-1551     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
-1552     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ecx  2/index/edx   .           2/r32/edx   .               .                 # copy ecx+edx to edx
-1553 $maybe-get-slice:search-loop:
-1554     # if (curr >= max) return null
-1555     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
-1556     73/jump-if-addr>=  $maybe-get-slice:null/disp8
-1557     # if (slice-equal?(key, *curr)) return curr+4
-1558     # . eax = slice-equal?(key, *curr)
-1559     # . . push args
-1560     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
-1561     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
-1562     # . . call
-1563     e8/call  slice-equal?/disp32
-1564     # . . discard args
-1565     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-1566     # . if (eax != false) return eax = curr+4
-1567     3d/compare-eax-and  0/imm32/false
-1568     74/jump-if-=  $maybe-get-slice:mismatch/disp8
-1569     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy ecx+4 to eax
-1570     eb/jump  $maybe-get-slice:end/disp8
-1571 $maybe-get-slice:mismatch:
-1572     # curr += row-size
-1573     03/add                          1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8      .                 # add *(ebp+16) to ecx
-1574     # loop
-1575     eb/jump  $maybe-get-slice:search-loop/disp8
-1576 $maybe-get-slice:null:
-1577     b8/copy-to-eax  0/imm32
-1578 $maybe-get-slice:end:
-1579     # . restore registers
-1580     5e/pop-to-esi
-1581     5a/pop-to-edx
-1582     59/pop-to-ecx
-1583     # . epilogue
-1584     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-1585     5d/pop-to-ebp
-1586     c3/return
-1587 
-1588 test-maybe-get-slice:
-1589     # . prologue
-1590     55/push-ebp
-1591     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-1592     # - setup: create a table with one row
-1593     # var table/ecx: (stream {string, number} 16)   # 2 rows * 8 bytes/row
-1594     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # subtract from esp
-1595     68/push  0x10/imm32/length
-1596     68/push  0/imm32/read
-1597     68/push  0/imm32/write
-1598     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
-1599     # insert(table, "code", 8 bytes per row)
-1600     # . . push args
-1601     68/push  8/imm32/row-size
-1602     68/push  "code"/imm32
-1603     51/push-ecx
-1604     # . . call
-1605     e8/call  get-or-insert/disp32
-1606     # . . discard args
-1607     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1608 $test-maybe-get-slice:success:
-1609     # - check for the same key, verify that it was reused
-1610     # (eax..edx) = "code"
-1611     b8/copy-to-eax  "code"/imm32
-1612     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           2/r32/edx   .               .                 # copy *eax to edx
-1613     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  2/index/edx   .           2/r32/edx   4/disp8         .                 # copy eax+edx+4 to edx
-1614     05/add-to-eax  4/imm32
-1615     # var slice/edx: slice = {eax, edx}
-1616     52/push-edx
-1617     50/push-eax
-1618     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
-1619     # eax = maybe-get-slice(table, "code" slice, 8 bytes per row)
-1620     # . . push args
-1621     68/push  8/imm32/row-size
-1622     52/push-edx
-1623     51/push-ecx
-1624     # . . call
-1625     e8/call  maybe-get-slice/disp32
-1626     # . . discard args
-1627     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1628     # check-ints-equal(eax - table->data, 4, msg)
-1629     # . check-ints-equal(eax - table, 16, msg)
-1630     # . . push args
-1631     68/push  "F - test-maybe-get-slice/0"/imm32
-1632     68/push  0x10/imm32
-1633     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
-1634     50/push-eax
-1635     # . . call
-1636     e8/call  check-ints-equal/disp32
-1637     # . . discard args
-1638     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1639     # no new row inserted
-1640     # . check-ints-equal(table->write, row-size = 8, msg)
-1641     # . . push args
-1642     68/push  "F - test-maybe-get-slice/1"/imm32
-1643     68/push  8/imm32/row-size
-1644     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
-1645     # . . call
-1646     e8/call  check-ints-equal/disp32
-1647     # . . discard args
-1648     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1649     # check-strings-equal(*table->data, "code", msg)
-1650     # . . push args
-1651     68/push  "F - test-maybe-get-slice/2"/imm32
-1652     68/push  "code"/imm32
-1653     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0xc/disp8       .                 # push *(ecx+12)
+1454     68/push  _test-error-stream/imm32
+1455     # . . call
+1456     e8/call  clear-stream/disp32
+1457     # . . discard args
+1458     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1459     # . clear-stream($_test-error-buffered-file->buffer)
+1460     # . . push args
+1461     68/push  $_test-error-buffered-file->buffer/imm32
+1462     # . . call
+1463     e8/call  clear-stream/disp32
+1464     # . . discard args
+1465     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1466     # var table/ecx: (stream {string, number} 24)  # 2 rows * 12 bytes/row
+1467     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x18/imm32        # subtract from esp
+1468     68/push  0x18/imm32/size
+1469     68/push  0/imm32/read
+1470     68/push  0/imm32/write
+1471     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+1472     # var ed/edx: exit-descriptor
+1473     68/push  0/imm32
+1474     68/push  0/imm32
+1475     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
+1476     # size 'ed' for the calls to 'get-or-stop'
+1477     # . tailor-exit-descriptor(ed, 24)
+1478     # . . push args
+1479     68/push  0x18/imm32/nbytes-of-args-for-get-or-stop
+1480     52/push-edx
+1481     # . . call
+1482     e8/call  tailor-exit-descriptor/disp32
+1483     # . . discard args
+1484     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1485     # insert(table, "code", 12 bytes/row, Heap)
+1486     # . . push args
+1487     68/push  Heap/imm32
+1488     68/push  0xc/imm32/row-size
+1489     68/push  "code"/imm32
+1490     51/push-ecx
+1491     # . . call
+1492     e8/call  get-or-insert/disp32
+1493     # . . discard args
+1494     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+1495 $test-get-or-stop:success:
+1496     # eax = get-or-stop(table, "code", row-size=12, msg, _test-error-buffered-file, ed)
+1497     # . . push args
+1498     52/push-edx/ed
+1499     68/push  _test-error-buffered-file/imm32
+1500     68/push  "foo"/imm32/abort-prefix
+1501     68/push  0xc/imm32/row-size
+1502     68/push  "code"/imm32
+1503     51/push-ecx
+1504     # . . call
+1505     e8/call  get-or-stop/disp32
+1506     # . . discard args
+1507     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x18/imm32        # add to esp
+1508 $test-get-or-stop:success-assertion:
+1509     # check-ints-equal(eax - table->data, 8, msg)
+1510     # . check-ints-equal(eax - table, 20, msg)
+1511     # . . push args
+1512     68/push  "F - test-get-or-stop/0"/imm32
+1513     68/push  0x14/imm32
+1514     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+1515     50/push-eax
+1516     # . . call
+1517     e8/call  check-ints-equal/disp32
+1518     # . . discard args
+1519     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1520 $test-get-or-stop:failure:
+1521     # eax = get-or-stop(table, "data", row-size=12, msg, _test-error-buffered-file, ed)
+1522     # . . push args
+1523     52/push-edx/ed
+1524     68/push  _test-error-buffered-file/imm32
+1525     68/push  "foo"/imm32/abort-prefix
+1526     68/push  0xc/imm32/row-size
+1527     68/push  "data"/imm32
+1528     51/push-ecx
+1529     # . . call
+1530     e8/call  get-or-stop/disp32
+1531     # registers except esp may be clobbered at this point
+1532     # restore register args, discard others
+1533     59/pop-to-ecx
+1534     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+1535     5a/pop-to-edx
+1536 $test-get-or-stop:failure-assertion:
+1537     # check that get-or-stop tried to call stop(1)
+1538     # . check-ints-equal(ed->value, 2, msg)
+1539     # . . push args
+1540     68/push  "F - test-get-or-stop/1"/imm32
+1541     68/push  2/imm32
+1542     # . . push ed->value
+1543     ff          6/subop/push        1/mod/*+disp8   2/rm32/edx    .           .             .           .           4/disp8         .                 # push *(edx+4)
+1544     # . . call
+1545     e8/call  check-ints-equal/disp32
+1546     # . . discard args
+1547     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1548 $test-get-or-stop:end:
+1549     # . epilogue
+1550     # don't restore esp from ebp; manually reclaim locals
+1551     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x2c/imm32        # add to esp
+1552     5d/pop-to-ebp
+1553     c3/return
+1554 
+1555 # if no row is found, stop(ed)
+1556 get-slice-or-stop:  # table: (addr stream {(handle array byte), _}), key: (addr slice), row-size: int,
+1557                     # abort-message-prefix: (addr string), err: (addr buffered-file), ed: (addr exit-descriptor)
+1558                     # -> eax: (addr _)
+1559     # pseudocode:
+1560     #   curr = table->data
+1561     #   max = &table->data[table->write]
+1562     #   while curr < max
+1563     #     var c: (addr array byte) = lookup(*curr)
+1564     #     if slice-equal?(key, c)
+1565     #       return curr+8
+1566     #     curr += row-size
+1567     #   write-buffered(err, msg)
+1568     #   stop(ed)
+1569     #
+1570     # . prologue
+1571     55/push-ebp
+1572     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1573     # . save registers
+1574     51/push-ecx
+1575     52/push-edx
+1576     56/push-esi
+1577     # esi = table
+1578     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+1579     # var curr/ecx: (addr handle array byte) = table->data
+1580     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy esi+12 to ecx
+1581     # var max/edx: (addr byte) = &table->data[table->write]
+1582     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
+1583     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ecx  2/index/edx   .           2/r32/edx   .               .                 # copy ecx+edx to edx
+1584 $get-slice-or-stop:search-loop:
+1585     # if (curr >= max) stop(ed)
+1586     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
+1587     73/jump-if-addr>=  $get-slice-or-stop:stop/disp8
+1588     # var c/eax: (addr array byte) = lookup(*curr)
+1589     # . . push args
+1590     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+1591     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+1592     # . . call
+1593     e8/call  lookup/disp32
+1594     # . . discard args
+1595     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1596     # if (slice-equal?(key, c)) return curr+4
+1597     # . eax = slice-equal?(key, c)
+1598     # . . push args
+1599     50/push-eax
+1600     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+1601     # . . call
+1602     e8/call  slice-equal?/disp32
+1603     # . . discard args
+1604     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1605     # . if (eax != false) return eax = curr+8
+1606     3d/compare-eax-and  0/imm32/false
+1607     74/jump-if-=  $get-slice-or-stop:mismatch/disp8
+1608     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   8/disp8         .                 # copy ecx+8 to eax
+1609     eb/jump  $get-slice-or-stop:end/disp8
+1610 $get-slice-or-stop:mismatch:
+1611     # curr += row-size
+1612     03/add                          1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8      .                 # add *(ebp+16) to ecx
+1613     # loop
+1614     eb/jump  $get-slice-or-stop:search-loop/disp8
+1615 $get-slice-or-stop:end:
+1616     # . restore registers
+1617     5e/pop-to-esi
+1618     5a/pop-to-edx
+1619     59/pop-to-ecx
+1620     # . epilogue
+1621     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1622     5d/pop-to-ebp
+1623     c3/return
+1624 
+1625 $get-slice-or-stop:stop:
+1626     # . write-buffered(err, abort-message-prefix)
+1627     # . . push args
+1628     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
+1629     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
+1630     # . . call
+1631     e8/call  write-buffered/disp32
+1632     # . . discard args
+1633     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1634     # . write-buffered(err, error)
+1635     # . . push args
+1636     68/push  ": get-slice-or-stop: key not found: "/imm32
+1637     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
+1638     # . . call
+1639     e8/call  write-buffered/disp32
+1640     # . . discard args
+1641     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1642     # . write-slice-buffered(err, key)
+1643     # . . push args
+1644     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+1645     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
+1646     # . . call
+1647     e8/call  write-slice-buffered/disp32
+1648     # . . discard args
+1649     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1650     # . write-buffered(err, "\n")
+1651     # . . push args
+1652     68/push  Newline/imm32
+1653     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
 1654     # . . call
-1655     e8/call  check-strings-equal/disp32
+1655     e8/call  write-buffered/disp32
 1656     # . . discard args
-1657     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1658 $test-maybe-get-slice:failure:
-1659     # - search for a new key
-1660     # (eax..edx) = "data"
-1661     b8/copy-to-eax  "data"/imm32
-1662     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           2/r32/edx   .               .                 # copy *eax to edx
-1663     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  2/index/edx   .           2/r32/edx   4/disp8         .                 # copy eax+edx+4 to edx
-1664     05/add-to-eax  4/imm32
-1665     # var slice/edx: slice = {eax, edx}
-1666     52/push-edx
-1667     50/push-eax
-1668     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
-1669     # eax = maybe-get-slice(table, "data" slice, 8 bytes per row)
-1670     # . . push args
-1671     68/push  8/imm32/row-size
-1672     52/push-edx
-1673     51/push-ecx
-1674     # . . call
-1675     e8/call  maybe-get-slice/disp32
-1676     # . . discard args
-1677     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1678     # check-ints-equal(eax, 0, msg)
+1657     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1658     # . stop(ed, 1)
+1659     # . . push args
+1660     68/push  1/imm32
+1661     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x1c/disp8      .                 # push *(ebp+28)
+1662     # . . call
+1663     e8/call  stop/disp32
+1664     # never gets here
+1665 $get-slice-or-stop:terminus:
+1666     # . . discard args
+1667     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1668     # syscall(exit, 1)
+1669     b8/copy-to-eax  1/imm32/exit
+1670     cd/syscall  0x80/imm8
+1671 
+1672 test-get-slice-or-stop:
+1673     # This test uses exit-descriptors. Use ebp for setting up local variables.
+1674     # . prologue
+1675     55/push-ebp
+1676     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1677     # setup
+1678     # . clear-stream(_test-error-stream)
 1679     # . . push args
-1680     68/push  "F - test-maybe-get-slice/3"/imm32
-1681     68/push  0/imm32
-1682     50/push-eax
-1683     # . . call
-1684     e8/call  check-ints-equal/disp32
-1685     # . . discard args
-1686     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-1687 $test-maybe-get-slice:end:
-1688     # . epilogue
-1689     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-1690     5d/pop-to-ebp
-1691     c3/return
-1692 
-1693 # . . vim:nowrap:textwidth=0
+1680     68/push  _test-error-stream/imm32
+1681     # . . call
+1682     e8/call  clear-stream/disp32
+1683     # . . discard args
+1684     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1685     # . clear-stream($_test-error-buffered-file->buffer)
+1686     # . . push args
+1687     68/push  $_test-error-buffered-file->buffer/imm32
+1688     # . . call
+1689     e8/call  clear-stream/disp32
+1690     # . . discard args
+1691     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1692     # var table/ecx: (stream {string, number} 24)  # 2 rows * 12 bytes/row
+1693     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x18/imm32        # subtract from esp
+1694     68/push  0x18/imm32/size
+1695     68/push  0/imm32/read
+1696     68/push  0/imm32/write
+1697     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+1698     # var ed/edx: exit-descriptor
+1699     68/push  0/imm32
+1700     68/push  0/imm32
+1701     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
+1702     # var slice/ebx: slice = "code"
+1703     # . (eax..ebx) = "code"
+1704     b8/copy-to-eax  "code"/imm32
+1705     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # copy *eax to ebx
+1706     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  3/index/ebx   .           3/r32/ebx   4/disp8         .                 # copy eax+ebx+4 to ebx
+1707     05/add-to-eax  4/imm32
+1708     # . ebx = {eax, ebx}
+1709     53/push-ebx
+1710     50/push-eax
+1711     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           4/r32/esp   .               .                 # copy esp to ebx
+1712     # size 'ed' for the calls to 'get-or-stop' (define no locals past this point)
+1713     # . tailor-exit-descriptor(ed, 24)
+1714     # . . push args
+1715     68/push  0x18/imm32/nbytes-of-args-for-get-or-stop
+1716     52/push-edx
+1717     # . . call
+1718     e8/call  tailor-exit-descriptor/disp32
+1719     # . . discard args
+1720     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1721     # insert(table, "code", 12 bytes/row, Heap)
+1722     # . . push args
+1723     68/push  Heap/imm32
+1724     68/push  0xc/imm32/row-size
+1725     68/push  "code"/imm32
+1726     51/push-ecx
+1727     # . . call
+1728     e8/call  get-or-insert/disp32
+1729     # . . discard args
+1730     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+1731 $test-get-slice-or-stop:success:
+1732     # eax = get-slice-or-stop(table, slice, row-size=12, msg, _test-error-buffered-file, ed)
+1733     # . . push args
+1734     52/push-edx/ed
+1735     68/push  _test-error-buffered-file/imm32
+1736     68/push  "foo"/imm32/abort-prefix
+1737     68/push  0xc/imm32/row-size
+1738     53/push-ebx/slice
+1739     51/push-ecx
+1740     # . . call
+1741     e8/call  get-slice-or-stop/disp32
+1742     # registers except esp may be clobbered at this point
+1743     # restore register args, discard others
+1744     59/pop-to-ecx
+1745     5b/pop-to-ebx
+1746     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1747     5a/pop-to-edx
+1748 $test-get-slice-or-stop:success-assertion:
+1749     # check-ints-equal(eax - table->data, 8, msg)  # first row's value slot returned
+1750     # . check-ints-equal(eax - table, 20, msg)
+1751     # . . push args
+1752     68/push  "F - test-get-slice-or-stop/0"/imm32
+1753     68/push  0x14/imm32
+1754     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+1755     50/push-eax
+1756     # . . call
+1757     e8/call  check-ints-equal/disp32
+1758     # . . discard args
+1759     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1760 $test-get-slice-or-stop:failure:
+1761     # slice = "segment2"
+1762     # . *ebx = "segment2"->data
+1763     b8/copy-to-eax  "segment2"/imm32
+1764     05/add-to-eax  4/imm32
+1765     89/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to *ebx
+1766     # . *(ebx+4) = "segment2"->data + len("segment2")
+1767     05/add-to-eax  8/imm32/strlen
+1768     89/copy                         1/mod/*+disp8   3/rm32/ebx    .           .             .           0/r32/eax   4/disp8         .                 # copy eax to *(ebx+4)
+1769     # eax = get-slice-or-stop(table, slice, row-size=12, msg, _test-error-buffered-file, ed)
+1770     # . . push args
+1771     52/push-edx/ed
+1772     68/push  _test-error-buffered-file/imm32
+1773     68/push  "foo"/imm32/abort-prefix
+1774     68/push  0xc/imm32/row-size
+1775     53/push-ebx/slice
+1776     51/push-ecx
+1777     # . . call
+1778     e8/call  get-slice-or-stop/disp32
+1779     # registers except esp may be clobbered at this point
+1780     # restore register args, discard others
+1781     59/pop-to-ecx
+1782     5b/pop-to-ebx
+1783     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1784     5a/pop-to-edx
+1785 $test-get-slice-or-stop:failure-assertion:
+1786     # check that get-or-stop tried to call stop(1)
+1787     # . check-ints-equal(ed->value, 2, msg)
+1788     # . . push args
+1789     68/push  "F - test-get-or-stop/1"/imm32
+1790     68/push  2/imm32
+1791     # . . push ed->value
+1792     ff          6/subop/push        1/mod/*+disp8   2/rm32/edx    .           .             .           .           4/disp8         .                 # push *(edx+4)
+1793     # . . call
+1794     e8/call  check-ints-equal/disp32
+1795     # . . discard args
+1796     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1797 $test-get-slice-or-stop:end:
+1798     # . epilogue
+1799     # don't restore esp from ebp; manually reclaim locals
+1800     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x34/imm32        # add to esp
+1801     5d/pop-to-ebp
+1802     c3/return
+1803 
+1804 # if no row is found, return null (0)
+1805 maybe-get:  # table: (addr stream {(handle array byte), T}), key: (addr array byte), row-size: int -> eax: (addr T)
+1806     # pseudocode:
+1807     #   curr = table->data
+1808     #   max = &table->data[table->write]
+1809     #   while curr < max
+1810     #     var c: (addr array byte) = lookup(*curr)
+1811     #     if string-equal?(key, c)
+1812     #       return curr+8
+1813     #     curr += row-size
+1814     #   return 0
+1815     #
+1816     # . prologue
+1817     55/push-ebp
+1818     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1819     # . save registers
+1820     51/push-ecx
+1821     52/push-edx
+1822     56/push-esi
+1823     # esi = table
+1824     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+1825     # var curr/ecx: (addr handle array byte) = table->data
+1826     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy esi+12 to ecx
+1827     # var max/edx: (addr byte) = &table->data[table->write]
+1828     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
+1829     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ecx  2/index/edx   .           2/r32/edx   .               .                 # copy ecx+edx to edx
+1830 $maybe-get:search-loop:
+1831     # if (curr >= max) return null
+1832     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
+1833     73/jump-if-addr>=  $maybe-get:null/disp8
+1834     # var c/eax: (addr array byte) = lookup(*curr)
+1835     # . . push args
+1836     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+1837     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+1838     # . . call
+1839     e8/call  lookup/disp32
+1840     # . . discard args
+1841     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1842     # if (string-equal?(key, c)) return curr+4
+1843     # . eax = string-equal?(key, c)
+1844     # . . push args
+1845     50/push-eax
+1846     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+1847     # . . call
+1848     e8/call  string-equal?/disp32
+1849     # . . discard args
+1850     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1851     # . if (eax != false) return eax = curr+8
+1852     3d/compare-eax-and  0/imm32/false
+1853     74/jump-if-=  $maybe-get:mismatch/disp8
+1854     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   8/disp8         .                 # copy ecx+8 to eax
+1855     eb/jump  $maybe-get:end/disp8
+1856 $maybe-get:mismatch:
+1857     # curr += row-size
+1858     03/add                          1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8      .                 # add *(ebp+16) to ecx
+1859     # loop
+1860     eb/jump  $maybe-get:search-loop/disp8
+1861 $maybe-get:null:
+1862     b8/copy-to-eax  0/imm32
+1863 $maybe-get:end:
+1864     # . restore registers
+1865     5e/pop-to-esi
+1866     5a/pop-to-edx
+1867     59/pop-to-ecx
+1868     # . epilogue
+1869     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1870     5d/pop-to-ebp
+1871     c3/return
+1872 
+1873 test-maybe-get:
+1874     # . prologue
+1875     55/push-ebp
+1876     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1877     # - setup: create a table with one row
+1878     # var table/ecx: (stream {string, number} 24)   # 2 rows * 12 bytes/row
+1879     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x18/imm32        # subtract from esp
+1880     68/push  0x18/imm32/size
+1881     68/push  0/imm32/read
+1882     68/push  0/imm32/write
+1883     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+1884     # eax = get-or-insert(table, "code", 12 bytes/row, Heap)
+1885     # . . push args
+1886     68/push  Heap/imm32
+1887     68/push  0xc/imm32/row-size
+1888     68/push  "code"/imm32
+1889     51/push-ecx
+1890     # . . call
+1891     e8/call  get-or-insert/disp32
+1892     # . . discard args
+1893     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+1894 $test-maybe-get:success:
+1895     # - check for the same key, verify that it was reused
+1896     # eax = maybe-get(table, "code", 12 bytes/row)
+1897     # . . push args
+1898     68/push  0xc/imm32/row-size
+1899     68/push  "code"/imm32
+1900     51/push-ecx
+1901     # . . call
+1902     e8/call  maybe-get/disp32
+1903     # . . discard args
+1904     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1905     # check-ints-equal(eax - table->data, 8, msg)
+1906     # . check-ints-equal(eax - table, 20, msg)
+1907     # . . push args
+1908     68/push  "F - test-maybe-get/0"/imm32
+1909     68/push  0x14/imm32
+1910     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+1911     50/push-eax
+1912     # . . call
+1913     e8/call  check-ints-equal/disp32
+1914     # . . discard args
+1915     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1916     # no new row inserted
+1917     # . check-ints-equal(table->write, row-size = 12, msg)
+1918     # . . push args
+1919     68/push  "F - test-maybe-get/1"/imm32
+1920     68/push  0xc/imm32/row-size
+1921     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+1922     # . . call
+1923     e8/call  check-ints-equal/disp32
+1924     # . . discard args
+1925     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1926     # var curr-addr/eax: (addr array byte) = lookup(table->data)
+1927     # . . push args
+1928     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0x10/disp8      .                 # push *(ecx+16)
+1929     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0xc/disp8       .                 # push *(ecx+12)
+1930     # . . call
+1931     e8/call  lookup/disp32
+1932     # . . discard args
+1933     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1934     # check-strings-equal(curr-addr, "code", msg)
+1935     # . . push args
+1936     68/push  "F - test-maybe-get/2"/imm32
+1937     68/push  "code"/imm32
+1938     50/push-eax
+1939     # . . call
+1940     e8/call  check-strings-equal/disp32
+1941     # . . discard args
+1942     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1943 $test-maybe-get:failure:
+1944     # - search for a new key
+1945     # eax = maybe-get(table, "data", 12 bytes/row)
+1946     # . . push args
+1947     68/push  0xc/imm32/row-size
+1948     68/push  "data"/imm32
+1949     51/push-ecx
+1950     # . . call
+1951     e8/call  maybe-get/disp32
+1952     # . . discard args
+1953     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1954     # check-ints-equal(eax, 0, msg)
+1955     # . . push args
+1956     68/push  "F - test-maybe-get/3"/imm32
+1957     68/push  0/imm32
+1958     50/push-eax
+1959     # . . call
+1960     e8/call  check-ints-equal/disp32
+1961     # . . discard args
+1962     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1963 $test-maybe-get:end:
+1964     # . epilogue
+1965     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1966     5d/pop-to-ebp
+1967     c3/return
+1968 
+1969 # if no row is found, return null (0)
+1970 maybe-get-slice:  # table: (addr stream {(handle array byte), T}), key: (addr slice), row-size: int -> eax: (addr T)
+1971     # pseudocode:
+1972     #   curr = table->data
+1973     #   max = &table->data[table->write]
+1974     #   while curr < max
+1975     #     var c: (addr array byte) = lookup(*curr)
+1976     #     if slice-equal?(key, c)
+1977     #       return curr+8
+1978     #     curr += row-size
+1979     #   return 0
+1980     #
+1981     # . prologue
+1982     55/push-ebp
+1983     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1984     # . save registers
+1985     51/push-ecx
+1986     52/push-edx
+1987     56/push-esi
+1988     # esi = table
+1989     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+1990     # var curr/ecx: (addr handle array byte) = table->data
+1991     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy esi+12 to ecx
+1992     # var max/edx: (addr byte) = &table->data[table->write]
+1993     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
+1994     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ecx  2/index/edx   .           2/r32/edx   .               .                 # copy ecx+edx to edx
+1995 $maybe-get-slice:search-loop:
+1996     # if (curr >= max) return null
+1997     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
+1998     73/jump-if-addr>=  $maybe-get-slice:null/disp8
+1999     # var c/eax: (addr array byte) = lookup(*curr)
+2000     # . . push args
+2001     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+2002     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+2003     # . . call
+2004     e8/call  lookup/disp32
+2005     # . . discard args
+2006     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+2007     # if (slice-equal?(key, c)) return curr+4
+2008     # . eax = slice-equal?(key, c)
+2009     # . . push args
+2010     50/push-eax
+2011     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+2012     # . . call
+2013     e8/call  slice-equal?/disp32
+2014     # . . discard args
+2015     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+2016     # . if (eax != false) return eax = curr+8
+2017     3d/compare-eax-and  0/imm32/false
+2018     74/jump-if-=  $maybe-get-slice:mismatch/disp8
+2019     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   8/disp8         .                 # copy ecx+8 to eax
+2020     eb/jump  $maybe-get-slice:end/disp8
+2021 $maybe-get-slice:mismatch:
+2022     # curr += row-size
+2023     03/add                          1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8      .                 # add *(ebp+16) to ecx
+2024     # loop
+2025     eb/jump  $maybe-get-slice:search-loop/disp8
+2026 $maybe-get-slice:null:
+2027     b8/copy-to-eax  0/imm32
+2028 $maybe-get-slice:end:
+2029     # . restore registers
+2030     5e/pop-to-esi
+2031     5a/pop-to-edx
+2032     59/pop-to-ecx
+2033     # . epilogue
+2034     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+2035     5d/pop-to-ebp
+2036     c3/return
+2037 
+2038 test-maybe-get-slice:
+2039     # . prologue
+2040     55/push-ebp
+2041     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+2042     # - setup: create a table with one row
+2043     # var table/ecx: (stream {string, number} 24)   # 2 rows * 12 bytes/row
+2044     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x18/imm32        # subtract from esp
+2045     68/push  0x18/imm32/size
+2046     68/push  0/imm32/read
+2047     68/push  0/imm32/write
+2048     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+2049     # insert(table, "code", 12 bytes/row, Heap)
+2050     # . . push args
+2051     68/push  Heap/imm32
+2052     68/push  0xc/imm32/row-size
+2053     68/push  "code"/imm32
+2054     51/push-ecx
+2055     # . . call
+2056     e8/call  get-or-insert/disp32
+2057     # . . discard args
+2058     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+2059 $test-maybe-get-slice:success:
+2060     # - check for the same key, verify that it was reused
+2061     # (eax..edx) = "code"
+2062     b8/copy-to-eax  "code"/imm32
+2063     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           2/r32/edx   .               .                 # copy *eax to edx
+2064     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  2/index/edx   .           2/r32/edx   4/disp8         .                 # copy eax+edx+4 to edx
+2065     05/add-to-eax  4/imm32
+2066     # var slice/edx: slice = {eax, edx}
+2067     52/push-edx
+2068     50/push-eax
+2069     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
+2070     # eax = maybe-get-slice(table, "code" slice, 12 bytes/row)
+2071     # . . push args
+2072     68/push  0xc/imm32/row-size
+2073     52/push-edx
+2074     51/push-ecx
+2075     # . . call
+2076     e8/call  maybe-get-slice/disp32
+2077     # . . discard args
+2078     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+2079     # check-ints-equal(eax - table->data, 8, msg)
+2080     # . check-ints-equal(eax - table, 20, msg)
+2081     # . . push args
+2082     68/push  "F - test-maybe-get-slice/0"/imm32
+2083     68/push  0x14/imm32
+2084     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+2085     50/push-eax
+2086     # . . call
+2087     e8/call  check-ints-equal/disp32
+2088     # . . discard args
+2089     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+2090     # no new row inserted
+2091     # . check-ints-equal(table->write, row-size = 12, msg)
+2092     # . . push args
+2093     68/push  "F - test-maybe-get-slice/1"/imm32
+2094     68/push  0xc/imm32/row-size
+2095     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+2096     # . . call
+2097     e8/call  check-ints-equal/disp32
+2098     # . . discard args
+2099     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+2100     # var curr-addr/eax: (addr array byte) = lookup(table->data)
+2101     # . . push args
+2102     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0x10/disp8      .                 # push *(ecx+16)
+2103     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           0xc/disp8       .                 # push *(ecx+12)
+2104     # . . call
+2105     e8/call  lookup/disp32
+2106     # . . discard args
+2107     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+2108     # check-strings-equal(curr-addr, "code", msg)
+2109     # . . push args
+2110     68/push  "F - test-maybe-get-slice/2"/imm32
+2111     68/push  "code"/imm32
+2112     50/push-eax
+2113     # . . call
+2114     e8/call  check-strings-equal/disp32
+2115     # . . discard args
+2116     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+2117 $test-maybe-get-slice:failure:
+2118     # - search for a new key
+2119     # (eax..edx) = "data"
+2120     b8/copy-to-eax  "data"/imm32
+2121     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           2/r32/edx   .               .                 # copy *eax to edx
+2122     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  2/index/edx   .           2/r32/edx   4/disp8         .                 # copy eax+edx+4 to edx
+2123     05/add-to-eax  4/imm32
+2124     # var slice/edx: slice = {eax, edx}
+2125     52/push-edx
+2126     50/push-eax
+2127     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
+2128     # eax = maybe-get-slice(table, "data" slice, 12 bytes/row)
+2129     # . . push args
+2130     68/push  0xc/imm32/row-size
+2131     52/push-edx
+2132     51/push-ecx
+2133     # . . call
+2134     e8/call  maybe-get-slice/disp32
+2135     # . . discard args
+2136     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+2137     # check-ints-equal(eax, 0, msg)
+2138     # . . push args
+2139     68/push  "F - test-maybe-get-slice/3"/imm32
+2140     68/push  0/imm32
+2141     50/push-eax
+2142     # . . call
+2143     e8/call  check-ints-equal/disp32
+2144     # . . discard args
+2145     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+2146 $test-maybe-get-slice:end:
+2147     # . epilogue
+2148     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+2149     5d/pop-to-ebp
+2150     c3/return
+2151 
+2152 # . . vim:nowrap:textwidth=0
 
diff --git a/html/082slurp.subx.html b/html/082slurp.subx.html index b182707c..843f0258 100644 --- a/html/082slurp.subx.html +++ b/html/082slurp.subx.html @@ -16,12 +16,12 @@ a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } .subxS2Comment { color: #8a8a8a; } +.subxTest { color: #5f8700; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } .subxS1Comment { color: #0000af; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .Constant { color: #008787; } -.subxTest { color: #5f8700; } --> @@ -67,7 +67,7 @@ if ('onhashchange' in window) { 8 slurp: # f: (addr buffered-file), s: (addr stream byte) 9 # pseudocode: 10 # while true - 11 # if (s->write >= s->length) abort + 11 # if (s->write >= s->size) abort 12 # if (f->read >= f->write) populate stream from file 13 # if (f->write == 0) break 14 # AL = f->data[f->read] @@ -92,7 +92,7 @@ if ('onhashchange' in window) { 33 # edx = s->write 34 8b/copy 0/mod/indirect 7/rm32/edi . . . 2/r32/edx . . # copy *edi to edx 35 $slurp:loop: - 36 # if (s->write >= s->length) abort + 36 # if (s->write >= s->size) abort 37 3b/compare 1/mod/*+disp8 7/rm32/edi . . . 2/r32/edx 8/disp8 . # compare edx with *(edi+8) 38 7d/jump-if->= $slurp:abort/disp8 39 # if (f->read >= f->write) populate stream from file diff --git a/html/083subx-widths.subx.html b/html/083subx-widths.subx.html index 5b219d66..84fde806 100644 --- a/html/083subx-widths.subx.html +++ b/html/083subx-widths.subx.html @@ -16,12 +16,12 @@ a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } .subxS2Comment { color: #8a8a8a; } +.subxTest { color: #5f8700; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } .subxS1Comment { color: #0000af; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .Constant { color: #008787; } -.subxTest { color: #5f8700; } --> @@ -75,7 +75,7 @@ if ('onhashchange' in window) { 16 51/push-ecx 17 # eax = word 18 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to ecx - 19 # var ecx: (addr byte) = &word[word->length] + 19 # var ecx: (addr byte) = &word[word->size] 20 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 21 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 22 # eax = word->data diff --git a/html/084emit-hex-array.subx.html b/html/084emit-hex-array.subx.html index 22af54c8..288edd92 100644 --- a/html/084emit-hex-array.subx.html +++ b/html/084emit-hex-array.subx.html @@ -16,13 +16,13 @@ a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } .subxS2Comment { color: #8a8a8a; } +.subxTest { color: #5f8700; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } .subxS1Comment { color: #0000af; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .Folded { color: #080808; background-color: #949494; } .Constant { color: #008787; } -.subxTest { color: #5f8700; } --> @@ -79,7 +79,7 @@ if ('onhashchange' in window) { 19 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx 20 # var curr/ecx: (addr byte) = arr->data 21 8d/copy-address 1/mod/*+disp8 2/rm32/edx . . . 1/r32/ecx 4/disp8 . # copy edx+4 to ecx - 22 # var max/edx: (addr byte) = &arr->data[arr->length] + 22 # var max/edx: (addr byte) = &arr->data[arr->size] 23 8b/copy 0/mod/indirect 2/rm32/edx . . . 2/r32/edx . . # copy *edx to edx 24 01/add 3/mod/direct 2/rm32/edx . . . 1/r32/ecx . . # add ecx to edx 25 # var c/eax: byte = 0 @@ -133,7 +133,7 @@ if ('onhashchange' in window) { 73 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 74 # var arr/ecx (array byte) = [01, 02, 03] 75 68/push 0x00030201/imm32 # bytes 01 02 03 - 76 68/push 3/imm32/length + 76 68/push 3/imm32/size 77 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 78 # emit-hex-array(_test-output-buffered-file, arr) 79 # . . push args diff --git a/html/085next-word-or-string.subx.html b/html/085next-word-or-string.subx.html index ecb3d241..5b4b089c 100644 --- a/html/085next-word-or-string.subx.html +++ b/html/085next-word-or-string.subx.html @@ -16,12 +16,12 @@ a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } .subxS2Comment { color: #8a8a8a; } +.subxTest { color: #5f8700; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } .subxS1Comment { color: #0000af; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .Constant { color: #008787; } -.subxTest { color: #5f8700; } --> diff --git a/html/090register-names.subx.html b/html/090register-names.subx.html index 46e18826..510dbe76 100644 --- a/html/090register-names.subx.html +++ b/html/090register-names.subx.html @@ -53,21 +53,112 @@ if ('onhashchange' in window) { https://github.com/akkartik/mu/blob/master/090register-names.subx
- 1 == data
- 2 Registers:  # (table string int)
- 3   # a table is a stream
- 4   0x40/imm32/write
- 5   0/imm32/read
- 6   0x40/imm32/length
- 7   # data
- 8   "eax"/imm32  0/imm32
- 9   "ecx"/imm32  1/imm32
-10   "edx"/imm32  2/imm32
-11   "ebx"/imm32  3/imm32
-12   "esp"/imm32  4/imm32
-13   "ebp"/imm32  5/imm32
-14   "esi"/imm32  6/imm32
-15   "edi"/imm32  7/imm32
+  1 == data
+  2 Registers:  # (addr stream {(handle array byte), int})
+  3   # a table is a stream
+  4   0xc0/imm32/write
+  5   0/imm32/read
+  6   0xc0/imm32/length
+  7   # data
+  8   # it is perfectly ok to use fake alloc-ids -- as long as you never try to reclaim them
+  9   0x11/imm32/alloc-id $Register-eax/imm32 0/imm32
+ 10   0x11/imm32/alloc-id $Register-ecx/imm32 1/imm32
+ 11   0x11/imm32/alloc-id $Register-edx/imm32 2/imm32
+ 12   0x11/imm32/alloc-id $Register-ebx/imm32 3/imm32
+ 13   0x11/imm32/alloc-id $Register-esp/imm32 4/imm32
+ 14   0x11/imm32/alloc-id $Register-ebp/imm32 5/imm32
+ 15   0x11/imm32/alloc-id $Register-esi/imm32 6/imm32
+ 16   0x11/imm32/alloc-id $Register-edi/imm32 7/imm32
+ 17   # for 8-byte registers
+ 18   # we don't actually check if these are used when they should be; be careful
+ 19   0x11/imm32/alloc-id $Register-al/imm32 0/imm32
+ 20   0x11/imm32/alloc-id $Register-cl/imm32 1/imm32
+ 21   0x11/imm32/alloc-id $Register-dl/imm32 2/imm32
+ 22   0x11/imm32/alloc-id $Register-bl/imm32 3/imm32
+ 23   0x11/imm32/alloc-id $Register-ah/imm32 4/imm32
+ 24   0x11/imm32/alloc-id $Register-ch/imm32 5/imm32
+ 25   0x11/imm32/alloc-id $Register-dh/imm32 6/imm32
+ 26   0x11/imm32/alloc-id $Register-bh/imm32 7/imm32
+ 27 
+ 28 $Register-eax:
+ 29   0x11/imm32/alloc-id
+ 30   3/imm32/size
+ 31   0x65/e 0x61/a 0x78/x
+ 32 
+ 33 $Register-ecx:
+ 34   0x11/imm32/alloc-id
+ 35   3/imm32/size
+ 36   0x65/e 0x63/c 0x78/x
+ 37 
+ 38 $Register-edx:
+ 39   0x11/imm32/alloc-id
+ 40   3/imm32/size
+ 41   0x65/e 0x64/d 0x78/x
+ 42 
+ 43 $Register-ebx:
+ 44   0x11/imm32/alloc-id
+ 45   3/imm32/size
+ 46   0x65/e 0x62/b 0x78/x
+ 47 
+ 48 $Register-esp:
+ 49   0x11/imm32/alloc-id
+ 50   3/imm32/size
+ 51   0x65/e 0x73/s 0x70/p
+ 52 
+ 53 $Register-ebp:
+ 54   0x11/imm32/alloc-id
+ 55   3/imm32/size
+ 56   0x65/e 0x62/b 0x70/p
+ 57 
+ 58 $Register-esi:
+ 59   0x11/imm32/alloc-id
+ 60   3/imm32/size
+ 61   0x65/e 0x73/s 0x69/i
+ 62 
+ 63 $Register-edi:
+ 64   0x11/imm32/alloc-id
+ 65   3/imm32/size
+ 66   0x65/e 0x64/d 0x69/i
+ 67 
+ 68 $Register-al:
+ 69   0x11/imm32/alloc-id
+ 70   2/imm32/size
+ 71   0x61/a 0x6c/l
+ 72 
+ 73 $Register-cl:
+ 74   0x11/imm32/alloc-id
+ 75   2/imm32/size
+ 76   0x63/c 0x6c/l
+ 77 
+ 78 $Register-dl:
+ 79   0x11/imm32/alloc-id
+ 80   2/imm32/size
+ 81   0x64/d 0x6c/l
+ 82 
+ 83 $Register-bl:
+ 84   0x11/imm32/alloc-id
+ 85   2/imm32/size
+ 86   0x62/b 0x6c/l
+ 87 
+ 88 $Register-ah:
+ 89   0x11/imm32/alloc-id
+ 90   2/imm32/size
+ 91   0x61/a 0x68/h
+ 92 
+ 93 $Register-ch:
+ 94   0x11/imm32/alloc-id
+ 95   2/imm32/size
+ 96   0x63/c 0x68/h
+ 97 
+ 98 $Register-dh:
+ 99   0x11/imm32/alloc-id
+100   2/imm32/size
+101   0x64/d 0x68/h
+102 
+103 $Register-bh:
+104   0x11/imm32/alloc-id
+105   2/imm32/size
+106   0x62/b 0x68/h
 
diff --git a/html/091write-int.subx.html b/html/091write-int.subx.html index da0c18a9..476927ee 100644 --- a/html/091write-int.subx.html +++ b/html/091write-int.subx.html @@ -16,13 +16,13 @@ a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } .subxS2Comment { color: #8a8a8a; } +.subxTest { color: #5f8700; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } .subxS1Comment { color: #0000af; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxH1Comment { color: #005faf; text-decoration: underline; } .Constant { color: #008787; } -.subxTest { color: #5f8700; } +.subxH1Comment { color: #005faf; text-decoration: underline; } --> @@ -77,7 +77,7 @@ if ('onhashchange' in window) { 17 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 8/disp8 . # copy *(ebp+8) to edi 18 # ecx = out->write 19 8b/copy 0/mod/indirect 7/rm32/edi . . . 1/r32/ecx . . # copy *edi to ecx - 20 # if (out->write >= out->length) abort + 20 # if (out->write >= out->size) abort 21 3b/compare 1/mod/*+disp8 7/rm32/edi . . . 1/r32/ecx 8/disp8 . # compare ecx with *(edi+8) 22 7d/jump-if->= $write-int:abort/disp8 23 $write-int:to-stream: diff --git a/html/092stack.subx.html b/html/092stack.subx.html index 4ccbbe55..7fa5461a 100644 --- a/html/092stack.subx.html +++ b/html/092stack.subx.html @@ -16,13 +16,13 @@ a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } .subxS2Comment { color: #8a8a8a; } -.LineNr { } -.SpecialChar { color: #d70000; } -.subxS1Comment { color: #0000af; } +.subxTest { color: #5f8700; } .subxFunction { color: #af5f00; text-decoration: underline; } +.LineNr { } +.subxS1Comment { color: #0000af; } +.SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .Constant { color: #008787; } -.subxTest { color: #5f8700; } --> @@ -60,417 +60,423 @@ if ('onhashchange' in window) {
   1 # A stack looks like this:
   2 #   top: int
-  3 #   data: (array byte)  # prefixed by length as usual
-  4 
-  5 == code
-  6 #   instruction                     effective address                                                   register    displacement    immediate
-  7 # . op          subop               mod             rm32          base        index         scale       r32
-  8 # . 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
-  9 
- 10 clear-stack:  # s: (addr stack)
- 11     # . prologue
- 12     55/push-ebp
- 13     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 14     # . save registers
- 15     50/push-eax
- 16     51/push-ecx
- 17     # eax = s
- 18     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   8/disp8         .                 # copy *(ebp+8) to eax
- 19     # var max/ecx: (addr byte) = &s->data[s->length]
- 20     8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(eax+4) to eax
- 21     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   8/disp8         .                 # copy eax+ecx+8 to ecx
- 22     # s->top = 0
- 23     c7          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0/imm32           # copy to *eax
- 24     # var curr/eax: (addr byte) = s->data
- 25     81          0/subop/add         3/mod/direct    0/rm32/eax    .           .             .           .           .               8/imm32           # add to eax
- 26 $clear-stack:loop:
- 27     # if (curr >= max) break
- 28     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # compare eax with ecx
- 29     73/jump-if-addr>=  $clear-stack:end/disp8
- 30     # *curr = 0
- 31     c6          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0/imm8            # copy byte to *eax
- 32     # ++curr
- 33     40/increment-eax
- 34     eb/jump $clear-stack:loop/disp8
- 35 $clear-stack:end:
- 36     # . restore registers
- 37     59/pop-to-ecx
- 38     58/pop-to-eax
- 39     # . epilogue
- 40     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
- 41     5d/pop-to-ebp
- 42     c3/return
- 43 
- 44 test-clear-stack:
- 45     # . prologue
- 46     55/push-ebp
- 47     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 48     # var stack/ecx = stack of size 8 with random data in it
- 49     68/push 34/imm32
- 50     68/push 35/imm32
- 51     68/push 8/imm32/length
- 52     68/push 14/imm32/top
- 53     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
- 54     # clear(stack)
- 55     # . . push args
- 56     51/push-ecx
- 57     # . . call
- 58     e8/call  clear-stack/disp32
- 59     # . . discard args
- 60     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
- 61     # top should be 0
- 62     58/pop-to-eax
- 63     # . check-ints-equal(eax, 0, msg)
- 64     # . . push args
- 65     68/push  "F - test-clear-stack: top"/imm32
- 66     68/push  0/imm32
- 67     50/push-eax
- 68     # . . call
- 69     e8/call  check-ints-equal/disp32
- 70     # . . discard args
- 71     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 72     # length should remain 8
- 73     58/pop-to-eax
- 74     # . check-ints-equal(eax, 8, msg)
- 75     # . . push args
- 76     68/push  "F - test-clear-stack: length"/imm32
- 77     68/push  8/imm32
- 78     50/push-eax
- 79     # . . call
- 80     e8/call  check-ints-equal/disp32
- 81     # . . discard args
- 82     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 83     # first word is 0
- 84     58/pop-to-eax
- 85     # . check-ints-equal(eax, 0, msg)
- 86     # . . push args
- 87     68/push  "F - test-clear-stack: data[0..3]"/imm32
- 88     68/push  0/imm32
- 89     50/push-eax
- 90     # . . call
- 91     e8/call  check-ints-equal/disp32
- 92     # . . discard args
- 93     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
- 94     # second word is 0
- 95     58/pop-to-eax
- 96     # . check-ints-equal(eax, 0, msg)
- 97     # . . push args
- 98     68/push  "F - test-clear-stack: data[4..7]"/imm32
- 99     68/push  0/imm32
-100     50/push-eax
-101     # . . call
-102     e8/call  check-ints-equal/disp32
-103     # . . discard args
-104     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-105     # . epilogue
-106     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-107     5d/pop-to-ebp
-108     c3/return
-109 
-110 push:  # s: (addr stack), n: int
-111     # . prologue
-112     55/push-ebp
-113     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-114     # . save registers
-115     50/push-eax
-116     51/push-ecx
-117     56/push-esi
-118     # esi = s
-119     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
-120     # ecx = s->top
-121     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
-122     # if (s->top >= s->length) abort
-123     39/compare                      1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # compare *(esi+4) and ecx
-124     7e/jump-if-<=  $push:abort/disp8
-125     # s->data[s->top] = n
-126     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0xc/disp8       .                 # copy *(ebp+12) to eax
-127     89/copy                         1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/eax   8/disp8         .                 # copy eax to *(esi+ecx+8)
-128     # s->top += 4
-129     81          0/subop/add         0/mod/direct    6/rm32/esi    .           .             .           .           .               4/imm32           # subtract from *esi
-130 $push:end:
-131     # . restore registers
-132     5e/pop-to-esi
-133     59/pop-to-ecx
-134     58/pop-to-eax
-135     # . epilogue
-136     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-137     5d/pop-to-ebp
-138     c3/return
-139 
-140 $push:abort:
-141     # print(stderr, "error: push: no space left")
-142     # . write-buffered(Stderr, "error: push: no space left")
-143     # . . push args
-144     68/push  "error: push: no space left"/imm32
-145     68/push  Stderr/imm32
-146     # . . call
-147     e8/call  write-buffered/disp32
-148     # . . discard args
-149     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-150     # . flush(Stderr)
-151     # . . push args
-152     68/push  Stderr/imm32
-153     # . . call
-154     e8/call  flush/disp32
-155     # . . discard args
-156     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-157     # . syscall(exit, 1)
-158     bb/copy-to-ebx  1/imm32
-159     b8/copy-to-eax  1/imm32/exit
-160     cd/syscall  0x80/imm8
-161     # never gets here
-162 
-163 test-push:
-164     # . prologue
-165     55/push-ebp
-166     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-167     # var stack/ecx = empty stack of size 8
-168     68/push 0/imm32
-169     68/push 0/imm32
-170     68/push 8/imm32/length
-171     68/push 0/imm32/top
-172     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
-173     # push(stack, 0x42)
-174     # . . push args
-175     68/push  0x42/imm32
-176     51/push-ecx
-177     # . . call
-178     e8/call  push/disp32
-179     # . . discard args
-180     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-181     # check top
-182     58/pop-to-eax
-183     # . check-ints-equal(eax, 4, msg)
-184     # . . push args
-185     68/push  "F - test-push: top"/imm32
-186     68/push  4/imm32
-187     50/push-eax
-188     # . . call
-189     e8/call  check-ints-equal/disp32
-190     # . . discard args
-191     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-192     # check length
-193     58/pop-to-eax
-194     # . check-ints-equal(eax, 8, msg)
-195     # . . push args
-196     68/push  "F - test-push: length"/imm32
-197     68/push  8/imm32
-198     50/push-eax
-199     # . . call
-200     e8/call  check-ints-equal/disp32
-201     # . . discard args
-202     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-203     # first word is 0x42
-204     58/pop-to-eax
-205     # . check-ints-equal(eax, 0x42, msg)
-206     # . . push args
-207     68/push  "F - test-push: data[0..3]"/imm32
-208     68/push  0x42/imm32
-209     50/push-eax
-210     # . . call
-211     e8/call  check-ints-equal/disp32
-212     # . . discard args
-213     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-214     # second word is 0
-215     58/pop-to-eax
-216     # . check-ints-equal(eax, 0, msg)
-217     # . . push args
-218     68/push  "F - test-push: data[4..7]"/imm32
-219     68/push  0/imm32
-220     50/push-eax
-221     # . . call
-222     e8/call  check-ints-equal/disp32
-223     # . . discard args
-224     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-225     # . epilogue
-226     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-227     5d/pop-to-ebp
-228     c3/return
-229 
-230 pop:  # s: (addr stack) -> n/eax: int
-231     # . prologue
-232     55/push-ebp
-233     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-234     # . save registers
-235     51/push-ecx
-236     56/push-esi
-237     # esi = s
-238     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
-239     # if (s->top <= 0) abort
-240     81          7/subop/compare     0/mod/indirect  6/rm32/esi    .           .             .           .           .               0/imm32           # compare *esi
-241     7e/jump-if-<=  $pop:abort/disp8
-242     # s->top -= 4
-243     81          5/subop/subtract    0/mod/direct    6/rm32/esi    .           .             .           .           .               4/imm32           # subtract from *esi
-244     # eax = s->data[s->top]
-245     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
-246     8b/copy                         1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/eax   8/disp8         .                 # copy *(esi+ecx+8) to eax
-247     # s->data[s->top] = 0
-248     c7          0/subop/copy        1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/eax   8/disp8         0/imm32           # copy to *(esi+ecx+8)
-249 $pop:end:
-250     # . restore registers
-251     5e/pop-to-esi
-252     59/pop-to-ecx
-253     # . epilogue
-254     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-255     5d/pop-to-ebp
-256     c3/return
-257 
-258 $pop:abort:
-259     # print(stderr, "error: pop: nothing left in stack")
-260     # . write-buffered(Stderr, "error: pop: nothing left in stack")
-261     # . . push args
-262     68/push  "error: pop: nothing left in stack"/imm32
-263     68/push  Stderr/imm32
-264     # . . call
-265     e8/call  write-buffered/disp32
-266     # . . discard args
-267     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-268     # . flush(Stderr)
-269     # . . push args
-270     68/push  Stderr/imm32
-271     # . . call
-272     e8/call  flush/disp32
-273     # . . discard args
-274     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-275     # . syscall(exit, 1)
-276     bb/copy-to-ebx  1/imm32
-277     b8/copy-to-eax  1/imm32/exit
-278     cd/syscall  0x80/imm8
-279     # never gets here
-280 
-281 test-pop:
-282     # . prologue
-283     55/push-ebp
-284     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-285     # var stack/ecx = stack of size 8 containing just 0x42
-286     68/push 0/imm32
-287     68/push 0x42/imm32
-288     68/push 8/imm32/length
-289     68/push 4/imm32/top
-290     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
-291     # eax = pop(stack)
-292     # . . push args
-293     51/push-ecx
-294     # . . call
-295     e8/call  pop/disp32
-296     # . . discard args
-297     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-298     # check-ints-equal(eax, 0x42, msg)
-299     # . . push args
-300     68/push  "F - test-pop: result"/imm32
-301     68/push  0x42/imm32
-302     50/push-eax
-303     # . . call
-304     e8/call  check-ints-equal/disp32
-305     # . . discard args
-306     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-307     # check top
-308     58/pop-to-eax
-309     # . check-ints-equal(eax, 0, msg)
-310     # . . push args
-311     68/push  "F - test-pop: top"/imm32
-312     68/push  0/imm32
-313     50/push-eax
-314     # . . call
-315     e8/call  check-ints-equal/disp32
-316     # . . discard args
-317     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-318     # check length
-319     58/pop-to-eax
-320     # . check-ints-equal(eax, 8, msg)
-321     # . . push args
-322     68/push  "F - test-pop: length"/imm32
-323     68/push  8/imm32
-324     50/push-eax
-325     # . . call
-326     e8/call  check-ints-equal/disp32
-327     # . . discard args
-328     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-329     # . epilogue
-330     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-331     5d/pop-to-ebp
-332     c3/return
-333 
-334 top:  # s: (addr stack) -> n/eax: int
-335     # . prologue
-336     55/push-ebp
-337     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-338     # . save registers
-339     51/push-ecx
-340     56/push-esi
-341     # esi = s
-342     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
-343     # if (s->top <= 0) abort
-344     81          7/subop/compare     0/mod/indirect  6/rm32/esi    .           .             .           .           .               0/imm32           # compare *esi
-345     7e/jump-if-<=  $top:abort/disp8
-346     # n = s->data[s->top - 4]
-347     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
-348     81          5/subop/subtract    3/mod/direct    1/rm32/ecx    .           .             .           .           .               4/imm32           # subtract from ecx
-349     8b/copy                         1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/eax   8/disp8         .                 # copy *(esi+ecx+8) to eax
-350 $top:end:
-351     # . restore registers
-352     5e/pop-to-esi
-353     59/pop-to-ecx
-354     # . epilogue
-355     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-356     5d/pop-to-ebp
-357     c3/return
-358 
-359 $top:abort:
-360     # print(stderr, "error: top: nothing left in stack")
-361     # . write-buffered(Stderr, "error: top: nothing left in stack")
-362     # . . push args
-363     68/push  "error: top: nothing left in stack"/imm32
-364     68/push  Stderr/imm32
-365     # . . call
-366     e8/call  write-buffered/disp32
-367     # . . discard args
-368     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-369     # . flush(Stderr)
-370     # . . push args
-371     68/push  Stderr/imm32
-372     # . . call
-373     e8/call  flush/disp32
-374     # . . discard args
-375     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-376     # . syscall(exit, 1)
-377     bb/copy-to-ebx  1/imm32
-378     b8/copy-to-eax  1/imm32/exit
-379     cd/syscall  0x80/imm8
-380     # never gets here
-381 
-382 test-top:
-383     # . prologue
-384     55/push-ebp
-385     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-386     # var stack/ecx = stack of size 8 containing just 0x42
-387     68/push  0/imm32
-388     68/push  0x42/imm32
-389     68/push  8/imm32/length
-390     68/push  4/imm32/top
-391     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
-392     # eax = top(stack)
-393     # . . push args
-394     51/push-ecx
-395     # . . call
-396     e8/call  top/disp32
-397     # . . discard args
-398     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-399     # check-ints-equal(eax, 42, msg")
-400     # . . push args
-401     68/push  "F - test-top: result"/imm32
-402     68/push  0x42/imm32
-403     50/push-eax
-404     # . . call
-405     e8/call  check-ints-equal/disp32
-406     # . . discard args
-407     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-408     # . epilogue
-409     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-410     5d/pop-to-ebp
-411     c3/return
-412 
-413 # . . vim:nowrap:textwidth=0
+  3 #   data: (array byte)  # prefixed by size as usual
+  4 #
+  5 # TODO: is it confusing that the push opcodes grow memory downward, but the
+  6 # push function grows stacks upward?
+  7 
+  8 == code
+  9 #   instruction                     effective address                                                   register    displacement    immediate
+ 10 # . op          subop               mod             rm32          base        index         scale       r32
+ 11 # . 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
+ 12 
+ 13 clear-stack:  # s: (addr stack)
+ 14     # . prologue
+ 15     55/push-ebp
+ 16     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 17     # . save registers
+ 18     50/push-eax
+ 19     51/push-ecx
+ 20     # eax = s
+ 21     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   8/disp8         .                 # copy *(ebp+8) to eax
+ 22     # var max/ecx: (addr byte) = &s->data[s->size]
+ 23     8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(eax+4) to eax
+ 24     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   8/disp8         .                 # copy eax+ecx+8 to ecx
+ 25     # s->top = 0
+ 26     c7          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0/imm32           # copy to *eax
+ 27     # var curr/eax: (addr byte) = s->data
+ 28     81          0/subop/add         3/mod/direct    0/rm32/eax    .           .             .           .           .               8/imm32           # add to eax
+ 29 $clear-stack:loop:
+ 30     # if (curr >= max) break
+ 31     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # compare eax with ecx
+ 32     73/jump-if-addr>=  $clear-stack:end/disp8
+ 33     # *curr = 0
+ 34     c6          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0/imm8            # copy byte to *eax
+ 35     # ++curr
+ 36     40/increment-eax
+ 37     eb/jump $clear-stack:loop/disp8
+ 38 $clear-stack:end:
+ 39     # . restore registers
+ 40     59/pop-to-ecx
+ 41     58/pop-to-eax
+ 42     # . epilogue
+ 43     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 44     5d/pop-to-ebp
+ 45     c3/return
+ 46 
+ 47 test-clear-stack:
+ 48     # . prologue
+ 49     55/push-ebp
+ 50     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 51     # var stack/ecx = stack of size 8 with random data in it
+ 52     68/push 34/imm32
+ 53     68/push 35/imm32
+ 54     68/push 8/imm32/size
+ 55     68/push 14/imm32/top
+ 56     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 57     # clear(stack)
+ 58     # . . push args
+ 59     51/push-ecx
+ 60     # . . call
+ 61     e8/call  clear-stack/disp32
+ 62     # . . discard args
+ 63     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 64     # top should be 0
+ 65     58/pop-to-eax
+ 66     # . check-ints-equal(eax, 0, msg)
+ 67     # . . push args
+ 68     68/push  "F - test-clear-stack: top"/imm32
+ 69     68/push  0/imm32
+ 70     50/push-eax
+ 71     # . . call
+ 72     e8/call  check-ints-equal/disp32
+ 73     # . . discard args
+ 74     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 75     # size should remain 8
+ 76     58/pop-to-eax
+ 77     # . check-ints-equal(eax, 8, msg)
+ 78     # . . push args
+ 79     68/push  "F - test-clear-stack: size"/imm32
+ 80     68/push  8/imm32
+ 81     50/push-eax
+ 82     # . . call
+ 83     e8/call  check-ints-equal/disp32
+ 84     # . . discard args
+ 85     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 86     # first word is 0
+ 87     58/pop-to-eax
+ 88     # . check-ints-equal(eax, 0, msg)
+ 89     # . . push args
+ 90     68/push  "F - test-clear-stack: data[0..3]"/imm32
+ 91     68/push  0/imm32
+ 92     50/push-eax
+ 93     # . . call
+ 94     e8/call  check-ints-equal/disp32
+ 95     # . . discard args
+ 96     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 97     # second word is 0
+ 98     58/pop-to-eax
+ 99     # . check-ints-equal(eax, 0, msg)
+100     # . . push args
+101     68/push  "F - test-clear-stack: data[4..7]"/imm32
+102     68/push  0/imm32
+103     50/push-eax
+104     # . . call
+105     e8/call  check-ints-equal/disp32
+106     # . . discard args
+107     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+108     # . epilogue
+109     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+110     5d/pop-to-ebp
+111     c3/return
+112 
+113 # TODO: make this generic
+114 push:  # s: (addr stack), n: int
+115     # . prologue
+116     55/push-ebp
+117     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+118     # . save registers
+119     50/push-eax
+120     51/push-ecx
+121     56/push-esi
+122     # esi = s
+123     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+124     # ecx = s->top
+125     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
+126     # if (s->top >= s->size) abort
+127     39/compare                      1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # compare *(esi+4) and ecx
+128     7e/jump-if-<=  $push:abort/disp8
+129     # s->data[s->top] = n
+130     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0xc/disp8       .                 # copy *(ebp+12) to eax
+131     89/copy                         1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/eax   8/disp8         .                 # copy eax to *(esi+ecx+8)
+132     # s->top += 4
+133     81          0/subop/add         0/mod/direct    6/rm32/esi    .           .             .           .           .               4/imm32           # subtract from *esi
+134 $push:end:
+135     # . restore registers
+136     5e/pop-to-esi
+137     59/pop-to-ecx
+138     58/pop-to-eax
+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 $push:abort:
+145     # print(stderr, "error: push: no space left")
+146     # . write-buffered(Stderr, "error: push: no space left")
+147     # . . push args
+148     68/push  "error: push: no space left"/imm32
+149     68/push  Stderr/imm32
+150     # . . call
+151     e8/call  write-buffered/disp32
+152     # . . discard args
+153     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+154     # . flush(Stderr)
+155     # . . push args
+156     68/push  Stderr/imm32
+157     # . . call
+158     e8/call  flush/disp32
+159     # . . discard args
+160     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+161     # . syscall(exit, 1)
+162     bb/copy-to-ebx  1/imm32
+163     b8/copy-to-eax  1/imm32/exit
+164     cd/syscall  0x80/imm8
+165     # never gets here
+166 
+167 test-push:
+168     # . prologue
+169     55/push-ebp
+170     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+171     # var stack/ecx = empty stack of size 8
+172     68/push 0/imm32
+173     68/push 0/imm32
+174     68/push 8/imm32/size
+175     68/push 0/imm32/top
+176     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+177     # push(stack, 0x42)
+178     # . . push args
+179     68/push  0x42/imm32
+180     51/push-ecx
+181     # . . call
+182     e8/call  push/disp32
+183     # . . discard args
+184     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+185     # check top
+186     58/pop-to-eax
+187     # . check-ints-equal(eax, 4, msg)
+188     # . . push args
+189     68/push  "F - test-push: top"/imm32
+190     68/push  4/imm32
+191     50/push-eax
+192     # . . call
+193     e8/call  check-ints-equal/disp32
+194     # . . discard args
+195     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+196     # check size
+197     58/pop-to-eax
+198     # . check-ints-equal(eax, 8, msg)
+199     # . . push args
+200     68/push  "F - test-push: size"/imm32
+201     68/push  8/imm32
+202     50/push-eax
+203     # . . call
+204     e8/call  check-ints-equal/disp32
+205     # . . discard args
+206     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+207     # first word is 0x42
+208     58/pop-to-eax
+209     # . check-ints-equal(eax, 0x42, msg)
+210     # . . push args
+211     68/push  "F - test-push: data[0..3]"/imm32
+212     68/push  0x42/imm32
+213     50/push-eax
+214     # . . call
+215     e8/call  check-ints-equal/disp32
+216     # . . discard args
+217     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+218     # second word is 0
+219     58/pop-to-eax
+220     # . check-ints-equal(eax, 0, msg)
+221     # . . push args
+222     68/push  "F - test-push: data[4..7]"/imm32
+223     68/push  0/imm32
+224     50/push-eax
+225     # . . call
+226     e8/call  check-ints-equal/disp32
+227     # . . discard args
+228     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+229     # . epilogue
+230     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+231     5d/pop-to-ebp
+232     c3/return
+233 
+234 # TODO: make this generic
+235 pop:  # s: (addr stack) -> n/eax: int
+236     # . prologue
+237     55/push-ebp
+238     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+239     # . save registers
+240     51/push-ecx
+241     56/push-esi
+242     # esi = s
+243     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+244     # if (s->top <= 0) abort
+245     81          7/subop/compare     0/mod/indirect  6/rm32/esi    .           .             .           .           .               0/imm32           # compare *esi
+246     7e/jump-if-<=  $pop:abort/disp8
+247     # s->top -= 4
+248     81          5/subop/subtract    0/mod/direct    6/rm32/esi    .           .             .           .           .               4/imm32           # subtract from *esi
+249     # eax = s->data[s->top]
+250     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
+251     8b/copy                         1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/eax   8/disp8         .                 # copy *(esi+ecx+8) to eax
+252     # s->data[s->top] = 0
+253     c7          0/subop/copy        1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/eax   8/disp8         0/imm32           # copy to *(esi+ecx+8)
+254 $pop:end:
+255     # . restore registers
+256     5e/pop-to-esi
+257     59/pop-to-ecx
+258     # . epilogue
+259     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+260     5d/pop-to-ebp
+261     c3/return
+262 
+263 $pop:abort:
+264     # print(stderr, "error: pop: nothing left in stack")
+265     # . write-buffered(Stderr, "error: pop: nothing left in stack")
+266     # . . push args
+267     68/push  "error: pop: nothing left in stack"/imm32
+268     68/push  Stderr/imm32
+269     # . . call
+270     e8/call  write-buffered/disp32
+271     # . . discard args
+272     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+273     # . flush(Stderr)
+274     # . . push args
+275     68/push  Stderr/imm32
+276     # . . call
+277     e8/call  flush/disp32
+278     # . . discard args
+279     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+280     # . syscall(exit, 1)
+281     bb/copy-to-ebx  1/imm32
+282     b8/copy-to-eax  1/imm32/exit
+283     cd/syscall  0x80/imm8
+284     # never gets here
+285 
+286 test-pop:
+287     # . prologue
+288     55/push-ebp
+289     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+290     # var stack/ecx = stack of size 8 containing just 0x42
+291     68/push 0/imm32
+292     68/push 0x42/imm32
+293     68/push 8/imm32/size
+294     68/push 4/imm32/top
+295     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+296     # eax = pop(stack)
+297     # . . push args
+298     51/push-ecx
+299     # . . call
+300     e8/call  pop/disp32
+301     # . . discard args
+302     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+303     # check-ints-equal(eax, 0x42, msg)
+304     # . . push args
+305     68/push  "F - test-pop: result"/imm32
+306     68/push  0x42/imm32
+307     50/push-eax
+308     # . . call
+309     e8/call  check-ints-equal/disp32
+310     # . . discard args
+311     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+312     # check top
+313     58/pop-to-eax
+314     # . check-ints-equal(eax, 0, msg)
+315     # . . push args
+316     68/push  "F - test-pop: top"/imm32
+317     68/push  0/imm32
+318     50/push-eax
+319     # . . call
+320     e8/call  check-ints-equal/disp32
+321     # . . discard args
+322     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+323     # check size
+324     58/pop-to-eax
+325     # . check-ints-equal(eax, 8, msg)
+326     # . . push args
+327     68/push  "F - test-pop: size"/imm32
+328     68/push  8/imm32
+329     50/push-eax
+330     # . . call
+331     e8/call  check-ints-equal/disp32
+332     # . . discard args
+333     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+334     # . epilogue
+335     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+336     5d/pop-to-ebp
+337     c3/return
+338 
+339 # TODO: make this generic
+340 top:  # s: (addr stack) -> n/eax: int
+341     # . prologue
+342     55/push-ebp
+343     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+344     # . save registers
+345     51/push-ecx
+346     56/push-esi
+347     # esi = s
+348     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+349     # if (s->top <= 0) abort
+350     81          7/subop/compare     0/mod/indirect  6/rm32/esi    .           .             .           .           .               0/imm32           # compare *esi
+351     7e/jump-if-<=  $top:abort/disp8
+352     # n = s->data[s->top - 4]
+353     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
+354     81          5/subop/subtract    3/mod/direct    1/rm32/ecx    .           .             .           .           .               4/imm32           # subtract from ecx
+355     8b/copy                         1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/eax   8/disp8         .                 # copy *(esi+ecx+8) to eax
+356 $top:end:
+357     # . restore registers
+358     5e/pop-to-esi
+359     59/pop-to-ecx
+360     # . epilogue
+361     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+362     5d/pop-to-ebp
+363     c3/return
+364 
+365 $top:abort:
+366     # print(stderr, "error: top: nothing left in stack")
+367     # . write-buffered(Stderr, "error: top: nothing left in stack")
+368     # . . push args
+369     68/push  "error: top: nothing left in stack"/imm32
+370     68/push  Stderr/imm32
+371     # . . call
+372     e8/call  write-buffered/disp32
+373     # . . discard args
+374     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+375     # . flush(Stderr)
+376     # . . push args
+377     68/push  Stderr/imm32
+378     # . . call
+379     e8/call  flush/disp32
+380     # . . discard args
+381     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+382     # . syscall(exit, 1)
+383     bb/copy-to-ebx  1/imm32
+384     b8/copy-to-eax  1/imm32/exit
+385     cd/syscall  0x80/imm8
+386     # never gets here
+387 
+388 test-top:
+389     # . prologue
+390     55/push-ebp
+391     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+392     # var stack/ecx = stack of size 8 containing just 0x42
+393     68/push  0/imm32
+394     68/push  0x42/imm32
+395     68/push  8/imm32/size
+396     68/push  4/imm32/top
+397     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+398     # eax = top(stack)
+399     # . . push args
+400     51/push-ecx
+401     # . . call
+402     e8/call  top/disp32
+403     # . . discard args
+404     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+405     # check-ints-equal(eax, 42, msg")
+406     # . . push args
+407     68/push  "F - test-top: result"/imm32
+408     68/push  0x42/imm32
+409     50/push-eax
+410     # . . call
+411     e8/call  check-ints-equal/disp32
+412     # . . discard args
+413     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+414     # . epilogue
+415     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+416     5d/pop-to-ebp
+417     c3/return
+418 
+419 # . . vim:nowrap:textwidth=0
 
diff --git a/html/100array-equal.subx.html b/html/100array-equal.subx.html index 452840cb..425e0879 100644 --- a/html/100array-equal.subx.html +++ b/html/100array-equal.subx.html @@ -16,12 +16,12 @@ a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } .subxS2Comment { color: #8a8a8a; } -.LineNr { } -.SpecialChar { color: #d70000; } -.subxS1Comment { color: #0000af; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } .subxTest { color: #5f8700; } +.subxFunction { color: #af5f00; text-decoration: underline; } +.LineNr { } +.subxS1Comment { color: #0000af; } +.SpecialChar { color: #d70000; } +.Constant { color: #008787; } .subxH1Comment { color: #005faf; text-decoration: underline; } --> @@ -64,12 +64,12 @@ if ('onhashchange' in window) { 4 5 array-equal?: # a: (addr array int), b: (addr array int) -> eax: boolean 6 # pseudocode: - 7 # lena = a->length - 8 # if (lena != b->length) return false + 7 # asize = a->size + 8 # if (asize != b->size) return false 9 # i = 0 10 # curra = a->data 11 # currb = b->data - 12 # while i < lena + 12 # while i < asize 13 # i1 = *curra 14 # i2 = *currb 15 # if (c1 != c2) return false @@ -78,7 +78,7 @@ if ('onhashchange' in window) { 18 # 19 # registers: 20 # i: ecx - 21 # lena: edx + 21 # asize: edx 22 # curra: esi 23 # currb: edi 24 # i1: eax @@ -97,10 +97,10 @@ if ('onhashchange' in window) { 37 8b/-> *(ebp+8) 6/r32/esi 38 # edi = b 39 8b/-> *(ebp+0xc) 7/r32/edi - 40 # var lena/edx: int = a->length + 40 # var asize/edx: int = a->size 41 8b/-> *esi 2/r32/edx - 42 $array-equal?:lengths: - 43 # if (lena != b->length) return false + 42 $array-equal?:sizes: + 43 # if (asize != b->size) return false 44 39/compare *edi 2/r32/edx 45 75/jump-if-!= $array-equal?:false/disp8 46 # var curra/esi: (addr byte) = a->data @@ -108,11 +108,11 @@ if ('onhashchange' in window) { 48 # var currb/edi: (addr byte) = b->data 49 81 0/subop/add %edi 4/imm32 50 # var i/ecx: int = 0 - 51 31/xor %ecx 1/r32/ecx + 51 31/xor-with %ecx 1/r32/ecx 52 # var vala/eax: int 53 # var valb/ebx: int 54 $array-equal?:loop: - 55 # if (i >= lena) return true + 55 # if (i >= asize) return true 56 39/compare %ecx 2/r32/edx 57 7d/jump-if->= $array-equal?:true/disp8 58 # var vala/eax: int = *curra @@ -156,507 +156,321 @@ if ('onhashchange' in window) { 96 # var edx: (array _) = [] 97 68/push 0/imm32/size 98 89/<- %edx 4/r32/esp - 99 # eax = array-equal?(ecx, edx) -100 # . . push args -101 52/push-edx -102 51/push-ecx -103 # . . call -104 e8/call array-equal?/disp32 -105 # . . discard args -106 81 0/subop/add %esp 8/imm32 -107 # check-ints-equal(eax, 1, msg) -108 # . . push args -109 68/push "F - test-compare-empty-with-empty-array"/imm32 -110 68/push 1/imm32/true -111 50/push-eax -112 # . . call -113 e8/call check-ints-equal/disp32 -114 # . . discard args -115 81 0/subop/add %esp 0xc/imm32 -116 # . epilogue -117 89/<- %esp 5/r32/ebp -118 5d/pop-to-ebp -119 c3/return -120 -121 test-compare-empty-with-non-empty-array: # also checks length-mismatch code path -122 # . prologue -123 55/push-ebp -124 89/<- %ebp 4/r32/esp -125 # var ecx: (array int) = [1] -126 68/push 1/imm32 -127 68/push 4/imm32/size -128 89/<- %ecx 4/r32/esp -129 # var edx: (array int) = [] -130 68/push 0/imm32/size -131 89/<- %edx 4/r32/esp -132 # eax = array-equal?(ecx, edx) -133 # . . push args -134 52/push-edx -135 51/push-ecx -136 # . . call -137 e8/call array-equal?/disp32 -138 # . . discard args -139 81 0/subop/add %esp 8/imm32 -140 # check-ints-equal(eax, 0, msg) -141 # . . push args -142 68/push "F - test-compare-empty-with-non-empty-array"/imm32 -143 68/push 0/imm32/false -144 50/push-eax -145 # . . call -146 e8/call check-ints-equal/disp32 -147 # . . discard args -148 81 0/subop/add %esp 0xc/imm32 -149 # . epilogue -150 89/<- %esp 5/r32/ebp -151 5d/pop-to-ebp -152 c3/return -153 -154 test-compare-equal-arrays: -155 # . prologue -156 55/push-ebp -157 89/<- %ebp 4/r32/esp -158 # var ecx: (array int) = [1, 2, 3] -159 68/push 3/imm32 -160 68/push 2/imm32 -161 68/push 1/imm32 -162 68/push 0xc/imm32/size -163 89/<- %ecx 4/r32/esp -164 # var edx: (array int) = [1, 2, 3] -165 68/push 3/imm32 -166 68/push 2/imm32 -167 68/push 1/imm32 -168 68/push 0xc/imm32/size -169 89/<- %edx 4/r32/esp -170 # eax = array-equal?(ecx, edx) -171 # . . push args -172 52/push-edx -173 51/push-ecx -174 # . . call -175 e8/call array-equal?/disp32 -176 # . . discard args -177 81 0/subop/add %esp 8/imm32 -178 # check-ints-equal(eax, 1, msg) -179 # . . push args -180 68/push "F - test-compare-equal-arrays"/imm32 -181 68/push 1/imm32/true -182 50/push-eax -183 # . . call -184 e8/call check-ints-equal/disp32 -185 # . . discard args -186 81 0/subop/add %esp 0xc/imm32 -187 # . epilogue -188 89/<- %esp 5/r32/ebp -189 5d/pop-to-ebp -190 c3/return -191 -192 test-compare-inequal-arrays-equal-lengths: -193 # . prologue -194 55/push-ebp -195 89/<- %ebp 4/r32/esp -196 # var ecx: (array int) = [1, 4, 3] -197 68/push 3/imm32 -198 68/push 4/imm32 -199 68/push 1/imm32 -200 68/push 0xc/imm32/size -201 89/<- %ecx 4/r32/esp -202 # var edx: (array int) = [1, 2, 3] -203 68/push 3/imm32 -204 68/push 2/imm32 -205 68/push 1/imm32 -206 68/push 0xc/imm32/size -207 89/<- %edx 4/r32/esp -208 # eax = array-equal?(ecx, edx) -209 # . . push args -210 52/push-edx -211 51/push-ecx -212 # . . call -213 e8/call array-equal?/disp32 -214 # . . discard args -215 81 0/subop/add %esp 8/imm32 -216 # check-ints-equal(eax, 0, msg) -217 # . . push args -218 68/push "F - test-compare-inequal-arrays-equal-lengths"/imm32 -219 68/push 0/imm32/false -220 50/push-eax -221 # . . call -222 e8/call check-ints-equal/disp32 -223 # . . discard args -224 81 0/subop/add %esp 0xc/imm32 -225 # . epilogue -226 89/<- %esp 5/r32/ebp -227 5d/pop-to-ebp -228 c3/return -229 -230 parse-array-of-ints: # ad: (addr allocation-descriptor), s: (addr string) -> result/eax: (handle array int) -231 # pseudocode -232 # end = &s->data[s->length] -233 # curr = s->data -234 # size = 0 -235 # while true -236 # if (curr >= end) break -237 # curr = skip-chars-matching-in-slice(curr, end, ' ') -238 # if (curr >= end) break -239 # curr = skip-chars-not-matching-in-slice(curr, end, ' ') -240 # ++size -241 # result = allocate(ad, (size+1)*4) -242 # result->size = (size+1)*4 -243 # var slice: slice = {s->data, 0} -244 # out = result->data -245 # while true -246 # if (slice->start >= end) break -247 # slice->start = skip-chars-matching-in-slice(slice->start, end, ' ') -248 # if (slice->start >= end) break -249 # slice->end = skip-chars-not-matching-in-slice(slice->start, end, ' ') -250 # *out = parse-hex-int-from-slice(slice) -251 # out += 4 -252 # slice->start = slice->end -253 # return result -254 # -255 # . prologue -256 55/push-ebp -257 89/<- %ebp 4/r32/esp -258 # . save registers -259 51/push-ecx -260 52/push-edx -261 53/push-ebx -262 56/push-esi -263 57/push-edi -264 # esi = s -265 8b/-> *(ebp+0xc) 6/r32/esi -266 # var curr/ecx: (addr byte) = s->data -267 8d/copy-address *(esi+4) 1/r32/ecx -268 # var end/edx: (addr byte) = &s->data[s->length] -269 # . edx = s->length -270 8b/-> *esi 2/r32/edx -271 # . edx += curr -272 01/add %edx 1/r32/ecx -273 # var size/ebx: int = 0 -274 31/xor %ebx 3/r32/ebx -275 $parse-array-of-ints:loop1: -276 # if (curr >= end) break -277 39/compare %ecx 2/r32/edx -278 73/jump-if-addr>= $parse-array-of-ints:break1/disp8 -279 # curr = skip-chars-matching-in-slice(curr, end, ' ') -280 # . eax = skip-chars-matching-in-slice(curr, end, ' ') -281 # . . push args -282 68/push 0x20/imm32/space -283 52/push-edx -284 51/push-ecx -285 # . . call -286 e8/call skip-chars-matching-in-slice/disp32 -287 # . . discard args -288 81 0/subop/add %esp 0xc/imm32 -289 # . ecx = eax -290 89/<- %ecx 0/r32/eax -291 # if (curr >= end) break -292 39/compare %ecx 2/r32/edx -293 73/jump-if-addr>= $parse-array-of-ints:break1/disp8 -294 # curr = skip-chars-not-matching-in-slice(curr, end, ' ') -295 # . eax = skip-chars-not-matching-in-slice(curr, end, ' ') -296 # . . push args -297 68/push 0x20/imm32/space -298 52/push-edx -299 51/push-ecx -300 # . . call -301 e8/call skip-chars-not-matching-in-slice/disp32 -302 # . . discard args -303 81 0/subop/add %esp 0xc/imm32 -304 # . ecx = eax -305 89/<- %ecx 0/r32/eax -306 # size += 4 -307 81 0/subop/add %ebx 4/imm32 -308 eb/jump $parse-array-of-ints:loop1/disp8 -309 $parse-array-of-ints:break1: -310 # var result/edi: (handle array int) = allocate(ad, size+4) -311 # . eax = allocate(ad, size+4) -312 # . . push args -313 89/<- %eax 3/r32/ebx -314 05/add-to-eax 4/imm32 -315 50/push-eax -316 ff 6/subop/push *(ebp+8) -317 # . . call -318 e8/call allocate/disp32 -319 # . . discard args -320 81 0/subop/add %esp 8/imm32 -321 # . edi = eax -322 89/<- %edi 0/r32/eax -323 # result->size = size -324 89/<- *eax 3/r32/ebx -325 $parse-array-of-ints:pass2: -326 # var slice/ecx: slice = {s->data, 0} -327 68/push 0/imm32/end -328 8d/copy-address *(esi+4) 1/r32/ecx -329 51/push-ecx -330 89/<- %ecx 4/r32/esp -331 # var out/ebx: (addr byte) = result->data -332 8d/copy-address *(eax+4) 3/r32/ebx -333 $parse-array-of-ints:loop2: -334 # if (slice->start >= end) break -335 39/compare *ecx 2/r32/edx -336 73/jump-if-addr>= $parse-array-of-ints:end/disp8 -337 # slice->start = skip-chars-matching-in-slice(slice->start, end, ' ') -338 # . eax = skip-chars-matching-in-slice(slice->start, end, ' ') -339 # . . push args -340 68/push 0x20/imm32/space -341 52/push-edx -342 ff 6/subop/push *ecx -343 # . . call -344 e8/call skip-chars-matching-in-slice/disp32 -345 # . . discard args -346 81 0/subop/add %esp 0xc/imm32 -347 # . slice->start = eax -348 89/<- *ecx 0/r32/eax -349 # if (slice->start >= end) break -350 39/compare *ecx 2/r32/edx -351 73/jump-if-addr>= $parse-array-of-ints:end/disp8 -352 # slice->end = skip-chars-not-matching-in-slice(slice->start, end, ' ') -353 # . eax = skip-chars-not-matching-in-slice(curr, end, ' ') -354 # . . push args -355 68/push 0x20/imm32/space -356 52/push-edx -357 50/push-eax -358 # . . call -359 e8/call skip-chars-not-matching-in-slice/disp32 -360 # . . discard args -361 81 0/subop/add %esp 0xc/imm32 -362 # . slice->end = eax -363 89/<- *(ecx+4) 0/r32/eax -364 # *out = parse-hex-int-from-slice(slice) -365 # . eax = parse-hex-int-from-slice(slice) -366 # . . push args -367 51/push-ecx -368 # . . call -369 e8/call parse-hex-int-from-slice/disp32 -370 # . . discard args -371 81 0/subop/add %esp 4/imm32 -372 # . *out = eax -373 89/<- *ebx 0/r32/eax -374 # out += 4 -375 81 0/subop/add %ebx 4/imm32 -376 # slice->start = slice->end -377 8b/-> *(ecx+4) 0/r32/eax -378 89/<- *ecx 0/r32/eax -379 81 0/subop/add %ecx 4/imm32 -380 eb/jump $parse-array-of-ints:loop2/disp8 -381 $parse-array-of-ints:end: -382 # return edi -383 89/<- %eax 7/r32/edi -384 # . reclaim locals -385 81 0/subop/add %esp 8/imm32 -386 # . restore registers -387 5f/pop-to-edi -388 5e/pop-to-esi -389 5b/pop-to-ebx -390 5a/pop-to-edx -391 59/pop-to-ecx -392 # . epilogue -393 89/<- %esp 5/r32/ebp -394 5d/pop-to-ebp -395 c3/return -396 -397 test-parse-array-of-ints: -398 # . prologue -399 55/push-ebp -400 89/<- %ebp 4/r32/esp -401 # var ecx: (array int) = [1, 2, 3] -402 68/push 3/imm32 -403 68/push 2/imm32 -404 68/push 1/imm32 -405 68/push 0xc/imm32/size -406 89/<- %ecx 4/r32/esp -407 # eax = parse-array-of-ints(Heap, "1 2 3") -408 # . . push args -409 68/push "1 2 3"/imm32 -410 68/push Heap/imm32 -411 # . . call -412 e8/call parse-array-of-ints/disp32 -413 # . . discard args -414 81 0/subop/add %esp 8/imm32 -415 # eax = array-equal?(ecx, eax) -416 # . . push args -417 50/push-eax -418 51/push-ecx -419 # . . call -420 e8/call array-equal?/disp32 -421 # . . discard args -422 81 0/subop/add %esp 8/imm32 -423 # check-ints-equal(eax, 1, msg) -424 # . . push args -425 68/push "F - test-parse-array-of-ints"/imm32 -426 68/push 1/imm32/true -427 50/push-eax -428 # . . call -429 e8/call check-ints-equal/disp32 -430 # . . discard args -431 81 0/subop/add %esp 0xc/imm32 -432 # . epilogue -433 89/<- %esp 5/r32/ebp -434 5d/pop-to-ebp -435 c3/return -436 -437 test-parse-array-of-ints-empty: -438 # - empty string = empty array -439 # . prologue -440 55/push-ebp -441 89/<- %ebp 4/r32/esp -442 # eax = parse-array-of-ints(Heap, "") -443 # . . push args -444 68/push ""/imm32 -445 68/push Heap/imm32 -446 # . . call -447 e8/call parse-array-of-ints/disp32 -448 # . . discard args -449 81 0/subop/add %esp 8/imm32 -450 # check-ints-equal(*eax, 0, msg) -451 # . . push args -452 68/push "F - test-parse-array-of-ints-empty"/imm32 -453 68/push 0/imm32/size -454 ff 6/subop/push *eax -455 # . . call -456 e8/call check-ints-equal/disp32 -457 # . . discard args -458 81 0/subop/add %esp 0xc/imm32 -459 # . epilogue -460 89/<- %esp 5/r32/ebp -461 5d/pop-to-ebp -462 c3/return -463 -464 test-parse-array-of-ints-just-whitespace: -465 # - just whitespace = empty array -466 # . prologue -467 55/push-ebp -468 89/<- %ebp 4/r32/esp -469 # eax = parse-array-of-ints(Heap, " ") -470 # . . push args -471 68/push Space/imm32 -472 68/push Heap/imm32 -473 # . . call -474 e8/call parse-array-of-ints/disp32 -475 # . . discard args -476 81 0/subop/add %esp 8/imm32 -477 # check-ints-equal(*eax, 0, msg) -478 # . . push args -479 68/push "F - test-parse-array-of-ints-empty"/imm32 -480 68/push 0/imm32/size -481 ff 6/subop/push *eax -482 # . . call -483 e8/call check-ints-equal/disp32 -484 # . . discard args -485 81 0/subop/add %esp 0xc/imm32 -486 # . epilogue -487 89/<- %esp 5/r32/ebp -488 5d/pop-to-ebp -489 c3/return -490 -491 test-parse-array-of-ints-extra-whitespace: -492 # . prologue -493 55/push-ebp -494 89/<- %ebp 4/r32/esp -495 # var ecx: (array int) = [1, 2, 3] -496 68/push 3/imm32 -497 68/push 2/imm32 -498 68/push 1/imm32 -499 68/push 0xc/imm32/size -500 89/<- %ecx 4/r32/esp -501 # eax = parse-array-of-ints(Heap, " 1 2 3 ") -502 # . . push args -503 68/push " 1 2 3 "/imm32 -504 68/push Heap/imm32 -505 # . . call -506 e8/call parse-array-of-ints/disp32 -507 # . . discard args -508 81 0/subop/add %esp 8/imm32 -509 # eax = array-equal?(ecx, eax) -510 # . . push args -511 50/push-eax -512 51/push-ecx -513 # . . call -514 e8/call array-equal?/disp32 -515 # . . discard args -516 81 0/subop/add %esp 8/imm32 -517 # check-ints-equal(eax, 1, msg) -518 # . . push args -519 68/push "F - test-parse-array-of-ints-extra-whitespace"/imm32 -520 68/push 1/imm32/true -521 50/push-eax -522 # . . call -523 e8/call check-ints-equal/disp32 -524 # . . discard args -525 81 0/subop/add %esp 0xc/imm32 -526 # . epilogue -527 89/<- %esp 5/r32/ebp -528 5d/pop-to-ebp -529 c3/return -530 -531 # helper for later tests -532 # compare an array with a string representation of an array literal -533 check-array-equal: # a: (addr array int), expected: (addr string), msg: (addr string) -534 # . prologue -535 55/push-ebp -536 89/<- %ebp 4/r32/esp -537 # . save registers -538 50/push-eax -539 # var b/ecx: (handle array int) = parse-array-of-ints(Heap, expected) -540 # . eax = parse-array-of-ints(Heap, expected) -541 # . . push args -542 ff 6/subop/push *(ebp+0xc) -543 68/push Heap/imm32 -544 # . . call -545 e8/call parse-array-of-ints/disp32 -546 # . . discard args -547 81 0/subop/add %esp 8/imm32 -548 # . b = eax -549 89/<- %ecx 0/r32/eax -550 # eax = array-equal?(a, b) -551 # . . push args -552 51/push-ecx -553 ff 6/subop/push *(ebp+8) -554 # . . call -555 e8/call array-equal?/disp32 -556 # . . discard args -557 81 0/subop/add %esp 8/imm32 -558 # check-ints-equal(eax, 1, msg) -559 # . . push args -560 ff 6/subop/push *(ebp+0x10) -561 68/push 1/imm32 -562 50/push-eax -563 # . . call -564 e8/call check-ints-equal/disp32 -565 # . . discard args -566 81 0/subop/add %esp 0xc/imm32 -567 $check-array-equal:end: -568 # . restore registers -569 58/pop-to-eax -570 # . epilogue -571 89/<- %esp 5/r32/ebp -572 5d/pop-to-ebp -573 c3/return -574 -575 test-check-array-equal: -576 # . prologue -577 55/push-ebp -578 89/<- %ebp 4/r32/esp -579 # var ecx: (array int) = [1, 2, 3] -580 68/push 3/imm32 -581 68/push 2/imm32 -582 68/push 1/imm32 -583 68/push 0xc/imm32/size -584 89/<- %ecx 4/r32/esp -585 # check-array-equal(ecx, "1 2 3", "msg") -586 # . . push args -587 68/push "F - test-check-array-equal"/imm32 -588 68/push "1 2 3"/imm32 -589 51/push-ecx -590 # . . call -591 e8/call check-array-equal/disp32 -592 # . . discard args -593 81 0/subop/add %esp 8/imm32 -594 # . epilogue -595 89/<- %esp 5/r32/ebp -596 5d/pop-to-ebp -597 c3/return -598 -599 # . . vim:nowrap:textwidth=0 + 99 # +100 (array-equal? %ecx %edx) # => eax +101 (check-ints-equal %eax 1 "F - test-compare-empty-with-empty-array") +102 # . epilogue +103 89/<- %esp 5/r32/ebp +104 5d/pop-to-ebp +105 c3/return +106 +107 test-compare-empty-with-non-empty-array: # also checks size-mismatch code path +108 # . prologue +109 55/push-ebp +110 89/<- %ebp 4/r32/esp +111 # var ecx: (array int) = [1] +112 68/push 1/imm32 +113 68/push 4/imm32/size +114 89/<- %ecx 4/r32/esp +115 # var edx: (array int) = [] +116 68/push 0/imm32/size +117 89/<- %edx 4/r32/esp +118 # +119 (array-equal? %ecx %edx) # => eax +120 (check-ints-equal %eax 0 "F - test-compare-empty-with-non-empty-array") +121 # . epilogue +122 89/<- %esp 5/r32/ebp +123 5d/pop-to-ebp +124 c3/return +125 +126 test-compare-equal-arrays: +127 # . prologue +128 55/push-ebp +129 89/<- %ebp 4/r32/esp +130 # var ecx: (array int) = [1, 2, 3] +131 68/push 3/imm32 +132 68/push 2/imm32 +133 68/push 1/imm32 +134 68/push 0xc/imm32/size +135 89/<- %ecx 4/r32/esp +136 # var edx: (array int) = [1, 2, 3] +137 68/push 3/imm32 +138 68/push 2/imm32 +139 68/push 1/imm32 +140 68/push 0xc/imm32/size +141 89/<- %edx 4/r32/esp +142 # +143 (array-equal? %ecx %edx) # => eax +144 (check-ints-equal %eax 1 "F - test-compare-equal-arrays") +145 # . epilogue +146 89/<- %esp 5/r32/ebp +147 5d/pop-to-ebp +148 c3/return +149 +150 test-compare-inequal-arrays-equal-sizes: +151 # . prologue +152 55/push-ebp +153 89/<- %ebp 4/r32/esp +154 # var ecx: (array int) = [1, 4, 3] +155 68/push 3/imm32 +156 68/push 4/imm32 +157 68/push 1/imm32 +158 68/push 0xc/imm32/size +159 89/<- %ecx 4/r32/esp +160 # var edx: (array int) = [1, 2, 3] +161 68/push 3/imm32 +162 68/push 2/imm32 +163 68/push 1/imm32 +164 68/push 0xc/imm32/size +165 89/<- %edx 4/r32/esp +166 # +167 (array-equal? %ecx %edx) # => eax +168 (check-ints-equal %eax 0 "F - test-compare-inequal-arrays-equal-sizes") +169 # . epilogue +170 89/<- %esp 5/r32/ebp +171 5d/pop-to-ebp +172 c3/return +173 +174 parse-array-of-ints: # ad: (addr allocation-descriptor), s: (addr string), out: (addr handle array int) +175 # pseudocode +176 # end = &s->data[s->size] +177 # curr = s->data +178 # size = 0 +179 # while true +180 # if (curr >= end) break +181 # curr = skip-chars-matching-in-slice(curr, end, ' ') +182 # if (curr >= end) break +183 # curr = skip-chars-not-matching-in-slice(curr, end, ' ') +184 # ++size +185 # allocate-array(ad, size*4, out) +186 # var slice: slice = {s->data, 0} +187 # curr = lookup(out)->data +188 # while true +189 # if (slice->start >= end) break +190 # slice->start = skip-chars-matching-in-slice(slice->start, end, ' ') +191 # if (slice->start >= end) break +192 # slice->end = skip-chars-not-matching-in-slice(slice->start, end, ' ') +193 # *curr = parse-hex-int-from-slice(slice) +194 # curr += 4 +195 # slice->start = slice->end +196 # return result +197 # +198 # . prologue +199 55/push-ebp +200 89/<- %ebp 4/r32/esp +201 # . save registers +202 50/push-eax +203 51/push-ecx +204 52/push-edx +205 53/push-ebx +206 56/push-esi +207 57/push-edi +208 # esi = s +209 8b/-> *(ebp+0xc) 6/r32/esi +210 # var curr/ecx: (addr byte) = s->data +211 8d/copy-address *(esi+4) 1/r32/ecx +212 # var end/edx: (addr byte) = &s->data[s->size] +213 # . edx = s->size +214 8b/-> *esi 2/r32/edx +215 # . edx += curr +216 01/add-to %edx 1/r32/ecx +217 # var size/ebx: int = 0 +218 31/xor-with %ebx 3/r32/ebx +219 $parse-array-of-ints:loop1: +220 # if (curr >= end) break +221 39/compare %ecx 2/r32/edx +222 73/jump-if-addr>= $parse-array-of-ints:break1/disp8 +223 # curr = skip-chars-matching-in-slice(curr, end, ' ') +224 (skip-chars-matching-in-slice %ecx %edx 0x20) # => eax +225 89/<- %ecx 0/r32/eax +226 # if (curr >= end) break +227 39/compare %ecx 2/r32/edx +228 73/jump-if-addr>= $parse-array-of-ints:break1/disp8 +229 # curr = skip-chars-not-matching-in-slice(curr, end, ' ') +230 (skip-chars-not-matching-in-slice %ecx %edx 0x20) # => eax +231 89/<- %ecx 0/r32/eax +232 # size += 4 +233 81 0/subop/add %ebx 4/imm32 +234 eb/jump $parse-array-of-ints:loop1/disp8 +235 $parse-array-of-ints:break1: +236 (allocate-array *(ebp+8) %ebx *(ebp+0x10)) +237 $parse-array-of-ints:pass2: +238 # var slice/edi: slice = {s->data, 0} +239 68/push 0/imm32/end +240 8d/copy-address *(esi+4) 7/r32/edi +241 57/push-edi +242 89/<- %edi 4/r32/esp +243 # curr = lookup(out)->data +244 8b/-> *(ebp+0x10) 0/r32/eax +245 (lookup *eax *(eax+4)) # => eax +246 8d/copy-address *(eax+4) 1/r32/ecx +247 $parse-array-of-ints:loop2: +248 # if (slice->start >= end) break +249 39/compare *edi 2/r32/edx +250 73/jump-if-addr>= $parse-array-of-ints:end/disp8 +251 # slice->start = skip-chars-matching-in-slice(slice->start, end, ' ') +252 (skip-chars-matching-in-slice *edi %edx 0x20) # => eax +253 89/<- *edi 0/r32/eax +254 # if (slice->start >= end) break +255 39/compare *edi 2/r32/edx +256 73/jump-if-addr>= $parse-array-of-ints:end/disp8 +257 # slice->end = skip-chars-not-matching-in-slice(slice->start, end, ' ') +258 (skip-chars-not-matching-in-slice *edi %edx 0x20) # => eax +259 89/<- *(edi+4) 0/r32/eax +260 # *curr = parse-hex-int-from-slice(slice) +261 (parse-hex-int-from-slice %edi) +262 89/<- *ecx 0/r32/eax +263 # curr += 4 +264 81 0/subop/add %ecx 4/imm32 +265 # slice->start = slice->end +266 8b/-> *(edi+4) 0/r32/eax +267 89/<- *edi 0/r32/eax +268 eb/jump $parse-array-of-ints:loop2/disp8 +269 $parse-array-of-ints:end: +270 # . reclaim locals +271 81 0/subop/add %esp 8/imm32 +272 # . restore registers +273 5f/pop-to-edi +274 5e/pop-to-esi +275 5b/pop-to-ebx +276 5a/pop-to-edx +277 59/pop-to-ecx +278 58/pop-to-eax +279 # . epilogue +280 89/<- %esp 5/r32/ebp +281 5d/pop-to-ebp +282 c3/return +283 +284 test-parse-array-of-ints: +285 # . prologue +286 55/push-ebp +287 89/<- %ebp 4/r32/esp +288 # var h/esi: (handle array int) +289 68/push 0/imm32 +290 68/push 0/imm32 +291 89/<- %esi 4/r32/esp +292 # var ecx: (array int) = [1, 2, 3] +293 68/push 3/imm32 +294 68/push 2/imm32 +295 68/push 1/imm32 +296 68/push 0xc/imm32/size +297 89/<- %ecx 4/r32/esp +298 # +299 (parse-array-of-ints Heap "1 2 3" %esi) +300 (lookup *esi *(esi+4)) # => eax +301 (array-equal? %ecx %eax) # => eax +302 (check-ints-equal %eax 1 "F - test-parse-array-of-ints") +303 # . epilogue +304 89/<- %esp 5/r32/ebp +305 5d/pop-to-ebp +306 c3/return +307 +308 test-parse-array-of-ints-empty: +309 # - empty string = empty array +310 # . prologue +311 55/push-ebp +312 89/<- %ebp 4/r32/esp +313 # var h/esi: handle +314 68/push 0/imm32 +315 68/push 0/imm32 +316 89/<- %esi 4/r32/esp +317 # +318 (parse-array-of-ints Heap "" %esi) +319 (lookup *esi *(esi+4)) # => eax +320 (check-ints-equal *eax 0 "F - test-parse-array-of-ints-empty") +321 # . epilogue +322 89/<- %esp 5/r32/ebp +323 5d/pop-to-ebp +324 c3/return +325 +326 test-parse-array-of-ints-just-whitespace: +327 # - just whitespace = empty array +328 # . prologue +329 55/push-ebp +330 89/<- %ebp 4/r32/esp +331 # var h/esi: handle +332 68/push 0/imm32 +333 68/push 0/imm32 +334 89/<- %esi 4/r32/esp +335 # +336 (parse-array-of-ints Heap Space %esi) +337 (lookup *esi *(esi+4)) # => eax +338 (check-ints-equal *eax 0 "F - test-parse-array-of-ints-just-whitespace") +339 # . epilogue +340 89/<- %esp 5/r32/ebp +341 5d/pop-to-ebp +342 c3/return +343 +344 test-parse-array-of-ints-extra-whitespace: +345 # . prologue +346 55/push-ebp +347 89/<- %ebp 4/r32/esp +348 # var h/esi: handle +349 68/push 0/imm32 +350 68/push 0/imm32 +351 89/<- %esi 4/r32/esp +352 # var ecx: (array int) = [1, 2, 3] +353 68/push 3/imm32 +354 68/push 2/imm32 +355 68/push 1/imm32 +356 68/push 0xc/imm32/size +357 89/<- %ecx 4/r32/esp +358 # +359 (parse-array-of-ints Heap " 1 2 3 " %esi) +360 (lookup *esi *(esi+4)) # => eax +361 (array-equal? %ecx %eax) # => eax +362 (check-ints-equal %eax 1 "F - test-parse-array-of-ints-extra-whitespace") +363 # . epilogue +364 89/<- %esp 5/r32/ebp +365 5d/pop-to-ebp +366 c3/return +367 +368 # helper for later tests +369 # compare an array with a string representation of an array literal +370 check-array-equal: # a: (addr array int), expected: (addr string), msg: (addr string) +371 # . prologue +372 55/push-ebp +373 89/<- %ebp 4/r32/esp +374 # . save registers +375 50/push-eax +376 56/push-esi +377 # var h/esi: handle +378 68/push 0/imm32 +379 68/push 0/imm32 +380 89/<- %esi 4/r32/esp +381 # var b/eax: (addr array int) = parse-array-of-ints(Heap, expected) +382 (parse-array-of-ints Heap *(ebp+0xc) %esi) +383 (lookup *esi *(esi+4)) # => eax +384 # +385 (array-equal? *(ebp+8) %eax) +386 (check-ints-equal %eax 1 *(ebp+0x10)) +387 $check-array-equal:end: +388 # . restore registers +389 5e/pop-to-esi +390 58/pop-to-eax +391 # . epilogue +392 89/<- %esp 5/r32/ebp +393 5d/pop-to-ebp +394 c3/return +395 +396 test-check-array-equal: +397 # . prologue +398 55/push-ebp +399 89/<- %ebp 4/r32/esp +400 # var ecx: (array int) = [1, 2, 3] +401 68/push 3/imm32 +402 68/push 2/imm32 +403 68/push 1/imm32 +404 68/push 0xc/imm32/size +405 89/<- %ecx 4/r32/esp +406 # +407 (check-array-equal %ecx "1 2 3" "F - test-check-array-equal") +408 # . epilogue +409 89/<- %esp 5/r32/ebp +410 5d/pop-to-ebp +411 c3/return +412 +413 # . . vim:nowrap:textwidth=0 diff --git a/html/101stack_allocate.subx.html b/html/101stack_allocate.subx.html new file mode 100644 index 00000000..ec7351de --- /dev/null +++ b/html/101stack_allocate.subx.html @@ -0,0 +1,123 @@ + + + + +Mu - 101stack_allocate.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/101stack_allocate.subx +
+ 1 # A function which pushes n zeros on the stack.
+ 2 # Not really useful to call manually.
+ 3 # The Mu compiler uses it when defining arrays on the stack.
+ 4 
+ 5 == code
+ 6 
+ 7 #? Entry:
+ 8 #?     # . prologue
+ 9 #?     89/<- %ebp 4/r32/esp
+10 #?     #
+11 #?     68/push 0xfcfdfeff/imm32
+12 #?     b8/copy-to-eax 0x34353637/imm32
+13 #? $dump-stack0:
+14 #?     (push-n-zero-bytes 4)
+15 #?     68/push 0x20/imm32
+16 #? $dump-stack9:
+17 #?     b8/copy-to-eax 1/imm32/exit
+18 #?     cd/syscall 0x80/imm8
+19 
+20 # This is not a regular function, so it won't be idiomatic.
+21 # Registers must be properly restored.
+22 # Registers can be spilled, but that modifies the stack and needs to be
+23 # cleaned up.
+24 
+25 # Overhead:
+26 #   62 + n*6 instructions to push n bytes.
+27 # If we just emitted code to push n zeroes, it would be:
+28 #   5 bytes for 4 zero bytes, so 1.25 bytes per zero. And that's not even
+29 #   instructions.
+30 # But on the other hand it would destroy the instruction cache, where this
+31 # approach requires 15 instructions, fixed.
+32 
+33 # n must be positive
+34 push-n-zero-bytes:  # n: int
+35 $push-n-zero-bytes:prologue:
+36     89/<- *Push-n-zero-bytes-ebp 5/r32/ebp  # spill ebp without affecting stack
+37     89/<- %ebp 4/r32/esp
+38 $push-n-zero-bytes:copy-ra:
+39     # -- esp = ebp
+40     50/push-eax
+41     # -- esp+8 = ebp+4
+42     # -- esp+4 = ebp
+43     8b/-> *(esp+4) 0/r32/eax
+44     2b/subtract *(ebp+4) 4/r32/esp
+45     # -- esp+4+n = ebp
+46     89/<- *(esp+4) 0/r32/eax
+47     58/pop-to-eax
+48     # -- esp+n = ebp
+49 $push-n-zero-bytes:bulk-cleaning:
+50     89/<- *Push-n-zero-bytes-esp 4/r32/esp
+51     81 0/subop/add *Push-n-zero-bytes-esp 4/imm32
+52     81 0/subop/add *(ebp+4) 4/imm32
+53     (zero-out *Push-n-zero-bytes-esp *(ebp+4))  # n+4
+54 $push-n-zero-bytes:epilogue:
+55     8b/-> *Push-n-zero-bytes-ebp 5/r32/ebp  # restore spill
+56     c3/return
+57 
+58 == data
+59 Push-n-zero-bytes-ebp:  # (addr int)
+60   0/imm32
+61 Push-n-zero-bytes-esp:  # (addr int)
+62   0/imm32
+
+ + + diff --git a/html/102kernel-string.subx.html b/html/102kernel-string.subx.html new file mode 100644 index 00000000..ccda9cb7 --- /dev/null +++ b/html/102kernel-string.subx.html @@ -0,0 +1,149 @@ + + + + +Mu - 102kernel-string.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/102kernel-string.subx +
+ 1 # We can't really do much with null-terminated kernel strings, and we don't
+ 2 # want to. Let's turn them into regular length-prefixed strings at the first
+ 3 # opportunity.
+ 4 
+ 5 == code
+ 6 
+ 7 kernel-string-to-string:  # ad: (addr allocation-descriptor), in: (addr kernel-string) -> result/eax: (addr array byte)
+ 8     # . prologue
+ 9     55/push-ebp
+10     89/<- %ebp 4/r32/esp
+11     # . save registers
+12     51/push-ecx
+13     52/push-edx
+14     53/push-ebx
+15     56/push-esi
+16     57/push-edi
+17     # var len/ecx: int = length(in)
+18     (kernel-string-length *(ebp+0xc))
+19     89/<- %ecx 0/r32/eax
+20     # result = allocate-array(ad, len)
+21     (allocate-array *(ebp+8) %ecx)  # => eax
+22     # var c/edx: byte = 0
+23     ba/copy-to-edx 0/imm32
+24     # var src/esi: (addr byte) = in
+25     8b/-> *(ebp+0xc) 6/r32/esi
+26     # var dest/edi: (addr byte) = result->data
+27     8d/copy-address *(eax+4) 7/r32/edi
+28     {
+29 $kernel-string-to-string:loop:
+30       # c = *src
+31       8a/byte-> *esi 2/r32/edx
+32       # if (c == 0) break
+33       81 7/subop/compare %edx 0/imm32
+34       74/jump-if-= break/disp8
+35       # *dest = c
+36       88/byte<- *edi 2/r32/edx
+37       # ++src
+38       46/increment-esi
+39       # ++dest
+40       47/increment-edi
+41       eb/jump loop/disp8
+42     }
+43 $kernel-string-to-string:end:
+44     # . restore registers
+45     5f/pop-to-edi
+46     5e/pop-to-esi
+47     5b/pop-to-ebx
+48     5a/pop-to-edx
+49     59/pop-to-ecx
+50     # . epilogue
+51     89/<- %esp 5/r32/ebp
+52     5d/pop-to-ebp
+53     c3/return
+54 
+55 kernel-string-length:  # in: (addr kernel-string) -> result/eax: int
+56     # . prologue
+57     55/push-ebp
+58     89/<- %ebp 4/r32/esp
+59     # . save registers
+60     51/push-ecx
+61     52/push-edx
+62     # result = 0
+63     b8/copy-to-eax 0/imm32
+64     # var c/ecx: byte = 0
+65     b9/copy-to-ecx 0/imm32
+66     # var curr/edx: (addr byte) = in
+67     8b/-> *(ebp+8) 2/r32/edx
+68     {
+69 $kernel-string-length:loop:
+70       # c = *curr
+71       8a/byte-> *edx 1/r32/ecx
+72       # if (c == 0) break
+73       81 7/subop/compare %ecx 0/imm32
+74       74/jump-if-= break/disp8
+75       # ++curr
+76       42/increment-edx
+77       # ++result
+78       40/increment-eax
+79       #
+80       eb/jump loop/disp8
+81     }
+82 $kernel-string-length:end:
+83     # . restore registers
+84     5a/pop-to-edx
+85     59/pop-to-ecx
+86     # . epilogue
+87     89/<- %esp 5/r32/ebp
+88     5d/pop-to-ebp
+89     c3/return
+
+ + + diff --git a/html/apps/mu.subx.html b/html/apps/mu.subx.html index bdcf4a03..ff7958cb 100644 --- a/html/apps/mu.subx.html +++ b/html/apps/mu.subx.html @@ -15,16 +15,16 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } +.subxTest { color: #5f8700; } .subxFunction { color: #af5f00; text-decoration: underline; } -.Folded { color: #080808; background-color: #949494; } .LineNr { } .subxS1Comment { color: #0000af; } .CommentedCode { color: #8a8a8a; } .SpecialChar { color: #d70000; } .Constant { color: #008787; } -.subxMinorFunction { color: #875f5f; } -.subxTest { color: #5f8700; } +.Folded { color: #080808; background-color: #949494; } .subxH1Comment { color: #005faf; text-decoration: underline; } +.subxMinorFunction { color: #875f5f; } --> @@ -305,2060 +305,2060 @@ if ('onhashchange' in window) { 243 Program: 244 _Program-functions: # (handle function) 245 0/imm32 - 246 _Program-types: # (handle typeinfo) + 246 _Program-functions->payload: 247 0/imm32 - 248 - 249 # Some constants for simulating the data structures described above. - 250 # Many constants here come with a type in a comment. - 251 # - 252 # Sometimes the type is of the value at that offset for the given type. For - 253 # example, if you start at a function record and move forward Function-inouts - 254 # bytes, you'll find a (handle list var). + 248 _Program-types: # (handle typeinfo) + 249 0/imm32 + 250 _Program-types->payload: + 251 0/imm32 + 252 + 253 # Some constants for simulating the data structures described above. + 254 # Many constants here come with a type in a comment. 255 # - 256 # At other times, the type is of the constant itself. For example, the type of - 257 # the constant Function-size is (addr int). To get the size of a function, - 258 # look in *Function-size. - 259 - 260 Function-name: # (handle array byte) - 261 0/imm32 - 262 _Function-unused: - 263 4/imm32 - 264 Function-inouts: # (handle list var) - 265 8/imm32 - 266 Function-outputs: # (handle list var) - 267 0xc/imm32 - 268 Function-body: # (handle block) + 256 # Sometimes the type is of the value at that offset for the given type. For + 257 # example, if you start at a function record and move forward Function-inouts + 258 # bytes, you'll find a (handle list var). + 259 # + 260 # At other times, the type is of the constant itself. For example, the type of + 261 # the constant Function-size is (addr int). To get the size of a function, + 262 # look in *Function-size. + 263 + 264 Function-name: # (handle array byte) + 265 0/imm32 + 266 Function-inouts: # (handle list var) + 267 8/imm32 + 268 Function-outputs: # (handle list var) 269 0x10/imm32 - 270 Function-next: # (handle function) - 271 0x14/imm32 - 272 Function-size: # (addr int) - 273 0x18/imm32/24 - 274 - 275 Primitive-name: # (handle array byte) - 276 0/imm32 - 277 Primitive-inouts: # (handle list var) - 278 4/imm32 - 279 Primitive-outputs: # (handle list var) + 270 Function-body: # (handle block) + 271 0x18/imm32 + 272 Function-next: # (handle function) + 273 0x20/imm32 + 274 Function-size: # (addr int) + 275 0x28/imm32/40 + 276 + 277 Primitive-name: # (handle array byte) + 278 0/imm32 + 279 Primitive-inouts: # (handle list var) 280 8/imm32 - 281 Primitive-subx-name: # (handle array byte) - 282 0xc/imm32 - 283 Primitive-subx-rm32: # enum arg-location - 284 0x10/imm32 - 285 Primitive-subx-r32: # enum arg-location - 286 0x14/imm32 - 287 Primitive-subx-imm32: # enum arg-location - 288 0x18/imm32 - 289 Primitive-subx-disp32: # enum arg-location -- only for branches - 290 0x1c/imm32 - 291 Primitive-output-is-write-only: # boolean - 292 0x20/imm32 - 293 Primitive-next: # (handle function) - 294 0x24/imm32 - 295 Primitive-size: # (addr int) - 296 0x28/imm32/36 - 297 - 298 Stmt-tag: # int - 299 0/imm32 - 300 - 301 Block-stmts: # (handle list stmt) - 302 4/imm32 - 303 Block-var: # (handle var) - 304 8/imm32 - 305 - 306 Stmt1-operation: # (handle array byte) - 307 4/imm32 - 308 Stmt1-inouts: # (handle stmt-var) - 309 8/imm32 - 310 Stmt1-outputs: # (handle stmt-var) + 281 Primitive-outputs: # (handle list var) + 282 0x10/imm32 + 283 Primitive-subx-name: # (handle array byte) + 284 0x18/imm32 + 285 Primitive-subx-rm32: # enum arg-location + 286 0x20/imm32 + 287 Primitive-subx-r32: # enum arg-location + 288 0x24/imm32 + 289 Primitive-subx-imm32: # enum arg-location + 290 0x28/imm32 + 291 Primitive-subx-disp32: # enum arg-location -- only for branches + 292 0x2c/imm32 + 293 Primitive-output-is-write-only: # boolean + 294 0x30/imm32 + 295 Primitive-next: # (handle function) + 296 0x34/imm32 + 297 Primitive-size: # (addr int) + 298 0x3c/imm32/60 + 299 + 300 Stmt-tag: # int + 301 0/imm32 + 302 + 303 Block-stmts: # (handle list stmt) + 304 4/imm32 + 305 Block-var: # (handle var) + 306 0xc/imm32 + 307 + 308 Stmt1-operation: # (handle array byte) + 309 4/imm32 + 310 Stmt1-inouts: # (handle stmt-var) 311 0xc/imm32 - 312 - 313 Vardef-var: # (handle var) - 314 4/imm32 - 315 - 316 Regvardef-operation: # (handle array byte) - 317 4/imm32 - 318 Regvardef-inouts: # (handle stmt-var) - 319 8/imm32 - 320 Regvardef-outputs: # (handle stmt-var) # will have exactly one element + 312 Stmt1-outputs: # (handle stmt-var) + 313 0x14/imm32 + 314 + 315 Vardef-var: # (handle var) + 316 4/imm32 + 317 + 318 Regvardef-operation: # (handle array byte) + 319 4/imm32 + 320 Regvardef-inouts: # (handle stmt-var) 321 0xc/imm32 - 322 - 323 Stmt-size: # (addr int) - 324 0x10/imm32 - 325 - 326 Var-name: # (handle array byte) - 327 0/imm32 - 328 Var-type: # (handle tree type-id) - 329 4/imm32 - 330 Var-block-depth: # int -- not available until code-generation time + 322 Regvardef-outputs: # (handle stmt-var) # will have exactly one element + 323 0x14/imm32 + 324 + 325 Stmt-size: # (addr int) + 326 0x1c/imm32 + 327 + 328 Var-name: # (handle array byte) + 329 0/imm32 + 330 Var-type: # (handle tree type-id) 331 8/imm32 - 332 Var-offset: # int -- not available until code-generation time - 333 0xc/imm32 - 334 Var-register: # (handle array byte) -- name of a register - 335 0x10/imm32 - 336 Var-size: # (addr int) - 337 0x14/imm32 - 338 - 339 Any-register: # wildcard - 340 # size - 341 1/imm32 - 342 # data - 343 2a/asterisk - 344 - 345 List-value: - 346 0/imm32 - 347 List-next: # (handle list _) - 348 4/imm32 - 349 List-size: # (addr int) - 350 8/imm32 - 351 - 352 # A stmt-var is like a list of vars with call-site specific metadata - 353 Stmt-var-value: # (handle var) - 354 0/imm32 - 355 Stmt-var-next: # (handle stmt-var) - 356 4/imm32 - 357 Stmt-var-is-deref: # boolean - 358 8/imm32 - 359 Stmt-var-size: # (addr int) - 360 0xc/imm32 - 361 - 362 # Types are expressed as trees (s-expressions) of type-ids (ints). - 363 # However, there's no need for singletons, so we can assume (int) == int - 364 # - if x->right == nil, x is an atom - 365 # - x->left contains either a pointer to a pair, or an atomic type-id directly. - 366 - 367 Tree-is-atom: # boolean - 368 0/imm32 - 369 # if left-is-atom? - 370 Tree-value: # type-id - 371 4/imm32 - 372 # unless left-is-atom? - 373 Tree-left: # (addr tree type-id) - 374 4/imm32 - 375 Tree-right: # (addr tree type-id) - 376 8/imm32 - 377 # - 378 Tree-size: # (addr int) - 379 0xc/imm32 - 380 - 381 # Types - 382 - 383 Type-id: # (stream (address array byte)) - 384 0x1c/imm32/write - 385 0/imm32/read - 386 0x100/imm32/size - 387 # data - 388 "literal"/imm32 # 0 - 389 "int"/imm32 # 1 - 390 "addr"/imm32 # 2 - 391 "array"/imm32 # 3 - 392 "handle"/imm32 # 4 - 393 "boolean"/imm32 # 5 - 394 "constant"/imm32 # 6: like a literal, but replaced with its value in Var-offset - 395 "offset"/imm32 # 7: (offset T) is guaranteed to be a 32-bit multiple of size-of(T) - 396 0/imm32 - 397 # 0x20 + 332 Var-block-depth: # int -- not available until code-generation time + 333 0x10/imm32 + 334 Var-offset: # int -- not available until code-generation time + 335 0x14/imm32 + 336 Var-register: # (handle array byte) -- name of a register + 337 0x18/imm32 + 338 Var-size: # (addr int) + 339 0x20/imm32 + 340 + 341 List-value: # (handle _) + 342 0/imm32 + 343 List-next: # (handle list _) + 344 8/imm32 + 345 List-size: # (addr int) + 346 0x10/imm32 + 347 + 348 # A stmt-var is like a list of vars with call-site specific metadata + 349 Stmt-var-value: # (handle var) + 350 0/imm32 + 351 Stmt-var-next: # (handle stmt-var) + 352 8/imm32 + 353 Stmt-var-is-deref: # boolean + 354 0x10/imm32 + 355 Stmt-var-size: # (addr int) + 356 0x14/imm32 + 357 + 358 # Types are expressed as trees (s-expressions) of type-ids (ints). + 359 # However, there's no need for singletons, so we can assume (int) == int + 360 # - if x->right == nil, x is an atom + 361 # - x->left contains either a pointer to a pair, or an atomic type-id directly. + 362 + 363 Tree-is-atom: # boolean + 364 0/imm32 + 365 # if left-is-atom? + 366 Tree-value: # type-id + 367 4/imm32 + 368 # unless left-is-atom? + 369 Tree-left: # (addr tree type-id) + 370 4/imm32 + 371 Tree-right: # (addr tree type-id) + 372 0xc/imm32 + 373 # + 374 Tree-size: # (addr int) + 375 0x14/imm32 + 376 + 377 # Types + 378 + 379 # TODO: heap allocations here can't be reclaimed + 380 Type-id: # (stream (addr array byte)) + 381 0x1c/imm32/write + 382 0/imm32/read + 383 0x100/imm32/size + 384 # data + 385 "literal"/imm32 # 0: value is just the name + 386 "int"/imm32 # 1 + 387 "addr"/imm32 # 2 + 388 "array"/imm32 # 3 + 389 "handle"/imm32 # 4 + 390 "boolean"/imm32 # 5 + 391 "constant"/imm32 # 6: like a literal, but value is an int in Var-offset + 392 "offset"/imm32 # 7: (offset T) is guaranteed to be a 32-bit multiple of size-of(T) + 393 0/imm32 + 394 # 0x20 + 395 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 + 396 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 + 397 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 398 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 399 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 400 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 401 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 - 402 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 - 403 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 - 404 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 - 405 - 406 # == Type definitions - 407 # Program->types contains some typeinfo for each type definition. - 408 # Types contain vars with types, but can't specify registers. - 409 Typeinfo-id: # type-id - 410 0/imm32 - 411 Typeinfo-fields: # (handle table string (handle typeinfo-entry)) - 412 4/imm32 - 413 # Total size must be >= 0 - 414 # During parsing it may take on two additional values: - 415 # -2: not yet initialized - 416 # -1: in process of being computed - 417 # See populate-mu-type-sizes for details. - 418 Typeinfo-total-size-in-bytes: # int - 419 8/imm32 - 420 Typeinfo-next: # (handle typeinfo) - 421 0xc/imm32 - 422 Typeinfo-size: # (addr int) - 423 0x10/imm32 - 424 - 425 # Each entry in the typeinfo->fields table has a pointer to a string and a - 426 # pointer to a typeinfo-entry. - 427 Typeinfo-fields-row-size: # (addr int) - 428 8/imm32 - 429 - 430 # typeinfo-entry objects have information about a field in a single record type - 431 # - 432 # each field of a type is represented using two var's: - 433 # 1. the input var: expected type of the field; convenient for creating using parse-var-with-type - 434 # 2. the output var: a constant containing the byte offset; convenient for code-generation - 435 # computing the output happens after parsing; in the meantime we preserve the - 436 # order of fields in the 'index' field. - 437 Typeinfo-entry-input-var: # (handle var) - 438 0/imm32 - 439 Typeinfo-entry-index: # int - 440 4/imm32 - 441 Typeinfo-entry-output-var: # (handle var) - 442 8/imm32 - 443 Typeinfo-entry-size: # (addr int) - 444 0xc/imm32 - 445 - 446 == code - 447 - 448 Entry: - 449 # . prologue - 450 89/<- %ebp 4/r32/esp - 451 (new-segment *Heap-size Heap) - 452 # if (argv[1] == "test') run-tests() - 453 { - 454 # if (argc <= 1) break - 455 81 7/subop/compare *ebp 1/imm32 - 456 7e/jump-if-<= break/disp8 - 457 # if (argv[1] != "test") break - 458 (kernel-string-equal? *(ebp+8) "test") # => eax - 459 3d/compare-eax-and 0/imm32/false - 460 74/jump-if-= break/disp8 - 461 # - 462 (run-tests) - 463 # syscall(exit, *Num-test-failures) - 464 8b/-> *Num-test-failures 3/r32/ebx - 465 eb/jump $mu-main:end/disp8 - 466 } - 467 # otherwise convert Stdin - 468 (convert-mu Stdin Stdout) - 469 (flush Stdout) - 470 # syscall(exit, 0) - 471 bb/copy-to-ebx 0/imm32 - 472 $mu-main:end: - 473 b8/copy-to-eax 1/imm32/exit - 474 cd/syscall 0x80/imm8 - 475 - 476 convert-mu: # in: (addr buffered-file), out: (addr buffered-file) - 477 # . prologue - 478 55/push-ebp - 479 89/<- %ebp 4/r32/esp - 480 # initialize global data structures - 481 c7 0/subop/copy *Next-block-index 1/imm32 - 482 c7 0/subop/copy *Type-id 0x1c/imm32 # stream-write - 483 c7 0/subop/copy *_Program-functions 0/imm32 - 484 c7 0/subop/copy *_Program-types 0/imm32 - 485 # - 486 (parse-mu *(ebp+8)) - 487 (populate-mu-type-sizes) - 488 (check-mu-types) - 489 (emit-subx *(ebp+0xc)) - 490 $convert-mu:end: - 491 # . epilogue - 492 89/<- %esp 5/r32/ebp - 493 5d/pop-to-ebp - 494 c3/return - 495 - 496 test-convert-empty-input: - 497 # empty input => empty output - 498 # . prologue - 499 55/push-ebp - 500 89/<- %ebp 4/r32/esp - 501 # setup - 502 (clear-stream _test-input-stream) - 503 (clear-stream $_test-input-buffered-file->buffer) - 504 (clear-stream _test-output-stream) - 505 (clear-stream $_test-output-buffered-file->buffer) - 506 # - 507 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 508 (flush _test-output-buffered-file) - 509 (check-stream-equal _test-output-stream "" "F - test-convert-empty-input") - 510 # . epilogue - 511 89/<- %esp 5/r32/ebp - 512 5d/pop-to-ebp - 513 c3/return - 514 - 515 test-convert-function-skeleton: - 516 # . prologue - 517 55/push-ebp - 518 89/<- %ebp 4/r32/esp - 519 # setup - 520 (clear-stream _test-input-stream) - 521 (clear-stream $_test-input-buffered-file->buffer) - 522 (clear-stream _test-output-stream) - 523 (clear-stream $_test-output-buffered-file->buffer) - 524 # - 525 (write _test-input-stream "fn foo {\n") - 526 (write _test-input-stream "}\n") - 527 # convert - 528 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 529 (flush _test-output-buffered-file) - 530 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 536 # check output - 537 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-skeleton/0") - 538 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-skeleton/1") - 539 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-skeleton/2") - 540 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-skeleton/3") - 541 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-skeleton/4") - 542 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-skeleton/5") - 543 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-skeleton/6") - 544 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-skeleton/7") - 545 # . epilogue - 546 89/<- %esp 5/r32/ebp - 547 5d/pop-to-ebp - 548 c3/return - 549 - 550 test-convert-multiple-function-skeletons: - 551 # . prologue - 552 55/push-ebp - 553 89/<- %ebp 4/r32/esp - 554 # setup - 555 (clear-stream _test-input-stream) - 556 (clear-stream $_test-input-buffered-file->buffer) - 557 (clear-stream _test-output-stream) - 558 (clear-stream $_test-output-buffered-file->buffer) - 559 # - 560 (write _test-input-stream "fn foo {\n") - 561 (write _test-input-stream "}\n") - 562 (write _test-input-stream "fn bar {\n") - 563 (write _test-input-stream "}\n") - 564 # convert - 565 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 566 (flush _test-output-buffered-file) - 567 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 573 # check first function - 574 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-multiple-function-skeletons/0") - 575 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-multiple-function-skeletons/1") - 576 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-multiple-function-skeletons/2") - 577 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-multiple-function-skeletons/3") - 578 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-multiple-function-skeletons/4") - 579 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-multiple-function-skeletons/5") - 580 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-multiple-function-skeletons/6") - 581 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-multiple-function-skeletons/7") - 582 # check second function - 583 (check-next-stream-line-equal _test-output-stream "bar:" "F - test-convert-multiple-function-skeletons/10") - 584 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-multiple-function-skeletons/11") - 585 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-multiple-function-skeletons/12") - 586 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-multiple-function-skeletons/13") - 587 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-multiple-function-skeletons/14") - 588 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-multiple-function-skeletons/15") - 589 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-multiple-function-skeletons/16") - 590 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-multiple-function-skeletons/17") - 591 # . epilogue - 592 89/<- %esp 5/r32/ebp - 593 5d/pop-to-ebp - 594 c3/return - 595 - 596 test-convert-function-with-arg: - 597 # . prologue - 598 55/push-ebp - 599 89/<- %ebp 4/r32/esp - 600 # setup - 601 (clear-stream _test-input-stream) - 602 (clear-stream $_test-input-buffered-file->buffer) - 603 (clear-stream _test-output-stream) - 604 (clear-stream $_test-output-buffered-file->buffer) - 605 # - 606 (write _test-input-stream "fn foo n: int {\n") - 607 (write _test-input-stream "}\n") - 608 # convert - 609 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 610 (flush _test-output-buffered-file) - 611 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 617 # check output - 618 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-arg/0") - 619 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-arg/1") - 620 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-arg/2") - 621 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-arg/3") - 622 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-arg/4") - 623 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-arg/5") - 624 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-arg/6") - 625 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-arg/7") - 626 # . epilogue - 627 89/<- %esp 5/r32/ebp - 628 5d/pop-to-ebp - 629 c3/return - 630 - 631 test-convert-function-with-arg-and-body: - 632 # . prologue - 633 55/push-ebp - 634 89/<- %ebp 4/r32/esp - 635 # setup - 636 (clear-stream _test-input-stream) - 637 (clear-stream $_test-input-buffered-file->buffer) - 638 (clear-stream _test-output-stream) - 639 (clear-stream $_test-output-buffered-file->buffer) - 640 # - 641 (write _test-input-stream "fn foo n: int {\n") - 642 (write _test-input-stream " increment n\n") - 643 (write _test-input-stream "}\n") - 644 # convert - 645 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 646 (flush _test-output-buffered-file) - 647 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 653 # check output - 654 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-arg-and-body/0") - 655 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-arg-and-body/1") - 656 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-arg-and-body/2") - 657 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-arg-and-body/3") - 658 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-arg-and-body/4") - 659 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-arg-and-body/5") - 660 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0x00000008)" "F - test-convert-function-with-arg-and-body/6") - 661 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-arg-and-body/7") - 662 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-arg-and-body/8") - 663 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-arg-and-body/9") - 664 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-arg-and-body/10") - 665 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-arg-and-body/11") - 666 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-arg-and-body/12") - 667 # . epilogue - 668 89/<- %esp 5/r32/ebp - 669 5d/pop-to-ebp - 670 c3/return - 671 - 672 test-convert-function-distinguishes-args: - 673 # . prologue - 674 55/push-ebp - 675 89/<- %ebp 4/r32/esp - 676 # setup - 677 (clear-stream _test-input-stream) - 678 (clear-stream $_test-input-buffered-file->buffer) - 679 (clear-stream _test-output-stream) - 680 (clear-stream $_test-output-buffered-file->buffer) - 681 # - 682 (write _test-input-stream "fn foo a: int, b: int {\n") - 683 (write _test-input-stream " increment b\n") - 684 (write _test-input-stream "}\n") - 685 # convert - 686 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 687 (flush _test-output-buffered-file) - 688 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 694 # check output - 695 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-distinguishes-args/0") - 696 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-distinguishes-args/1") - 697 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-distinguishes-args/2") - 698 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-distinguishes-args/3") - 699 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-distinguishes-args/4") - 700 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-distinguishes-args/5") - 701 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0x0000000c)" "F - test-convert-function-distinguishes-args/6") - 702 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-distinguishes-args/7") - 703 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-distinguishes-args/8") - 704 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-distinguishes-args/9") - 705 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-distinguishes-args/10") - 706 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-distinguishes-args/11") - 707 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-distinguishes-args/12") - 708 # . epilogue - 709 89/<- %esp 5/r32/ebp - 710 5d/pop-to-ebp - 711 c3/return - 712 - 713 test-convert-function-returns-result: - 714 # . prologue - 715 55/push-ebp - 716 89/<- %ebp 4/r32/esp - 717 # setup - 718 (clear-stream _test-input-stream) - 719 (clear-stream $_test-input-buffered-file->buffer) - 720 (clear-stream _test-output-stream) - 721 (clear-stream $_test-output-buffered-file->buffer) - 722 # - 723 (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n") - 724 (write _test-input-stream " result <- copy a\n") - 725 (write _test-input-stream " result <- increment\n") - 726 (write _test-input-stream "}\n") - 727 # convert - 728 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 729 (flush _test-output-buffered-file) - 730 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 736 # check output - 737 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-returns-result/0") - 738 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-returns-result/1") - 739 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-returns-result/2") - 740 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-returns-result/3") - 741 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-returns-result/4") - 742 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-returns-result/5") - 743 (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-function-returns-result/6") - 744 (check-next-stream-line-equal _test-output-stream " 40/increment-eax" "F - test-convert-function-returns-result/7") - 745 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-returns-result/8") - 746 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-returns-result/9") - 747 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-returns-result/10") - 748 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-returns-result/11") - 749 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-returns-result/12") - 750 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-returns-result/13") - 751 # . epilogue - 752 89/<- %esp 5/r32/ebp - 753 5d/pop-to-ebp - 754 c3/return - 755 - 756 test-convert-function-with-literal-arg: - 757 # . prologue - 758 55/push-ebp - 759 89/<- %ebp 4/r32/esp - 760 # setup - 761 (clear-stream _test-input-stream) - 762 (clear-stream $_test-input-buffered-file->buffer) - 763 (clear-stream _test-output-stream) - 764 (clear-stream $_test-output-buffered-file->buffer) - 765 # - 766 (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n") - 767 (write _test-input-stream " result <- copy a\n") - 768 (write _test-input-stream " result <- add 1\n") - 769 (write _test-input-stream "}\n") - 770 # convert - 771 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 772 (flush _test-output-buffered-file) - 773 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 779 # check output - 780 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-literal-arg/0") - 781 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-literal-arg/1") - 782 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-literal-arg/2") - 783 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-literal-arg/3") - 784 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-literal-arg/4") - 785 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-literal-arg/5") - 786 (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-function-with-literal-arg/6") - 787 (check-next-stream-line-equal _test-output-stream " 05/add-to-eax 1/imm32" "F - test-convert-function-with-literal-arg/7") - 788 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-literal-arg/8") - 789 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-literal-arg/9") - 790 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-literal-arg/10") - 791 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-literal-arg/11") - 792 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-literal-arg/12") - 793 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-literal-arg/13") - 794 # . epilogue - 795 89/<- %esp 5/r32/ebp - 796 5d/pop-to-ebp - 797 c3/return - 798 - 799 test-convert-function-with-literal-arg-2: - 800 # . prologue - 801 55/push-ebp - 802 89/<- %ebp 4/r32/esp - 803 # setup - 804 (clear-stream _test-input-stream) - 805 (clear-stream $_test-input-buffered-file->buffer) - 806 (clear-stream _test-output-stream) - 807 (clear-stream $_test-output-buffered-file->buffer) - 808 # - 809 (write _test-input-stream "fn foo a: int, b: int -> result/ebx: int {\n") - 810 (write _test-input-stream " result <- copy a\n") - 811 (write _test-input-stream " result <- add 1\n") - 812 (write _test-input-stream "}\n") - 813 # convert - 814 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 815 (flush _test-output-buffered-file) - 816 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 822 # check output - 823 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-literal-arg-2/0") - 824 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-literal-arg-2/1") - 825 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-literal-arg-2/2") - 826 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-literal-arg-2/3") - 827 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-literal-arg-2/4") - 828 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-literal-arg-2/5") - 829 (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x00000008) 0x00000003/r32" "F - test-convert-function-with-literal-arg-2/6") - 830 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %ebx 1/imm32" "F - test-convert-function-with-literal-arg-2/7") - 831 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-literal-arg-2/8") - 832 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-literal-arg-2/9") - 833 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-literal-arg-2/10") - 834 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-literal-arg-2/11") - 835 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-literal-arg-2/12") - 836 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-literal-arg-2/13") - 837 # . epilogue - 838 89/<- %esp 5/r32/ebp - 839 5d/pop-to-ebp - 840 c3/return - 841 - 842 test-convert-function-call-with-literal-arg: - 843 # . prologue - 844 55/push-ebp - 845 89/<- %ebp 4/r32/esp - 846 # setup - 847 (clear-stream _test-input-stream) - 848 (clear-stream $_test-input-buffered-file->buffer) - 849 (clear-stream _test-output-stream) - 850 (clear-stream $_test-output-buffered-file->buffer) - 851 # - 852 (write _test-input-stream "fn main -> result/ebx: int {\n") - 853 (write _test-input-stream " result <- do-add 3 4\n") - 854 (write _test-input-stream "}\n") - 855 (write _test-input-stream "fn do-add a: int, b: int -> result/ebx: int {\n") - 856 (write _test-input-stream " result <- copy a\n") - 857 (write _test-input-stream " result <- add b\n") - 858 (write _test-input-stream "}\n") - 859 # convert - 860 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 861 (flush _test-output-buffered-file) - 862 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 868 # check output - 869 (check-next-stream-line-equal _test-output-stream "main:" "F - test-convert-function-call-with-literal-arg/0") - 870 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-literal-arg/1") - 871 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-literal-arg/2") - 872 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-literal-arg/3") - 873 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-literal-arg/4") - 874 (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:" "F - test-convert-function-call-with-literal-arg/5") - 875 (check-next-stream-line-equal _test-output-stream " (do-add 3 4)" "F - test-convert-function-call-with-literal-arg/6") - 876 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-literal-arg/7") - 877 (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-literal-arg/8") - 878 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-literal-arg/9") - 879 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-literal-arg/10") - 880 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-literal-arg/11") - 881 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-literal-arg/12") - 882 (check-next-stream-line-equal _test-output-stream "do-add:" "F - test-convert-function-call-with-literal-arg/13") - 883 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-literal-arg/14") - 884 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-literal-arg/15") - 885 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-literal-arg/16") - 886 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-literal-arg/17") - 887 (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:loop:" "F - test-convert-function-call-with-literal-arg/18") - 888 (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x00000008) 0x00000003/r32" "F - test-convert-function-call-with-literal-arg/19") - 889 (check-next-stream-line-equal _test-output-stream " 03/add *(ebp+0x0000000c) 0x00000003/r32" "F - test-convert-function-call-with-literal-arg/20") - 890 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-literal-arg/21") - 891 (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:break:" "F - test-convert-function-call-with-literal-arg/22") - 892 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-literal-arg/23") - 893 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-literal-arg/24") - 894 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-literal-arg/25") - 895 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-literal-arg/26") - 896 # . epilogue - 897 89/<- %esp 5/r32/ebp - 898 5d/pop-to-ebp - 899 c3/return - 900 - 901 test-convert-function-with-local-var-in-mem: - 902 # . prologue - 903 55/push-ebp - 904 89/<- %ebp 4/r32/esp - 905 # setup - 906 (clear-stream _test-input-stream) - 907 (clear-stream $_test-input-buffered-file->buffer) - 908 (clear-stream _test-output-stream) - 909 (clear-stream $_test-output-buffered-file->buffer) - 910 # - 911 (write _test-input-stream "fn foo {\n") - 912 (write _test-input-stream " var x: int\n") - 913 (write _test-input-stream " increment x\n") - 914 (write _test-input-stream "}\n") - 915 # convert - 916 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 917 (flush _test-output-buffered-file) - 918 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 924 # check output - 925 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-in-mem/0") - 926 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-in-mem/1") - 927 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-in-mem/2") - 928 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-in-mem/3") - 929 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-mem/4") - 930 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-in-mem/5") - 931 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-local-var-in-mem/6") - 932 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-local-var-in-mem/7") - 933 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-local-var-in-mem/8") - 934 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-mem/9") - 935 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-in-mem/10") - 936 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-in-mem/11") - 937 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-in-mem/12") - 938 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-in-mem/13") - 939 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-in-mem/14") - 940 # . epilogue - 941 89/<- %esp 5/r32/ebp - 942 5d/pop-to-ebp - 943 c3/return - 944 - 945 test-convert-function-with-local-var-with-compound-type-in-mem: - 946 # . prologue - 947 55/push-ebp - 948 89/<- %ebp 4/r32/esp - 949 # setup - 950 (clear-stream _test-input-stream) - 951 (clear-stream $_test-input-buffered-file->buffer) - 952 (clear-stream _test-output-stream) - 953 (clear-stream $_test-output-buffered-file->buffer) - 954 # - 955 (write _test-input-stream "fn foo {\n") - 956 (write _test-input-stream " var x: (addr int)\n") - 957 (write _test-input-stream " copy-to x, 0\n") - 958 (write _test-input-stream "}\n") - 959 # convert - 960 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 961 (flush _test-output-buffered-file) - 962 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 968 # check output - 969 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-with-compound-type-in-mem/0") - 970 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-with-compound-type-in-mem/1") - 971 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-with-compound-type-in-mem/2") - 972 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-with-compound-type-in-mem/3") - 973 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-with-compound-type-in-mem/4") - 974 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-with-compound-type-in-mem/5") - 975 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-local-var-with-compound-type-in-mem/6") - 976 (check-next-stream-line-equal _test-output-stream " c7 0/subop/copy *(ebp+0xfffffffc) 0/imm32" "F - test-convert-function-with-local-var-with-compound-type-in-mem/7") - 977 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-local-var-with-compound-type-in-mem/8") - 978 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-with-compound-type-in-mem/9") - 979 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-with-compound-type-in-mem/10") - 980 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-with-compound-type-in-mem/11") - 981 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-with-compound-type-in-mem/12") - 982 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-with-compound-type-in-mem/13") - 983 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-with-compound-type-in-mem/14") - 984 # . epilogue - 985 89/<- %esp 5/r32/ebp - 986 5d/pop-to-ebp - 987 c3/return - 988 - 989 test-convert-function-with-local-var-in-reg: - 990 # . prologue - 991 55/push-ebp - 992 89/<- %ebp 4/r32/esp - 993 # setup - 994 (clear-stream _test-input-stream) - 995 (clear-stream $_test-input-buffered-file->buffer) - 996 (clear-stream _test-output-stream) - 997 (clear-stream $_test-output-buffered-file->buffer) - 998 # - 999 (write _test-input-stream "fn foo {\n") - 1000 (write _test-input-stream " var x/ecx: int <- copy 3\n") - 1001 (write _test-input-stream " x <- increment\n") - 1002 (write _test-input-stream "}\n") - 1003 # convert - 1004 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 1005 (flush _test-output-buffered-file) - 1006 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1012 # check output - 1013 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-in-reg/0") - 1014 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-in-reg/1") - 1015 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-in-reg/2") - 1016 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-in-reg/3") - 1017 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-reg/4") - 1018 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-in-reg/5") - 1019 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-with-local-var-in-reg/6") - 1020 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-function-with-local-var-in-reg/7") - 1021 (check-next-stream-line-equal _test-output-stream " 41/increment-ecx" "F - test-convert-function-with-local-var-in-reg/8") - 1022 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-in-reg/9") - 1023 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-reg/10") - 1024 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-in-reg/11") - 1025 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-in-reg/12") - 1026 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-in-reg/13") - 1027 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-in-reg/14") - 1028 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-in-reg/15") - 1029 # . epilogue - 1030 89/<- %esp 5/r32/ebp - 1031 5d/pop-to-ebp - 1032 c3/return - 1033 - 1034 test-convert-function-with-second-local-var-in-same-reg: - 1035 # . prologue - 1036 55/push-ebp - 1037 89/<- %ebp 4/r32/esp - 1038 # setup - 1039 (clear-stream _test-input-stream) - 1040 (clear-stream $_test-input-buffered-file->buffer) - 1041 (clear-stream _test-output-stream) - 1042 (clear-stream $_test-output-buffered-file->buffer) - 1043 # - 1044 (write _test-input-stream "fn foo {\n") - 1045 (write _test-input-stream " var x/ecx: int <- copy 3\n") - 1046 (write _test-input-stream " var y/ecx: int <- copy 4\n") - 1047 (write _test-input-stream " y <- increment\n") - 1048 (write _test-input-stream "}\n") - 1049 # convert - 1050 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 1051 (flush _test-output-buffered-file) - 1052 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1058 # check output - 1059 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-second-local-var-in-same-reg/0") - 1060 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-second-local-var-in-same-reg/1") - 1061 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-second-local-var-in-same-reg/2") - 1062 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-second-local-var-in-same-reg/3") - 1063 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-second-local-var-in-same-reg/4") - 1064 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-second-local-var-in-same-reg/5") - 1065 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-with-second-local-var-in-same-reg/6") - 1066 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-function-with-second-local-var-in-same-reg/7") - 1067 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-convert-function-with-second-local-var-in-same-reg/8") - 1068 (check-next-stream-line-equal _test-output-stream " 41/increment-ecx" "F - test-convert-function-with-second-local-var-in-same-reg/9") - 1069 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-with-second-local-var-in-same-reg/10") - 1070 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-second-local-var-in-same-reg/11") - 1071 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-second-local-var-in-same-reg/12") - 1072 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-second-local-var-in-same-reg/13") - 1073 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-second-local-var-in-same-reg/14") - 1074 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-second-local-var-in-same-reg/15") - 1075 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-second-local-var-in-same-reg/16") - 1076 # . epilogue - 1077 89/<- %esp 5/r32/ebp - 1078 5d/pop-to-ebp - 1079 c3/return - 1080 - 1081 test-convert-function-with-local-var-dereferenced: - 1082 # . prologue - 1083 55/push-ebp - 1084 89/<- %ebp 4/r32/esp - 1085 # setup - 1086 (clear-stream _test-input-stream) - 1087 (clear-stream $_test-input-buffered-file->buffer) - 1088 (clear-stream _test-output-stream) - 1089 (clear-stream $_test-output-buffered-file->buffer) - 1090 # - 1091 (write _test-input-stream "fn foo {\n") - 1092 (write _test-input-stream " var x/ecx: (addr int) <- copy 0\n") - 1093 (write _test-input-stream " increment *x\n") - 1094 (write _test-input-stream "}\n") - 1095 # convert - 1096 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 1097 (flush _test-output-buffered-file) - 1098 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1104 # check output - 1105 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-dereferenced/0") - 1106 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-dereferenced/1") - 1107 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-dereferenced/2") - 1108 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-dereferenced/3") - 1109 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-dereferenced/4") - 1110 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-dereferenced/5") - 1111 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-with-local-var-dereferenced/6") - 1112 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 0/imm32" "F - test-convert-function-with-local-var-dereferenced/7") - 1113 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *ecx" "F - test-convert-function-with-local-var-dereferenced/8") - 1114 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-dereferenced/9") - 1115 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-dereferenced/10") - 1116 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-dereferenced/11") - 1117 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-dereferenced/12") - 1118 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-dereferenced/13") - 1119 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-dereferenced/14") - 1120 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-dereferenced/15") - 1121 # . epilogue - 1122 89/<- %esp 5/r32/ebp - 1123 5d/pop-to-ebp - 1124 c3/return - 1125 - 1126 test-convert-compare-register-with-literal: - 1127 # . prologue - 1128 55/push-ebp - 1129 89/<- %ebp 4/r32/esp - 1130 # setup - 1131 (clear-stream _test-input-stream) - 1132 (clear-stream $_test-input-buffered-file->buffer) - 1133 (clear-stream _test-output-stream) - 1134 (clear-stream $_test-output-buffered-file->buffer) - 1135 # - 1136 (write _test-input-stream "fn foo {\n") - 1137 (write _test-input-stream " var x/ecx: int <- copy 0\n") - 1138 (write _test-input-stream " compare x, 0\n") - 1139 (write _test-input-stream "}\n") - 1140 # convert - 1141 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 1142 (flush _test-output-buffered-file) - 1143 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1149 # check output - 1150 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-compare-register-with-literal/0") - 1151 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-compare-register-with-literal/1") - 1152 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-compare-register-with-literal/2") - 1153 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-compare-register-with-literal/3") - 1154 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-compare-register-with-literal/4") - 1155 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-compare-register-with-literal/5") - 1156 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-compare-register-with-literal/6") - 1157 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 0/imm32" "F - test-convert-compare-register-with-literal/7") - 1158 (check-next-stream-line-equal _test-output-stream " 81 7/subop/compare %ecx 0/imm32" "F - test-convert-compare-register-with-literal/8") - 1159 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9") - 1160 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-compare-register-with-literal/10") - 1161 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-compare-register-with-literal/11") - 1162 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-compare-register-with-literal/12") - 1163 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-compare-register-with-literal/13") - 1164 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-compare-register-with-literal/14") - 1165 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-compare-register-with-literal/15") - 1166 # . epilogue - 1167 89/<- %esp 5/r32/ebp - 1168 5d/pop-to-ebp - 1169 c3/return - 1170 - 1171 test-convert-function-with-local-var-in-block: - 1172 # . prologue - 1173 55/push-ebp - 1174 89/<- %ebp 4/r32/esp - 1175 # setup - 1176 (clear-stream _test-input-stream) - 1177 (clear-stream $_test-input-buffered-file->buffer) - 1178 (clear-stream _test-output-stream) - 1179 (clear-stream $_test-output-buffered-file->buffer) - 1180 # - 1181 (write _test-input-stream "fn foo {\n") - 1182 (write _test-input-stream " {\n") - 1183 (write _test-input-stream " var x: int\n") - 1184 (write _test-input-stream " increment x\n") - 1185 (write _test-input-stream " }\n") - 1186 (write _test-input-stream "}\n") - 1187 # convert - 1188 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 1189 (flush _test-output-buffered-file) - 1190 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1196 # check output - 1197 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-in-block/0") - 1198 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-in-block/1") - 1199 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-in-block/2") - 1200 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-in-block/3") - 1201 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-block/4") - 1202 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-in-block/5") - 1203 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-block/6") - 1204 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-local-var-in-block/7") - 1205 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-local-var-in-block/8") - 1206 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-local-var-in-block/9") - 1207 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-local-var-in-block/10") - 1208 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-block/11") - 1209 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-local-var-in-block/12") - 1210 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-block/13") - 1211 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-in-block/14") - 1212 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-in-block/15") - 1213 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-in-block/16") - 1214 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-in-block/17") - 1215 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-in-block/18") - 1216 # . epilogue - 1217 89/<- %esp 5/r32/ebp - 1218 5d/pop-to-ebp - 1219 c3/return - 1220 - 1221 test-convert-function-with-local-var-in-named-block: - 1222 # . prologue - 1223 55/push-ebp - 1224 89/<- %ebp 4/r32/esp - 1225 # setup - 1226 (clear-stream _test-input-stream) - 1227 (clear-stream $_test-input-buffered-file->buffer) - 1228 (clear-stream _test-output-stream) - 1229 (clear-stream $_test-output-buffered-file->buffer) - 1230 # - 1231 (write _test-input-stream "fn foo {\n") - 1232 (write _test-input-stream " $bar: {\n") - 1233 (write _test-input-stream " var x: int\n") - 1234 (write _test-input-stream " increment x\n") - 1235 (write _test-input-stream " }\n") - 1236 (write _test-input-stream "}\n") - 1237 # convert - 1238 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 1239 (flush _test-output-buffered-file) - 1240 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1246 # check output - 1247 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-in-named-block/0") - 1248 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-in-named-block/1") - 1249 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-in-named-block/2") - 1250 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-in-named-block/3") - 1251 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-named-block/4") - 1252 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-in-named-block/5") - 1253 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-named-block/6") - 1254 (check-next-stream-line-equal _test-output-stream "$bar:loop:" "F - test-convert-function-with-local-var-in-named-block/7") - 1255 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-local-var-in-named-block/8") - 1256 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-local-var-in-named-block/9") - 1257 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-local-var-in-named-block/10") - 1258 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-named-block/11") - 1259 (check-next-stream-line-equal _test-output-stream "$bar:break:" "F - test-convert-function-with-local-var-in-named-block/12") - 1260 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-named-block/13") - 1261 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-in-named-block/14") - 1262 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-in-named-block/15") - 1263 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-in-named-block/16") - 1264 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-in-named-block/17") - 1265 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-in-named-block/18") - 1266 # . epilogue - 1267 89/<- %esp 5/r32/ebp - 1268 5d/pop-to-ebp - 1269 c3/return - 1270 - 1271 test-always-shadow-outermost-reg-vars-in-function: - 1272 # . prologue - 1273 55/push-ebp - 1274 89/<- %ebp 4/r32/esp - 1275 # setup - 1276 (clear-stream _test-input-stream) - 1277 (clear-stream $_test-input-buffered-file->buffer) - 1278 (clear-stream _test-output-stream) - 1279 (clear-stream $_test-output-buffered-file->buffer) - 1280 # - 1281 (write _test-input-stream "fn foo {\n") - 1282 (write _test-input-stream " var x/ecx: int <- copy 3\n") - 1283 (write _test-input-stream "}\n") - 1284 # convert - 1285 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 1286 (flush _test-output-buffered-file) - 1287 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1293 # check output - 1294 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-always-shadow-outermost-reg-vars-in-function/0") - 1295 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-always-shadow-outermost-reg-vars-in-function/1") - 1296 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-always-shadow-outermost-reg-vars-in-function/2") - 1297 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-always-shadow-outermost-reg-vars-in-function/3") - 1298 (check-next-stream-line-equal _test-output-stream " {" "F - test-always-shadow-outermost-reg-vars-in-function/4") - 1299 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-always-shadow-outermost-reg-vars-in-function/5") - 1300 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-compare-register-with-literal/6") - 1301 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-always-shadow-outermost-reg-vars-in-function/8") - 1302 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9") - 1303 (check-next-stream-line-equal _test-output-stream " }" "F - test-always-shadow-outermost-reg-vars-in-function/12") - 1304 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-always-shadow-outermost-reg-vars-in-function/13") - 1305 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-always-shadow-outermost-reg-vars-in-function/14") - 1306 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-always-shadow-outermost-reg-vars-in-function/15") - 1307 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-always-shadow-outermost-reg-vars-in-function/16") - 1308 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-always-shadow-outermost-reg-vars-in-function/17") - 1309 # . epilogue - 1310 89/<- %esp 5/r32/ebp - 1311 5d/pop-to-ebp - 1312 c3/return - 1313 - 1314 _pending-test-clobber-dead-local: - 1315 # . prologue - 1316 55/push-ebp - 1317 89/<- %ebp 4/r32/esp - 1318 # setup - 1319 (clear-stream _test-input-stream) - 1320 (clear-stream $_test-input-buffered-file->buffer) - 1321 (clear-stream _test-output-stream) - 1322 (clear-stream $_test-output-buffered-file->buffer) - 1323 # - 1324 (write _test-input-stream "fn foo {\n") - 1325 (write _test-input-stream " var x/ecx: int <- copy 3\n") - 1326 (write _test-input-stream " {\n") - 1327 (write _test-input-stream " var y/ecx: int <- copy 4\n") - 1328 (write _test-input-stream " }\n") - 1329 (write _test-input-stream "}\n") - 1330 # convert - 1331 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 1332 (flush _test-output-buffered-file) - 1333 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1339 # check output - 1340 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-clobber-dead-local/0") - 1341 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-clobber-dead-local/1") - 1342 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-clobber-dead-local/2") - 1343 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-clobber-dead-local/3") - 1344 (check-next-stream-line-equal _test-output-stream " {" "F - test-clobber-dead-local/4") - 1345 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-clobber-dead-local/5") - 1346 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-clobber-dead-local/6") - 1347 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-clobber-dead-local/7") - 1348 (check-next-stream-line-equal _test-output-stream " {" "F - test-clobber-dead-local/8") - 1349 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-clobber-dead-local/9") - 1350 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-clobber-dead-local/10") # no push/pop here - 1351 (check-next-stream-line-equal _test-output-stream " }" "F - test-clobber-dead-local/11") - 1352 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-clobber-dead-local/12") - 1353 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-clobber-dead-local/13") - 1354 (check-next-stream-line-equal _test-output-stream " }" "F - test-clobber-dead-local/14") - 1355 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-clobber-dead-local/15") - 1356 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-clobber-dead-local/16") - 1357 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-clobber-dead-local/17") - 1358 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-clobber-dead-local/18") - 1359 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-clobber-dead-local/19") - 1360 # . epilogue - 1361 89/<- %esp 5/r32/ebp - 1362 5d/pop-to-ebp - 1363 c3/return - 1364 - 1365 test-shadow-live-local: - 1366 # . prologue - 1367 55/push-ebp - 1368 89/<- %ebp 4/r32/esp - 1369 # setup - 1370 (clear-stream _test-input-stream) - 1371 (clear-stream $_test-input-buffered-file->buffer) - 1372 (clear-stream _test-output-stream) - 1373 (clear-stream $_test-output-buffered-file->buffer) - 1374 # - 1375 (write _test-input-stream "fn foo {\n") - 1376 (write _test-input-stream " var x/ecx: int <- copy 3\n") - 1377 (write _test-input-stream " {\n") - 1378 (write _test-input-stream " var y/ecx: int <- copy 4\n") - 1379 (write _test-input-stream " }\n") - 1380 (write _test-input-stream " x <- increment\n") - 1381 (write _test-input-stream "}\n") - 1382 # convert - 1383 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 1384 (flush _test-output-buffered-file) - 1385 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1391 # check output - 1392 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-shadow-live-local/0") - 1393 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-shadow-live-local/1") - 1394 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-shadow-live-local/2") - 1395 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-shadow-live-local/3") - 1396 (check-next-stream-line-equal _test-output-stream " {" "F - test-shadow-live-local/4") - 1397 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-shadow-live-local/5") - 1398 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-shadow-live-local/6") - 1399 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-shadow-live-local/7") - 1400 (check-next-stream-line-equal _test-output-stream " {" "F - test-shadow-live-local/8") - 1401 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-shadow-live-local/9") - 1402 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-shadow-live-local/10") - 1403 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-shadow-live-local/11") - 1404 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-shadow-live-local/12") - 1405 (check-next-stream-line-equal _test-output-stream " }" "F - test-shadow-live-local/13") - 1406 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-shadow-live-local/14") - 1407 (check-next-stream-line-equal _test-output-stream " 41/increment-ecx" "F - test-shadow-live-local/15") - 1408 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-shadow-live-local/16") - 1409 (check-next-stream-line-equal _test-output-stream " }" "F - test-shadow-live-local/17") - 1410 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-shadow-live-local/18") - 1411 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-shadow-live-local/19") - 1412 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-shadow-live-local/20") - 1413 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-shadow-live-local/21") - 1414 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-shadow-live-local/21") - 1415 # . epilogue - 1416 89/<- %esp 5/r32/ebp - 1417 5d/pop-to-ebp - 1418 c3/return - 1419 - 1420 test-shadow-live-output: - 1421 # . prologue - 1422 55/push-ebp - 1423 89/<- %ebp 4/r32/esp - 1424 # setup - 1425 (clear-stream _test-input-stream) - 1426 (clear-stream $_test-input-buffered-file->buffer) - 1427 (clear-stream _test-output-stream) - 1428 (clear-stream $_test-output-buffered-file->buffer) - 1429 # - 1430 (write _test-input-stream "fn foo -> x/ecx: int {\n") - 1431 (write _test-input-stream " x <- copy 3\n") - 1432 (write _test-input-stream " {\n") - 1433 (write _test-input-stream " var y/ecx: int <- copy 4\n") - 1434 (write _test-input-stream " }\n") - 1435 (write _test-input-stream " x <- increment\n") - 1436 (write _test-input-stream "}\n") - 1437 # convert - 1438 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 1439 (flush _test-output-buffered-file) - 1440 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1446 # check output - 1447 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-shadow-live-output/0") - 1448 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-shadow-live-output/1") - 1449 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-shadow-live-output/2") - 1450 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-shadow-live-output/3") - 1451 (check-next-stream-line-equal _test-output-stream " {" "F - test-shadow-live-output/4") - 1452 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-shadow-live-output/5") - 1453 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-shadow-live-output/7") # no push because it's an output reg - 1454 (check-next-stream-line-equal _test-output-stream " {" "F - test-shadow-live-output/8") - 1455 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-shadow-live-output/9") - 1456 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-shadow-live-output/10") - 1457 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-shadow-live-output/11") - 1458 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-shadow-live-output/12") - 1459 (check-next-stream-line-equal _test-output-stream " }" "F - test-shadow-live-output/13") - 1460 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-shadow-live-output/14") - 1461 (check-next-stream-line-equal _test-output-stream " 41/increment-ecx" "F - test-shadow-live-output/15") - 1462 (check-next-stream-line-equal _test-output-stream " }" "F - test-shadow-live-output/17") - 1463 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-shadow-live-output/18") - 1464 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-shadow-live-output/19") - 1465 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-shadow-live-output/20") - 1466 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-shadow-live-output/21") - 1467 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-shadow-live-output/21") - 1468 # . epilogue - 1469 89/<- %esp 5/r32/ebp - 1470 5d/pop-to-ebp - 1471 c3/return - 1472 - 1473 _pending-test-local-clobbered-by-output: - 1474 # also doesn't spill - 1475 # . prologue - 1476 55/push-ebp - 1477 89/<- %ebp 4/r32/esp - 1478 # setup - 1479 (clear-stream _test-input-stream) - 1480 (clear-stream $_test-input-buffered-file->buffer) - 1481 (clear-stream _test-output-stream) - 1482 (clear-stream $_test-output-buffered-file->buffer) - 1483 # - 1484 (write _test-input-stream "fn foo -> x/ecx: int {\n") - 1485 (write _test-input-stream " var y/ecx: int <- copy 4\n") - 1486 (write _test-input-stream " x <- copy y\n") - 1487 (write _test-input-stream "}\n") - 1488 # convert - 1489 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 1490 (flush _test-output-buffered-file) - 1491 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1497 # check output - 1498 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-local-clobbered-by-output/0") - 1499 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-local-clobbered-by-output/1") - 1500 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-local-clobbered-by-output/2") - 1501 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-local-clobbered-by-output/3") - 1502 (check-next-stream-line-equal _test-output-stream " {" "F - test-local-clobbered-by-output/4") - 1503 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-local-clobbered-by-output/5") - 1504 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-local-clobbered-by-output/6") - 1505 (check-next-stream-line-equal _test-output-stream " 89/<- %ecx 0x00000001/r32" "F - test-local-clobbered-by-output/7") - 1506 (check-next-stream-line-equal _test-output-stream " }" "F - test-local-clobbered-by-output/8") - 1507 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-local-clobbered-by-output/9") - 1508 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-local-clobbered-by-output/10") - 1509 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-local-clobbered-by-output/11") - 1510 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-local-clobbered-by-output/12") - 1511 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-local-clobbered-by-output/13") - 1512 # . epilogue - 1513 89/<- %esp 5/r32/ebp - 1514 5d/pop-to-ebp - 1515 c3/return - 1516 - 1517 test-convert-function-with-branches-in-block: - 1518 # . prologue - 1519 55/push-ebp - 1520 89/<- %ebp 4/r32/esp - 1521 # setup - 1522 (clear-stream _test-input-stream) - 1523 (clear-stream $_test-input-buffered-file->buffer) - 1524 (clear-stream _test-output-stream) - 1525 (clear-stream $_test-output-buffered-file->buffer) - 1526 # - 1527 (write _test-input-stream "fn foo x: int {\n") - 1528 (write _test-input-stream " {\n") - 1529 (write _test-input-stream " break-if->=\n") - 1530 (write _test-input-stream " loop-if-addr<\n") - 1531 (write _test-input-stream " increment x\n") - 1532 (write _test-input-stream " loop\n") - 1533 (write _test-input-stream " }\n") - 1534 (write _test-input-stream "}\n") - 1535 # convert - 1536 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 1537 (flush _test-output-buffered-file) - 1538 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1544 # check output - 1545 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-branches-in-block/0") - 1546 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-branches-in-block/1") - 1547 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-branches-in-block/2") - 1548 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-branches-in-block/3") - 1549 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-in-block/4") - 1550 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-branches-in-block/5") - 1551 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-in-block/6") - 1552 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-branches-in-block/7") - 1553 (check-next-stream-line-equal _test-output-stream " 0f 8d/jump-if->= break/disp32" "F - test-convert-function-with-branches-in-block/8") - 1554 (check-next-stream-line-equal _test-output-stream " 0f 82/jump-if-addr< loop/disp32" "F - test-convert-function-with-branches-in-block/9") - 1555 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0x00000008)" "F - test-convert-function-with-branches-in-block/10") - 1556 (check-next-stream-line-equal _test-output-stream " e9/jump loop/disp32" "F - test-convert-function-with-branches-in-block/11") - 1557 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-block/12") - 1558 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-branches-in-block/13") - 1559 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-block/14") - 1560 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-branches-in-block/15") - 1561 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-branches-in-block/16") - 1562 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-branches-in-block/17") - 1563 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-branches-in-block/18") - 1564 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-branches-in-block/19") - 1565 # . epilogue - 1566 89/<- %esp 5/r32/ebp - 1567 5d/pop-to-ebp - 1568 c3/return - 1569 - 1570 test-convert-function-with-branches-in-named-block: - 1571 # . prologue - 1572 55/push-ebp - 1573 89/<- %ebp 4/r32/esp - 1574 # setup - 1575 (clear-stream _test-input-stream) - 1576 (clear-stream $_test-input-buffered-file->buffer) - 1577 (clear-stream _test-output-stream) - 1578 (clear-stream $_test-output-buffered-file->buffer) - 1579 # - 1580 (write _test-input-stream "fn foo x: int {\n") - 1581 (write _test-input-stream " $bar: {\n") - 1582 (write _test-input-stream " break-if->= $bar\n") - 1583 (write _test-input-stream " loop-if-addr< $bar\n") - 1584 (write _test-input-stream " increment x\n") - 1585 (write _test-input-stream " loop\n") - 1586 (write _test-input-stream " }\n") - 1587 (write _test-input-stream "}\n") - 1588 # convert - 1589 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 1590 (flush _test-output-buffered-file) - 1591 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1597 # check output - 1598 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-branches-in-named-block/0") - 1599 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-branches-in-named-block/1") - 1600 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-branches-in-named-block/2") - 1601 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-branches-in-named-block/3") - 1602 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-in-named-block/4") - 1603 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-branches-in-named-block/5") - 1604 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-in-named-block/6") - 1605 (check-next-stream-line-equal _test-output-stream "$bar:loop:" "F - test-convert-function-with-branches-in-named-block/7") - 1606 (check-next-stream-line-equal _test-output-stream " 0f 8d/jump-if->= $bar:break/disp32" "F - test-convert-function-with-branches-in-named-block/8") - 1607 (check-next-stream-line-equal _test-output-stream " 0f 82/jump-if-addr< $bar:loop/disp32" "F - test-convert-function-with-branches-in-named-block/9") - 1608 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0x00000008)" "F - test-convert-function-with-branches-in-named-block/10") - 1609 (check-next-stream-line-equal _test-output-stream " e9/jump loop/disp32" "F - test-convert-function-with-branches-in-named-block/11") - 1610 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-named-block/12") - 1611 (check-next-stream-line-equal _test-output-stream "$bar:break:" "F - test-convert-function-with-branches-in-named-block/13") - 1612 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-named-block/14") - 1613 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-branches-in-named-block/15") - 1614 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-branches-in-named-block/16") - 1615 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-branches-in-named-block/17") - 1616 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-branches-in-named-block/18") - 1617 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-branches-in-named-block/19") - 1618 # . epilogue - 1619 89/<- %esp 5/r32/ebp - 1620 5d/pop-to-ebp - 1621 c3/return - 1622 - 1623 test-convert-function-with-var-in-nested-block: - 1624 # . prologue - 1625 55/push-ebp - 1626 89/<- %ebp 4/r32/esp - 1627 # setup - 1628 (clear-stream _test-input-stream) - 1629 (clear-stream $_test-input-buffered-file->buffer) - 1630 (clear-stream _test-output-stream) - 1631 (clear-stream $_test-output-buffered-file->buffer) - 1632 # - 1633 (write _test-input-stream "fn foo x: int {\n") - 1634 (write _test-input-stream " {\n") - 1635 (write _test-input-stream " {\n") - 1636 (write _test-input-stream " var x: int\n") - 1637 (write _test-input-stream " increment x\n") - 1638 (write _test-input-stream " }\n") - 1639 (write _test-input-stream " }\n") - 1640 (write _test-input-stream "}\n") - 1641 # convert - 1642 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 1643 (flush _test-output-buffered-file) - 1644 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1650 # check output - 1651 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-var-in-nested-block/0") - 1652 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-var-in-nested-block/1") - 1653 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-var-in-nested-block/2") - 1654 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-var-in-nested-block/3") - 1655 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-var-in-nested-block/4") - 1656 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-var-in-nested-block/5") - 1657 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-var-in-nested-block/6") - 1658 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-var-in-nested-block/7") - 1659 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-var-in-nested-block/8") - 1660 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-var-in-nested-block/9") - 1661 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-var-in-nested-block/10") - 1662 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-var-in-nested-block/11") - 1663 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-var-in-nested-block/12") - 1664 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-var-in-nested-block/13") - 1665 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-var-in-nested-block/14") - 1666 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-var-in-nested-block/15") - 1667 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-var-in-nested-block/16") - 1668 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-var-in-nested-block/17") - 1669 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-var-in-nested-block/18") - 1670 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-var-in-nested-block/19") - 1671 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-var-in-nested-block/20") - 1672 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-var-in-nested-block/21") - 1673 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-var-in-nested-block/22") - 1674 # . epilogue - 1675 89/<- %esp 5/r32/ebp - 1676 5d/pop-to-ebp - 1677 c3/return - 1678 - 1679 test-convert-function-with-multiple-vars-in-nested-blocks: - 1680 # . prologue - 1681 55/push-ebp - 1682 89/<- %ebp 4/r32/esp - 1683 # setup - 1684 (clear-stream _test-input-stream) - 1685 (clear-stream $_test-input-buffered-file->buffer) - 1686 (clear-stream _test-output-stream) - 1687 (clear-stream $_test-output-buffered-file->buffer) - 1688 # - 1689 (write _test-input-stream "fn foo x: int {\n") - 1690 (write _test-input-stream " {\n") - 1691 (write _test-input-stream " var x/eax: int <- copy 0\n") - 1692 (write _test-input-stream " {\n") - 1693 (write _test-input-stream " var y: int\n") - 1694 (write _test-input-stream " x <- add y\n") - 1695 (write _test-input-stream " }\n") - 1696 (write _test-input-stream " }\n") - 1697 (write _test-input-stream "}\n") - 1698 # convert - 1699 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 1700 (flush _test-output-buffered-file) - 1701 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1707 # check output - 1708 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-multiple-vars-in-nested-blocks/0") - 1709 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-multiple-vars-in-nested-blocks/1") - 1710 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-multiple-vars-in-nested-blocks/2") - 1711 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-multiple-vars-in-nested-blocks/3") - 1712 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-multiple-vars-in-nested-blocks/4") - 1713 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-multiple-vars-in-nested-blocks/5") - 1714 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-multiple-vars-in-nested-blocks/6") - 1715 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-multiple-vars-in-nested-blocks/7") - 1716 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-function-with-multiple-vars-in-nested-blocks/8") - 1717 (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/9") - 1718 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-multiple-vars-in-nested-blocks/10") - 1719 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-multiple-vars-in-nested-blocks/11") - 1720 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/12") - 1721 (check-next-stream-line-equal _test-output-stream " 03/add *(ebp+0xfffffff8) 0x00000000/r32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/13") - 1722 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/14") - 1723 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-multiple-vars-in-nested-blocks/15") - 1724 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-multiple-vars-in-nested-blocks/16") - 1725 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-function-with-multiple-vars-in-nested-blocks/17") - 1726 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-multiple-vars-in-nested-blocks/18") - 1727 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-multiple-vars-in-nested-blocks/19") - 1728 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-multiple-vars-in-nested-blocks/20") - 1729 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-multiple-vars-in-nested-blocks/21") - 1730 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-multiple-vars-in-nested-blocks/22") - 1731 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-multiple-vars-in-nested-blocks/23") - 1732 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-multiple-vars-in-nested-blocks/24") - 1733 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-multiple-vars-in-nested-blocks/25") - 1734 # . epilogue - 1735 89/<- %esp 5/r32/ebp - 1736 5d/pop-to-ebp - 1737 c3/return - 1738 - 1739 test-convert-function-with-branches-and-local-vars: - 1740 # A conditional 'break' after a 'var' in a block is converted into a - 1741 # nested block that performs all necessary cleanup before jumping. This - 1742 # results in some ugly code duplication. - 1743 # . prologue - 1744 55/push-ebp - 1745 89/<- %ebp 4/r32/esp - 1746 # setup - 1747 (clear-stream _test-input-stream) - 1748 (clear-stream $_test-input-buffered-file->buffer) - 1749 (clear-stream _test-output-stream) - 1750 (clear-stream $_test-output-buffered-file->buffer) - 1751 # - 1752 (write _test-input-stream "fn foo {\n") - 1753 (write _test-input-stream " {\n") - 1754 (write _test-input-stream " var x: int\n") - 1755 (write _test-input-stream " break-if->=\n") - 1756 (write _test-input-stream " increment x\n") - 1757 (write _test-input-stream " }\n") - 1758 (write _test-input-stream "}\n") - 1759 # convert - 1760 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 1761 (flush _test-output-buffered-file) - 1762 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1768 # check output - 1769 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-branches-and-local-vars/0") - 1770 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-branches-and-local-vars/1") - 1771 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-branches-and-local-vars/2") - 1772 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-branches-and-local-vars/3") - 1773 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-and-local-vars/4") - 1774 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-branches-and-local-vars/5") - 1775 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-and-local-vars/6") - 1776 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-branches-and-local-vars/7") - 1777 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-branches-and-local-vars/8") - 1778 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-and-local-vars/9") - 1779 (check-next-stream-line-equal _test-output-stream " 0f 8c/jump-if-< break/disp32" "F - test-convert-function-with-branches-and-local-vars/10") - 1780 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-branches-and-local-vars/11") - 1781 (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000002:break/disp32" "F - test-convert-function-with-branches-and-local-vars/12") - 1782 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-and-local-vars/13") - 1783 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-branches-and-local-vars/14") - 1784 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-branches-and-local-vars/15") - 1785 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-and-local-vars/16") - 1786 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-branches-and-local-vars/17") - 1787 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-and-local-vars/18") - 1788 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-branches-and-local-vars/19") - 1789 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-branches-and-local-vars/20") - 1790 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-branches-and-local-vars/21") - 1791 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-branches-and-local-vars/22") - 1792 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-branches-and-local-vars/23") - 1793 # . epilogue - 1794 89/<- %esp 5/r32/ebp - 1795 5d/pop-to-ebp - 1796 c3/return - 1797 - 1798 test-convert-function-with-conditional-loops-and-local-vars: - 1799 # A conditional 'loop' after a 'var' in a block is converted into a nested - 1800 # block that performs all necessary cleanup before jumping. This results - 1801 # in some ugly code duplication. - 1802 # . prologue - 1803 55/push-ebp - 1804 89/<- %ebp 4/r32/esp - 1805 # setup - 1806 (clear-stream _test-input-stream) - 1807 (clear-stream $_test-input-buffered-file->buffer) - 1808 (clear-stream _test-output-stream) - 1809 (clear-stream $_test-output-buffered-file->buffer) - 1810 # - 1811 (write _test-input-stream "fn foo {\n") - 1812 (write _test-input-stream " {\n") - 1813 (write _test-input-stream " var x: int\n") - 1814 (write _test-input-stream " loop-if->=\n") - 1815 (write _test-input-stream " increment x\n") - 1816 (write _test-input-stream " }\n") - 1817 (write _test-input-stream "}\n") - 1818 # convert - 1819 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 1820 (flush _test-output-buffered-file) - 1821 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1827 # check output - 1828 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-conditional-loops-and-local-vars/0") - 1829 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-conditional-loops-and-local-vars/1") - 1830 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-conditional-loops-and-local-vars/2") - 1831 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-conditional-loops-and-local-vars/3") - 1832 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-conditional-loops-and-local-vars/4") - 1833 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-conditional-loops-and-local-vars/5") - 1834 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-conditional-loops-and-local-vars/6") - 1835 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-conditional-loops-and-local-vars/7") - 1836 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-conditional-loops-and-local-vars/8") - 1837 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-conditional-loops-and-local-vars/9") - 1838 (check-next-stream-line-equal _test-output-stream " 0f 8c/jump-if-< break/disp32" "F - test-convert-function-with-conditional-loops-and-local-vars/10") - 1839 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-conditional-loops-and-local-vars/11") - 1840 (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000002:loop/disp32" "F - test-convert-function-with-conditional-loops-and-local-vars/12") - 1841 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-conditional-loops-and-local-vars/13") - 1842 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-conditional-loops-and-local-vars/14") - 1843 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-conditional-loops-and-local-vars/15") - 1844 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-conditional-loops-and-local-vars/16") - 1845 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-conditional-loops-and-local-vars/17") - 1846 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-conditional-loops-and-local-vars/18") - 1847 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-conditional-loops-and-local-vars/19") - 1848 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-conditional-loops-and-local-vars/20") - 1849 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-conditional-loops-and-local-vars/21") - 1850 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-conditional-loops-and-local-vars/22") - 1851 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-conditional-loops-and-local-vars/23") - 1852 # . epilogue - 1853 89/<- %esp 5/r32/ebp - 1854 5d/pop-to-ebp - 1855 c3/return - 1856 - 1857 test-convert-function-with-unconditional-loops-and-local-vars: - 1858 # An unconditional 'loop' after a 'var' in a block is emitted _after_ the - 1859 # regular block cleanup. Any instructions after 'loop' are dead and - 1860 # therefore skipped. - 1861 # . prologue - 1862 55/push-ebp - 1863 89/<- %ebp 4/r32/esp - 1864 # setup - 1865 (clear-stream _test-input-stream) - 1866 (clear-stream $_test-input-buffered-file->buffer) - 1867 (clear-stream _test-output-stream) - 1868 (clear-stream $_test-output-buffered-file->buffer) - 1869 # - 1870 (write _test-input-stream "fn foo {\n") - 1871 (write _test-input-stream " {\n") - 1872 (write _test-input-stream " var x: int\n") - 1873 (write _test-input-stream " loop\n") - 1874 (write _test-input-stream " increment x\n") - 1875 (write _test-input-stream " }\n") - 1876 (write _test-input-stream "}\n") - 1877 # convert - 1878 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 1879 (flush _test-output-buffered-file) - 1880 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1886 # check output - 1887 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-unconditional-loops-and-local-vars/0") - 1888 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-unconditional-loops-and-local-vars/1") - 1889 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-unconditional-loops-and-local-vars/2") - 1890 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-unconditional-loops-and-local-vars/3") - 1891 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-unconditional-loops-and-local-vars/4") - 1892 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-unconditional-loops-and-local-vars/5") - 1893 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-unconditional-loops-and-local-vars/6") - 1894 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-unconditional-loops-and-local-vars/7") - 1895 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-unconditional-loops-and-local-vars/8") - 1896 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-unconditional-loops-and-local-vars/9") - 1897 (check-next-stream-line-equal _test-output-stream " e9/jump loop/disp32" "F - test-convert-function-with-unconditional-loops-and-local-vars/10") - 1898 # not emitted: ff 0/subop/increment *(ebp+0xfffffffc) - 1899 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-unconditional-loops-and-local-vars/11") - 1900 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-unconditional-loops-and-local-vars/12") - 1901 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-unconditional-loops-and-local-vars/13") - 1902 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-unconditional-loops-and-local-vars/14") - 1903 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-unconditional-loops-and-local-vars/15") - 1904 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-unconditional-loops-and-local-vars/16") - 1905 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-unconditional-loops-and-local-vars/17") - 1906 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-unconditional-loops-and-local-vars/18") - 1907 # . epilogue - 1908 89/<- %esp 5/r32/ebp - 1909 5d/pop-to-ebp - 1910 c3/return - 1911 - 1912 test-convert-function-with-branches-and-loops-and-local-vars: - 1913 # . prologue - 1914 55/push-ebp - 1915 89/<- %ebp 4/r32/esp - 1916 # setup - 1917 (clear-stream _test-input-stream) - 1918 (clear-stream $_test-input-buffered-file->buffer) - 1919 (clear-stream _test-output-stream) - 1920 (clear-stream $_test-output-buffered-file->buffer) - 1921 # - 1922 (write _test-input-stream "fn foo {\n") - 1923 (write _test-input-stream " {\n") - 1924 (write _test-input-stream " var x: int\n") - 1925 (write _test-input-stream " break-if->=\n") - 1926 (write _test-input-stream " increment x\n") - 1927 (write _test-input-stream " loop\n") - 1928 (write _test-input-stream " }\n") - 1929 (write _test-input-stream "}\n") - 1930 # convert - 1931 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 1932 (flush _test-output-buffered-file) - 1933 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1939 # check output - 1940 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-branches-and-loops-and-local-vars/0") - 1941 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-branches-and-loops-and-local-vars/1") - 1942 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-branches-and-loops-and-local-vars/2") - 1943 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-branches-and-loops-and-local-vars/3") - 1944 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-and-loops-and-local-vars/4") - 1945 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-branches-and-loops-and-local-vars/5") - 1946 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-and-loops-and-local-vars/6") - 1947 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-branches-and-loops-and-local-vars/7") - 1948 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-branches-and-loops-and-local-vars/8") - 1949 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-and-loops-and-local-vars/9") - 1950 (check-next-stream-line-equal _test-output-stream " 0f 8c/jump-if-< break/disp32" "F - test-convert-function-with-branches-and-loops-and-local-vars/10") - 1951 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-branches-and-loops-and-local-vars/11") - 1952 (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000002:break/disp32" "F - test-convert-function-with-branches-and-loops-and-local-vars/12") - 1953 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-and-loops-and-local-vars/13") - 1954 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-branches-and-loops-and-local-vars/14") - 1955 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-branches-and-loops-and-local-vars/15") - 1956 (check-next-stream-line-equal _test-output-stream " e9/jump loop/disp32" "F - test-convert-function-with-branches-and-loops-and-local-vars/16") - 1957 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-and-loops-and-local-vars/17") - 1958 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-branches-and-loops-and-local-vars/18") - 1959 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-and-loops-and-local-vars/19") - 1960 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-branches-and-loops-and-local-vars/20") - 1961 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-branches-and-loops-and-local-vars/21") - 1962 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-branches-and-loops-and-local-vars/22") - 1963 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-branches-and-loops-and-local-vars/23") - 1964 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-branches-and-loops-and-local-vars/24") - 1965 # . epilogue - 1966 89/<- %esp 5/r32/ebp - 1967 5d/pop-to-ebp - 1968 c3/return - 1969 - 1970 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars: - 1971 # . prologue - 1972 55/push-ebp - 1973 89/<- %ebp 4/r32/esp - 1974 # setup - 1975 (clear-stream _test-input-stream) - 1976 (clear-stream $_test-input-buffered-file->buffer) - 1977 (clear-stream _test-output-stream) - 1978 (clear-stream $_test-output-buffered-file->buffer) - 1979 # - 1980 (write _test-input-stream "fn foo {\n") - 1981 (write _test-input-stream " a: {\n") - 1982 (write _test-input-stream " var x: int\n") - 1983 (write _test-input-stream " {\n") - 1984 (write _test-input-stream " var y: int\n") - 1985 (write _test-input-stream " break-if->= a\n") - 1986 (write _test-input-stream " increment x\n") - 1987 (write _test-input-stream " loop\n") - 1988 (write _test-input-stream " }\n") - 1989 (write _test-input-stream " }\n") - 1990 (write _test-input-stream "}\n") - 1991 # convert - 1992 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 1993 (flush _test-output-buffered-file) - 1994 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 2000 # check output - 2001 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/0") - 2002 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/1") - 2003 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/2") - 2004 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/3") - 2005 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/4") - 2006 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/5") - 2007 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/6") - 2008 (check-next-stream-line-equal _test-output-stream "a:loop:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/7") - 2009 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/8") - 2010 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/9") - 2011 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/10") - 2012 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/11") - 2013 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/12") - 2014 (check-next-stream-line-equal _test-output-stream " 0f 8c/jump-if-< break/disp32" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/13") - 2015 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/14") - 2016 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/15") - 2017 (check-next-stream-line-equal _test-output-stream " e9/jump a:break/disp32" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/16") - 2018 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/17") - 2019 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/18") - 2020 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/19") - 2021 (check-next-stream-line-equal _test-output-stream " e9/jump loop/disp32" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/20") - 2022 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/21") - 2023 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/22") - 2024 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/23") - 2025 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/24") - 2026 (check-next-stream-line-equal _test-output-stream "a:break:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/25") - 2027 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/26") - 2028 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/27") - 2029 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/28") - 2030 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/29") - 2031 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/30") - 2032 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/31") - 2033 # . epilogue - 2034 89/<- %esp 5/r32/ebp - 2035 5d/pop-to-ebp - 2036 c3/return - 2037 - 2038 test-convert-function-with-nonlocal-unconditional-break-and-local-vars: - 2039 # . prologue - 2040 55/push-ebp - 2041 89/<- %ebp 4/r32/esp - 2042 # setup - 2043 (clear-stream _test-input-stream) - 2044 (clear-stream $_test-input-buffered-file->buffer) - 2045 (clear-stream _test-output-stream) - 2046 (clear-stream $_test-output-buffered-file->buffer) - 2047 # - 2048 (write _test-input-stream "fn foo {\n") - 2049 (write _test-input-stream " a: {\n") - 2050 (write _test-input-stream " var x: int\n") - 2051 (write _test-input-stream " {\n") - 2052 (write _test-input-stream " var y: int\n") - 2053 (write _test-input-stream " break a\n") - 2054 (write _test-input-stream " increment x\n") - 2055 (write _test-input-stream " }\n") - 2056 (write _test-input-stream " }\n") - 2057 (write _test-input-stream "}\n") - 2058 # convert - 2059 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 2060 (flush _test-output-buffered-file) - 2061 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 2067 # check output - 2068 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/0") - 2069 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/1") - 2070 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/2") - 2071 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/3") - 2072 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/4") - 2073 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/5") - 2074 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/6") - 2075 (check-next-stream-line-equal _test-output-stream "a:loop:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/7") - 2076 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/8") - 2077 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/9") - 2078 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/10") - 2079 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/11") - 2080 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/12") - 2081 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/13") - 2082 (check-next-stream-line-equal _test-output-stream " e9/jump a:break/disp32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/14") - 2083 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/15") - 2084 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/16") - 2085 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/17") - 2086 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/18") - 2087 (check-next-stream-line-equal _test-output-stream "a:break:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/19") - 2088 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/20") - 2089 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/21") - 2090 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/22") - 2091 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/23") - 2092 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/24") - 2093 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/25") - 2094 # . epilogue - 2095 89/<- %esp 5/r32/ebp - 2096 5d/pop-to-ebp - 2097 c3/return - 2098 - 2099 test-convert-function-with-unconditional-break-and-local-vars: - 2100 # . prologue - 2101 55/push-ebp - 2102 89/<- %ebp 4/r32/esp - 2103 # setup - 2104 (clear-stream _test-input-stream) - 2105 (clear-stream $_test-input-buffered-file->buffer) - 2106 (clear-stream _test-output-stream) - 2107 (clear-stream $_test-output-buffered-file->buffer) - 2108 # - 2109 (write _test-input-stream "fn foo {\n") - 2110 (write _test-input-stream " {\n") - 2111 (write _test-input-stream " var x: int\n") - 2112 (write _test-input-stream " {\n") - 2113 (write _test-input-stream " var y: int\n") - 2114 (write _test-input-stream " break\n") - 2115 (write _test-input-stream " increment x\n") - 2116 (write _test-input-stream " }\n") - 2117 (write _test-input-stream " }\n") - 2118 (write _test-input-stream "}\n") - 2119 # convert - 2120 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 2121 (flush _test-output-buffered-file) - 2122 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 2128 # check output - 2129 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-unconditional-break-and-local-vars/0") - 2130 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-unconditional-break-and-local-vars/1") - 2131 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-unconditional-break-and-local-vars/2") - 2132 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-unconditional-break-and-local-vars/3") - 2133 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-unconditional-break-and-local-vars/4") - 2134 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-unconditional-break-and-local-vars/5") - 2135 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-unconditional-break-and-local-vars/6") - 2136 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-unconditional-break-and-local-vars/7") - 2137 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/8") - 2138 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-unconditional-break-and-local-vars/9") - 2139 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-unconditional-break-and-local-vars/10") - 2140 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/11") - 2141 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/12") - 2142 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-unconditional-break-and-local-vars/13") - 2143 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-unconditional-break-and-local-vars/14") - 2144 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/15") - 2145 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-unconditional-break-and-local-vars/16") - 2146 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-unconditional-break-and-local-vars/17") - 2147 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-unconditional-break-and-local-vars/18") - 2148 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-unconditional-break-and-local-vars/19") - 2149 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-unconditional-break-and-local-vars/20") - 2150 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-unconditional-break-and-local-vars/21") - 2151 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-unconditional-break-and-local-vars/22") - 2152 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-unconditional-break-and-local-vars/23") - 2153 # . epilogue - 2154 89/<- %esp 5/r32/ebp - 2155 5d/pop-to-ebp - 2156 c3/return - 2157 - 2158 test-convert-function-with-nonlocal-unconditional-loop-and-local-vars: - 2159 # . prologue - 2160 55/push-ebp - 2161 89/<- %ebp 4/r32/esp - 2162 # setup - 2163 (clear-stream _test-input-stream) - 2164 (clear-stream $_test-input-buffered-file->buffer) - 2165 (clear-stream _test-output-stream) - 2166 (clear-stream $_test-output-buffered-file->buffer) - 2167 # - 2168 (write _test-input-stream "fn foo {\n") - 2169 (write _test-input-stream " a: {\n") - 2170 (write _test-input-stream " var x: int\n") - 2171 (write _test-input-stream " {\n") - 2172 (write _test-input-stream " var y: int\n") - 2173 (write _test-input-stream " loop a\n") - 2174 (write _test-input-stream " increment x\n") - 2175 (write _test-input-stream " }\n") - 2176 (write _test-input-stream " }\n") - 2177 (write _test-input-stream "}\n") - 2178 # convert - 2179 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 2180 (flush _test-output-buffered-file) - 2181 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 2187 # check output - 2188 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/0") - 2189 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/1") - 2190 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/2") - 2191 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/3") - 2192 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/4") - 2193 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/5") - 2194 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/6") - 2195 (check-next-stream-line-equal _test-output-stream "a:loop:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/7") - 2196 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/8") - 2197 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/9") - 2198 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/10") - 2199 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/11") - 2200 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/12") - 2201 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/13") - 2202 (check-next-stream-line-equal _test-output-stream " e9/jump a:loop/disp32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/14") - 2203 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/15") - 2204 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/16") - 2205 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/17") - 2206 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/18") - 2207 (check-next-stream-line-equal _test-output-stream "a:break:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/19") - 2208 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/20") - 2209 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/21") - 2210 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/22") - 2211 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/23") - 2212 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/24") - 2213 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/25") - 2214 # . epilogue - 2215 89/<- %esp 5/r32/ebp - 2216 5d/pop-to-ebp - 2217 c3/return - 2218 - 2219 test-convert-function-with-local-array-var-in-mem: - 2220 # . prologue - 2221 55/push-ebp - 2222 89/<- %ebp 4/r32/esp - 2223 # setup - 2224 (clear-stream _test-input-stream) - 2225 (clear-stream $_test-input-buffered-file->buffer) - 2226 (clear-stream _test-output-stream) - 2227 (clear-stream $_test-output-buffered-file->buffer) - 2228 # - 2229 (write _test-input-stream "fn foo {\n") - 2230 (write _test-input-stream " var x: (array int 3)\n") - 2231 (write _test-input-stream "}\n") - 2232 # convert - 2233 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 2234 (flush _test-output-buffered-file) - 2235 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 2241 # check output - 2242 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-array-var-in-mem/0") - 2243 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-array-var-in-mem/1") - 2244 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-array-var-in-mem/2") - 2245 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-array-var-in-mem/3") - 2246 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-array-var-in-mem/4") - 2247 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-array-var-in-mem/5") - 2248 # define x - 2249 (check-next-stream-line-equal _test-output-stream " (push-n-zero-bytes 0x0000000c)" "F - test-convert-function-with-local-array-var-in-mem/7") - 2250 (check-next-stream-line-equal _test-output-stream " 68/push 0x0000000c/imm32" "F - test-convert-function-with-local-array-var-in-mem/8") - 2251 # reclaim x - 2252 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000010/imm32" "F - test-convert-function-with-local-array-var-in-mem/9") - 2253 # - 2254 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-array-var-in-mem/10") - 2255 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-array-var-in-mem/11") - 2256 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-array-var-in-mem/12") - 2257 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-array-var-in-mem/13") - 2258 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-array-var-in-mem/14") - 2259 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-array-var-in-mem/15") - 2260 # . epilogue - 2261 89/<- %esp 5/r32/ebp - 2262 5d/pop-to-ebp - 2263 c3/return - 2264 - 2265 test-convert-address: - 2266 # . prologue - 2267 55/push-ebp - 2268 89/<- %ebp 4/r32/esp - 2269 # setup - 2270 (clear-stream _test-input-stream) - 2271 (clear-stream $_test-input-buffered-file->buffer) - 2272 (clear-stream _test-output-stream) - 2273 (clear-stream $_test-output-buffered-file->buffer) - 2274 # - 2275 (write _test-input-stream "fn foo {\n") - 2276 (write _test-input-stream " var a: int\n") - 2277 (write _test-input-stream " var b/eax: (addr int) <- address a\n") - 2278 (write _test-input-stream "}\n") - 2279 # convert - 2280 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 2281 (flush _test-output-buffered-file) - 2282 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 2288 # check output - 2289 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-address/0") - 2290 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-address/1") - 2291 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-address/2") - 2292 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-address/3") - 2293 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-address/4") - 2294 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-address/5") - 2295 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-address/6") - 2296 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-address/7") - 2297 (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp+0xfffffffc) 0x00000000/r32" "F - test-convert-address/8") - 2298 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-address/9") - 2299 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-address/10") - 2300 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-address/11") - 2301 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-address/12") - 2302 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-address/13") - 2303 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-address/14") - 2304 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-address/15") - 2305 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-address/16") - 2306 # . epilogue - 2307 89/<- %esp 5/r32/ebp - 2308 5d/pop-to-ebp - 2309 c3/return - 2310 - 2311 test-convert-length-of-array: - 2312 # . prologue - 2313 55/push-ebp - 2314 89/<- %ebp 4/r32/esp - 2315 # setup - 2316 (clear-stream _test-input-stream) - 2317 (clear-stream $_test-input-buffered-file->buffer) - 2318 (clear-stream _test-output-stream) - 2319 (clear-stream $_test-output-buffered-file->buffer) - 2320 # - 2321 (write _test-input-stream "fn foo a: (addr array int) {\n") - 2322 (write _test-input-stream " var b/eax: (addr array int) <- copy a\n") - 2323 (write _test-input-stream " var c/eax: int <- length b\n") - 2324 (write _test-input-stream "}\n") - 2325 # convert - 2326 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 2327 (flush _test-output-buffered-file) - 2328 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 2334 # check output - 2335 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-length-of-array/0") - 2336 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-length-of-array/1") - 2337 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-length-of-array/2") - 2338 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-length-of-array/3") - 2339 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-length-of-array/4") - 2340 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-length-of-array/5") - 2341 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-length-of-array/6") - 2342 (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-length-of-array/7") - 2343 (check-next-stream-line-equal _test-output-stream " 8b/-> *eax 0x00000000/r32" "F - test-convert-length-of-array/9") - 2344 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-length-of-array/11") - 2345 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-length-of-array/12") - 2346 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-length-of-array/13") - 2347 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-length-of-array/14") - 2348 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-length-of-array/15") - 2349 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-length-of-array/16") - 2350 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-length-of-array/17") - 2351 # . epilogue - 2352 89/<- %esp 5/r32/ebp - 2353 5d/pop-to-ebp - 2354 c3/return - 2355 - 2356 test-convert-length-of-array-on-stack: - 2357 # . prologue - 2358 55/push-ebp - 2359 89/<- %ebp 4/r32/esp - 2360 # setup - 2361 (clear-stream _test-input-stream) - 2362 (clear-stream $_test-input-buffered-file->buffer) - 2363 (clear-stream _test-output-stream) - 2364 (clear-stream $_test-output-buffered-file->buffer) - 2365 # - 2366 (write _test-input-stream "fn foo {\n") - 2367 (write _test-input-stream " var a: (array int 3)\n") - 2368 (write _test-input-stream " var b/eax: int <- length a\n") - 2369 (write _test-input-stream "}\n") - 2370 # convert - 2371 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 2372 (flush _test-output-buffered-file) - 2373 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 2379 # check output - 2380 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-length-of-array-on-stack/0") - 2381 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-length-of-array-on-stack/1") - 2382 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-length-of-array-on-stack/2") - 2383 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-length-of-array-on-stack/3") - 2384 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-length-of-array-on-stack/4") - 2385 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-length-of-array-on-stack/5") - 2386 # define x - 2387 (check-next-stream-line-equal _test-output-stream " (push-n-zero-bytes 0x0000000c)" "F - test-convert-length-of-array-on-stack/6") - 2388 (check-next-stream-line-equal _test-output-stream " 68/push 0x0000000c/imm32" "F - test-convert-length-of-array-on-stack/7") - 2389 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-length-of-array-on-stack/8") - 2390 (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0xfffffff0) 0x00000000/r32" "F - test-convert-length-of-array-on-stack/9") - 2391 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-length-of-array-on-stack/10") - 2392 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000010/imm32" "F - test-convert-length-of-array-on-stack/11") - 2393 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-length-of-array-on-stack/12") - 2394 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-length-of-array-on-stack/13") - 2395 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-length-of-array-on-stack/14") - 2396 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-length-of-array-on-stack/15") - 2397 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-length-of-array-on-stack/16") - 2398 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-length-of-array-on-stack/17") - 2399 # . epilogue - 2400 89/<- %esp 5/r32/ebp - 2401 5d/pop-to-ebp - 2402 c3/return - 2403 - 2404 test-convert-index-into-array: - 2405 # . prologue - 2406 55/push-ebp - 2407 89/<- %ebp 4/r32/esp - 2408 # setup - 2409 (clear-stream _test-input-stream) - 2410 (clear-stream $_test-input-buffered-file->buffer) - 2411 (clear-stream _test-output-stream) - 2412 (clear-stream $_test-output-buffered-file->buffer) - 2413 # - 2414 (write _test-input-stream "fn foo {\n") - 2415 (write _test-input-stream " var arr/eax: (addr array int) <- copy 0\n") - 2416 (write _test-input-stream " var idx/ecx: int <- copy 3\n") - 2417 (write _test-input-stream " var x/eax: (addr int) <- index arr, idx\n") - 2418 (write _test-input-stream "}\n") - 2419 # convert - 2420 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 2421 (flush _test-output-buffered-file) - 2422 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 2428 # check output - 2429 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array/0") - 2430 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array/1") - 2431 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array/2") - 2432 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-index-into-array/3") - 2433 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array/4") - 2434 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array/5") - 2435 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array/6") - 2436 (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-index-into-array/7") - 2437 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array/8") - 2438 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-index-into-array/9") - 2439 (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32" "F - test-convert-index-into-array/11") - 2440 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array/13") - 2441 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array/14") - 2442 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array/15") - 2443 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array/16") - 2444 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array/17") - 2445 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array/18") - 2446 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array/19") - 2447 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array/20") - 2448 # . epilogue - 2449 89/<- %esp 5/r32/ebp - 2450 5d/pop-to-ebp - 2451 c3/return - 2452 - 2453 test-convert-index-into-array-with-literal: - 2454 # . prologue - 2455 55/push-ebp - 2456 89/<- %ebp 4/r32/esp - 2457 # setup - 2458 (clear-stream _test-input-stream) - 2459 (clear-stream $_test-input-buffered-file->buffer) - 2460 (clear-stream _test-output-stream) - 2461 (clear-stream $_test-output-buffered-file->buffer) - 2462 # - 2463 (write _test-input-stream "fn foo {\n") - 2464 (write _test-input-stream " var arr/eax: (addr array int) <- copy 0\n") - 2465 (write _test-input-stream " var x/eax: (addr int) <- index arr, 2\n") - 2466 (write _test-input-stream "}\n") - 2467 # convert - 2468 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 2469 (flush _test-output-buffered-file) - 2470 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 2476 # check output - 2477 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array-with-literal/0") - 2478 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array-with-literal/1") - 2479 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array-with-literal/2") - 2480 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-index-into-array-with-literal/3") - 2481 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array-with-literal/4") - 2482 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-with-literal/5") - 2483 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-with-literal/6") - 2484 (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-index-into-array-with-literal/7") - 2485 # 2 * 4 bytes/elem + 4 bytes for size = offset 12 - 2486 (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + 0x0000000c) 0x00000000/r32" "F - test-convert-index-into-array-with-literal/8") - 2487 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-with-literal/9") - 2488 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-with-literal/10") - 2489 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-with-literal/11") - 2490 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-with-literal/12") - 2491 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-with-literal/13") - 2492 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-with-literal/14") - 2493 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-with-literal/15") + 402 + 403 # == Type definitions + 404 # Program->types contains some typeinfo for each type definition. + 405 # Types contain vars with types, but can't specify registers. + 406 Typeinfo-id: # type-id + 407 0/imm32 + 408 Typeinfo-fields: # (handle table (handle array byte) (handle typeinfo-entry)) + 409 4/imm32 + 410 # Total size must be >= 0 + 411 # During parsing it may take on two additional values: + 412 # -2: not yet initialized + 413 # -1: in process of being computed + 414 # See populate-mu-type-sizes for details. + 415 Typeinfo-total-size-in-bytes: # int + 416 0xc/imm32 + 417 Typeinfo-next: # (handle typeinfo) + 418 0x10/imm32 + 419 Typeinfo-size: # (addr int) + 420 0x18/imm32 + 421 + 422 # Each entry in the typeinfo->fields table has a pointer to a string and a + 423 # pointer to a typeinfo-entry. + 424 Typeinfo-fields-row-size: # (addr int) + 425 0x10/imm32 + 426 + 427 # typeinfo-entry objects have information about a field in a single record type + 428 # + 429 # each field of a type is represented using two var's: + 430 # 1. the input var: expected type of the field; convenient for creating using parse-var-with-type + 431 # 2. the output var: a constant containing the byte offset; convenient for code-generation + 432 # computing the output happens after parsing; in the meantime we preserve the + 433 # order of fields in the 'index' field. + 434 Typeinfo-entry-input-var: # (handle var) + 435 0/imm32 + 436 Typeinfo-entry-index: # int + 437 8/imm32 + 438 Typeinfo-entry-output-var: # (handle var) + 439 0xc/imm32 + 440 Typeinfo-entry-size: # (addr int) + 441 0x14/imm32 + 442 + 443 == code + 444 + 445 Entry: + 446 # . prologue + 447 89/<- %ebp 4/r32/esp + 448 (new-segment *Heap-size Heap) + 449 # if (argv[1] == "test') run-tests() + 450 { + 451 # if (argc <= 1) break + 452 81 7/subop/compare *ebp 1/imm32 + 453 7e/jump-if-<= break/disp8 + 454 # if (argv[1] != "test") break + 455 (kernel-string-equal? *(ebp+8) "test") # => eax + 456 3d/compare-eax-and 0/imm32/false + 457 74/jump-if-= break/disp8 + 458 # + 459 (run-tests) + 460 # syscall(exit, *Num-test-failures) + 461 8b/-> *Num-test-failures 3/r32/ebx + 462 eb/jump $mu-main:end/disp8 + 463 } + 464 # otherwise convert Stdin + 465 (convert-mu Stdin Stdout) + 466 (flush Stdout) + 467 # syscall(exit, 0) + 468 bb/copy-to-ebx 0/imm32 + 469 $mu-main:end: + 470 b8/copy-to-eax 1/imm32/exit + 471 cd/syscall 0x80/imm8 + 472 + 473 convert-mu: # in: (addr buffered-file), out: (addr buffered-file) + 474 # . prologue + 475 55/push-ebp + 476 89/<- %ebp 4/r32/esp + 477 # initialize global data structures + 478 c7 0/subop/copy *Next-block-index 1/imm32 + 479 c7 0/subop/copy *Type-id 0x1c/imm32 # stream-write + 480 c7 0/subop/copy *_Program-functions 0/imm32 + 481 c7 0/subop/copy *_Program-functions->payload 0/imm32 + 482 c7 0/subop/copy *_Program-types 0/imm32 + 483 c7 0/subop/copy *_Program-types->payload 0/imm32 + 484 # + 485 (parse-mu *(ebp+8)) + 486 (populate-mu-type-sizes) + 487 (check-mu-types) + 488 (emit-subx *(ebp+0xc)) + 489 $convert-mu:end: + 490 # . epilogue + 491 89/<- %esp 5/r32/ebp + 492 5d/pop-to-ebp + 493 c3/return + 494 + 495 test-convert-empty-input: + 496 # empty input => empty output + 497 # . prologue + 498 55/push-ebp + 499 89/<- %ebp 4/r32/esp + 500 # setup + 501 (clear-stream _test-input-stream) + 502 (clear-stream $_test-input-buffered-file->buffer) + 503 (clear-stream _test-output-stream) + 504 (clear-stream $_test-output-buffered-file->buffer) + 505 # + 506 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 507 (flush _test-output-buffered-file) + 508 (check-stream-equal _test-output-stream "" "F - test-convert-empty-input") + 509 # . epilogue + 510 89/<- %esp 5/r32/ebp + 511 5d/pop-to-ebp + 512 c3/return + 513 + 514 test-convert-function-skeleton: + 515 # . prologue + 516 55/push-ebp + 517 89/<- %ebp 4/r32/esp + 518 # setup + 519 (clear-stream _test-input-stream) + 520 (clear-stream $_test-input-buffered-file->buffer) + 521 (clear-stream _test-output-stream) + 522 (clear-stream $_test-output-buffered-file->buffer) + 523 # + 524 (write _test-input-stream "fn foo {\n") + 525 (write _test-input-stream "}\n") + 526 # convert + 527 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 528 (flush _test-output-buffered-file) + 529 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 535 # check output + 536 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-skeleton/0") + 537 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-skeleton/1") + 538 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-skeleton/2") + 539 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-skeleton/3") + 540 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-skeleton/4") + 541 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-skeleton/5") + 542 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-skeleton/6") + 543 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-skeleton/7") + 544 # . epilogue + 545 89/<- %esp 5/r32/ebp + 546 5d/pop-to-ebp + 547 c3/return + 548 + 549 test-convert-multiple-function-skeletons: + 550 # . prologue + 551 55/push-ebp + 552 89/<- %ebp 4/r32/esp + 553 # setup + 554 (clear-stream _test-input-stream) + 555 (clear-stream $_test-input-buffered-file->buffer) + 556 (clear-stream _test-output-stream) + 557 (clear-stream $_test-output-buffered-file->buffer) + 558 # + 559 (write _test-input-stream "fn foo {\n") + 560 (write _test-input-stream "}\n") + 561 (write _test-input-stream "fn bar {\n") + 562 (write _test-input-stream "}\n") + 563 # convert + 564 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 565 (flush _test-output-buffered-file) + 566 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 572 # check first function + 573 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-multiple-function-skeletons/0") + 574 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-multiple-function-skeletons/1") + 575 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-multiple-function-skeletons/2") + 576 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-multiple-function-skeletons/3") + 577 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-multiple-function-skeletons/4") + 578 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-multiple-function-skeletons/5") + 579 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-multiple-function-skeletons/6") + 580 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-multiple-function-skeletons/7") + 581 # check second function + 582 (check-next-stream-line-equal _test-output-stream "bar:" "F - test-convert-multiple-function-skeletons/10") + 583 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-multiple-function-skeletons/11") + 584 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-multiple-function-skeletons/12") + 585 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-multiple-function-skeletons/13") + 586 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-multiple-function-skeletons/14") + 587 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-multiple-function-skeletons/15") + 588 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-multiple-function-skeletons/16") + 589 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-multiple-function-skeletons/17") + 590 # . epilogue + 591 89/<- %esp 5/r32/ebp + 592 5d/pop-to-ebp + 593 c3/return + 594 + 595 test-convert-function-with-arg: + 596 # . prologue + 597 55/push-ebp + 598 89/<- %ebp 4/r32/esp + 599 # setup + 600 (clear-stream _test-input-stream) + 601 (clear-stream $_test-input-buffered-file->buffer) + 602 (clear-stream _test-output-stream) + 603 (clear-stream $_test-output-buffered-file->buffer) + 604 # + 605 (write _test-input-stream "fn foo n: int {\n") + 606 (write _test-input-stream "}\n") + 607 # convert + 608 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 609 (flush _test-output-buffered-file) + 610 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 616 # check output + 617 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-arg/0") + 618 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-arg/1") + 619 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-arg/2") + 620 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-arg/3") + 621 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-arg/4") + 622 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-arg/5") + 623 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-arg/6") + 624 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-arg/7") + 625 # . epilogue + 626 89/<- %esp 5/r32/ebp + 627 5d/pop-to-ebp + 628 c3/return + 629 + 630 test-convert-function-with-arg-and-body: + 631 # . prologue + 632 55/push-ebp + 633 89/<- %ebp 4/r32/esp + 634 # setup + 635 (clear-stream _test-input-stream) + 636 (clear-stream $_test-input-buffered-file->buffer) + 637 (clear-stream _test-output-stream) + 638 (clear-stream $_test-output-buffered-file->buffer) + 639 # + 640 (write _test-input-stream "fn foo n: int {\n") + 641 (write _test-input-stream " increment n\n") + 642 (write _test-input-stream "}\n") + 643 # convert + 644 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 645 (flush _test-output-buffered-file) + 646 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 652 # check output + 653 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-arg-and-body/0") + 654 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-arg-and-body/1") + 655 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-arg-and-body/2") + 656 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-arg-and-body/3") + 657 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-arg-and-body/4") + 658 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-arg-and-body/5") + 659 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0x00000008)" "F - test-convert-function-with-arg-and-body/6") + 660 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-arg-and-body/7") + 661 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-arg-and-body/8") + 662 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-arg-and-body/9") + 663 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-arg-and-body/10") + 664 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-arg-and-body/11") + 665 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-arg-and-body/12") + 666 # . epilogue + 667 89/<- %esp 5/r32/ebp + 668 5d/pop-to-ebp + 669 c3/return + 670 + 671 test-convert-function-distinguishes-args: + 672 # . prologue + 673 55/push-ebp + 674 89/<- %ebp 4/r32/esp + 675 # setup + 676 (clear-stream _test-input-stream) + 677 (clear-stream $_test-input-buffered-file->buffer) + 678 (clear-stream _test-output-stream) + 679 (clear-stream $_test-output-buffered-file->buffer) + 680 # + 681 (write _test-input-stream "fn foo a: int, b: int {\n") + 682 (write _test-input-stream " increment b\n") + 683 (write _test-input-stream "}\n") + 684 # convert + 685 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 686 (flush _test-output-buffered-file) + 687 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 693 # check output + 694 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-distinguishes-args/0") + 695 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-distinguishes-args/1") + 696 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-distinguishes-args/2") + 697 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-distinguishes-args/3") + 698 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-distinguishes-args/4") + 699 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-distinguishes-args/5") + 700 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0x0000000c)" "F - test-convert-function-distinguishes-args/6") + 701 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-distinguishes-args/7") + 702 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-distinguishes-args/8") + 703 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-distinguishes-args/9") + 704 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-distinguishes-args/10") + 705 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-distinguishes-args/11") + 706 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-distinguishes-args/12") + 707 # . epilogue + 708 89/<- %esp 5/r32/ebp + 709 5d/pop-to-ebp + 710 c3/return + 711 + 712 test-convert-function-returns-result: + 713 # . prologue + 714 55/push-ebp + 715 89/<- %ebp 4/r32/esp + 716 # setup + 717 (clear-stream _test-input-stream) + 718 (clear-stream $_test-input-buffered-file->buffer) + 719 (clear-stream _test-output-stream) + 720 (clear-stream $_test-output-buffered-file->buffer) + 721 # + 722 (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n") + 723 (write _test-input-stream " result <- copy a\n") + 724 (write _test-input-stream " result <- increment\n") + 725 (write _test-input-stream "}\n") + 726 # convert + 727 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 728 (flush _test-output-buffered-file) + 729 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 735 # check output + 736 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-returns-result/0") + 737 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-returns-result/1") + 738 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-returns-result/2") + 739 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-returns-result/3") + 740 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-returns-result/4") + 741 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-returns-result/5") + 742 (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-function-returns-result/6") + 743 (check-next-stream-line-equal _test-output-stream " 40/increment-eax" "F - test-convert-function-returns-result/7") + 744 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-returns-result/8") + 745 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-returns-result/9") + 746 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-returns-result/10") + 747 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-returns-result/11") + 748 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-returns-result/12") + 749 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-returns-result/13") + 750 # . epilogue + 751 89/<- %esp 5/r32/ebp + 752 5d/pop-to-ebp + 753 c3/return + 754 + 755 test-convert-function-with-literal-arg: + 756 # . prologue + 757 55/push-ebp + 758 89/<- %ebp 4/r32/esp + 759 # setup + 760 (clear-stream _test-input-stream) + 761 (clear-stream $_test-input-buffered-file->buffer) + 762 (clear-stream _test-output-stream) + 763 (clear-stream $_test-output-buffered-file->buffer) + 764 # + 765 (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n") + 766 (write _test-input-stream " result <- copy a\n") + 767 (write _test-input-stream " result <- add 1\n") + 768 (write _test-input-stream "}\n") + 769 # convert + 770 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 771 (flush _test-output-buffered-file) + 772 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 778 # check output + 779 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-literal-arg/0") + 780 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-literal-arg/1") + 781 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-literal-arg/2") + 782 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-literal-arg/3") + 783 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-literal-arg/4") + 784 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-literal-arg/5") + 785 (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-function-with-literal-arg/6") + 786 (check-next-stream-line-equal _test-output-stream " 05/add-to-eax 1/imm32" "F - test-convert-function-with-literal-arg/7") + 787 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-literal-arg/8") + 788 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-literal-arg/9") + 789 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-literal-arg/10") + 790 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-literal-arg/11") + 791 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-literal-arg/12") + 792 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-literal-arg/13") + 793 # . epilogue + 794 89/<- %esp 5/r32/ebp + 795 5d/pop-to-ebp + 796 c3/return + 797 + 798 test-convert-function-with-literal-arg-2: + 799 # . prologue + 800 55/push-ebp + 801 89/<- %ebp 4/r32/esp + 802 # setup + 803 (clear-stream _test-input-stream) + 804 (clear-stream $_test-input-buffered-file->buffer) + 805 (clear-stream _test-output-stream) + 806 (clear-stream $_test-output-buffered-file->buffer) + 807 # + 808 (write _test-input-stream "fn foo a: int, b: int -> result/ebx: int {\n") + 809 (write _test-input-stream " result <- copy a\n") + 810 (write _test-input-stream " result <- add 1\n") + 811 (write _test-input-stream "}\n") + 812 # convert + 813 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 814 (flush _test-output-buffered-file) + 815 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 821 # check output + 822 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-literal-arg-2/0") + 823 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-literal-arg-2/1") + 824 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-literal-arg-2/2") + 825 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-literal-arg-2/3") + 826 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-literal-arg-2/4") + 827 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-literal-arg-2/5") + 828 (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x00000008) 0x00000003/r32" "F - test-convert-function-with-literal-arg-2/6") + 829 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %ebx 1/imm32" "F - test-convert-function-with-literal-arg-2/7") + 830 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-literal-arg-2/8") + 831 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-literal-arg-2/9") + 832 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-literal-arg-2/10") + 833 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-literal-arg-2/11") + 834 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-literal-arg-2/12") + 835 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-literal-arg-2/13") + 836 # . epilogue + 837 89/<- %esp 5/r32/ebp + 838 5d/pop-to-ebp + 839 c3/return + 840 + 841 test-convert-function-call-with-literal-arg: + 842 # . prologue + 843 55/push-ebp + 844 89/<- %ebp 4/r32/esp + 845 # setup + 846 (clear-stream _test-input-stream) + 847 (clear-stream $_test-input-buffered-file->buffer) + 848 (clear-stream _test-output-stream) + 849 (clear-stream $_test-output-buffered-file->buffer) + 850 # + 851 (write _test-input-stream "fn main -> result/ebx: int {\n") + 852 (write _test-input-stream " result <- do-add 3 4\n") + 853 (write _test-input-stream "}\n") + 854 (write _test-input-stream "fn do-add a: int, b: int -> result/ebx: int {\n") + 855 (write _test-input-stream " result <- copy a\n") + 856 (write _test-input-stream " result <- add b\n") + 857 (write _test-input-stream "}\n") + 858 # convert + 859 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 860 (flush _test-output-buffered-file) + 861 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 867 # check output + 868 (check-next-stream-line-equal _test-output-stream "main:" "F - test-convert-function-call-with-literal-arg/0") + 869 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-literal-arg/1") + 870 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-literal-arg/2") + 871 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-literal-arg/3") + 872 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-literal-arg/4") + 873 (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:" "F - test-convert-function-call-with-literal-arg/5") + 874 (check-next-stream-line-equal _test-output-stream " (do-add 3 4)" "F - test-convert-function-call-with-literal-arg/6") + 875 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-literal-arg/7") + 876 (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-literal-arg/8") + 877 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-literal-arg/9") + 878 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-literal-arg/10") + 879 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-literal-arg/11") + 880 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-literal-arg/12") + 881 (check-next-stream-line-equal _test-output-stream "do-add:" "F - test-convert-function-call-with-literal-arg/13") + 882 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-literal-arg/14") + 883 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-literal-arg/15") + 884 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-literal-arg/16") + 885 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-literal-arg/17") + 886 (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:loop:" "F - test-convert-function-call-with-literal-arg/18") + 887 (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x00000008) 0x00000003/r32" "F - test-convert-function-call-with-literal-arg/19") + 888 (check-next-stream-line-equal _test-output-stream " 03/add *(ebp+0x0000000c) 0x00000003/r32" "F - test-convert-function-call-with-literal-arg/20") + 889 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-literal-arg/21") + 890 (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:break:" "F - test-convert-function-call-with-literal-arg/22") + 891 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-literal-arg/23") + 892 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-literal-arg/24") + 893 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-literal-arg/25") + 894 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-literal-arg/26") + 895 # . epilogue + 896 89/<- %esp 5/r32/ebp + 897 5d/pop-to-ebp + 898 c3/return + 899 + 900 test-convert-function-with-local-var-in-mem: + 901 # . prologue + 902 55/push-ebp + 903 89/<- %ebp 4/r32/esp + 904 # setup + 905 (clear-stream _test-input-stream) + 906 (clear-stream $_test-input-buffered-file->buffer) + 907 (clear-stream _test-output-stream) + 908 (clear-stream $_test-output-buffered-file->buffer) + 909 # + 910 (write _test-input-stream "fn foo {\n") + 911 (write _test-input-stream " var x: int\n") + 912 (write _test-input-stream " increment x\n") + 913 (write _test-input-stream "}\n") + 914 # convert + 915 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 916 (flush _test-output-buffered-file) + 917 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 923 # check output + 924 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-in-mem/0") + 925 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-in-mem/1") + 926 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-in-mem/2") + 927 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-in-mem/3") + 928 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-mem/4") + 929 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-in-mem/5") + 930 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-local-var-in-mem/6") + 931 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-local-var-in-mem/7") + 932 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-local-var-in-mem/8") + 933 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-mem/9") + 934 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-in-mem/10") + 935 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-in-mem/11") + 936 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-in-mem/12") + 937 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-in-mem/13") + 938 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-in-mem/14") + 939 # . epilogue + 940 89/<- %esp 5/r32/ebp + 941 5d/pop-to-ebp + 942 c3/return + 943 + 944 test-convert-function-with-local-var-with-compound-type-in-mem: + 945 # . prologue + 946 55/push-ebp + 947 89/<- %ebp 4/r32/esp + 948 # setup + 949 (clear-stream _test-input-stream) + 950 (clear-stream $_test-input-buffered-file->buffer) + 951 (clear-stream _test-output-stream) + 952 (clear-stream $_test-output-buffered-file->buffer) + 953 # + 954 (write _test-input-stream "fn foo {\n") + 955 (write _test-input-stream " var x: (addr int)\n") + 956 (write _test-input-stream " copy-to x, 0\n") + 957 (write _test-input-stream "}\n") + 958 # convert + 959 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 960 (flush _test-output-buffered-file) + 961 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 967 # check output + 968 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-with-compound-type-in-mem/0") + 969 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-with-compound-type-in-mem/1") + 970 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-with-compound-type-in-mem/2") + 971 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-with-compound-type-in-mem/3") + 972 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-with-compound-type-in-mem/4") + 973 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-with-compound-type-in-mem/5") + 974 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-local-var-with-compound-type-in-mem/6") + 975 (check-next-stream-line-equal _test-output-stream " c7 0/subop/copy *(ebp+0xfffffffc) 0/imm32" "F - test-convert-function-with-local-var-with-compound-type-in-mem/7") + 976 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-local-var-with-compound-type-in-mem/8") + 977 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-with-compound-type-in-mem/9") + 978 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-with-compound-type-in-mem/10") + 979 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-with-compound-type-in-mem/11") + 980 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-with-compound-type-in-mem/12") + 981 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-with-compound-type-in-mem/13") + 982 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-with-compound-type-in-mem/14") + 983 # . epilogue + 984 89/<- %esp 5/r32/ebp + 985 5d/pop-to-ebp + 986 c3/return + 987 + 988 test-convert-function-with-local-var-in-reg: + 989 # . prologue + 990 55/push-ebp + 991 89/<- %ebp 4/r32/esp + 992 # setup + 993 (clear-stream _test-input-stream) + 994 (clear-stream $_test-input-buffered-file->buffer) + 995 (clear-stream _test-output-stream) + 996 (clear-stream $_test-output-buffered-file->buffer) + 997 # + 998 (write _test-input-stream "fn foo {\n") + 999 (write _test-input-stream " var x/ecx: int <- copy 3\n") + 1000 (write _test-input-stream " x <- increment\n") + 1001 (write _test-input-stream "}\n") + 1002 # convert + 1003 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 1004 (flush _test-output-buffered-file) + 1005 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 1011 # check output + 1012 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-in-reg/0") + 1013 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-in-reg/1") + 1014 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-in-reg/2") + 1015 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-in-reg/3") + 1016 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-reg/4") + 1017 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-in-reg/5") + 1018 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-with-local-var-in-reg/6") + 1019 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-function-with-local-var-in-reg/7") + 1020 (check-next-stream-line-equal _test-output-stream " 41/increment-ecx" "F - test-convert-function-with-local-var-in-reg/8") + 1021 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-in-reg/9") + 1022 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-reg/10") + 1023 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-in-reg/11") + 1024 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-in-reg/12") + 1025 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-in-reg/13") + 1026 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-in-reg/14") + 1027 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-in-reg/15") + 1028 # . epilogue + 1029 89/<- %esp 5/r32/ebp + 1030 5d/pop-to-ebp + 1031 c3/return + 1032 + 1033 test-convert-function-with-second-local-var-in-same-reg: + 1034 # . prologue + 1035 55/push-ebp + 1036 89/<- %ebp 4/r32/esp + 1037 # setup + 1038 (clear-stream _test-input-stream) + 1039 (clear-stream $_test-input-buffered-file->buffer) + 1040 (clear-stream _test-output-stream) + 1041 (clear-stream $_test-output-buffered-file->buffer) + 1042 # + 1043 (write _test-input-stream "fn foo {\n") + 1044 (write _test-input-stream " var x/ecx: int <- copy 3\n") + 1045 (write _test-input-stream " var y/ecx: int <- copy 4\n") + 1046 (write _test-input-stream " y <- increment\n") + 1047 (write _test-input-stream "}\n") + 1048 # convert + 1049 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 1050 (flush _test-output-buffered-file) + 1051 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 1057 # check output + 1058 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-second-local-var-in-same-reg/0") + 1059 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-second-local-var-in-same-reg/1") + 1060 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-second-local-var-in-same-reg/2") + 1061 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-second-local-var-in-same-reg/3") + 1062 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-second-local-var-in-same-reg/4") + 1063 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-second-local-var-in-same-reg/5") + 1064 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-with-second-local-var-in-same-reg/6") + 1065 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-function-with-second-local-var-in-same-reg/7") + 1066 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-convert-function-with-second-local-var-in-same-reg/8") + 1067 (check-next-stream-line-equal _test-output-stream " 41/increment-ecx" "F - test-convert-function-with-second-local-var-in-same-reg/9") + 1068 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-with-second-local-var-in-same-reg/10") + 1069 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-second-local-var-in-same-reg/11") + 1070 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-second-local-var-in-same-reg/12") + 1071 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-second-local-var-in-same-reg/13") + 1072 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-second-local-var-in-same-reg/14") + 1073 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-second-local-var-in-same-reg/15") + 1074 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-second-local-var-in-same-reg/16") + 1075 # . epilogue + 1076 89/<- %esp 5/r32/ebp + 1077 5d/pop-to-ebp + 1078 c3/return + 1079 + 1080 test-convert-function-with-local-var-dereferenced: + 1081 # . prologue + 1082 55/push-ebp + 1083 89/<- %ebp 4/r32/esp + 1084 # setup + 1085 (clear-stream _test-input-stream) + 1086 (clear-stream $_test-input-buffered-file->buffer) + 1087 (clear-stream _test-output-stream) + 1088 (clear-stream $_test-output-buffered-file->buffer) + 1089 # + 1090 (write _test-input-stream "fn foo {\n") + 1091 (write _test-input-stream " var x/ecx: (addr int) <- copy 0\n") + 1092 (write _test-input-stream " increment *x\n") + 1093 (write _test-input-stream "}\n") + 1094 # convert + 1095 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 1096 (flush _test-output-buffered-file) + 1097 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 1103 # check output + 1104 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-dereferenced/0") + 1105 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-dereferenced/1") + 1106 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-dereferenced/2") + 1107 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-dereferenced/3") + 1108 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-dereferenced/4") + 1109 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-dereferenced/5") + 1110 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-with-local-var-dereferenced/6") + 1111 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 0/imm32" "F - test-convert-function-with-local-var-dereferenced/7") + 1112 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *ecx" "F - test-convert-function-with-local-var-dereferenced/8") + 1113 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-dereferenced/9") + 1114 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-dereferenced/10") + 1115 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-dereferenced/11") + 1116 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-dereferenced/12") + 1117 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-dereferenced/13") + 1118 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-dereferenced/14") + 1119 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-dereferenced/15") + 1120 # . epilogue + 1121 89/<- %esp 5/r32/ebp + 1122 5d/pop-to-ebp + 1123 c3/return + 1124 + 1125 test-convert-compare-register-with-literal: + 1126 # . prologue + 1127 55/push-ebp + 1128 89/<- %ebp 4/r32/esp + 1129 # setup + 1130 (clear-stream _test-input-stream) + 1131 (clear-stream $_test-input-buffered-file->buffer) + 1132 (clear-stream _test-output-stream) + 1133 (clear-stream $_test-output-buffered-file->buffer) + 1134 # + 1135 (write _test-input-stream "fn foo {\n") + 1136 (write _test-input-stream " var x/ecx: int <- copy 0\n") + 1137 (write _test-input-stream " compare x, 0\n") + 1138 (write _test-input-stream "}\n") + 1139 # convert + 1140 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 1141 (flush _test-output-buffered-file) + 1142 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 1148 # check output + 1149 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-compare-register-with-literal/0") + 1150 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-compare-register-with-literal/1") + 1151 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-compare-register-with-literal/2") + 1152 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-compare-register-with-literal/3") + 1153 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-compare-register-with-literal/4") + 1154 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-compare-register-with-literal/5") + 1155 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-compare-register-with-literal/6") + 1156 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 0/imm32" "F - test-convert-compare-register-with-literal/7") + 1157 (check-next-stream-line-equal _test-output-stream " 81 7/subop/compare %ecx 0/imm32" "F - test-convert-compare-register-with-literal/8") + 1158 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9") + 1159 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-compare-register-with-literal/10") + 1160 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-compare-register-with-literal/11") + 1161 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-compare-register-with-literal/12") + 1162 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-compare-register-with-literal/13") + 1163 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-compare-register-with-literal/14") + 1164 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-compare-register-with-literal/15") + 1165 # . epilogue + 1166 89/<- %esp 5/r32/ebp + 1167 5d/pop-to-ebp + 1168 c3/return + 1169 + 1170 test-convert-function-with-local-var-in-block: + 1171 # . prologue + 1172 55/push-ebp + 1173 89/<- %ebp 4/r32/esp + 1174 # setup + 1175 (clear-stream _test-input-stream) + 1176 (clear-stream $_test-input-buffered-file->buffer) + 1177 (clear-stream _test-output-stream) + 1178 (clear-stream $_test-output-buffered-file->buffer) + 1179 # + 1180 (write _test-input-stream "fn foo {\n") + 1181 (write _test-input-stream " {\n") + 1182 (write _test-input-stream " var x: int\n") + 1183 (write _test-input-stream " increment x\n") + 1184 (write _test-input-stream " }\n") + 1185 (write _test-input-stream "}\n") + 1186 # convert + 1187 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 1188 (flush _test-output-buffered-file) + 1189 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 1195 # check output + 1196 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-in-block/0") + 1197 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-in-block/1") + 1198 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-in-block/2") + 1199 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-in-block/3") + 1200 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-block/4") + 1201 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-in-block/5") + 1202 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-block/6") + 1203 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-local-var-in-block/7") + 1204 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-local-var-in-block/8") + 1205 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-local-var-in-block/9") + 1206 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-local-var-in-block/10") + 1207 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-block/11") + 1208 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-local-var-in-block/12") + 1209 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-block/13") + 1210 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-in-block/14") + 1211 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-in-block/15") + 1212 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-in-block/16") + 1213 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-in-block/17") + 1214 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-in-block/18") + 1215 # . epilogue + 1216 89/<- %esp 5/r32/ebp + 1217 5d/pop-to-ebp + 1218 c3/return + 1219 + 1220 test-convert-function-with-local-var-in-named-block: + 1221 # . prologue + 1222 55/push-ebp + 1223 89/<- %ebp 4/r32/esp + 1224 # setup + 1225 (clear-stream _test-input-stream) + 1226 (clear-stream $_test-input-buffered-file->buffer) + 1227 (clear-stream _test-output-stream) + 1228 (clear-stream $_test-output-buffered-file->buffer) + 1229 # + 1230 (write _test-input-stream "fn foo {\n") + 1231 (write _test-input-stream " $bar: {\n") + 1232 (write _test-input-stream " var x: int\n") + 1233 (write _test-input-stream " increment x\n") + 1234 (write _test-input-stream " }\n") + 1235 (write _test-input-stream "}\n") + 1236 # convert + 1237 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 1238 (flush _test-output-buffered-file) + 1239 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 1245 # check output + 1246 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-in-named-block/0") + 1247 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-in-named-block/1") + 1248 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-in-named-block/2") + 1249 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-in-named-block/3") + 1250 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-named-block/4") + 1251 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-in-named-block/5") + 1252 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-named-block/6") + 1253 (check-next-stream-line-equal _test-output-stream "$bar:loop:" "F - test-convert-function-with-local-var-in-named-block/7") + 1254 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-local-var-in-named-block/8") + 1255 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-local-var-in-named-block/9") + 1256 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-local-var-in-named-block/10") + 1257 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-named-block/11") + 1258 (check-next-stream-line-equal _test-output-stream "$bar:break:" "F - test-convert-function-with-local-var-in-named-block/12") + 1259 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-named-block/13") + 1260 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-in-named-block/14") + 1261 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-in-named-block/15") + 1262 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-in-named-block/16") + 1263 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-in-named-block/17") + 1264 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-in-named-block/18") + 1265 # . epilogue + 1266 89/<- %esp 5/r32/ebp + 1267 5d/pop-to-ebp + 1268 c3/return + 1269 + 1270 test-always-shadow-outermost-reg-vars-in-function: + 1271 # . prologue + 1272 55/push-ebp + 1273 89/<- %ebp 4/r32/esp + 1274 # setup + 1275 (clear-stream _test-input-stream) + 1276 (clear-stream $_test-input-buffered-file->buffer) + 1277 (clear-stream _test-output-stream) + 1278 (clear-stream $_test-output-buffered-file->buffer) + 1279 # + 1280 (write _test-input-stream "fn foo {\n") + 1281 (write _test-input-stream " var x/ecx: int <- copy 3\n") + 1282 (write _test-input-stream "}\n") + 1283 # convert + 1284 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 1285 (flush _test-output-buffered-file) + 1286 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 1292 # check output + 1293 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-always-shadow-outermost-reg-vars-in-function/0") + 1294 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-always-shadow-outermost-reg-vars-in-function/1") + 1295 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-always-shadow-outermost-reg-vars-in-function/2") + 1296 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-always-shadow-outermost-reg-vars-in-function/3") + 1297 (check-next-stream-line-equal _test-output-stream " {" "F - test-always-shadow-outermost-reg-vars-in-function/4") + 1298 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-always-shadow-outermost-reg-vars-in-function/5") + 1299 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-compare-register-with-literal/6") + 1300 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-always-shadow-outermost-reg-vars-in-function/8") + 1301 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9") + 1302 (check-next-stream-line-equal _test-output-stream " }" "F - test-always-shadow-outermost-reg-vars-in-function/12") + 1303 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-always-shadow-outermost-reg-vars-in-function/13") + 1304 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-always-shadow-outermost-reg-vars-in-function/14") + 1305 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-always-shadow-outermost-reg-vars-in-function/15") + 1306 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-always-shadow-outermost-reg-vars-in-function/16") + 1307 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-always-shadow-outermost-reg-vars-in-function/17") + 1308 # . epilogue + 1309 89/<- %esp 5/r32/ebp + 1310 5d/pop-to-ebp + 1311 c3/return + 1312 + 1313 _pending-test-clobber-dead-local: + 1314 # . prologue + 1315 55/push-ebp + 1316 89/<- %ebp 4/r32/esp + 1317 # setup + 1318 (clear-stream _test-input-stream) + 1319 (clear-stream $_test-input-buffered-file->buffer) + 1320 (clear-stream _test-output-stream) + 1321 (clear-stream $_test-output-buffered-file->buffer) + 1322 # + 1323 (write _test-input-stream "fn foo {\n") + 1324 (write _test-input-stream " var x/ecx: int <- copy 3\n") + 1325 (write _test-input-stream " {\n") + 1326 (write _test-input-stream " var y/ecx: int <- copy 4\n") + 1327 (write _test-input-stream " }\n") + 1328 (write _test-input-stream "}\n") + 1329 # convert + 1330 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 1331 (flush _test-output-buffered-file) + 1332 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 1338 # check output + 1339 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-clobber-dead-local/0") + 1340 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-clobber-dead-local/1") + 1341 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-clobber-dead-local/2") + 1342 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-clobber-dead-local/3") + 1343 (check-next-stream-line-equal _test-output-stream " {" "F - test-clobber-dead-local/4") + 1344 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-clobber-dead-local/5") + 1345 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-clobber-dead-local/6") + 1346 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-clobber-dead-local/7") + 1347 (check-next-stream-line-equal _test-output-stream " {" "F - test-clobber-dead-local/8") + 1348 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-clobber-dead-local/9") + 1349 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-clobber-dead-local/10") # no push/pop here + 1350 (check-next-stream-line-equal _test-output-stream " }" "F - test-clobber-dead-local/11") + 1351 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-clobber-dead-local/12") + 1352 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-clobber-dead-local/13") + 1353 (check-next-stream-line-equal _test-output-stream " }" "F - test-clobber-dead-local/14") + 1354 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-clobber-dead-local/15") + 1355 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-clobber-dead-local/16") + 1356 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-clobber-dead-local/17") + 1357 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-clobber-dead-local/18") + 1358 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-clobber-dead-local/19") + 1359 # . epilogue + 1360 89/<- %esp 5/r32/ebp + 1361 5d/pop-to-ebp + 1362 c3/return + 1363 + 1364 test-shadow-live-local: + 1365 # . prologue + 1366 55/push-ebp + 1367 89/<- %ebp 4/r32/esp + 1368 # setup + 1369 (clear-stream _test-input-stream) + 1370 (clear-stream $_test-input-buffered-file->buffer) + 1371 (clear-stream _test-output-stream) + 1372 (clear-stream $_test-output-buffered-file->buffer) + 1373 # + 1374 (write _test-input-stream "fn foo {\n") + 1375 (write _test-input-stream " var x/ecx: int <- copy 3\n") + 1376 (write _test-input-stream " {\n") + 1377 (write _test-input-stream " var y/ecx: int <- copy 4\n") + 1378 (write _test-input-stream " }\n") + 1379 (write _test-input-stream " x <- increment\n") + 1380 (write _test-input-stream "}\n") + 1381 # convert + 1382 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 1383 (flush _test-output-buffered-file) + 1384 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 1390 # check output + 1391 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-shadow-live-local/0") + 1392 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-shadow-live-local/1") + 1393 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-shadow-live-local/2") + 1394 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-shadow-live-local/3") + 1395 (check-next-stream-line-equal _test-output-stream " {" "F - test-shadow-live-local/4") + 1396 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-shadow-live-local/5") + 1397 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-shadow-live-local/6") + 1398 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-shadow-live-local/7") + 1399 (check-next-stream-line-equal _test-output-stream " {" "F - test-shadow-live-local/8") + 1400 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-shadow-live-local/9") + 1401 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-shadow-live-local/10") + 1402 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-shadow-live-local/11") + 1403 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-shadow-live-local/12") + 1404 (check-next-stream-line-equal _test-output-stream " }" "F - test-shadow-live-local/13") + 1405 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-shadow-live-local/14") + 1406 (check-next-stream-line-equal _test-output-stream " 41/increment-ecx" "F - test-shadow-live-local/15") + 1407 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-shadow-live-local/16") + 1408 (check-next-stream-line-equal _test-output-stream " }" "F - test-shadow-live-local/17") + 1409 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-shadow-live-local/18") + 1410 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-shadow-live-local/19") + 1411 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-shadow-live-local/20") + 1412 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-shadow-live-local/21") + 1413 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-shadow-live-local/21") + 1414 # . epilogue + 1415 89/<- %esp 5/r32/ebp + 1416 5d/pop-to-ebp + 1417 c3/return + 1418 + 1419 test-do-not-spill-same-register-in-block: + 1420 # . prologue + 1421 55/push-ebp + 1422 89/<- %ebp 4/r32/esp + 1423 # setup + 1424 (clear-stream _test-input-stream) + 1425 (clear-stream $_test-input-buffered-file->buffer) + 1426 (clear-stream _test-output-stream) + 1427 (clear-stream $_test-output-buffered-file->buffer) + 1428 # + 1429 (write _test-input-stream "fn foo {\n") + 1430 (write _test-input-stream " var x/ecx: int <- copy 3\n") + 1431 (write _test-input-stream " var y/ecx: int <- copy 4\n") + 1432 (write _test-input-stream " y <- increment\n") + 1433 (write _test-input-stream "}\n") + 1434 # convert + 1435 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 1436 (flush _test-output-buffered-file) + 1437 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 1443 # check output + 1444 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-do-not-spill-same-register-in-block/0") + 1445 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-do-not-spill-same-register-in-block/1") + 1446 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-do-not-spill-same-register-in-block/2") + 1447 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-do-not-spill-same-register-in-block/3") + 1448 (check-next-stream-line-equal _test-output-stream " {" "F - test-do-not-spill-same-register-in-block/4") + 1449 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-do-not-spill-same-register-in-block/5") + 1450 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-do-not-spill-same-register-in-block/6") + 1451 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-do-not-spill-same-register-in-block/7") + 1452 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-do-not-spill-same-register-in-block/8") + 1453 (check-next-stream-line-equal _test-output-stream " 41/increment-ecx" "F - test-do-not-spill-same-register-in-block/9") + 1454 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-do-not-spill-same-register-in-block/10") + 1455 (check-next-stream-line-equal _test-output-stream " }" "F - test-do-not-spill-same-register-in-block/11") + 1456 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-do-not-spill-same-register-in-block/12") + 1457 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-do-not-spill-same-register-in-block/13") + 1458 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-do-not-spill-same-register-in-block/14") + 1459 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-do-not-spill-same-register-in-block/15") + 1460 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-do-not-spill-same-register-in-block/16") + 1461 # . epilogue + 1462 89/<- %esp 5/r32/ebp + 1463 5d/pop-to-ebp + 1464 c3/return + 1465 + 1466 test-spill-different-register-in-block: + 1467 # . prologue + 1468 55/push-ebp + 1469 89/<- %ebp 4/r32/esp + 1470 # setup + 1471 (clear-stream _test-input-stream) + 1472 (clear-stream $_test-input-buffered-file->buffer) + 1473 (clear-stream _test-output-stream) + 1474 (clear-stream $_test-output-buffered-file->buffer) + 1475 # + 1476 (write _test-input-stream "fn foo {\n") + 1477 (write _test-input-stream " var x/eax: int <- copy 3\n") + 1478 (write _test-input-stream " var y/ecx: int <- copy 4\n") + 1479 (write _test-input-stream " y <- increment\n") + 1480 (write _test-input-stream "}\n") + 1481 # convert + 1482 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 1483 (flush _test-output-buffered-file) + 1484 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 1490 # check output + 1491 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-spill-different-register-in-block/0") + 1492 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-spill-different-register-in-block/1") + 1493 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-spill-different-register-in-block/2") + 1494 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-spill-different-register-in-block/3") + 1495 (check-next-stream-line-equal _test-output-stream " {" "F - test-spill-different-register-in-block/4") + 1496 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-spill-different-register-in-block/5") + 1497 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-spill-different-register-in-block/6") + 1498 (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 3/imm32" "F - test-spill-different-register-in-block/7") + 1499 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-spill-different-register-in-block/8") + 1500 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-spill-different-register-in-block/9") + 1501 (check-next-stream-line-equal _test-output-stream " 41/increment-ecx" "F - test-spill-different-register-in-block/10") + 1502 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-spill-different-register-in-block/11") + 1503 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-spill-different-register-in-block/12") + 1504 (check-next-stream-line-equal _test-output-stream " }" "F - test-spill-different-register-in-block/13") + 1505 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-spill-different-register-in-block/14") + 1506 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-spill-different-register-in-block/15") + 1507 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-spill-different-register-in-block/16") + 1508 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-spill-different-register-in-block/17") + 1509 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-spill-different-register-in-block/18") + 1510 # . epilogue + 1511 89/<- %esp 5/r32/ebp + 1512 5d/pop-to-ebp + 1513 c3/return + 1514 + 1515 test-shadow-live-output: + 1516 # . prologue + 1517 55/push-ebp + 1518 89/<- %ebp 4/r32/esp + 1519 # setup + 1520 (clear-stream _test-input-stream) + 1521 (clear-stream $_test-input-buffered-file->buffer) + 1522 (clear-stream _test-output-stream) + 1523 (clear-stream $_test-output-buffered-file->buffer) + 1524 # + 1525 (write _test-input-stream "fn foo -> x/ecx: int {\n") + 1526 (write _test-input-stream " x <- copy 3\n") + 1527 (write _test-input-stream " {\n") + 1528 (write _test-input-stream " var y/ecx: int <- copy 4\n") + 1529 (write _test-input-stream " }\n") + 1530 (write _test-input-stream " x <- increment\n") + 1531 (write _test-input-stream "}\n") + 1532 # convert + 1533 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 1534 (flush _test-output-buffered-file) + 1535 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 1541 # check output + 1542 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-shadow-live-output/0") + 1543 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-shadow-live-output/1") + 1544 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-shadow-live-output/2") + 1545 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-shadow-live-output/3") + 1546 (check-next-stream-line-equal _test-output-stream " {" "F - test-shadow-live-output/4") + 1547 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-shadow-live-output/5") + 1548 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-shadow-live-output/7") # no push because it's an output reg + 1549 (check-next-stream-line-equal _test-output-stream " {" "F - test-shadow-live-output/8") + 1550 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-shadow-live-output/9") + 1551 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-shadow-live-output/10") + 1552 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-shadow-live-output/11") + 1553 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-shadow-live-output/12") + 1554 (check-next-stream-line-equal _test-output-stream " }" "F - test-shadow-live-output/13") + 1555 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-shadow-live-output/14") + 1556 (check-next-stream-line-equal _test-output-stream " 41/increment-ecx" "F - test-shadow-live-output/15") + 1557 (check-next-stream-line-equal _test-output-stream " }" "F - test-shadow-live-output/17") + 1558 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-shadow-live-output/18") + 1559 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-shadow-live-output/19") + 1560 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-shadow-live-output/20") + 1561 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-shadow-live-output/21") + 1562 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-shadow-live-output/21") + 1563 # . epilogue + 1564 89/<- %esp 5/r32/ebp + 1565 5d/pop-to-ebp + 1566 c3/return + 1567 + 1568 _pending-test-local-clobbered-by-output: + 1569 # also doesn't spill + 1570 # . prologue + 1571 55/push-ebp + 1572 89/<- %ebp 4/r32/esp + 1573 # setup + 1574 (clear-stream _test-input-stream) + 1575 (clear-stream $_test-input-buffered-file->buffer) + 1576 (clear-stream _test-output-stream) + 1577 (clear-stream $_test-output-buffered-file->buffer) + 1578 # + 1579 (write _test-input-stream "fn foo -> x/ecx: int {\n") + 1580 (write _test-input-stream " var y/ecx: int <- copy 4\n") + 1581 (write _test-input-stream " x <- copy y\n") + 1582 (write _test-input-stream "}\n") + 1583 # convert + 1584 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 1585 (flush _test-output-buffered-file) + 1586 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 1592 # check output + 1593 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-local-clobbered-by-output/0") + 1594 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-local-clobbered-by-output/1") + 1595 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-local-clobbered-by-output/2") + 1596 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-local-clobbered-by-output/3") + 1597 (check-next-stream-line-equal _test-output-stream " {" "F - test-local-clobbered-by-output/4") + 1598 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-local-clobbered-by-output/5") + 1599 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-local-clobbered-by-output/6") + 1600 (check-next-stream-line-equal _test-output-stream " 89/<- %ecx 0x00000001/r32" "F - test-local-clobbered-by-output/7") + 1601 (check-next-stream-line-equal _test-output-stream " }" "F - test-local-clobbered-by-output/8") + 1602 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-local-clobbered-by-output/9") + 1603 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-local-clobbered-by-output/10") + 1604 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-local-clobbered-by-output/11") + 1605 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-local-clobbered-by-output/12") + 1606 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-local-clobbered-by-output/13") + 1607 # . epilogue + 1608 89/<- %esp 5/r32/ebp + 1609 5d/pop-to-ebp + 1610 c3/return + 1611 + 1612 test-convert-function-with-branches-in-block: + 1613 # . prologue + 1614 55/push-ebp + 1615 89/<- %ebp 4/r32/esp + 1616 # setup + 1617 (clear-stream _test-input-stream) + 1618 (clear-stream $_test-input-buffered-file->buffer) + 1619 (clear-stream _test-output-stream) + 1620 (clear-stream $_test-output-buffered-file->buffer) + 1621 # + 1622 (write _test-input-stream "fn foo x: int {\n") + 1623 (write _test-input-stream " {\n") + 1624 (write _test-input-stream " break-if->=\n") + 1625 (write _test-input-stream " loop-if-addr<\n") + 1626 (write _test-input-stream " increment x\n") + 1627 (write _test-input-stream " loop\n") + 1628 (write _test-input-stream " }\n") + 1629 (write _test-input-stream "}\n") + 1630 # convert + 1631 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 1632 (flush _test-output-buffered-file) + 1633 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 1639 # check output + 1640 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-branches-in-block/0") + 1641 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-branches-in-block/1") + 1642 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-branches-in-block/2") + 1643 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-branches-in-block/3") + 1644 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-in-block/4") + 1645 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-branches-in-block/5") + 1646 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-in-block/6") + 1647 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-branches-in-block/7") + 1648 (check-next-stream-line-equal _test-output-stream " 0f 8d/jump-if->= break/disp32" "F - test-convert-function-with-branches-in-block/8") + 1649 (check-next-stream-line-equal _test-output-stream " 0f 82/jump-if-addr< loop/disp32" "F - test-convert-function-with-branches-in-block/9") + 1650 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0x00000008)" "F - test-convert-function-with-branches-in-block/10") + 1651 (check-next-stream-line-equal _test-output-stream " e9/jump loop/disp32" "F - test-convert-function-with-branches-in-block/11") + 1652 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-block/12") + 1653 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-branches-in-block/13") + 1654 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-block/14") + 1655 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-branches-in-block/15") + 1656 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-branches-in-block/16") + 1657 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-branches-in-block/17") + 1658 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-branches-in-block/18") + 1659 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-branches-in-block/19") + 1660 # . epilogue + 1661 89/<- %esp 5/r32/ebp + 1662 5d/pop-to-ebp + 1663 c3/return + 1664 + 1665 test-convert-function-with-branches-in-named-block: + 1666 # . prologue + 1667 55/push-ebp + 1668 89/<- %ebp 4/r32/esp + 1669 # setup + 1670 (clear-stream _test-input-stream) + 1671 (clear-stream $_test-input-buffered-file->buffer) + 1672 (clear-stream _test-output-stream) + 1673 (clear-stream $_test-output-buffered-file->buffer) + 1674 # + 1675 (write _test-input-stream "fn foo x: int {\n") + 1676 (write _test-input-stream " $bar: {\n") + 1677 (write _test-input-stream " break-if->= $bar\n") + 1678 (write _test-input-stream " loop-if-addr< $bar\n") + 1679 (write _test-input-stream " increment x\n") + 1680 (write _test-input-stream " loop\n") + 1681 (write _test-input-stream " }\n") + 1682 (write _test-input-stream "}\n") + 1683 # convert + 1684 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 1685 (flush _test-output-buffered-file) + 1686 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 1692 # check output + 1693 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-branches-in-named-block/0") + 1694 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-branches-in-named-block/1") + 1695 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-branches-in-named-block/2") + 1696 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-branches-in-named-block/3") + 1697 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-in-named-block/4") + 1698 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-branches-in-named-block/5") + 1699 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-in-named-block/6") + 1700 (check-next-stream-line-equal _test-output-stream "$bar:loop:" "F - test-convert-function-with-branches-in-named-block/7") + 1701 (check-next-stream-line-equal _test-output-stream " 0f 8d/jump-if->= $bar:break/disp32" "F - test-convert-function-with-branches-in-named-block/8") + 1702 (check-next-stream-line-equal _test-output-stream " 0f 82/jump-if-addr< $bar:loop/disp32" "F - test-convert-function-with-branches-in-named-block/9") + 1703 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0x00000008)" "F - test-convert-function-with-branches-in-named-block/10") + 1704 (check-next-stream-line-equal _test-output-stream " e9/jump loop/disp32" "F - test-convert-function-with-branches-in-named-block/11") + 1705 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-named-block/12") + 1706 (check-next-stream-line-equal _test-output-stream "$bar:break:" "F - test-convert-function-with-branches-in-named-block/13") + 1707 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-named-block/14") + 1708 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-branches-in-named-block/15") + 1709 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-branches-in-named-block/16") + 1710 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-branches-in-named-block/17") + 1711 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-branches-in-named-block/18") + 1712 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-branches-in-named-block/19") + 1713 # . epilogue + 1714 89/<- %esp 5/r32/ebp + 1715 5d/pop-to-ebp + 1716 c3/return + 1717 + 1718 test-convert-function-with-var-in-nested-block: + 1719 # . prologue + 1720 55/push-ebp + 1721 89/<- %ebp 4/r32/esp + 1722 # setup + 1723 (clear-stream _test-input-stream) + 1724 (clear-stream $_test-input-buffered-file->buffer) + 1725 (clear-stream _test-output-stream) + 1726 (clear-stream $_test-output-buffered-file->buffer) + 1727 # + 1728 (write _test-input-stream "fn foo x: int {\n") + 1729 (write _test-input-stream " {\n") + 1730 (write _test-input-stream " {\n") + 1731 (write _test-input-stream " var x: int\n") + 1732 (write _test-input-stream " increment x\n") + 1733 (write _test-input-stream " }\n") + 1734 (write _test-input-stream " }\n") + 1735 (write _test-input-stream "}\n") + 1736 # convert + 1737 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 1738 (flush _test-output-buffered-file) + 1739 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 1745 # check output + 1746 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-var-in-nested-block/0") + 1747 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-var-in-nested-block/1") + 1748 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-var-in-nested-block/2") + 1749 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-var-in-nested-block/3") + 1750 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-var-in-nested-block/4") + 1751 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-var-in-nested-block/5") + 1752 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-var-in-nested-block/6") + 1753 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-var-in-nested-block/7") + 1754 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-var-in-nested-block/8") + 1755 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-var-in-nested-block/9") + 1756 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-var-in-nested-block/10") + 1757 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-var-in-nested-block/11") + 1758 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-var-in-nested-block/12") + 1759 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-var-in-nested-block/13") + 1760 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-var-in-nested-block/14") + 1761 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-var-in-nested-block/15") + 1762 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-var-in-nested-block/16") + 1763 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-var-in-nested-block/17") + 1764 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-var-in-nested-block/18") + 1765 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-var-in-nested-block/19") + 1766 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-var-in-nested-block/20") + 1767 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-var-in-nested-block/21") + 1768 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-var-in-nested-block/22") + 1769 # . epilogue + 1770 89/<- %esp 5/r32/ebp + 1771 5d/pop-to-ebp + 1772 c3/return + 1773 + 1774 test-convert-function-with-multiple-vars-in-nested-blocks: + 1775 # . prologue + 1776 55/push-ebp + 1777 89/<- %ebp 4/r32/esp + 1778 # setup + 1779 (clear-stream _test-input-stream) + 1780 (clear-stream $_test-input-buffered-file->buffer) + 1781 (clear-stream _test-output-stream) + 1782 (clear-stream $_test-output-buffered-file->buffer) + 1783 # + 1784 (write _test-input-stream "fn foo x: int {\n") + 1785 (write _test-input-stream " {\n") + 1786 (write _test-input-stream " var x/eax: int <- copy 0\n") + 1787 (write _test-input-stream " {\n") + 1788 (write _test-input-stream " var y: int\n") + 1789 (write _test-input-stream " x <- add y\n") + 1790 (write _test-input-stream " }\n") + 1791 (write _test-input-stream " }\n") + 1792 (write _test-input-stream "}\n") + 1793 # convert + 1794 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 1795 (flush _test-output-buffered-file) + 1796 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 1802 # check output + 1803 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-multiple-vars-in-nested-blocks/0") + 1804 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-multiple-vars-in-nested-blocks/1") + 1805 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-multiple-vars-in-nested-blocks/2") + 1806 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-multiple-vars-in-nested-blocks/3") + 1807 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-multiple-vars-in-nested-blocks/4") + 1808 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-multiple-vars-in-nested-blocks/5") + 1809 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-multiple-vars-in-nested-blocks/6") + 1810 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-multiple-vars-in-nested-blocks/7") + 1811 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-function-with-multiple-vars-in-nested-blocks/8") + 1812 (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/9") + 1813 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-multiple-vars-in-nested-blocks/10") + 1814 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-multiple-vars-in-nested-blocks/11") + 1815 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/12") + 1816 (check-next-stream-line-equal _test-output-stream " 03/add *(ebp+0xfffffff8) 0x00000000/r32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/13") + 1817 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/14") + 1818 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-multiple-vars-in-nested-blocks/15") + 1819 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-multiple-vars-in-nested-blocks/16") + 1820 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-function-with-multiple-vars-in-nested-blocks/17") + 1821 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-multiple-vars-in-nested-blocks/18") + 1822 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-multiple-vars-in-nested-blocks/19") + 1823 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-multiple-vars-in-nested-blocks/20") + 1824 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-multiple-vars-in-nested-blocks/21") + 1825 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-multiple-vars-in-nested-blocks/22") + 1826 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-multiple-vars-in-nested-blocks/23") + 1827 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-multiple-vars-in-nested-blocks/24") + 1828 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-multiple-vars-in-nested-blocks/25") + 1829 # . epilogue + 1830 89/<- %esp 5/r32/ebp + 1831 5d/pop-to-ebp + 1832 c3/return + 1833 + 1834 test-convert-function-with-branches-and-local-vars: + 1835 # A conditional 'break' after a 'var' in a block is converted into a + 1836 # nested block that performs all necessary cleanup before jumping. This + 1837 # results in some ugly code duplication. + 1838 # . prologue + 1839 55/push-ebp + 1840 89/<- %ebp 4/r32/esp + 1841 # setup + 1842 (clear-stream _test-input-stream) + 1843 (clear-stream $_test-input-buffered-file->buffer) + 1844 (clear-stream _test-output-stream) + 1845 (clear-stream $_test-output-buffered-file->buffer) + 1846 # + 1847 (write _test-input-stream "fn foo {\n") + 1848 (write _test-input-stream " {\n") + 1849 (write _test-input-stream " var x: int\n") + 1850 (write _test-input-stream " break-if->=\n") + 1851 (write _test-input-stream " increment x\n") + 1852 (write _test-input-stream " }\n") + 1853 (write _test-input-stream "}\n") + 1854 # convert + 1855 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 1856 (flush _test-output-buffered-file) + 1857 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 1863 # check output + 1864 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-branches-and-local-vars/0") + 1865 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-branches-and-local-vars/1") + 1866 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-branches-and-local-vars/2") + 1867 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-branches-and-local-vars/3") + 1868 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-and-local-vars/4") + 1869 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-branches-and-local-vars/5") + 1870 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-and-local-vars/6") + 1871 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-branches-and-local-vars/7") + 1872 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-branches-and-local-vars/8") + 1873 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-and-local-vars/9") + 1874 (check-next-stream-line-equal _test-output-stream " 0f 8c/jump-if-< break/disp32" "F - test-convert-function-with-branches-and-local-vars/10") + 1875 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-branches-and-local-vars/11") + 1876 (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000002:break/disp32" "F - test-convert-function-with-branches-and-local-vars/12") + 1877 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-and-local-vars/13") + 1878 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-branches-and-local-vars/14") + 1879 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-branches-and-local-vars/15") + 1880 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-and-local-vars/16") + 1881 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-branches-and-local-vars/17") + 1882 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-and-local-vars/18") + 1883 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-branches-and-local-vars/19") + 1884 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-branches-and-local-vars/20") + 1885 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-branches-and-local-vars/21") + 1886 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-branches-and-local-vars/22") + 1887 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-branches-and-local-vars/23") + 1888 # . epilogue + 1889 89/<- %esp 5/r32/ebp + 1890 5d/pop-to-ebp + 1891 c3/return + 1892 + 1893 test-convert-function-with-conditional-loops-and-local-vars: + 1894 # A conditional 'loop' after a 'var' in a block is converted into a nested + 1895 # block that performs all necessary cleanup before jumping. This results + 1896 # in some ugly code duplication. + 1897 # . prologue + 1898 55/push-ebp + 1899 89/<- %ebp 4/r32/esp + 1900 # setup + 1901 (clear-stream _test-input-stream) + 1902 (clear-stream $_test-input-buffered-file->buffer) + 1903 (clear-stream _test-output-stream) + 1904 (clear-stream $_test-output-buffered-file->buffer) + 1905 # + 1906 (write _test-input-stream "fn foo {\n") + 1907 (write _test-input-stream " {\n") + 1908 (write _test-input-stream " var x: int\n") + 1909 (write _test-input-stream " loop-if->=\n") + 1910 (write _test-input-stream " increment x\n") + 1911 (write _test-input-stream " }\n") + 1912 (write _test-input-stream "}\n") + 1913 # convert + 1914 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 1915 (flush _test-output-buffered-file) + 1916 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 1922 # check output + 1923 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-conditional-loops-and-local-vars/0") + 1924 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-conditional-loops-and-local-vars/1") + 1925 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-conditional-loops-and-local-vars/2") + 1926 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-conditional-loops-and-local-vars/3") + 1927 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-conditional-loops-and-local-vars/4") + 1928 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-conditional-loops-and-local-vars/5") + 1929 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-conditional-loops-and-local-vars/6") + 1930 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-conditional-loops-and-local-vars/7") + 1931 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-conditional-loops-and-local-vars/8") + 1932 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-conditional-loops-and-local-vars/9") + 1933 (check-next-stream-line-equal _test-output-stream " 0f 8c/jump-if-< break/disp32" "F - test-convert-function-with-conditional-loops-and-local-vars/10") + 1934 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-conditional-loops-and-local-vars/11") + 1935 (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000002:loop/disp32" "F - test-convert-function-with-conditional-loops-and-local-vars/12") + 1936 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-conditional-loops-and-local-vars/13") + 1937 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-conditional-loops-and-local-vars/14") + 1938 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-conditional-loops-and-local-vars/15") + 1939 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-conditional-loops-and-local-vars/16") + 1940 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-conditional-loops-and-local-vars/17") + 1941 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-conditional-loops-and-local-vars/18") + 1942 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-conditional-loops-and-local-vars/19") + 1943 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-conditional-loops-and-local-vars/20") + 1944 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-conditional-loops-and-local-vars/21") + 1945 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-conditional-loops-and-local-vars/22") + 1946 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-conditional-loops-and-local-vars/23") + 1947 # . epilogue + 1948 89/<- %esp 5/r32/ebp + 1949 5d/pop-to-ebp + 1950 c3/return + 1951 + 1952 test-convert-function-with-unconditional-loops-and-local-vars: + 1953 # An unconditional 'loop' after a 'var' in a block is emitted _after_ the + 1954 # regular block cleanup. Any instructions after 'loop' are dead and + 1955 # therefore skipped. + 1956 # . prologue + 1957 55/push-ebp + 1958 89/<- %ebp 4/r32/esp + 1959 # setup + 1960 (clear-stream _test-input-stream) + 1961 (clear-stream $_test-input-buffered-file->buffer) + 1962 (clear-stream _test-output-stream) + 1963 (clear-stream $_test-output-buffered-file->buffer) + 1964 # + 1965 (write _test-input-stream "fn foo {\n") + 1966 (write _test-input-stream " {\n") + 1967 (write _test-input-stream " var x: int\n") + 1968 (write _test-input-stream " loop\n") + 1969 (write _test-input-stream " increment x\n") + 1970 (write _test-input-stream " }\n") + 1971 (write _test-input-stream "}\n") + 1972 # convert + 1973 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 1974 (flush _test-output-buffered-file) + 1975 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 1981 # check output + 1982 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-unconditional-loops-and-local-vars/0") + 1983 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-unconditional-loops-and-local-vars/1") + 1984 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-unconditional-loops-and-local-vars/2") + 1985 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-unconditional-loops-and-local-vars/3") + 1986 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-unconditional-loops-and-local-vars/4") + 1987 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-unconditional-loops-and-local-vars/5") + 1988 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-unconditional-loops-and-local-vars/6") + 1989 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-unconditional-loops-and-local-vars/7") + 1990 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-unconditional-loops-and-local-vars/8") + 1991 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-unconditional-loops-and-local-vars/9") + 1992 (check-next-stream-line-equal _test-output-stream " e9/jump loop/disp32" "F - test-convert-function-with-unconditional-loops-and-local-vars/10") + 1993 # not emitted: ff 0/subop/increment *(ebp+0xfffffffc) + 1994 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-unconditional-loops-and-local-vars/11") + 1995 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-unconditional-loops-and-local-vars/12") + 1996 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-unconditional-loops-and-local-vars/13") + 1997 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-unconditional-loops-and-local-vars/14") + 1998 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-unconditional-loops-and-local-vars/15") + 1999 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-unconditional-loops-and-local-vars/16") + 2000 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-unconditional-loops-and-local-vars/17") + 2001 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-unconditional-loops-and-local-vars/18") + 2002 # . epilogue + 2003 89/<- %esp 5/r32/ebp + 2004 5d/pop-to-ebp + 2005 c3/return + 2006 + 2007 test-convert-function-with-branches-and-loops-and-local-vars: + 2008 # . prologue + 2009 55/push-ebp + 2010 89/<- %ebp 4/r32/esp + 2011 # setup + 2012 (clear-stream _test-input-stream) + 2013 (clear-stream $_test-input-buffered-file->buffer) + 2014 (clear-stream _test-output-stream) + 2015 (clear-stream $_test-output-buffered-file->buffer) + 2016 # + 2017 (write _test-input-stream "fn foo {\n") + 2018 (write _test-input-stream " {\n") + 2019 (write _test-input-stream " var x: int\n") + 2020 (write _test-input-stream " break-if->=\n") + 2021 (write _test-input-stream " increment x\n") + 2022 (write _test-input-stream " loop\n") + 2023 (write _test-input-stream " }\n") + 2024 (write _test-input-stream "}\n") + 2025 # convert + 2026 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 2027 (flush _test-output-buffered-file) + 2028 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 2034 # check output + 2035 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-branches-and-loops-and-local-vars/0") + 2036 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-branches-and-loops-and-local-vars/1") + 2037 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-branches-and-loops-and-local-vars/2") + 2038 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-branches-and-loops-and-local-vars/3") + 2039 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-and-loops-and-local-vars/4") + 2040 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-branches-and-loops-and-local-vars/5") + 2041 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-and-loops-and-local-vars/6") + 2042 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-branches-and-loops-and-local-vars/7") + 2043 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-branches-and-loops-and-local-vars/8") + 2044 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-and-loops-and-local-vars/9") + 2045 (check-next-stream-line-equal _test-output-stream " 0f 8c/jump-if-< break/disp32" "F - test-convert-function-with-branches-and-loops-and-local-vars/10") + 2046 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-branches-and-loops-and-local-vars/11") + 2047 (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000002:break/disp32" "F - test-convert-function-with-branches-and-loops-and-local-vars/12") + 2048 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-and-loops-and-local-vars/13") + 2049 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-branches-and-loops-and-local-vars/14") + 2050 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-branches-and-loops-and-local-vars/15") + 2051 (check-next-stream-line-equal _test-output-stream " e9/jump loop/disp32" "F - test-convert-function-with-branches-and-loops-and-local-vars/16") + 2052 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-and-loops-and-local-vars/17") + 2053 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-branches-and-loops-and-local-vars/18") + 2054 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-and-loops-and-local-vars/19") + 2055 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-branches-and-loops-and-local-vars/20") + 2056 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-branches-and-loops-and-local-vars/21") + 2057 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-branches-and-loops-and-local-vars/22") + 2058 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-branches-and-loops-and-local-vars/23") + 2059 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-branches-and-loops-and-local-vars/24") + 2060 # . epilogue + 2061 89/<- %esp 5/r32/ebp + 2062 5d/pop-to-ebp + 2063 c3/return + 2064 + 2065 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars: + 2066 # . prologue + 2067 55/push-ebp + 2068 89/<- %ebp 4/r32/esp + 2069 # setup + 2070 (clear-stream _test-input-stream) + 2071 (clear-stream $_test-input-buffered-file->buffer) + 2072 (clear-stream _test-output-stream) + 2073 (clear-stream $_test-output-buffered-file->buffer) + 2074 # + 2075 (write _test-input-stream "fn foo {\n") + 2076 (write _test-input-stream " a: {\n") + 2077 (write _test-input-stream " var x: int\n") + 2078 (write _test-input-stream " {\n") + 2079 (write _test-input-stream " var y: int\n") + 2080 (write _test-input-stream " break-if->= a\n") + 2081 (write _test-input-stream " increment x\n") + 2082 (write _test-input-stream " loop\n") + 2083 (write _test-input-stream " }\n") + 2084 (write _test-input-stream " }\n") + 2085 (write _test-input-stream "}\n") + 2086 # convert + 2087 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 2088 (flush _test-output-buffered-file) + 2089 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 2095 # check output + 2096 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/0") + 2097 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/1") + 2098 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/2") + 2099 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/3") + 2100 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/4") + 2101 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/5") + 2102 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/6") + 2103 (check-next-stream-line-equal _test-output-stream "a:loop:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/7") + 2104 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/8") + 2105 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/9") + 2106 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/10") + 2107 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/11") + 2108 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/12") + 2109 (check-next-stream-line-equal _test-output-stream " 0f 8c/jump-if-< break/disp32" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/13") + 2110 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/14") + 2111 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/15") + 2112 (check-next-stream-line-equal _test-output-stream " e9/jump a:break/disp32" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/16") + 2113 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/17") + 2114 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/18") + 2115 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/19") + 2116 (check-next-stream-line-equal _test-output-stream " e9/jump loop/disp32" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/20") + 2117 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/21") + 2118 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/22") + 2119 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/23") + 2120 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/24") + 2121 (check-next-stream-line-equal _test-output-stream "a:break:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/25") + 2122 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/26") + 2123 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/27") + 2124 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/28") + 2125 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/29") + 2126 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/30") + 2127 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/31") + 2128 # . epilogue + 2129 89/<- %esp 5/r32/ebp + 2130 5d/pop-to-ebp + 2131 c3/return + 2132 + 2133 test-convert-function-with-nonlocal-unconditional-break-and-local-vars: + 2134 # . prologue + 2135 55/push-ebp + 2136 89/<- %ebp 4/r32/esp + 2137 # setup + 2138 (clear-stream _test-input-stream) + 2139 (clear-stream $_test-input-buffered-file->buffer) + 2140 (clear-stream _test-output-stream) + 2141 (clear-stream $_test-output-buffered-file->buffer) + 2142 # + 2143 (write _test-input-stream "fn foo {\n") + 2144 (write _test-input-stream " a: {\n") + 2145 (write _test-input-stream " var x: int\n") + 2146 (write _test-input-stream " {\n") + 2147 (write _test-input-stream " var y: int\n") + 2148 (write _test-input-stream " break a\n") + 2149 (write _test-input-stream " increment x\n") + 2150 (write _test-input-stream " }\n") + 2151 (write _test-input-stream " }\n") + 2152 (write _test-input-stream "}\n") + 2153 # convert + 2154 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 2155 (flush _test-output-buffered-file) + 2156 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 2162 # check output + 2163 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/0") + 2164 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/1") + 2165 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/2") + 2166 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/3") + 2167 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/4") + 2168 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/5") + 2169 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/6") + 2170 (check-next-stream-line-equal _test-output-stream "a:loop:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/7") + 2171 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/8") + 2172 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/9") + 2173 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/10") + 2174 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/11") + 2175 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/12") + 2176 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/13") + 2177 (check-next-stream-line-equal _test-output-stream " e9/jump a:break/disp32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/14") + 2178 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/15") + 2179 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/16") + 2180 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/17") + 2181 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/18") + 2182 (check-next-stream-line-equal _test-output-stream "a:break:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/19") + 2183 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/20") + 2184 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/21") + 2185 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/22") + 2186 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/23") + 2187 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/24") + 2188 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/25") + 2189 # . epilogue + 2190 89/<- %esp 5/r32/ebp + 2191 5d/pop-to-ebp + 2192 c3/return + 2193 + 2194 test-convert-function-with-unconditional-break-and-local-vars: + 2195 # . prologue + 2196 55/push-ebp + 2197 89/<- %ebp 4/r32/esp + 2198 # setup + 2199 (clear-stream _test-input-stream) + 2200 (clear-stream $_test-input-buffered-file->buffer) + 2201 (clear-stream _test-output-stream) + 2202 (clear-stream $_test-output-buffered-file->buffer) + 2203 # + 2204 (write _test-input-stream "fn foo {\n") + 2205 (write _test-input-stream " {\n") + 2206 (write _test-input-stream " var x: int\n") + 2207 (write _test-input-stream " {\n") + 2208 (write _test-input-stream " var y: int\n") + 2209 (write _test-input-stream " break\n") + 2210 (write _test-input-stream " increment x\n") + 2211 (write _test-input-stream " }\n") + 2212 (write _test-input-stream " }\n") + 2213 (write _test-input-stream "}\n") + 2214 # convert + 2215 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 2216 (flush _test-output-buffered-file) + 2217 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 2223 # check output + 2224 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-unconditional-break-and-local-vars/0") + 2225 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-unconditional-break-and-local-vars/1") + 2226 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-unconditional-break-and-local-vars/2") + 2227 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-unconditional-break-and-local-vars/3") + 2228 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-unconditional-break-and-local-vars/4") + 2229 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-unconditional-break-and-local-vars/5") + 2230 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-unconditional-break-and-local-vars/6") + 2231 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-unconditional-break-and-local-vars/7") + 2232 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/8") + 2233 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-unconditional-break-and-local-vars/9") + 2234 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-unconditional-break-and-local-vars/10") + 2235 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/11") + 2236 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/12") + 2237 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-unconditional-break-and-local-vars/13") + 2238 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-unconditional-break-and-local-vars/14") + 2239 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/15") + 2240 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-unconditional-break-and-local-vars/16") + 2241 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-unconditional-break-and-local-vars/17") + 2242 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-unconditional-break-and-local-vars/18") + 2243 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-unconditional-break-and-local-vars/19") + 2244 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-unconditional-break-and-local-vars/20") + 2245 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-unconditional-break-and-local-vars/21") + 2246 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-unconditional-break-and-local-vars/22") + 2247 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-unconditional-break-and-local-vars/23") + 2248 # . epilogue + 2249 89/<- %esp 5/r32/ebp + 2250 5d/pop-to-ebp + 2251 c3/return + 2252 + 2253 test-convert-function-with-nonlocal-unconditional-loop-and-local-vars: + 2254 # . prologue + 2255 55/push-ebp + 2256 89/<- %ebp 4/r32/esp + 2257 # setup + 2258 (clear-stream _test-input-stream) + 2259 (clear-stream $_test-input-buffered-file->buffer) + 2260 (clear-stream _test-output-stream) + 2261 (clear-stream $_test-output-buffered-file->buffer) + 2262 # + 2263 (write _test-input-stream "fn foo {\n") + 2264 (write _test-input-stream " a: {\n") + 2265 (write _test-input-stream " var x: int\n") + 2266 (write _test-input-stream " {\n") + 2267 (write _test-input-stream " var y: int\n") + 2268 (write _test-input-stream " loop a\n") + 2269 (write _test-input-stream " increment x\n") + 2270 (write _test-input-stream " }\n") + 2271 (write _test-input-stream " }\n") + 2272 (write _test-input-stream "}\n") + 2273 # convert + 2274 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 2275 (flush _test-output-buffered-file) + 2276 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 2282 # check output + 2283 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/0") + 2284 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/1") + 2285 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/2") + 2286 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/3") + 2287 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/4") + 2288 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/5") + 2289 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/6") + 2290 (check-next-stream-line-equal _test-output-stream "a:loop:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/7") + 2291 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/8") + 2292 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/9") + 2293 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/10") + 2294 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/11") + 2295 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/12") + 2296 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/13") + 2297 (check-next-stream-line-equal _test-output-stream " e9/jump a:loop/disp32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/14") + 2298 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/15") + 2299 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/16") + 2300 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/17") + 2301 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/18") + 2302 (check-next-stream-line-equal _test-output-stream "a:break:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/19") + 2303 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/20") + 2304 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/21") + 2305 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/22") + 2306 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/23") + 2307 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/24") + 2308 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/25") + 2309 # . epilogue + 2310 89/<- %esp 5/r32/ebp + 2311 5d/pop-to-ebp + 2312 c3/return + 2313 + 2314 test-convert-function-with-local-array-var-in-mem: + 2315 # . prologue + 2316 55/push-ebp + 2317 89/<- %ebp 4/r32/esp + 2318 # setup + 2319 (clear-stream _test-input-stream) + 2320 (clear-stream $_test-input-buffered-file->buffer) + 2321 (clear-stream _test-output-stream) + 2322 (clear-stream $_test-output-buffered-file->buffer) + 2323 # + 2324 (write _test-input-stream "fn foo {\n") + 2325 (write _test-input-stream " var x: (array int 3)\n") + 2326 (write _test-input-stream "}\n") + 2327 # convert + 2328 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 2329 (flush _test-output-buffered-file) + 2330 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 2336 # check output + 2337 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-array-var-in-mem/0") + 2338 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-array-var-in-mem/1") + 2339 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-array-var-in-mem/2") + 2340 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-array-var-in-mem/3") + 2341 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-array-var-in-mem/4") + 2342 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-array-var-in-mem/5") + 2343 # define x + 2344 (check-next-stream-line-equal _test-output-stream " (push-n-zero-bytes 0x0000000c)" "F - test-convert-function-with-local-array-var-in-mem/7") + 2345 (check-next-stream-line-equal _test-output-stream " 68/push 0x0000000c/imm32" "F - test-convert-function-with-local-array-var-in-mem/8") + 2346 # reclaim x + 2347 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000010/imm32" "F - test-convert-function-with-local-array-var-in-mem/9") + 2348 # + 2349 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-array-var-in-mem/10") + 2350 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-array-var-in-mem/11") + 2351 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-array-var-in-mem/12") + 2352 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-array-var-in-mem/13") + 2353 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-array-var-in-mem/14") + 2354 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-array-var-in-mem/15") + 2355 # . epilogue + 2356 89/<- %esp 5/r32/ebp + 2357 5d/pop-to-ebp + 2358 c3/return + 2359 + 2360 test-convert-address: + 2361 # . prologue + 2362 55/push-ebp + 2363 89/<- %ebp 4/r32/esp + 2364 # setup + 2365 (clear-stream _test-input-stream) + 2366 (clear-stream $_test-input-buffered-file->buffer) + 2367 (clear-stream _test-output-stream) + 2368 (clear-stream $_test-output-buffered-file->buffer) + 2369 # + 2370 (write _test-input-stream "fn foo {\n") + 2371 (write _test-input-stream " var a: int\n") + 2372 (write _test-input-stream " var b/eax: (addr int) <- address a\n") + 2373 (write _test-input-stream "}\n") + 2374 # convert + 2375 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 2376 (flush _test-output-buffered-file) + 2377 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 2383 # check output + 2384 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-address/0") + 2385 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-address/1") + 2386 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-address/2") + 2387 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-address/3") + 2388 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-address/4") + 2389 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-address/5") + 2390 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-address/6") + 2391 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-address/7") + 2392 (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp+0xfffffffc) 0x00000000/r32" "F - test-convert-address/8") + 2393 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-address/9") + 2394 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-address/10") + 2395 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-address/11") + 2396 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-address/12") + 2397 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-address/13") + 2398 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-address/14") + 2399 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-address/15") + 2400 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-address/16") + 2401 # . epilogue + 2402 89/<- %esp 5/r32/ebp + 2403 5d/pop-to-ebp + 2404 c3/return + 2405 + 2406 test-convert-length-of-array: + 2407 # . prologue + 2408 55/push-ebp + 2409 89/<- %ebp 4/r32/esp + 2410 # setup + 2411 (clear-stream _test-input-stream) + 2412 (clear-stream $_test-input-buffered-file->buffer) + 2413 (clear-stream _test-output-stream) + 2414 (clear-stream $_test-output-buffered-file->buffer) + 2415 # + 2416 (write _test-input-stream "fn foo a: (addr array int) {\n") + 2417 (write _test-input-stream " var b/eax: (addr array int) <- copy a\n") + 2418 (write _test-input-stream " var c/eax: int <- length b\n") + 2419 (write _test-input-stream "}\n") + 2420 # convert + 2421 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 2422 (flush _test-output-buffered-file) + 2423 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 2429 # check output + 2430 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-length-of-array/0") + 2431 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-length-of-array/1") + 2432 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-length-of-array/2") + 2433 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-length-of-array/3") + 2434 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-length-of-array/4") + 2435 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-length-of-array/5") + 2436 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-length-of-array/6") + 2437 (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-length-of-array/7") + 2438 (check-next-stream-line-equal _test-output-stream " 8b/-> *eax 0x00000000/r32" "F - test-convert-length-of-array/9") + 2439 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-length-of-array/11") + 2440 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-length-of-array/12") + 2441 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-length-of-array/13") + 2442 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-length-of-array/14") + 2443 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-length-of-array/15") + 2444 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-length-of-array/16") + 2445 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-length-of-array/17") + 2446 # . epilogue + 2447 89/<- %esp 5/r32/ebp + 2448 5d/pop-to-ebp + 2449 c3/return + 2450 + 2451 test-convert-length-of-array-on-stack: + 2452 # . prologue + 2453 55/push-ebp + 2454 89/<- %ebp 4/r32/esp + 2455 # setup + 2456 (clear-stream _test-input-stream) + 2457 (clear-stream $_test-input-buffered-file->buffer) + 2458 (clear-stream _test-output-stream) + 2459 (clear-stream $_test-output-buffered-file->buffer) + 2460 # + 2461 (write _test-input-stream "fn foo {\n") + 2462 (write _test-input-stream " var a: (array int 3)\n") + 2463 (write _test-input-stream " var b/eax: int <- length a\n") + 2464 (write _test-input-stream "}\n") + 2465 # convert + 2466 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 2467 (flush _test-output-buffered-file) + 2468 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 2474 # check output + 2475 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-length-of-array-on-stack/0") + 2476 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-length-of-array-on-stack/1") + 2477 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-length-of-array-on-stack/2") + 2478 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-length-of-array-on-stack/3") + 2479 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-length-of-array-on-stack/4") + 2480 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-length-of-array-on-stack/5") + 2481 # define x + 2482 (check-next-stream-line-equal _test-output-stream " (push-n-zero-bytes 0x0000000c)" "F - test-convert-length-of-array-on-stack/6") + 2483 (check-next-stream-line-equal _test-output-stream " 68/push 0x0000000c/imm32" "F - test-convert-length-of-array-on-stack/7") + 2484 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-length-of-array-on-stack/8") + 2485 (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0xfffffff0) 0x00000000/r32" "F - test-convert-length-of-array-on-stack/9") + 2486 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-length-of-array-on-stack/10") + 2487 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000010/imm32" "F - test-convert-length-of-array-on-stack/11") + 2488 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-length-of-array-on-stack/12") + 2489 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-length-of-array-on-stack/13") + 2490 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-length-of-array-on-stack/14") + 2491 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-length-of-array-on-stack/15") + 2492 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-length-of-array-on-stack/16") + 2493 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-length-of-array-on-stack/17") 2494 # . epilogue 2495 89/<- %esp 5/r32/ebp 2496 5d/pop-to-ebp 2497 c3/return 2498 - 2499 test-convert-index-into-array-on-stack: + 2499 test-convert-index-into-array: 2500 # . prologue 2501 55/push-ebp 2502 89/<- %ebp 4/r32/esp @@ -2369,9087 +2369,12250 @@ if ('onhashchange' in window) { 2507 (clear-stream $_test-output-buffered-file->buffer) 2508 # 2509 (write _test-input-stream "fn foo {\n") - 2510 (write _test-input-stream " var arr: (array int 3)\n") - 2511 (write _test-input-stream " var idx/eax: int <- copy 2\n") + 2510 (write _test-input-stream " var arr/eax: (addr array int) <- copy 0\n") + 2511 (write _test-input-stream " var idx/ecx: int <- copy 3\n") 2512 (write _test-input-stream " var x/eax: (addr int) <- index arr, idx\n") 2513 (write _test-input-stream "}\n") 2514 # convert - 2515 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 2515 (convert-mu _test-input-buffered-file _test-output-buffered-file) 2516 (flush _test-output-buffered-file) - 2517 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 2517 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- 2523 # check output - 2524 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array-on-stack/0") - 2525 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array-on-stack/1") - 2526 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array-on-stack/2") - 2527 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-index-into-array-on-stack/3") - 2528 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array-on-stack/4") - 2529 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-on-stack/5") - 2530 # var arr - 2531 (check-next-stream-line-equal _test-output-stream " (push-n-zero-bytes 0x0000000c)" "F - test-convert-index-into-array-on-stack/6") - 2532 (check-next-stream-line-equal _test-output-stream " 68/push 0x0000000c/imm32" "F - test-convert-index-into-array-on-stack/7") - 2533 # var idx - 2534 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-on-stack/8") - 2535 (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 2/imm32" "F - test-convert-index-into-array-on-stack/9") - 2536 # var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc - 2537 (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") - 2538 # reclaim idx - 2539 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-on-stack/11") - 2540 # reclaim arr - 2541 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000010/imm32" "F - test-convert-index-into-array-on-stack/12") - 2542 # - 2543 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-on-stack/13") - 2544 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-on-stack/14") - 2545 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-on-stack/15") - 2546 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-on-stack/16") - 2547 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-on-stack/17") - 2548 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-on-stack/18") - 2549 # . epilogue - 2550 89/<- %esp 5/r32/ebp - 2551 5d/pop-to-ebp - 2552 c3/return - 2553 - 2554 test-convert-index-into-array-on-stack-with-literal: - 2555 # . prologue - 2556 55/push-ebp - 2557 89/<- %ebp 4/r32/esp - 2558 # setup - 2559 (clear-stream _test-input-stream) - 2560 (clear-stream $_test-input-buffered-file->buffer) - 2561 (clear-stream _test-output-stream) - 2562 (clear-stream $_test-output-buffered-file->buffer) - 2563 # - 2564 (write _test-input-stream "fn foo {\n") - 2565 (write _test-input-stream " var arr: (array int 3)\n") - 2566 (write _test-input-stream " var x/eax: (addr int) <- index arr, 2\n") - 2567 (write _test-input-stream "}\n") - 2568 # convert - 2569 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 2570 (flush _test-output-buffered-file) - 2571 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 2577 # check output - 2578 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array-on-stack-with-literal/0") - 2579 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array-on-stack-with-literal/1") - 2580 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array-on-stack-with-literal/2") - 2581 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-index-into-array-on-stack-with-literal/3") - 2582 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array-on-stack-with-literal/4") - 2583 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-on-stack-with-literal/5") - 2584 # var arr - 2585 (check-next-stream-line-equal _test-output-stream " (push-n-zero-bytes 0x0000000c)" "F - test-convert-index-into-array-on-stack-with-literal/6") - 2586 (check-next-stream-line-equal _test-output-stream " 68/push 0x0000000c/imm32" "F - test-convert-index-into-array-on-stack-with-literal/7") - 2587 # var x - 2588 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-on-stack-with-literal/8") - 2589 # x is at (ebp-0x10) + 4 + 2*4 = ebp-4 - 2590 (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") - 2591 # reclaim x - 2592 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-on-stack-with-literal/10") - 2593 # reclaim arr - 2594 (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") - 2595 # - 2596 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-on-stack-with-literal/12") - 2597 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-on-stack-with-literal/13") - 2598 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-on-stack-with-literal/14") - 2599 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-on-stack-with-literal/15") - 2600 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-on-stack-with-literal/16") - 2601 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-on-stack-with-literal/17") - 2602 # . epilogue - 2603 89/<- %esp 5/r32/ebp - 2604 5d/pop-to-ebp - 2605 c3/return - 2606 - 2607 test-convert-index-into-array-using-offset: - 2608 # . prologue - 2609 55/push-ebp - 2610 89/<- %ebp 4/r32/esp - 2611 # setup - 2612 (clear-stream _test-input-stream) - 2613 (clear-stream $_test-input-buffered-file->buffer) - 2614 (clear-stream _test-output-stream) - 2615 (clear-stream $_test-output-buffered-file->buffer) - 2616 # - 2617 (write _test-input-stream "fn foo {\n") - 2618 (write _test-input-stream " var arr/eax: (addr array int) <- copy 0\n") - 2619 (write _test-input-stream " var idx/ecx: int <- copy 3\n") - 2620 (write _test-input-stream " var off/ecx: (offset int) <- compute-offset arr, idx\n") - 2621 (write _test-input-stream " var x/eax: (addr int) <- index arr, off\n") - 2622 (write _test-input-stream "}\n") - 2623 # convert - 2624 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 2625 (flush _test-output-buffered-file) - 2626 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 2632 # check output - 2633 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array-using-offset/0") - 2634 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array-using-offset/1") - 2635 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array-using-offset/2") - 2636 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-index-into-array-using-offset/3") - 2637 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array-using-offset/4") - 2638 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-using-offset/5") - 2639 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-using-offset/6") - 2640 (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-index-into-array-using-offset/7") - 2641 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array-using-offset/8") - 2642 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-index-into-array-using-offset/9") - 2643 (check-next-stream-line-equal _test-output-stream " 69/multiply %ecx 0x00000004/imm32 0x00000001/r32" "F - test-convert-index-into-array-using-offset/10") - 2644 (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") - 2645 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-using-offset/12") - 2646 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-using-offset/13") - 2647 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-using-offset/14") - 2648 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-using-offset/15") - 2649 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-using-offset/16") - 2650 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-using-offset/17") - 2651 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-using-offset/18") - 2652 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-using-offset/19") - 2653 # . epilogue - 2654 89/<- %esp 5/r32/ebp - 2655 5d/pop-to-ebp - 2656 c3/return - 2657 - 2658 test-convert-index-into-array-using-offset-on-stack: - 2659 # . prologue - 2660 55/push-ebp - 2661 89/<- %ebp 4/r32/esp - 2662 # setup - 2663 (clear-stream _test-input-stream) - 2664 (clear-stream $_test-input-buffered-file->buffer) - 2665 (clear-stream _test-output-stream) - 2666 (clear-stream $_test-output-buffered-file->buffer) - 2667 # - 2668 (write _test-input-stream "fn foo {\n") - 2669 (write _test-input-stream " var arr/eax: (addr array int) <- copy 0\n") - 2670 (write _test-input-stream " var idx: int\n") - 2671 (write _test-input-stream " var off/ecx: (offset int) <- compute-offset arr, idx\n") - 2672 (write _test-input-stream " var x/eax: (addr int) <- index arr, off\n") - 2673 (write _test-input-stream "}\n") - 2674 # convert - 2675 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 2676 (flush _test-output-buffered-file) - 2677 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 2683 # check output - 2684 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array-using-offset-on-stack/0") - 2685 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array-using-offset-on-stack/1") - 2686 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array-using-offset-on-stack/2") - 2687 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-index-into-array-using-offset-on-stack/3") - 2688 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array-using-offset-on-stack/4") - 2689 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-using-offset-on-stack/5") - 2690 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-using-offset-on-stack/6") - 2691 (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-index-into-array-using-offset-on-stack/7") - 2692 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-index-into-array-using-offset-on-stack/8") - 2693 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array-using-offset-on-stack/9") - 2694 (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") - 2695 (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") - 2696 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-using-offset-on-stack/12") - 2697 (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") - 2698 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-using-offset-on-stack/14") - 2699 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-using-offset-on-stack/15") - 2700 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-using-offset-on-stack/16") - 2701 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-using-offset-on-stack/17") - 2702 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-using-offset-on-stack/18") - 2703 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-using-offset-on-stack/19") - 2704 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-using-offset-on-stack/20") - 2705 # . epilogue - 2706 89/<- %esp 5/r32/ebp - 2707 5d/pop-to-ebp - 2708 c3/return - 2709 - 2710 test-convert-function-and-type-definition: - 2711 # . prologue - 2712 55/push-ebp - 2713 89/<- %ebp 4/r32/esp - 2714 # setup - 2715 (clear-stream _test-input-stream) - 2716 (clear-stream $_test-input-buffered-file->buffer) - 2717 (clear-stream _test-output-stream) - 2718 (clear-stream $_test-output-buffered-file->buffer) - 2719 # - 2720 (write _test-input-stream "fn foo a: (addr t) {\n") - 2721 (write _test-input-stream " var _a/eax: (addr t) <- copy a\n") - 2722 (write _test-input-stream " var b/ecx: (addr int) <- get _a, x\n") - 2723 (write _test-input-stream " var c/ecx: (addr int) <- get _a, y\n") - 2724 (write _test-input-stream "}\n") - 2725 (write _test-input-stream "type t {\n") - 2726 (write _test-input-stream " x: int\n") - 2727 (write _test-input-stream " y: int\n") - 2728 (write _test-input-stream "}\n") - 2729 # convert - 2730 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 2731 (flush _test-output-buffered-file) - 2732 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 2738 # check output - 2739 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-and-type-definition/0") - 2740 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-and-type-definition/1") - 2741 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-and-type-definition/2") - 2742 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-and-type-definition/3") - 2743 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-and-type-definition/4") - 2744 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-and-type-definition/5") - 2745 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-function-and-type-definition/6") - 2746 (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-function-and-type-definition/7") - 2747 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-and-type-definition/8") - 2748 (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + 0x00000000) 0x00000001/r32" "F - test-convert-function-and-type-definition/9") - 2749 (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + 0x00000004) 0x00000001/r32" "F - test-convert-function-and-type-definition/11") - 2750 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-and-type-definition/13") - 2751 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-function-and-type-definition/14") - 2752 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-and-type-definition/15") - 2753 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-and-type-definition/16") - 2754 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-and-type-definition/17") - 2755 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-and-type-definition/18") - 2756 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-and-type-definition/19") - 2757 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-and-type-definition/20") - 2758 # . epilogue - 2759 89/<- %esp 5/r32/ebp - 2760 5d/pop-to-ebp - 2761 c3/return - 2762 - 2763 test-convert-function-with-local-var-with-user-defined-type: - 2764 # . prologue - 2765 55/push-ebp - 2766 89/<- %ebp 4/r32/esp - 2767 # setup - 2768 (clear-stream _test-input-stream) - 2769 (clear-stream $_test-input-buffered-file->buffer) - 2770 (clear-stream _test-output-stream) - 2771 (clear-stream $_test-output-buffered-file->buffer) - 2772 # - 2773 (write _test-input-stream "fn foo {\n") - 2774 (write _test-input-stream " var a: t\n") - 2775 (write _test-input-stream "}\n") - 2776 (write _test-input-stream "type t {\n") - 2777 (write _test-input-stream " x: int\n") - 2778 (write _test-input-stream " y: int\n") - 2779 (write _test-input-stream "}\n") - 2780 # convert - 2781 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 2782 (flush _test-output-buffered-file) - 2783 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 2789 # check output - 2790 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-with-user-defined-type/0") - 2791 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-with-user-defined-type/1") - 2792 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-with-user-defined-type/2") - 2793 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-with-user-defined-type/3") - 2794 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-with-user-defined-type/4") - 2795 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-with-user-defined-type/5") - 2796 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-local-var-with-user-defined-type/6") - 2797 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-local-var-with-user-defined-type/7") - 2798 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000008/imm32" "F - test-convert-function-with-local-var-with-user-defined-type/8") - 2799 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-with-user-defined-type/9") - 2800 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-with-user-defined-type/10") - 2801 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-with-user-defined-type/11") - 2802 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-with-user-defined-type/12") - 2803 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-with-user-defined-type/13") - 2804 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-with-user-defined-type/14") - 2805 # . epilogue - 2806 89/<- %esp 5/r32/ebp - 2807 5d/pop-to-ebp - 2808 c3/return - 2809 - 2810 test-convert-function-call-with-arg-of-user-defined-type: - 2811 # . prologue - 2812 55/push-ebp - 2813 89/<- %ebp 4/r32/esp - 2814 # setup - 2815 (clear-stream _test-input-stream) - 2816 (clear-stream $_test-input-buffered-file->buffer) - 2817 (clear-stream _test-output-stream) - 2818 (clear-stream $_test-output-buffered-file->buffer) - 2819 # - 2820 (write _test-input-stream "fn f {\n") - 2821 (write _test-input-stream " var a: t\n") - 2822 (write _test-input-stream " foo a\n") + 2524 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array/0") + 2525 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array/1") + 2526 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array/2") + 2527 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-index-into-array/3") + 2528 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array/4") + 2529 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array/5") + 2530 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array/6") + 2531 (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-index-into-array/7") + 2532 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array/8") + 2533 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-index-into-array/9") + 2534 (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32" "F - test-convert-index-into-array/11") + 2535 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array/13") + 2536 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array/14") + 2537 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array/15") + 2538 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array/16") + 2539 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array/17") + 2540 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array/18") + 2541 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array/19") + 2542 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array/20") + 2543 # . epilogue + 2544 89/<- %esp 5/r32/ebp + 2545 5d/pop-to-ebp + 2546 c3/return + 2547 + 2548 test-convert-index-into-array-with-literal: + 2549 # . prologue + 2550 55/push-ebp + 2551 89/<- %ebp 4/r32/esp + 2552 # setup + 2553 (clear-stream _test-input-stream) + 2554 (clear-stream $_test-input-buffered-file->buffer) + 2555 (clear-stream _test-output-stream) + 2556 (clear-stream $_test-output-buffered-file->buffer) + 2557 # + 2558 (write _test-input-stream "fn foo {\n") + 2559 (write _test-input-stream " var arr/eax: (addr array int) <- copy 0\n") + 2560 (write _test-input-stream " var x/eax: (addr int) <- index arr, 2\n") + 2561 (write _test-input-stream "}\n") + 2562 # convert + 2563 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 2564 (flush _test-output-buffered-file) + 2565 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 2571 # check output + 2572 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array-with-literal/0") + 2573 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array-with-literal/1") + 2574 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array-with-literal/2") + 2575 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-index-into-array-with-literal/3") + 2576 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array-with-literal/4") + 2577 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-with-literal/5") + 2578 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-with-literal/6") + 2579 (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-index-into-array-with-literal/7") + 2580 # 2 * 4 bytes/elem + 4 bytes for size = offset 12 + 2581 (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + 0x0000000c) 0x00000000/r32" "F - test-convert-index-into-array-with-literal/8") + 2582 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-with-literal/9") + 2583 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-with-literal/10") + 2584 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-with-literal/11") + 2585 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-with-literal/12") + 2586 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-with-literal/13") + 2587 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-with-literal/14") + 2588 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-with-literal/15") + 2589 # . epilogue + 2590 89/<- %esp 5/r32/ebp + 2591 5d/pop-to-ebp + 2592 c3/return + 2593 + 2594 test-convert-index-into-array-on-stack: + 2595 # . prologue + 2596 55/push-ebp + 2597 89/<- %ebp 4/r32/esp + 2598 # setup + 2599 (clear-stream _test-input-stream) + 2600 (clear-stream $_test-input-buffered-file->buffer) + 2601 (clear-stream _test-output-stream) + 2602 (clear-stream $_test-output-buffered-file->buffer) + 2603 # + 2604 (write _test-input-stream "fn foo {\n") + 2605 (write _test-input-stream " var arr: (array int 3)\n") + 2606 (write _test-input-stream " var idx/eax: int <- copy 2\n") + 2607 (write _test-input-stream " var x/eax: (addr int) <- index arr, idx\n") + 2608 (write _test-input-stream "}\n") + 2609 # convert + 2610 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 2611 (flush _test-output-buffered-file) + 2612 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 2618 # check output + 2619 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array-on-stack/0") + 2620 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array-on-stack/1") + 2621 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array-on-stack/2") + 2622 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-index-into-array-on-stack/3") + 2623 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array-on-stack/4") + 2624 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-on-stack/5") + 2625 # var arr + 2626 (check-next-stream-line-equal _test-output-stream " (push-n-zero-bytes 0x0000000c)" "F - test-convert-index-into-array-on-stack/6") + 2627 (check-next-stream-line-equal _test-output-stream " 68/push 0x0000000c/imm32" "F - test-convert-index-into-array-on-stack/7") + 2628 # var idx + 2629 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-on-stack/8") + 2630 (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 2/imm32" "F - test-convert-index-into-array-on-stack/9") + 2631 # var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc + 2632 (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") + 2633 # reclaim idx + 2634 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-on-stack/11") + 2635 # reclaim arr + 2636 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000010/imm32" "F - test-convert-index-into-array-on-stack/12") + 2637 # + 2638 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-on-stack/13") + 2639 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-on-stack/14") + 2640 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-on-stack/15") + 2641 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-on-stack/16") + 2642 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-on-stack/17") + 2643 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-on-stack/18") + 2644 # . epilogue + 2645 89/<- %esp 5/r32/ebp + 2646 5d/pop-to-ebp + 2647 c3/return + 2648 + 2649 test-convert-index-into-array-on-stack-with-literal: + 2650 # . prologue + 2651 55/push-ebp + 2652 89/<- %ebp 4/r32/esp + 2653 # setup + 2654 (clear-stream _test-input-stream) + 2655 (clear-stream $_test-input-buffered-file->buffer) + 2656 (clear-stream _test-output-stream) + 2657 (clear-stream $_test-output-buffered-file->buffer) + 2658 # + 2659 (write _test-input-stream "fn foo {\n") + 2660 (write _test-input-stream " var arr: (array int 3)\n") + 2661 (write _test-input-stream " var x/eax: (addr int) <- index arr, 2\n") + 2662 (write _test-input-stream "}\n") + 2663 # convert + 2664 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 2665 (flush _test-output-buffered-file) + 2666 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 2672 # check output + 2673 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array-on-stack-with-literal/0") + 2674 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array-on-stack-with-literal/1") + 2675 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array-on-stack-with-literal/2") + 2676 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-index-into-array-on-stack-with-literal/3") + 2677 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array-on-stack-with-literal/4") + 2678 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-on-stack-with-literal/5") + 2679 # var arr + 2680 (check-next-stream-line-equal _test-output-stream " (push-n-zero-bytes 0x0000000c)" "F - test-convert-index-into-array-on-stack-with-literal/6") + 2681 (check-next-stream-line-equal _test-output-stream " 68/push 0x0000000c/imm32" "F - test-convert-index-into-array-on-stack-with-literal/7") + 2682 # var x + 2683 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-on-stack-with-literal/8") + 2684 # x is at (ebp-0x10) + 4 + 2*4 = ebp-4 + 2685 (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") + 2686 # reclaim x + 2687 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-on-stack-with-literal/10") + 2688 # reclaim arr + 2689 (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") + 2690 # + 2691 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-on-stack-with-literal/12") + 2692 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-on-stack-with-literal/13") + 2693 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-on-stack-with-literal/14") + 2694 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-on-stack-with-literal/15") + 2695 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-on-stack-with-literal/16") + 2696 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-on-stack-with-literal/17") + 2697 # . epilogue + 2698 89/<- %esp 5/r32/ebp + 2699 5d/pop-to-ebp + 2700 c3/return + 2701 + 2702 test-convert-index-into-array-using-offset: + 2703 # . prologue + 2704 55/push-ebp + 2705 89/<- %ebp 4/r32/esp + 2706 # setup + 2707 (clear-stream _test-input-stream) + 2708 (clear-stream $_test-input-buffered-file->buffer) + 2709 (clear-stream _test-output-stream) + 2710 (clear-stream $_test-output-buffered-file->buffer) + 2711 # + 2712 (write _test-input-stream "fn foo {\n") + 2713 (write _test-input-stream " var arr/eax: (addr array int) <- copy 0\n") + 2714 (write _test-input-stream " var idx/ecx: int <- copy 3\n") + 2715 (write _test-input-stream " var off/ecx: (offset int) <- compute-offset arr, idx\n") + 2716 (write _test-input-stream " var x/eax: (addr int) <- index arr, off\n") + 2717 (write _test-input-stream "}\n") + 2718 # convert + 2719 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 2720 (flush _test-output-buffered-file) + 2721 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 2727 # check output + 2728 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array-using-offset/0") + 2729 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array-using-offset/1") + 2730 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array-using-offset/2") + 2731 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-index-into-array-using-offset/3") + 2732 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array-using-offset/4") + 2733 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-using-offset/5") + 2734 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-using-offset/6") + 2735 (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-index-into-array-using-offset/7") + 2736 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array-using-offset/8") + 2737 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-index-into-array-using-offset/9") + 2738 (check-next-stream-line-equal _test-output-stream " 69/multiply %ecx 0x00000004/imm32 0x00000001/r32" "F - test-convert-index-into-array-using-offset/10") + 2739 (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") + 2740 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-using-offset/12") + 2741 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-using-offset/13") + 2742 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-using-offset/14") + 2743 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-using-offset/15") + 2744 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-using-offset/16") + 2745 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-using-offset/17") + 2746 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-using-offset/18") + 2747 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-using-offset/19") + 2748 # . epilogue + 2749 89/<- %esp 5/r32/ebp + 2750 5d/pop-to-ebp + 2751 c3/return + 2752 + 2753 test-convert-index-into-array-using-offset-on-stack: + 2754 # . prologue + 2755 55/push-ebp + 2756 89/<- %ebp 4/r32/esp + 2757 # setup + 2758 (clear-stream _test-input-stream) + 2759 (clear-stream $_test-input-buffered-file->buffer) + 2760 (clear-stream _test-output-stream) + 2761 (clear-stream $_test-output-buffered-file->buffer) + 2762 # + 2763 (write _test-input-stream "fn foo {\n") + 2764 (write _test-input-stream " var arr/eax: (addr array int) <- copy 0\n") + 2765 (write _test-input-stream " var idx: int\n") + 2766 (write _test-input-stream " var off/ecx: (offset int) <- compute-offset arr, idx\n") + 2767 (write _test-input-stream " var x/eax: (addr int) <- index arr, off\n") + 2768 (write _test-input-stream "}\n") + 2769 # convert + 2770 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 2771 (flush _test-output-buffered-file) + 2772 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 2778 # check output + 2779 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array-using-offset-on-stack/0") + 2780 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array-using-offset-on-stack/1") + 2781 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array-using-offset-on-stack/2") + 2782 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-index-into-array-using-offset-on-stack/3") + 2783 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array-using-offset-on-stack/4") + 2784 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-using-offset-on-stack/5") + 2785 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-using-offset-on-stack/6") + 2786 (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-index-into-array-using-offset-on-stack/7") + 2787 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-index-into-array-using-offset-on-stack/8") + 2788 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array-using-offset-on-stack/9") + 2789 (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") + 2790 (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") + 2791 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-using-offset-on-stack/12") + 2792 (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") + 2793 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-using-offset-on-stack/14") + 2794 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-using-offset-on-stack/15") + 2795 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-using-offset-on-stack/16") + 2796 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-using-offset-on-stack/17") + 2797 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-using-offset-on-stack/18") + 2798 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-using-offset-on-stack/19") + 2799 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-using-offset-on-stack/20") + 2800 # . epilogue + 2801 89/<- %esp 5/r32/ebp + 2802 5d/pop-to-ebp + 2803 c3/return + 2804 + 2805 test-convert-function-and-type-definition: + 2806 # . prologue + 2807 55/push-ebp + 2808 89/<- %ebp 4/r32/esp + 2809 # setup + 2810 (clear-stream _test-input-stream) + 2811 (clear-stream $_test-input-buffered-file->buffer) + 2812 (clear-stream _test-output-stream) + 2813 (clear-stream $_test-output-buffered-file->buffer) + 2814 # + 2815 (write _test-input-stream "fn foo a: (addr t) {\n") + 2816 (write _test-input-stream " var _a/eax: (addr t) <- copy a\n") + 2817 (write _test-input-stream " var b/ecx: (addr int) <- get _a, x\n") + 2818 (write _test-input-stream " var c/ecx: (addr int) <- get _a, y\n") + 2819 (write _test-input-stream "}\n") + 2820 (write _test-input-stream "type t {\n") + 2821 (write _test-input-stream " x: int\n") + 2822 (write _test-input-stream " y: int\n") 2823 (write _test-input-stream "}\n") - 2824 (write _test-input-stream "fn foo x: t {\n") - 2825 (write _test-input-stream "}\n") - 2826 (write _test-input-stream "type t {\n") - 2827 (write _test-input-stream " x: int\n") - 2828 (write _test-input-stream " y: int\n") - 2829 (write _test-input-stream "}\n") - 2830 # convert - 2831 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 2832 (flush _test-output-buffered-file) - 2833 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 2839 # check output - 2840 (check-next-stream-line-equal _test-output-stream "f:" "F - test-convert-function-call-with-arg-of-user-defined-type/0") - 2841 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-arg-of-user-defined-type/1") - 2842 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/2") - 2843 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-arg-of-user-defined-type/3") - 2844 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-arg-of-user-defined-type/4") - 2845 (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:" "F - test-convert-function-call-with-arg-of-user-defined-type/5") - 2846 # var a: t - 2847 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-call-with-arg-of-user-defined-type/6") - 2848 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-call-with-arg-of-user-defined-type/7") - 2849 # foo a - 2850 (check-next-stream-line-equal _test-output-stream " (foo *(ebp+0xfffffff8) *(ebp+0xfffffffc))" "F - test-convert-function-call-with-arg-of-user-defined-type/8") - 2851 # - 2852 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000008/imm32" "F - test-convert-function-call-with-arg-of-user-defined-type/9") - 2853 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-arg-of-user-defined-type/10") - 2854 (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:" "F - test-convert-function-call-with-arg-of-user-defined-type/11") - 2855 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-arg-of-user-defined-type/12") - 2856 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/13") - 2857 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/14") - 2858 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-arg-of-user-defined-type/15") - 2859 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-call-with-arg-of-user-defined-type/16") - 2860 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-arg-of-user-defined-type/17") - 2861 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/18") - 2862 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-arg-of-user-defined-type/19") - 2863 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-arg-of-user-defined-type/20") - 2864 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/21") - 2865 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/22") - 2866 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-arg-of-user-defined-type/23") - 2867 # . epilogue - 2868 89/<- %esp 5/r32/ebp - 2869 5d/pop-to-ebp - 2870 c3/return - 2871 - 2872 test-convert-function-call-with-arg-of-user-defined-type-register-indirect: - 2873 # . prologue - 2874 55/push-ebp - 2875 89/<- %ebp 4/r32/esp - 2876 # setup - 2877 (clear-stream _test-input-stream) - 2878 (clear-stream $_test-input-buffered-file->buffer) - 2879 (clear-stream _test-output-stream) - 2880 (clear-stream $_test-output-buffered-file->buffer) - 2881 # - 2882 (write _test-input-stream "fn f {\n") - 2883 (write _test-input-stream " var a/eax: (addr t) <- copy 0\n") - 2884 (write _test-input-stream " foo *a\n") - 2885 (write _test-input-stream "}\n") - 2886 (write _test-input-stream "fn foo x: t {\n") - 2887 (write _test-input-stream "}\n") - 2888 (write _test-input-stream "type t {\n") - 2889 (write _test-input-stream " x: int\n") - 2890 (write _test-input-stream " y: int\n") - 2891 (write _test-input-stream "}\n") - 2892 # convert - 2893 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 2894 (flush _test-output-buffered-file) - 2895 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 2901 # check output - 2902 (check-next-stream-line-equal _test-output-stream "f:" "F - test-convert-function-call-with-arg-of-user-defined-type/0") - 2903 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-arg-of-user-defined-type/1") - 2904 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/2") - 2905 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-arg-of-user-defined-type/3") - 2906 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-arg-of-user-defined-type/4") - 2907 (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:" "F - test-convert-function-call-with-arg-of-user-defined-type/5") - 2908 # var a - 2909 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-function-call-with-arg-of-user-defined-type/6") - 2910 (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-function-call-with-arg-of-user-defined-type/7") - 2911 # foo a - 2912 (check-next-stream-line-equal _test-output-stream " (foo *(eax+0x00000000) *(eax+0x00000004))" "F - test-convert-function-call-with-arg-of-user-defined-type/8") - 2913 # - 2914 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-function-call-with-arg-of-user-defined-type/9") - 2915 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-arg-of-user-defined-type/10") - 2916 (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:" "F - test-convert-function-call-with-arg-of-user-defined-type/11") - 2917 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-arg-of-user-defined-type/12") - 2918 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/13") - 2919 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/14") - 2920 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-arg-of-user-defined-type/15") - 2921 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-call-with-arg-of-user-defined-type/16") - 2922 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-arg-of-user-defined-type/17") - 2923 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/18") - 2924 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-arg-of-user-defined-type/19") - 2925 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-arg-of-user-defined-type/20") - 2926 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/21") - 2927 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/22") - 2928 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-arg-of-user-defined-type/23") - 2929 # . epilogue - 2930 89/<- %esp 5/r32/ebp - 2931 5d/pop-to-ebp - 2932 c3/return - 2933 - 2934 # we don't have special support for call-by-reference; just explicitly create - 2935 # a new variable with the address of the arg - 2936 test-convert-function-call-with-arg-of-user-defined-type-by-reference: - 2937 # . prologue - 2938 55/push-ebp - 2939 89/<- %ebp 4/r32/esp - 2940 # setup - 2941 (clear-stream _test-input-stream) - 2942 (clear-stream $_test-input-buffered-file->buffer) - 2943 (clear-stream _test-output-stream) - 2944 (clear-stream $_test-output-buffered-file->buffer) - 2945 # - 2946 (write _test-input-stream "fn f {\n") - 2947 (write _test-input-stream " var a: t\n") - 2948 (write _test-input-stream " var b/eax: (addr t) <- address a\n") - 2949 (write _test-input-stream " foo b\n") - 2950 (write _test-input-stream "}\n") - 2951 (write _test-input-stream "fn foo x: (addr t) {\n") - 2952 (write _test-input-stream " var x/ecx: (addr int) <- copy x\n") - 2953 (write _test-input-stream " increment *x\n") - 2954 (write _test-input-stream "}\n") - 2955 (write _test-input-stream "type t {\n") - 2956 (write _test-input-stream " x: int\n") - 2957 (write _test-input-stream " y: int\n") - 2958 (write _test-input-stream "}\n") - 2959 # convert - 2960 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 2961 (flush _test-output-buffered-file) - 2962 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 2968 # check output - 2969 (check-next-stream-line-equal _test-output-stream "f:" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/0") - 2970 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/1") - 2971 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/2") - 2972 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/3") - 2973 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/4") - 2974 (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/5") - 2975 # var a: t - 2976 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/6") - 2977 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/7") - 2978 # var b/eax: (addr t) - 2979 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/8") - 2980 (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp+0xfffffff8) 0x00000000/r32" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/9") - 2981 # foo a - 2982 (check-next-stream-line-equal _test-output-stream " (foo %eax)" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/10") - 2983 # - 2984 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/11") - 2985 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000008/imm32" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/12") - 2986 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/13") - 2987 (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/14") - 2988 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/15") - 2989 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/16") - 2990 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/17") - 2991 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/18") - 2992 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/19") - 2993 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/20") - 2994 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/21") - 2995 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/22") - 2996 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/23") - 2997 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/24") - 2998 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/25") - 2999 (check-next-stream-line-equal _test-output-stream " 89/<- %ecx 0x00000001/r32" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/26") - 3000 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *ecx" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/27") - 3001 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/28") - 3002 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/29") - 3003 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/30") - 3004 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/31") - 3005 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/32") - 3006 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/33") - 3007 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/34") - 3008 # . epilogue - 3009 89/<- %esp 5/r32/ebp - 3010 5d/pop-to-ebp - 3011 c3/return - 3012 - 3013 test-convert-get-of-type-on-stack: - 3014 # . prologue - 3015 55/push-ebp - 3016 89/<- %ebp 4/r32/esp - 3017 # setup - 3018 (clear-stream _test-input-stream) - 3019 (clear-stream $_test-input-buffered-file->buffer) - 3020 (clear-stream _test-output-stream) - 3021 (clear-stream $_test-output-buffered-file->buffer) - 3022 # - 3023 (write _test-input-stream "fn foo {\n") - 3024 (write _test-input-stream " var a: t\n") - 3025 (write _test-input-stream " var c/ecx: (addr int) <- get a, y\n") - 3026 (write _test-input-stream "}\n") - 3027 (write _test-input-stream "type t {\n") - 3028 (write _test-input-stream " x: int\n") - 3029 (write _test-input-stream " y: int\n") - 3030 (write _test-input-stream "}\n") - 3031 # convert - 3032 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 3033 (flush _test-output-buffered-file) - 3034 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 3040 # check output - 3041 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-get-of-type-on-stack/0") - 3042 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-get-of-type-on-stack/1") - 3043 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-get-of-type-on-stack/2") - 3044 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-get-of-type-on-stack/3") - 3045 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-get-of-type-on-stack/4") - 3046 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-get-of-type-on-stack/5") - 3047 # var a - 3048 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-get-of-type-on-stack/6") - 3049 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-get-of-type-on-stack/7") - 3050 # var c - 3051 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-get-of-type-on-stack/8") - 3052 # get - 3053 (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp+0xfffffffc) 0x00000001/r32" "F - test-convert-get-of-type-on-stack/9") - 3054 # reclaim c - 3055 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-get-of-type-on-stack/10") - 3056 # reclaim a - 3057 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000008/imm32" "F - test-convert-get-of-type-on-stack/11") - 3058 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-get-of-type-on-stack/12") - 3059 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-get-of-type-on-stack/13") - 3060 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-get-of-type-on-stack/14") - 3061 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-get-of-type-on-stack/15") - 3062 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-get-of-type-on-stack/16") - 3063 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-get-of-type-on-stack/17") - 3064 # . epilogue - 3065 89/<- %esp 5/r32/ebp - 3066 5d/pop-to-ebp - 3067 c3/return - 3068 - 3069 test-convert-array-of-user-defined-types: - 3070 # . prologue - 3071 55/push-ebp - 3072 89/<- %ebp 4/r32/esp - 3073 # setup - 3074 (clear-stream _test-input-stream) - 3075 (clear-stream $_test-input-buffered-file->buffer) - 3076 (clear-stream _test-output-stream) - 3077 (clear-stream $_test-output-buffered-file->buffer) + 2824 # convert + 2825 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 2826 (flush _test-output-buffered-file) + 2827 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 2833 # check output + 2834 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-and-type-definition/0") + 2835 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-and-type-definition/1") + 2836 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-and-type-definition/2") + 2837 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-and-type-definition/3") + 2838 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-and-type-definition/4") + 2839 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-and-type-definition/5") + 2840 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-function-and-type-definition/6") + 2841 (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-function-and-type-definition/7") + 2842 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-and-type-definition/8") + 2843 (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + 0x00000000) 0x00000001/r32" "F - test-convert-function-and-type-definition/9") + 2844 (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + 0x00000004) 0x00000001/r32" "F - test-convert-function-and-type-definition/11") + 2845 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-and-type-definition/13") + 2846 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-function-and-type-definition/14") + 2847 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-and-type-definition/15") + 2848 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-and-type-definition/16") + 2849 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-and-type-definition/17") + 2850 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-and-type-definition/18") + 2851 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-and-type-definition/19") + 2852 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-and-type-definition/20") + 2853 # . epilogue + 2854 89/<- %esp 5/r32/ebp + 2855 5d/pop-to-ebp + 2856 c3/return + 2857 + 2858 test-convert-function-with-local-var-with-user-defined-type: + 2859 # . prologue + 2860 55/push-ebp + 2861 89/<- %ebp 4/r32/esp + 2862 # setup + 2863 (clear-stream _test-input-stream) + 2864 (clear-stream $_test-input-buffered-file->buffer) + 2865 (clear-stream _test-output-stream) + 2866 (clear-stream $_test-output-buffered-file->buffer) + 2867 # + 2868 (write _test-input-stream "fn foo {\n") + 2869 (write _test-input-stream " var a: t\n") + 2870 (write _test-input-stream "}\n") + 2871 (write _test-input-stream "type t {\n") + 2872 (write _test-input-stream " x: int\n") + 2873 (write _test-input-stream " y: int\n") + 2874 (write _test-input-stream "}\n") + 2875 # convert + 2876 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 2877 (flush _test-output-buffered-file) + 2878 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 2884 # check output + 2885 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-with-user-defined-type/0") + 2886 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-with-user-defined-type/1") + 2887 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-with-user-defined-type/2") + 2888 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-with-user-defined-type/3") + 2889 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-with-user-defined-type/4") + 2890 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-with-user-defined-type/5") + 2891 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-local-var-with-user-defined-type/6") + 2892 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-local-var-with-user-defined-type/7") + 2893 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000008/imm32" "F - test-convert-function-with-local-var-with-user-defined-type/8") + 2894 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-with-user-defined-type/9") + 2895 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-with-user-defined-type/10") + 2896 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-with-user-defined-type/11") + 2897 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-with-user-defined-type/12") + 2898 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-with-user-defined-type/13") + 2899 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-with-user-defined-type/14") + 2900 # . epilogue + 2901 89/<- %esp 5/r32/ebp + 2902 5d/pop-to-ebp + 2903 c3/return + 2904 + 2905 test-convert-function-call-with-arg-of-user-defined-type: + 2906 # . prologue + 2907 55/push-ebp + 2908 89/<- %ebp 4/r32/esp + 2909 # setup + 2910 (clear-stream _test-input-stream) + 2911 (clear-stream $_test-input-buffered-file->buffer) + 2912 (clear-stream _test-output-stream) + 2913 (clear-stream $_test-output-buffered-file->buffer) + 2914 # + 2915 (write _test-input-stream "fn f {\n") + 2916 (write _test-input-stream " var a: t\n") + 2917 (write _test-input-stream " foo a\n") + 2918 (write _test-input-stream "}\n") + 2919 (write _test-input-stream "fn foo x: t {\n") + 2920 (write _test-input-stream "}\n") + 2921 (write _test-input-stream "type t {\n") + 2922 (write _test-input-stream " x: int\n") + 2923 (write _test-input-stream " y: int\n") + 2924 (write _test-input-stream "}\n") + 2925 # convert + 2926 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 2927 (flush _test-output-buffered-file) + 2928 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 2934 # check output + 2935 (check-next-stream-line-equal _test-output-stream "f:" "F - test-convert-function-call-with-arg-of-user-defined-type/0") + 2936 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-arg-of-user-defined-type/1") + 2937 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/2") + 2938 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-arg-of-user-defined-type/3") + 2939 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-arg-of-user-defined-type/4") + 2940 (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:" "F - test-convert-function-call-with-arg-of-user-defined-type/5") + 2941 # var a: t + 2942 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-call-with-arg-of-user-defined-type/6") + 2943 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-call-with-arg-of-user-defined-type/7") + 2944 # foo a + 2945 (check-next-stream-line-equal _test-output-stream " (foo *(ebp+0xfffffff8) *(ebp+0xfffffffc))" "F - test-convert-function-call-with-arg-of-user-defined-type/8") + 2946 # + 2947 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000008/imm32" "F - test-convert-function-call-with-arg-of-user-defined-type/9") + 2948 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-arg-of-user-defined-type/10") + 2949 (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:" "F - test-convert-function-call-with-arg-of-user-defined-type/11") + 2950 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-arg-of-user-defined-type/12") + 2951 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/13") + 2952 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/14") + 2953 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-arg-of-user-defined-type/15") + 2954 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-call-with-arg-of-user-defined-type/16") + 2955 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-arg-of-user-defined-type/17") + 2956 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/18") + 2957 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-arg-of-user-defined-type/19") + 2958 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-arg-of-user-defined-type/20") + 2959 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/21") + 2960 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/22") + 2961 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-arg-of-user-defined-type/23") + 2962 # . epilogue + 2963 89/<- %esp 5/r32/ebp + 2964 5d/pop-to-ebp + 2965 c3/return + 2966 + 2967 test-convert-function-call-with-arg-of-user-defined-type-register-indirect: + 2968 # . prologue + 2969 55/push-ebp + 2970 89/<- %ebp 4/r32/esp + 2971 # setup + 2972 (clear-stream _test-input-stream) + 2973 (clear-stream $_test-input-buffered-file->buffer) + 2974 (clear-stream _test-output-stream) + 2975 (clear-stream $_test-output-buffered-file->buffer) + 2976 # + 2977 (write _test-input-stream "fn f {\n") + 2978 (write _test-input-stream " var a/eax: (addr t) <- copy 0\n") + 2979 (write _test-input-stream " foo *a\n") + 2980 (write _test-input-stream "}\n") + 2981 (write _test-input-stream "fn foo x: t {\n") + 2982 (write _test-input-stream "}\n") + 2983 (write _test-input-stream "type t {\n") + 2984 (write _test-input-stream " x: int\n") + 2985 (write _test-input-stream " y: int\n") + 2986 (write _test-input-stream "}\n") + 2987 # convert + 2988 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 2989 (flush _test-output-buffered-file) + 2990 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 2996 # check output + 2997 (check-next-stream-line-equal _test-output-stream "f:" "F - test-convert-function-call-with-arg-of-user-defined-type/0") + 2998 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-arg-of-user-defined-type/1") + 2999 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/2") + 3000 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-arg-of-user-defined-type/3") + 3001 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-arg-of-user-defined-type/4") + 3002 (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:" "F - test-convert-function-call-with-arg-of-user-defined-type/5") + 3003 # var a + 3004 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-function-call-with-arg-of-user-defined-type/6") + 3005 (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-function-call-with-arg-of-user-defined-type/7") + 3006 # foo a + 3007 (check-next-stream-line-equal _test-output-stream " (foo *(eax+0x00000000) *(eax+0x00000004))" "F - test-convert-function-call-with-arg-of-user-defined-type/8") + 3008 # + 3009 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-function-call-with-arg-of-user-defined-type/9") + 3010 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-arg-of-user-defined-type/10") + 3011 (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:" "F - test-convert-function-call-with-arg-of-user-defined-type/11") + 3012 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-arg-of-user-defined-type/12") + 3013 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/13") + 3014 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/14") + 3015 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-arg-of-user-defined-type/15") + 3016 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-call-with-arg-of-user-defined-type/16") + 3017 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-arg-of-user-defined-type/17") + 3018 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/18") + 3019 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-arg-of-user-defined-type/19") + 3020 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-arg-of-user-defined-type/20") + 3021 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/21") + 3022 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/22") + 3023 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-arg-of-user-defined-type/23") + 3024 # . epilogue + 3025 89/<- %esp 5/r32/ebp + 3026 5d/pop-to-ebp + 3027 c3/return + 3028 + 3029 # we don't have special support for call-by-reference; just explicitly create + 3030 # a new variable with the address of the arg + 3031 test-convert-function-call-with-arg-of-user-defined-type-by-reference: + 3032 # . prologue + 3033 55/push-ebp + 3034 89/<- %ebp 4/r32/esp + 3035 # setup + 3036 (clear-stream _test-input-stream) + 3037 (clear-stream $_test-input-buffered-file->buffer) + 3038 (clear-stream _test-output-stream) + 3039 (clear-stream $_test-output-buffered-file->buffer) + 3040 # + 3041 (write _test-input-stream "fn f {\n") + 3042 (write _test-input-stream " var a: t\n") + 3043 (write _test-input-stream " var b/eax: (addr t) <- address a\n") + 3044 (write _test-input-stream " foo b\n") + 3045 (write _test-input-stream "}\n") + 3046 (write _test-input-stream "fn foo x: (addr t) {\n") + 3047 (write _test-input-stream " var x/ecx: (addr int) <- copy x\n") + 3048 (write _test-input-stream " increment *x\n") + 3049 (write _test-input-stream "}\n") + 3050 (write _test-input-stream "type t {\n") + 3051 (write _test-input-stream " x: int\n") + 3052 (write _test-input-stream " y: int\n") + 3053 (write _test-input-stream "}\n") + 3054 # convert + 3055 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 3056 (flush _test-output-buffered-file) + 3057 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 3063 # check output + 3064 (check-next-stream-line-equal _test-output-stream "f:" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/0") + 3065 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/1") + 3066 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/2") + 3067 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/3") + 3068 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/4") + 3069 (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/5") + 3070 # var a: t + 3071 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/6") + 3072 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/7") + 3073 # var b/eax: (addr t) + 3074 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/8") + 3075 (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp+0xfffffff8) 0x00000000/r32" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/9") + 3076 # foo a + 3077 (check-next-stream-line-equal _test-output-stream " (foo %eax)" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/10") 3078 # - 3079 (write _test-input-stream "type t {\n") # each t is 8 bytes, which is a power of 2 - 3080 (write _test-input-stream " x: int\n") - 3081 (write _test-input-stream " y: int\n") - 3082 (write _test-input-stream "}\n") - 3083 (write _test-input-stream "fn foo {\n") - 3084 (write _test-input-stream " var arr/eax: (addr array t) <- copy 0\n") - 3085 (write _test-input-stream " var idx/ecx: int <- copy 3\n") - 3086 (write _test-input-stream " var x/eax: (addr int) <- index arr, idx\n") - 3087 (write _test-input-stream "}\n") - 3088 # convert - 3089 (convert-mu _test-input-buffered-file _test-output-buffered-file) - 3090 (flush _test-output-buffered-file) - 3091 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 3097 # check output - 3098 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-array-of-user-defined-types/0") - 3099 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-array-of-user-defined-types/1") - 3100 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-array-of-user-defined-types/2") - 3101 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-array-of-user-defined-types/3") - 3102 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-array-of-user-defined-types/4") - 3103 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-array-of-user-defined-types/5") - 3104 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-array-of-user-defined-types/6") - 3105 (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-array-of-user-defined-types/7") - 3106 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-array-of-user-defined-types/8") - 3107 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-array-of-user-defined-types/9") - 3108 (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") - 3109 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-array-of-user-defined-types/13") - 3110 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-array-of-user-defined-types/14") - 3111 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-array-of-user-defined-types/15") - 3112 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-array-of-user-defined-types/16") - 3113 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-array-of-user-defined-types/17") - 3114 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-array-of-user-defined-types/18") - 3115 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-array-of-user-defined-types/19") - 3116 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-array-of-user-defined-types/20") - 3117 # . epilogue - 3118 89/<- %esp 5/r32/ebp - 3119 5d/pop-to-ebp - 3120 c3/return - 3121 - 3122 ####################################################### - 3123 # Parsing - 3124 ####################################################### - 3125 - 3126 parse-mu: # in: (addr buffered-file) - 3127 # pseudocode - 3128 # var curr-function: (addr (handle function)) = Program->functions - 3129 # var curr-type: (addr (handle typeinfo)) = Program->types - 3130 # var line: (stream byte 512) - 3131 # var word-slice: slice - 3132 # while true # line loop - 3133 # clear-stream(line) - 3134 # read-line-buffered(in, line) - 3135 # if (line->write == 0) break # end of file - 3136 # word-slice = next-mu-token(line) - 3137 # if slice-empty?(word-slice) # end of line - 3138 # continue - 3139 # else if slice-starts-with?(word-slice, "#") # comment - 3140 # continue # end of line - 3141 # else if slice-equal?(word-slice, "fn") - 3142 # var new-function: (handle function) = allocate(function) - 3143 # var vars: (stack (addr var) 256) - 3144 # populate-mu-function-header(in, new-function, vars) - 3145 # populate-mu-function-body(in, new-function, vars) - 3146 # assert(vars->top == 0) - 3147 # *curr-function = new-function - 3148 # curr-function = &new-function->next - 3149 # else if slice-equal?(word-slice, "type") - 3150 # word-slice = next-mu-token(line) - 3151 # type-id = pos-or-insert-slice(Type-id, word-slice) - 3152 # var new-type: (handle typeinfo) = find-or-create-typeinfo(type-id) - 3153 # assert(next-word(line) == "{") - 3154 # populate-mu-type(in, new-type) - 3155 # else - 3156 # abort() - 3157 # - 3158 # . prologue - 3159 55/push-ebp - 3160 89/<- %ebp 4/r32/esp - 3161 # . save registers - 3162 50/push-eax - 3163 51/push-ecx - 3164 52/push-edx - 3165 53/push-ebx - 3166 56/push-esi - 3167 57/push-edi - 3168 # var line/ecx: (stream byte 512) - 3169 81 5/subop/subtract %esp 0x200/imm32 - 3170 68/push 0x200/imm32/size - 3171 68/push 0/imm32/read - 3172 68/push 0/imm32/write - 3173 89/<- %ecx 4/r32/esp - 3174 # var word-slice/edx: slice - 3175 68/push 0/imm32/end - 3176 68/push 0/imm32/start - 3177 89/<- %edx 4/r32/esp - 3178 # var curr-function/edi: (addr (handle function)) - 3179 bf/copy-to-edi _Program-functions/imm32 - 3180 # var curr-type/esi: (addr (handle typeinfo)) - 3181 be/copy-to-esi _Program-types/imm32 - 3182 # var vars/ebx: (stack (addr var) 256) - 3183 81 5/subop/subtract %esp 0x400/imm32 - 3184 68/push 0x400/imm32/size - 3185 68/push 0/imm32/top - 3186 89/<- %ebx 4/r32/esp - 3187 { - 3188 $parse-mu:line-loop: - 3189 (clear-stream %ecx) - 3190 (read-line-buffered *(ebp+8) %ecx) - 3191 # if (line->write == 0) break - 3192 81 7/subop/compare *ecx 0/imm32 - 3193 0f 84/jump-if-= break/disp32 - 3194 +-- 6 lines: #? # dump line --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 3200 (next-mu-token %ecx %edx) - 3201 # if slice-empty?(word-slice) continue - 3202 (slice-empty? %edx) - 3203 3d/compare-eax-and 0/imm32/false - 3204 0f 85/jump-if-!= loop/disp32 - 3205 # if (*word-slice->start == "#") continue - 3206 # . eax = *word-slice->start - 3207 8b/-> *edx 0/r32/eax - 3208 8a/copy-byte *eax 0/r32/AL - 3209 81 4/subop/and %eax 0xff/imm32 - 3210 # . if (eax == '#') continue - 3211 3d/compare-eax-and 0x23/imm32/hash - 3212 0f 84/jump-if-= loop/disp32 - 3213 # if (slice-equal?(word-slice, "fn")) parse a function - 3214 { - 3215 $parse-mu:fn: - 3216 (slice-equal? %edx "fn") - 3217 3d/compare-eax-and 0/imm32/false - 3218 0f 84/jump-if-= break/disp32 - 3219 # var new-function/eax: (handle function) = populate-mu-function(line, in, vars) - 3220 (allocate Heap *Function-size) # => eax - 3221 (clear-stack %ebx) - 3222 (populate-mu-function-header %ecx %eax %ebx) - 3223 (populate-mu-function-body *(ebp+8) %eax %ebx) - 3224 # *curr-function = new-function - 3225 89/<- *edi 0/r32/eax - 3226 # curr-function = &new-function->next - 3227 8d/address-> *(eax+0x14) 7/r32/edi # Function-next - 3228 e9/jump $parse-mu:line-loop/disp32 - 3229 } - 3230 # if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition - 3231 { - 3232 $parse-mu:type: - 3233 (slice-equal? %edx "type") - 3234 3d/compare-eax-and 0/imm32 - 3235 0f 84/jump-if-= break/disp32 - 3236 (next-mu-token %ecx %edx) - 3237 # var type-id/eax: int - 3238 (pos-or-insert-slice Type-id %edx) # => eax - 3239 # var new-type/eax: (handle typeinfo) - 3240 (find-or-create-typeinfo %eax) # => eax - 3241 # TODO: ensure that 'line' has nothing else but '{' - 3242 (populate-mu-type *(ebp+8) %eax) # => eax - 3243 e9/jump $parse-mu:line-loop/disp32 - 3244 } - 3245 # otherwise abort - 3246 e9/jump $parse-mu:error1/disp32 - 3247 } # end line loop - 3248 $parse-mu:end: - 3249 # . reclaim locals - 3250 81 0/subop/add %esp 0x630/imm32 - 3251 # . restore registers - 3252 5f/pop-to-edi - 3253 5e/pop-to-esi - 3254 5b/pop-to-ebx - 3255 5a/pop-to-edx - 3256 59/pop-to-ecx - 3257 58/pop-to-eax - 3258 # . epilogue - 3259 89/<- %esp 5/r32/ebp - 3260 5d/pop-to-ebp - 3261 c3/return - 3262 - 3263 $parse-mu:error1: - 3264 # error("unexpected top-level command: " word-slice "\n") - 3265 (write-buffered Stderr "unexpected top-level command: ") - 3266 (write-slice-buffered Stderr %edx) - 3267 (write-buffered Stderr "\n") - 3268 (flush Stderr) - 3269 # . syscall(exit, 1) - 3270 bb/copy-to-ebx 1/imm32 - 3271 b8/copy-to-eax 1/imm32/exit - 3272 cd/syscall 0x80/imm8 - 3273 # never gets here - 3274 - 3275 $parse-mu:error2: - 3276 # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n") - 3277 (print-int32-buffered Stderr *ebx) - 3278 (write-buffered Stderr " vars not reclaimed after fn '") - 3279 (write-slice-buffered Stderr *eax) # Function-name - 3280 (write-buffered Stderr "'\n") - 3281 (flush Stderr) - 3282 # . syscall(exit, 1) - 3283 bb/copy-to-ebx 1/imm32 - 3284 b8/copy-to-eax 1/imm32/exit - 3285 cd/syscall 0x80/imm8 - 3286 # never gets here - 3287 - 3288 # scenarios considered: - 3289 # ✗ fn foo # no block - 3290 # ✓ fn foo { - 3291 # ✗ fn foo { { - 3292 # ✗ fn foo { } - 3293 # ✗ fn foo { } { - 3294 # ✗ fn foo x { - 3295 # ✗ fn foo x: { - 3296 # ✓ fn foo x: int { - 3297 # ✓ fn foo x: int { - 3298 # ✓ fn foo x: int -> y/eax: int { - 3299 populate-mu-function-header: # first-line: (addr stream byte), out: (handle function), vars: (addr stack (handle var)) - 3300 # pseudocode: - 3301 # var name: slice - 3302 # next-mu-token(first-line, name) - 3303 # assert(name not in '{' '}' '->') - 3304 # out->name = slice-to-string(name) - 3305 # ## inouts - 3306 # while true - 3307 # ## name - 3308 # name = next-mu-token(first-line) - 3309 # if (name == '{') goto done - 3310 # if (name == '->') break - 3311 # assert(name != '}') - 3312 # var v: (handle var) = parse-var-with-type(name, first-line) - 3313 # assert(v->register == null) - 3314 # # v->block-depth is implicitly 0 - 3315 # out->inouts = append(out->inouts, v) - 3316 # push(vars, v) - 3317 # ## outputs - 3318 # while true - 3319 # ## name - 3320 # name = next-mu-token(first-line) - 3321 # assert(name not in '{' '}' '->') - 3322 # var v: (handle var) = parse-var-with-type(name, first-line) - 3323 # assert(v->register != null) - 3324 # out->outputs = append(out->outputs, v) - 3325 # done: - 3326 # - 3327 # . prologue - 3328 55/push-ebp - 3329 89/<- %ebp 4/r32/esp - 3330 # . save registers - 3331 50/push-eax - 3332 51/push-ecx - 3333 52/push-edx - 3334 53/push-ebx - 3335 57/push-edi - 3336 # edi = out - 3337 8b/-> *(ebp+0xc) 7/r32/edi - 3338 # var word-slice/ecx: slice - 3339 68/push 0/imm32/end - 3340 68/push 0/imm32/start - 3341 89/<- %ecx 4/r32/esp - 3342 # read function name - 3343 (next-mu-token *(ebp+8) %ecx) - 3344 # error checking - 3345 # TODO: error if name starts with 'break' or 'loop' - 3346 # if (word-slice == '{') abort - 3347 (slice-equal? %ecx "{") # => eax - 3348 3d/compare-eax-and 0/imm32/false - 3349 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 - 3350 # if (word-slice == '->') abort - 3351 (slice-equal? %ecx "->") # => eax - 3352 3d/compare-eax-and 0/imm32/false - 3353 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 - 3354 # if (word-slice == '}') abort - 3355 (slice-equal? %ecx "}") # => eax - 3356 3d/compare-eax-and 0/imm32/false - 3357 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 - 3358 # save function name - 3359 (slice-to-string Heap %ecx) # => eax - 3360 89/<- *edi 0/r32/eax # Function-name - 3361 # save function inouts - 3362 { - 3363 $populate-mu-function-header:check-for-inout: - 3364 (next-mu-token *(ebp+8) %ecx) - 3365 # if (word-slice == '{') goto done - 3366 (slice-equal? %ecx "{") # => eax - 3367 3d/compare-eax-and 0/imm32/false - 3368 0f 85/jump-if-!= $populate-mu-function-header:done/disp32 - 3369 # if (word-slice == '->') break - 3370 (slice-equal? %ecx "->") # => eax - 3371 3d/compare-eax-and 0/imm32/false - 3372 0f 85/jump-if-!= break/disp32 - 3373 # if (word-slice == '}') abort - 3374 (slice-equal? %ecx "}") # => eax - 3375 3d/compare-eax-and 0/imm32/false - 3376 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 - 3377 # var v/ebx: (handle var) = parse-var-with-type(word-slice, first-line) - 3378 (parse-var-with-type %ecx *(ebp+8)) # => eax - 3379 89/<- %ebx 0/r32/eax - 3380 # assert(v->register == null) - 3381 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register - 3382 0f 85/jump-if-!= $populate-mu-function-header:error2/disp32 - 3383 # v->block-depth is implicitly 0 - 3384 # - 3385 # out->inouts = append(out->inouts, v) - 3386 (append-list Heap %ebx *(edi+8)) # Function-inouts => eax - 3387 89/<- *(edi+8) 0/r32/eax # Function-inouts - 3388 # push(vars, v) - 3389 (push *(ebp+0x10) %ebx) - 3390 # - 3391 e9/jump loop/disp32 - 3392 } - 3393 # save function outputs - 3394 { - 3395 $populate-mu-function-header:check-for-out: - 3396 (next-mu-token *(ebp+8) %ecx) - 3397 # if (word-slice == '{') break - 3398 (slice-equal? %ecx "{") # => eax - 3399 3d/compare-eax-and 0/imm32/false - 3400 0f 85/jump-if-!= break/disp32 - 3401 # if (word-slice == '->') abort - 3402 (slice-equal? %ecx "->") # => eax - 3403 3d/compare-eax-and 0/imm32/false - 3404 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 - 3405 # if (word-slice == '}') abort - 3406 (slice-equal? %ecx "}") # => eax - 3407 3d/compare-eax-and 0/imm32/false - 3408 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 - 3409 # - 3410 (parse-var-with-type %ecx *(ebp+8)) # => eax - 3411 89/<- %ebx 0/r32/eax - 3412 # assert(var->register != null) - 3413 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register - 3414 0f 84/jump-if-= $populate-mu-function-header:error3/disp32 - 3415 (append-list Heap %ebx *(edi+0xc)) # Function-outputs => eax - 3416 89/<- *(edi+0xc) 0/r32/eax # Function-outputs - 3417 e9/jump loop/disp32 - 3418 } - 3419 $populate-mu-function-header:done: - 3420 (check-no-tokens-left *(ebp+8)) - 3421 $populate-mu-function-header:end: - 3422 # . reclaim locals - 3423 81 0/subop/add %esp 8/imm32 - 3424 # . restore registers - 3425 5f/pop-to-edi - 3426 5b/pop-to-ebx - 3427 5a/pop-to-edx - 3428 59/pop-to-ecx - 3429 58/pop-to-eax - 3430 # . epilogue - 3431 89/<- %esp 5/r32/ebp - 3432 5d/pop-to-ebp - 3433 c3/return - 3434 - 3435 $populate-mu-function-header:error1: - 3436 # error("function header not in form 'fn <name> {'") - 3437 (write-buffered Stderr "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '") - 3438 (flush Stderr) - 3439 (rewind-stream *(ebp+8)) - 3440 (write-stream 2 *(ebp+8)) - 3441 (write-buffered Stderr "'\n") - 3442 (flush Stderr) - 3443 # . syscall(exit, 1) - 3444 bb/copy-to-ebx 1/imm32 - 3445 b8/copy-to-eax 1/imm32/exit - 3446 cd/syscall 0x80/imm8 - 3447 # never gets here - 3448 - 3449 $populate-mu-function-header:error2: - 3450 # error("function input '" var "' cannot be in a register") - 3451 (write-buffered Stderr "function input '") - 3452 (write-buffered Stderr *ebx) # Var-name - 3453 (write-buffered Stderr "' cannot be in a register") - 3454 (flush Stderr) - 3455 # . syscall(exit, 1) - 3456 bb/copy-to-ebx 1/imm32 - 3457 b8/copy-to-eax 1/imm32/exit - 3458 cd/syscall 0x80/imm8 - 3459 # never gets here - 3460 - 3461 $populate-mu-function-header:error3: - 3462 # error("function input '" var "' must be in a register") - 3463 (write-buffered Stderr "function input '") - 3464 (write-buffered Stderr *eax) # Var-name - 3465 (write-buffered Stderr " must be in a register'") - 3466 (flush Stderr) - 3467 (rewind-stream *(ebp+8)) - 3468 (write-stream 2 *(ebp+8)) - 3469 (write-buffered Stderr "'\n") - 3470 (flush Stderr) - 3471 # . syscall(exit, 1) - 3472 bb/copy-to-ebx 1/imm32 - 3473 b8/copy-to-eax 1/imm32/exit - 3474 cd/syscall 0x80/imm8 - 3475 # never gets here - 3476 - 3477 test-function-header-with-arg: - 3478 # . prologue - 3479 55/push-ebp - 3480 89/<- %ebp 4/r32/esp - 3481 # setup - 3482 (clear-stream _test-input-stream) - 3483 (write _test-input-stream "foo n: int {\n") - 3484 # var result/ecx: function - 3485 2b/subtract *Function-size 4/r32/esp - 3486 89/<- %ecx 4/r32/esp - 3487 (zero-out %ecx *Function-size) - 3488 # var vars/ebx: (stack (addr var) 16) - 3489 81 5/subop/subtract %esp 0x10/imm32 - 3490 68/push 0x10/imm32/size - 3491 68/push 0/imm32/top - 3492 89/<- %ebx 4/r32/esp - 3493 # convert - 3494 (populate-mu-function-header _test-input-stream %ecx %ebx) - 3495 # check result - 3496 (check-strings-equal *ecx "foo" "F - test-function-header-with-arg/name") # Function-name - 3497 # edx: (handle list var) = result->inouts - 3498 8b/-> *(ecx+8) 2/r32/edx # Function-inouts - 3499 # ebx: (handle var) = result->inouts->value - 3500 8b/-> *edx 3/r32/ebx # List-value - 3501 (check-strings-equal *ebx "n" "F - test-function-header-with-arg/inout:0") # Var-name - 3502 8b/-> *(ebx+4) 3/r32/ebx # Var-type - 3503 (check-ints-equal *ebx 1 "F - test-function-header-with-arg/inout:0/type:0") # Tree-is-atom - 3504 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/inout:0/type:1") # Tree-value - 3505 (check-ints-equal *(ebx+8) 0 "F - test-function-header-with-arg/inout:0/type:2") # Tree-right - 3506 # . epilogue - 3507 89/<- %esp 5/r32/ebp - 3508 5d/pop-to-ebp - 3509 c3/return - 3510 - 3511 test-function-header-with-multiple-args: - 3512 # . prologue - 3513 55/push-ebp - 3514 89/<- %ebp 4/r32/esp - 3515 # setup - 3516 (clear-stream _test-input-stream) - 3517 (write _test-input-stream "foo a: int, b: int c: int {\n") - 3518 # result/ecx: (handle function) - 3519 2b/subtract *Function-size 4/r32/esp - 3520 89/<- %ecx 4/r32/esp - 3521 (zero-out %ecx *Function-size) - 3522 # var vars/ebx: (stack (addr var) 16) - 3523 81 5/subop/subtract %esp 0x10/imm32 - 3524 68/push 0x10/imm32/size - 3525 68/push 0/imm32/top - 3526 89/<- %ebx 4/r32/esp - 3527 # convert - 3528 (populate-mu-function-header _test-input-stream %ecx %ebx) - 3529 # check result - 3530 (check-strings-equal *ecx "foo") # Function-name - 3531 # edx: (handle list var) = result->inouts - 3532 8b/-> *(ecx+8) 2/r32/edx # Function-inouts - 3533 $test-function-header-with-multiple-args:inout0: - 3534 # ebx: (handle var) = result->inouts->value - 3535 8b/-> *edx 3/r32/ebx # List-value - 3536 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args/inout:0") # Var-name - 3537 8b/-> *(ebx+4) 3/r32/ebx # Var-type - 3538 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:0/type:0") # Tree-is-atom - 3539 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-multiple-args/inout:0/type:1") # Tree-value - 3540 (check-ints-equal *(ebx+8) 0 "F - test-function-header-with-multiple-args/inout:0/type:2") # Tree-right - 3541 # edx = result->inouts->next - 3542 8b/-> *(edx+4) 2/r32/edx # List-next - 3543 $test-function-header-with-multiple-args:inout1: - 3544 # ebx = result->inouts->next->value - 3545 8b/-> *edx 3/r32/ebx # List-value - 3546 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args/inout:1") # Var-name - 3547 8b/-> *(ebx+4) 3/r32/ebx # Var-type - 3548 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:1/type:0") # Tree-is-atom - 3549 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-multiple-args/inout:1/type:1") # Tree-value - 3550 (check-ints-equal *(ebx+8) 0 "F - test-function-header-with-multiple-args/inout:1/type:2") # Tree-right - 3551 # edx = result->inouts->next->next - 3552 8b/-> *(edx+4) 2/r32/edx # List-next - 3553 $test-function-header-with-multiple-args:inout2: - 3554 # ebx = result->inouts->next->next->value - 3555 8b/-> *edx 3/r32/ebx # List-value - 3556 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args/inout:2") # Var-name - 3557 8b/-> *(ebx+4) 3/r32/ebx # Var-type - 3558 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:2/type:0") # Tree-is-atom - 3559 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-multiple-args/inout:2/type:1") # Tree-value - 3560 (check-ints-equal *(ebx+8) 0 "F - test-function-header-with-multiple-args/inout:2/type:2") # Tree-right - 3561 # . epilogue - 3562 89/<- %esp 5/r32/ebp - 3563 5d/pop-to-ebp - 3564 c3/return - 3565 - 3566 test-function-with-multiple-args-and-outputs: - 3567 # . prologue - 3568 55/push-ebp - 3569 89/<- %ebp 4/r32/esp - 3570 # setup - 3571 (clear-stream _test-input-stream) - 3572 (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n") - 3573 # result/ecx: (handle function) - 3574 2b/subtract *Function-size 4/r32/esp - 3575 89/<- %ecx 4/r32/esp - 3576 (zero-out %ecx *Function-size) - 3577 # var vars/ebx: (stack (addr var) 16) - 3578 81 5/subop/subtract %esp 0x10/imm32 - 3579 68/push 0x10/imm32/size - 3580 68/push 0/imm32/top - 3581 89/<- %ebx 4/r32/esp - 3582 # convert - 3583 (populate-mu-function-header _test-input-stream %ecx %ebx) - 3584 # check result - 3585 (check-strings-equal *ecx "foo") # Function-name - 3586 # edx: (handle list var) = result->inouts - 3587 8b/-> *(ecx+8) 2/r32/edx # Function-inouts - 3588 # ebx: (handle var) = result->inouts->value - 3589 8b/-> *edx 3/r32/ebx # List-value - 3590 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0") # Var-name - 3591 8b/-> *(ebx+4) 3/r32/ebx # Var-type - 3592 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0") # Tree-is-atom - 3593 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1") # Tree-value - 3594 (check-ints-equal *(ebx+8) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:2") # Tree-right - 3595 # edx = result->inouts->next - 3596 8b/-> *(edx+4) 2/r32/edx # List-next - 3597 # ebx = result->inouts->next->value - 3598 8b/-> *edx 3/r32/ebx # List-value - 3599 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1") # Var-name - 3600 8b/-> *(ebx+4) 3/r32/ebx # Var-type - 3601 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0") # Tree-is-atom - 3602 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1") # Tree-value - 3603 (check-ints-equal *(ebx+8) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:2") # Tree-right - 3604 # edx = result->inouts->next->next - 3605 8b/-> *(edx+4) 2/r32/edx # List-next - 3606 # ebx = result->inouts->next->next->value - 3607 8b/-> *edx 3/r32/ebx # List-value - 3608 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2") # Var-name - 3609 8b/-> *(ebx+4) 3/r32/ebx # Var-type - 3610 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0") # Tree-is-atom - 3611 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1") # Tree-value - 3612 (check-ints-equal *(ebx+8) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:2") # Tree-right - 3613 # edx: (handle list var) = result->outputs - 3614 8b/-> *(ecx+0xc) 2/r32/edx # Function-outputs - 3615 # ebx: (handle var) = result->outputs->value - 3616 8b/-> *edx 3/r32/ebx # List-value - 3617 (check-strings-equal *ebx "x" "F - test-function-header-with-multiple-args-and-outputs/output:0") # Var-name - 3618 (check-strings-equal *(ebx+0x10) "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") # Var-register - 3619 8b/-> *(ebx+4) 3/r32/ebx # Var-type - 3620 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:0") # Tree-is-atom - 3621 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Tree-value - 3622 (check-ints-equal *(ebx+8) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:2") # Tree-right - 3623 # edx = result->outputs->next - 3624 8b/-> *(edx+4) 2/r32/edx # List-next - 3625 # ebx = result->outputs->next->value - 3626 8b/-> *edx 3/r32/ebx # List-value - 3627 (check-strings-equal *ebx "y" "F - test-function-header-with-multiple-args-and-outputs/output:1") # Var-name - 3628 (check-strings-equal *(ebx+0x10) "edx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") # Var-register - 3629 8b/-> *(ebx+4) 3/r32/ebx # Var-type - 3630 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:0") # Tree-is-atom - 3631 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Tree-value - 3632 (check-ints-equal *(ebx+8) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:2") # Tree-right - 3633 # . epilogue - 3634 89/<- %esp 5/r32/ebp - 3635 5d/pop-to-ebp - 3636 c3/return - 3637 - 3638 # format for variables with types - 3639 # x: int - 3640 # x: int, - 3641 # x/eax: int - 3642 # x/eax: int, - 3643 # ignores at most one trailing comma - 3644 # WARNING: modifies name - 3645 parse-var-with-type: # name: (addr slice), first-line: (addr stream byte) -> result/eax: (handle var) - 3646 # pseudocode: - 3647 # var s: slice - 3648 # if (!slice-ends-with(name, ":")) - 3649 # abort - 3650 # --name->end to skip ':' - 3651 # next-token-from-slice(name->start, name->end, '/', s) - 3652 # result = new-var-from-slice(s) - 3653 # ## register - 3654 # next-token-from-slice(s->end, name->end, '/', s) - 3655 # if (!slice-empty?(s)) - 3656 # v->register = slice-to-string(s) - 3657 # ## type - 3658 # var type: (handle tree type-id) = parse-type(first-line) - 3659 # v->type = type - 3660 # return v - 3661 # - 3662 # . prologue - 3663 55/push-ebp - 3664 89/<- %ebp 4/r32/esp - 3665 # . save registers - 3666 51/push-ecx - 3667 52/push-edx - 3668 53/push-ebx - 3669 56/push-esi - 3670 57/push-edi - 3671 # esi = name - 3672 8b/-> *(ebp+8) 6/r32/esi - 3673 # if (!slice-ends-with?(name, ":")) abort - 3674 8b/-> *(esi+4) 1/r32/ecx # Slice-end - 3675 49/decrement-ecx - 3676 8a/copy-byte *ecx 1/r32/CL - 3677 81 4/subop/and %ecx 0xff/imm32 - 3678 81 7/subop/compare %ecx 0x3a/imm32/colon - 3679 0f 85/jump-if-!= $parse-var-with-type:abort/disp32 - 3680 # --name->end to skip ':' - 3681 ff 1/subop/decrement *(esi+4) - 3682 # var s/ecx: slice - 3683 68/push 0/imm32/end - 3684 68/push 0/imm32/start - 3685 89/<- %ecx 4/r32/esp - 3686 $parse-var-with-type:parse-name: - 3687 (next-token-from-slice *esi *(esi+4) 0x2f %ecx) # Slice-start, Slice-end, '/' - 3688 $parse-var-with-type:create-var: - 3689 # edi = new-var-from-slice(s) - 3690 (new-var-from-slice Heap %ecx) # => eax - 3691 89/<- %edi 0/r32/eax - 3692 # save v->register - 3693 $parse-var-with-type:save-register: - 3694 # s = next-token(...) - 3695 (next-token-from-slice *(ecx+4) *(esi+4) 0x2f %ecx) # s->end, name->end, '/' - 3696 # if (!slice-empty?(s)) v->register = slice-to-string(s) - 3697 { - 3698 $parse-var-with-type:write-register: - 3699 (slice-empty? %ecx) # => eax - 3700 3d/compare-eax-and 0/imm32/false - 3701 75/jump-if-!= break/disp8 - 3702 (slice-to-string Heap %ecx) - 3703 89/<- *(edi+0x10) 0/r32/eax # Var-register - 3704 } - 3705 $parse-var-with-type:save-type: - 3706 (parse-type Heap *(ebp+0xc)) # => eax - 3707 #? (write-buffered Stderr "saving to var ") - 3708 #? (print-int32-buffered Stderr %edi) - 3709 #? (write-buffered Stderr Newline) - 3710 #? (flush Stderr) - 3711 89/<- *(edi+4) 0/r32/eax # Var-type - 3712 $parse-var-with-type:end: - 3713 # return result - 3714 89/<- %eax 7/r32/edi - 3715 # . reclaim locals - 3716 81 0/subop/add %esp 8/imm32 - 3717 # . restore registers - 3718 5f/pop-to-edi - 3719 5e/pop-to-esi - 3720 5b/pop-to-ebx - 3721 5a/pop-to-edx - 3722 59/pop-to-ecx - 3723 # . epilogue - 3724 89/<- %esp 5/r32/ebp - 3725 5d/pop-to-ebp - 3726 c3/return - 3727 - 3728 $parse-var-with-type:abort: - 3729 # error("var should have form 'name: type' in '" line "'\n") - 3730 (write-buffered Stderr "var should have form 'name: type' in '") - 3731 (flush Stderr) - 3732 (rewind-stream *(ebp+0xc)) - 3733 (write-stream 2 *(ebp+0xc)) - 3734 (write-buffered Stderr "'\n") - 3735 (flush Stderr) - 3736 # . syscall(exit, 1) - 3737 bb/copy-to-ebx 1/imm32 - 3738 b8/copy-to-eax 1/imm32/exit - 3739 cd/syscall 0x80/imm8 - 3740 # never gets here - 3741 - 3742 parse-type: # ad: (address allocation-descriptor), in: (addr stream byte) -> result/eax: (handle tree type-id) - 3743 # pseudocode: - 3744 # var s: slice = next-mu-token(in) - 3745 # assert s != "" - 3746 # assert s != "->" - 3747 # assert s != "{" - 3748 # assert s != "}" - 3749 # if s == ")" - 3750 # return 0 - 3751 # result = allocate(Tree) - 3752 # zero-out(result, *Tree-size) - 3753 # if s != "(" - 3754 # result->left-is-atom? = true - 3755 # result->value = pos-or-insert-slice(Type-id, s) - 3756 # return - 3757 # result->left = parse-type(ad, in) - 3758 # result->right = parse-type-tree(ad, in) - 3759 # - 3760 # . prologue - 3761 55/push-ebp - 3762 89/<- %ebp 4/r32/esp - 3763 # . save registers - 3764 51/push-ecx - 3765 52/push-edx - 3766 # var s/ecx: slice - 3767 68/push 0/imm32 - 3768 68/push 0/imm32 - 3769 89/<- %ecx 4/r32/esp - 3770 # s = next-mu-token(in) - 3771 (next-mu-token *(ebp+0xc) %ecx) - 3772 #? (write-buffered Stderr "tok: ") - 3773 #? (write-slice-buffered Stderr %ecx) - 3774 #? (write-buffered Stderr "$\n") - 3775 #? (flush Stderr) - 3776 # assert s != "" - 3777 (slice-equal? %ecx "") - 3778 3d/compare-eax-and 0/imm32/false - 3779 0f 85/jump-if-!= $parse-type:abort/disp32 - 3780 # assert s != "{" - 3781 (slice-equal? %ecx "{") - 3782 3d/compare-eax-and 0/imm32/false - 3783 0f 85/jump-if-!= $parse-type:abort/disp32 - 3784 # assert s != "}" - 3785 (slice-equal? %ecx "}") - 3786 3d/compare-eax-and 0/imm32/false - 3787 0f 85/jump-if-!= $parse-type:abort/disp32 - 3788 # assert s != "->" - 3789 (slice-equal? %ecx "->") - 3790 3d/compare-eax-and 0/imm32/false - 3791 0f 85/jump-if-!= $parse-type:abort/disp32 - 3792 # if (s == ")") return 0 - 3793 (slice-equal? %ecx ")") - 3794 3d/compare-eax-and 0/imm32/false - 3795 b8/copy-to-eax 0/imm32 - 3796 0f 85/jump-if-!= $parse-type:end/disp32 - 3797 # var result/edx: (handle tree type-id) - 3798 (allocate *(ebp+8) *Tree-size) # => eax - 3799 $aa-alloc: - 3800 89/<- %edx 0/r32/eax - 3801 { - 3802 # if (s != "(") break - 3803 (slice-equal? %ecx "(") - 3804 3d/compare-eax-and 0/imm32/false - 3805 75/jump-if-!= break/disp8 - 3806 # EGREGIOUS HACK for static array sizes: if s is a number, parse it - 3807 { - 3808 $parse-type:int: - 3809 (is-hex-int? %ecx) # => eax - 3810 3d/compare-eax-and 0/imm32/false - 3811 74/jump-if-= break/disp8 - 3812 (parse-hex-int-from-slice %ecx) # => eax - 3813 89/<- *(edx+4) 0/r32/eax # Tree-left - 3814 e9/jump $parse-type:return-edx/disp32 - 3815 } - 3816 $parse-type:atom: - 3817 # result->left-is-atom? = true - 3818 c7 0/subop/copy *edx 1/imm32/true # Tree-is-atom - 3819 # result->value = pos-or-insert-slice(Type-id, s) - 3820 (pos-or-insert-slice Type-id %ecx) # => eax - 3821 #? (write-buffered Stderr "=> {") - 3822 #? (print-int32-buffered Stderr %eax) - 3823 #? (write-buffered Stderr ", 0}\n") - 3824 #? (flush Stderr) - 3825 89/<- *(edx+4) 0/r32/eax # Tree-value - 3826 e9/jump $parse-type:return-edx/disp32 - 3827 } - 3828 $parse-type:non-atom: - 3829 # otherwise s == "(" - 3830 # result->left = parse-type(ad, in) - 3831 (parse-type *(ebp+8) *(ebp+0xc)) - 3832 #? (write-buffered Stderr "=> {") - 3833 #? (print-int32-buffered Stderr %eax) - 3834 89/<- *(edx+4) 0/r32/eax # Tree-left - 3835 # result->right = parse-type-tree(ad, in) - 3836 (parse-type-tree *(ebp+8) *(ebp+0xc)) - 3837 #? (write-buffered Stderr Space) - 3838 #? (print-int32-buffered Stderr %eax) - 3839 #? (write-buffered Stderr "}\n") - 3840 #? (flush Stderr) - 3841 89/<- *(edx+8) 0/r32/eax # Tree-right - 3842 $parse-type:return-edx: - 3843 89/<- %eax 2/r32/edx - 3844 $parse-type:end: - 3845 # . reclaim locals - 3846 81 0/subop/add %esp 8/imm32 - 3847 # . restore registers - 3848 5a/pop-to-edx - 3849 59/pop-to-ecx - 3850 # . epilogue - 3851 89/<- %esp 5/r32/ebp - 3852 5d/pop-to-ebp - 3853 c3/return - 3854 - 3855 $parse-type:abort: - 3856 # error("unexpected token when parsing type: '" s "'\n") - 3857 (write-buffered Stderr "unexpected token when parsing type: '") - 3858 (write-slice-buffered Stderr %ecx) - 3859 (write-buffered Stderr "'\n") - 3860 (flush Stderr) - 3861 # . syscall(exit, 1) - 3862 bb/copy-to-ebx 1/imm32 - 3863 b8/copy-to-eax 1/imm32/exit - 3864 cd/syscall 0x80/imm8 - 3865 # never gets here - 3866 - 3867 parse-type-tree: # ad: (address allocation-descriptor), in: (addr stream byte) -> result/eax: (handle tree type-id) - 3868 # pseudocode: - 3869 # var tmp: (handle tree type-id) = parse-type(ad, in) - 3870 # if tmp == 0 - 3871 # return 0 - 3872 # result = allocate(Tree) - 3873 # zero-out(result, *Tree-size) - 3874 # result->left = tmp - 3875 # result->right = parse-type-tree(ad, in) - 3876 # - 3877 # . prologue - 3878 55/push-ebp - 3879 89/<- %ebp 4/r32/esp - 3880 # . save registers - 3881 51/push-ecx - 3882 52/push-edx - 3883 # var tmp/eax: (handle tree type-id) = parse-type(ad, in) - 3884 (parse-type *(ebp+8) *(ebp+0xc)) - 3885 # if (tmp == 0) return tmp - 3886 3d/compare-eax-and 0/imm32 - 3887 74/jump-if-= $parse-type-tree:end/disp8 - 3888 # var tmp2/ecx = tmp - 3889 89/<- %ecx 0/r32/eax - 3890 # var result/edx: (handle tree type-id) - 3891 (allocate *(ebp+8) *Tree-size) # => eax - 3892 89/<- %edx 0/r32/eax - 3893 # result->left = tmp2 - 3894 89/<- *(edx+4) 1/r32/ecx # Tree-left - 3895 # result->right = parse-type-tree(ad, in) - 3896 (parse-type-tree *(ebp+8) *(ebp+0xc)) - 3897 89/<- *(edx+8) 0/r32/eax # Tree-right - 3898 $parse-type-tree:return-edx: - 3899 89/<- %eax 2/r32/edx - 3900 $parse-type-tree:end: + 3079 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/11") + 3080 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000008/imm32" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/12") + 3081 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/13") + 3082 (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/14") + 3083 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/15") + 3084 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/16") + 3085 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/17") + 3086 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/18") + 3087 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/19") + 3088 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/20") + 3089 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/21") + 3090 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/22") + 3091 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/23") + 3092 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/24") + 3093 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/25") + 3094 (check-next-stream-line-equal _test-output-stream " 89/<- %ecx 0x00000001/r32" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/26") + 3095 (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *ecx" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/27") + 3096 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/28") + 3097 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/29") + 3098 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/30") + 3099 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/31") + 3100 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/32") + 3101 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/33") + 3102 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/34") + 3103 # . epilogue + 3104 89/<- %esp 5/r32/ebp + 3105 5d/pop-to-ebp + 3106 c3/return + 3107 + 3108 test-convert-get-of-type-on-stack: + 3109 # . prologue + 3110 55/push-ebp + 3111 89/<- %ebp 4/r32/esp + 3112 # setup + 3113 (clear-stream _test-input-stream) + 3114 (clear-stream $_test-input-buffered-file->buffer) + 3115 (clear-stream _test-output-stream) + 3116 (clear-stream $_test-output-buffered-file->buffer) + 3117 # + 3118 (write _test-input-stream "fn foo {\n") + 3119 (write _test-input-stream " var a: t\n") + 3120 (write _test-input-stream " var c/ecx: (addr int) <- get a, y\n") + 3121 (write _test-input-stream "}\n") + 3122 (write _test-input-stream "type t {\n") + 3123 (write _test-input-stream " x: int\n") + 3124 (write _test-input-stream " y: int\n") + 3125 (write _test-input-stream "}\n") + 3126 # convert + 3127 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 3128 (flush _test-output-buffered-file) + 3129 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 3135 # check output + 3136 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-get-of-type-on-stack/0") + 3137 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-get-of-type-on-stack/1") + 3138 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-get-of-type-on-stack/2") + 3139 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-get-of-type-on-stack/3") + 3140 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-get-of-type-on-stack/4") + 3141 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-get-of-type-on-stack/5") + 3142 # var a + 3143 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-get-of-type-on-stack/6") + 3144 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-get-of-type-on-stack/7") + 3145 # var c + 3146 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-get-of-type-on-stack/8") + 3147 # get + 3148 (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp+0xfffffffc) 0x00000001/r32" "F - test-convert-get-of-type-on-stack/9") + 3149 # reclaim c + 3150 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-get-of-type-on-stack/10") + 3151 # reclaim a + 3152 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000008/imm32" "F - test-convert-get-of-type-on-stack/11") + 3153 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-get-of-type-on-stack/12") + 3154 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-get-of-type-on-stack/13") + 3155 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-get-of-type-on-stack/14") + 3156 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-get-of-type-on-stack/15") + 3157 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-get-of-type-on-stack/16") + 3158 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-get-of-type-on-stack/17") + 3159 # . epilogue + 3160 89/<- %esp 5/r32/ebp + 3161 5d/pop-to-ebp + 3162 c3/return + 3163 + 3164 test-convert-array-of-user-defined-types: + 3165 # . prologue + 3166 55/push-ebp + 3167 89/<- %ebp 4/r32/esp + 3168 # setup + 3169 (clear-stream _test-input-stream) + 3170 (clear-stream $_test-input-buffered-file->buffer) + 3171 (clear-stream _test-output-stream) + 3172 (clear-stream $_test-output-buffered-file->buffer) + 3173 # + 3174 (write _test-input-stream "type t {\n") # each t is 8 bytes, which is a power of 2 + 3175 (write _test-input-stream " x: int\n") + 3176 (write _test-input-stream " y: int\n") + 3177 (write _test-input-stream "}\n") + 3178 (write _test-input-stream "fn foo {\n") + 3179 (write _test-input-stream " var arr/eax: (addr array t) <- copy 0\n") + 3180 (write _test-input-stream " var idx/ecx: int <- copy 3\n") + 3181 (write _test-input-stream " var x/eax: (addr int) <- index arr, idx\n") + 3182 (write _test-input-stream "}\n") + 3183 # convert + 3184 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 3185 (flush _test-output-buffered-file) + 3186 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- + 3192 # check output + 3193 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-array-of-user-defined-types/0") + 3194 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-array-of-user-defined-types/1") + 3195 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-array-of-user-defined-types/2") + 3196 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-array-of-user-defined-types/3") + 3197 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-array-of-user-defined-types/4") + 3198 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-array-of-user-defined-types/5") + 3199 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-array-of-user-defined-types/6") + 3200 (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-array-of-user-defined-types/7") + 3201 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-array-of-user-defined-types/8") + 3202 (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-array-of-user-defined-types/9") + 3203 (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") + 3204 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-array-of-user-defined-types/13") + 3205 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-array-of-user-defined-types/14") + 3206 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-array-of-user-defined-types/15") + 3207 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-array-of-user-defined-types/16") + 3208 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-array-of-user-defined-types/17") + 3209 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-array-of-user-defined-types/18") + 3210 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-array-of-user-defined-types/19") + 3211 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-array-of-user-defined-types/20") + 3212 # . epilogue + 3213 89/<- %esp 5/r32/ebp + 3214 5d/pop-to-ebp + 3215 c3/return + 3216 + 3217 ####################################################### + 3218 # Parsing + 3219 ####################################################### + 3220 + 3221 parse-mu: # in: (addr buffered-file) + 3222 # pseudocode + 3223 # var curr-function: (addr handle function) = Program->functions + 3224 # var curr-type: (addr handle typeinfo) = Program->types + 3225 # var line: (stream byte 512) + 3226 # var word-slice: slice + 3227 # while true # line loop + 3228 # clear-stream(line) + 3229 # read-line-buffered(in, line) + 3230 # if (line->write == 0) break # end of file + 3231 # word-slice = next-mu-token(line) + 3232 # if slice-empty?(word-slice) # end of line + 3233 # continue + 3234 # else if slice-starts-with?(word-slice, "#") # comment + 3235 # continue # end of line + 3236 # else if slice-equal?(word-slice, "fn") + 3237 # var new-function: (handle function) = allocate(function) + 3238 # var vars: (stack (handle var) 256) + 3239 # populate-mu-function-header(line, new-function, vars) + 3240 # populate-mu-function-body(in, new-function, vars) + 3241 # assert(vars->top == 0) + 3242 # *curr-function = new-function + 3243 # curr-function = &new-function->next + 3244 # else if slice-equal?(word-slice, "type") + 3245 # word-slice = next-mu-token(line) + 3246 # type-id = pos-or-insert-slice(Type-id, word-slice) + 3247 # var new-type: (handle typeinfo) = find-or-create-typeinfo(type-id) + 3248 # assert(next-word(line) == "{") + 3249 # populate-mu-type(in, new-type) + 3250 # else + 3251 # abort() + 3252 # + 3253 # . prologue + 3254 55/push-ebp + 3255 89/<- %ebp 4/r32/esp + 3256 # . save registers + 3257 50/push-eax + 3258 51/push-ecx + 3259 52/push-edx + 3260 53/push-ebx + 3261 56/push-esi + 3262 57/push-edi + 3263 # var line/ecx: (stream byte 512) + 3264 81 5/subop/subtract %esp 0x200/imm32 + 3265 68/push 0x200/imm32/size + 3266 68/push 0/imm32/read + 3267 68/push 0/imm32/write + 3268 89/<- %ecx 4/r32/esp + 3269 # var word-slice/edx: slice + 3270 68/push 0/imm32/end + 3271 68/push 0/imm32/start + 3272 89/<- %edx 4/r32/esp + 3273 # var curr-function/edi: (addr handle function) + 3274 bf/copy-to-edi _Program-functions/imm32 + 3275 # var vars/ebx: (stack (handle var) 256) + 3276 81 5/subop/subtract %esp 0x800/imm32 + 3277 68/push 0x800/imm32/size + 3278 68/push 0/imm32/top + 3279 89/<- %ebx 4/r32/esp + 3280 { + 3281 $parse-mu:line-loop: + 3282 (clear-stream %ecx) + 3283 (read-line-buffered *(ebp+8) %ecx) + 3284 # if (line->write == 0) break + 3285 81 7/subop/compare *ecx 0/imm32 + 3286 0f 84/jump-if-= break/disp32 + 3287 +-- 6 lines: #? # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------ + 3293 (next-mu-token %ecx %edx) + 3294 # if slice-empty?(word-slice) continue + 3295 (slice-empty? %edx) # => eax + 3296 3d/compare-eax-and 0/imm32/false + 3297 0f 85/jump-if-!= loop/disp32 + 3298 # if (*word-slice->start == "#") continue + 3299 # . eax = *word-slice->start + 3300 8b/-> *edx 0/r32/eax + 3301 8a/copy-byte *eax 0/r32/AL + 3302 81 4/subop/and %eax 0xff/imm32 + 3303 # . if (eax == '#') continue + 3304 3d/compare-eax-and 0x23/imm32/hash + 3305 0f 84/jump-if-= loop/disp32 + 3306 # if (slice-equal?(word-slice, "fn")) parse a function + 3307 { + 3308 $parse-mu:fn: + 3309 (slice-equal? %edx "fn") # => eax + 3310 3d/compare-eax-and 0/imm32/false + 3311 0f 84/jump-if-= break/disp32 + 3312 # var new-function/esi: (handle function) + 3313 68/push 0/imm32 + 3314 68/push 0/imm32 + 3315 89/<- %esi 4/r32/esp + 3316 # populate-mu-function(line, in, vars, new-function) + 3317 (allocate Heap *Function-size %esi) + 3318 # var new-function-addr/eax: (addr function) + 3319 (lookup *esi *(esi+4)) # => eax + 3320 (clear-stack %ebx) + 3321 (populate-mu-function-header %ecx %eax %ebx) + 3322 (populate-mu-function-body *(ebp+8) %eax %ebx) + 3323 # *curr-function = new-function + 3324 8b/-> *esi 0/r32/eax + 3325 89/<- *edi 0/r32/eax + 3326 8b/-> *(esi+4) 0/r32/eax + 3327 89/<- *(edi+4) 0/r32/eax + 3328 # curr-function = &new-function->next + 3329 # . var tmp/eax: (addr function) = lookup(new-function) + 3330 (lookup *esi *(esi+4)) # => eax + 3331 # . curr-function = &tmp->next + 3332 8d/copy-address *(eax+0x20) 7/r32/edi # Function-next + 3333 # reclaim new-function + 3334 81 0/subop/add %esp 8/imm32 + 3335 # + 3336 e9/jump $parse-mu:line-loop/disp32 + 3337 } + 3338 # if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition + 3339 { + 3340 $parse-mu:type: + 3341 (slice-equal? %edx "type") # => eax + 3342 3d/compare-eax-and 0/imm32 + 3343 0f 84/jump-if-= break/disp32 + 3344 (next-mu-token %ecx %edx) + 3345 # var type-id/eax: int + 3346 (pos-or-insert-slice Type-id %edx) # => eax + 3347 # spill + 3348 51/push-ecx + 3349 # var new-type/ecx: (handle typeinfo) + 3350 68/push 0/imm32 + 3351 68/push 0/imm32 + 3352 89/<- %ecx 4/r32/esp + 3353 (find-or-create-typeinfo %eax %ecx) + 3354 # + 3355 (lookup *ecx *(ecx+4)) # => eax + 3356 # TODO: ensure that 'line' has nothing else but '{' + 3357 #? (dump-typeinfos "=== aaa\n") + 3358 (populate-mu-type *(ebp+8) %eax) # => eax + 3359 #? (dump-typeinfos "=== zzz\n") + 3360 # reclaim new-type + 3361 81 0/subop/add %esp 8/imm32 + 3362 # restore + 3363 59/pop-to-ecx + 3364 e9/jump $parse-mu:line-loop/disp32 + 3365 } + 3366 # otherwise abort + 3367 e9/jump $parse-mu:error1/disp32 + 3368 } # end line loop + 3369 $parse-mu:end: + 3370 # . reclaim locals + 3371 81 0/subop/add %esp 0x630/imm32 + 3372 # . restore registers + 3373 5f/pop-to-edi + 3374 5e/pop-to-esi + 3375 5b/pop-to-ebx + 3376 5a/pop-to-edx + 3377 59/pop-to-ecx + 3378 58/pop-to-eax + 3379 # . epilogue + 3380 89/<- %esp 5/r32/ebp + 3381 5d/pop-to-ebp + 3382 c3/return + 3383 + 3384 $parse-mu:error1: + 3385 # error("unexpected top-level command: " word-slice "\n") + 3386 (write-buffered Stderr "unexpected top-level command: ") + 3387 (write-slice-buffered Stderr %edx) + 3388 (write-buffered Stderr "\n") + 3389 (flush Stderr) + 3390 # . syscall(exit, 1) + 3391 bb/copy-to-ebx 1/imm32 + 3392 b8/copy-to-eax 1/imm32/exit + 3393 cd/syscall 0x80/imm8 + 3394 # never gets here + 3395 + 3396 $parse-mu:error2: + 3397 # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n") + 3398 (print-int32-buffered Stderr *ebx) + 3399 (write-buffered Stderr " vars not reclaimed after fn '") + 3400 (write-slice-buffered Stderr *eax) # Function-name + 3401 (write-buffered Stderr "'\n") + 3402 (flush Stderr) + 3403 # . syscall(exit, 1) + 3404 bb/copy-to-ebx 1/imm32 + 3405 b8/copy-to-eax 1/imm32/exit + 3406 cd/syscall 0x80/imm8 + 3407 # never gets here + 3408 + 3409 # scenarios considered: + 3410 # ✗ fn foo # no block + 3411 # ✓ fn foo { + 3412 # ✗ fn foo { { + 3413 # ✗ fn foo { } + 3414 # ✗ fn foo { } { + 3415 # ✗ fn foo x { + 3416 # ✗ fn foo x: { + 3417 # ✓ fn foo x: int { + 3418 # ✓ fn foo x: int { + 3419 # ✓ fn foo x: int -> y/eax: int { + 3420 populate-mu-function-header: # first-line: (addr stream byte), out: (addr function), vars: (addr stack (handle var)) + 3421 # pseudocode: + 3422 # var name: slice + 3423 # next-mu-token(first-line, name) + 3424 # assert(name not in '{' '}' '->') + 3425 # out->name = slice-to-string(name) + 3426 # ## inouts + 3427 # while true + 3428 # ## name + 3429 # name = next-mu-token(first-line) + 3430 # if (name == '{') goto done + 3431 # if (name == '->') break + 3432 # assert(name != '}') + 3433 # var v: (handle var) = parse-var-with-type(name, first-line) + 3434 # assert(v->register == null) + 3435 # # v->block-depth is implicitly 0 + 3436 # out->inouts = append(v, out->inouts) + 3437 # push(vars, v) + 3438 # ## outputs + 3439 # while true + 3440 # ## name + 3441 # name = next-mu-token(first-line) + 3442 # assert(name not in '{' '}' '->') + 3443 # var v: (handle var) = parse-var-with-type(name, first-line) + 3444 # assert(v->register != null) + 3445 # out->outputs = append(v, out->outputs) + 3446 # done: + 3447 # + 3448 # . prologue + 3449 55/push-ebp + 3450 89/<- %ebp 4/r32/esp + 3451 # . save registers + 3452 50/push-eax + 3453 51/push-ecx + 3454 52/push-edx + 3455 53/push-ebx + 3456 57/push-edi + 3457 # edi = out + 3458 8b/-> *(ebp+0xc) 7/r32/edi + 3459 # var word-slice/ecx: slice + 3460 68/push 0/imm32/end + 3461 68/push 0/imm32/start + 3462 89/<- %ecx 4/r32/esp + 3463 # var v/ebx: (handle var) + 3464 68/push 0/imm32 + 3465 68/push 0/imm32 + 3466 89/<- %ebx 4/r32/esp + 3467 # read function name + 3468 (next-mu-token *(ebp+8) %ecx) + 3469 # error checking + 3470 # TODO: error if name starts with 'break' or 'loop' + 3471 # if (word-slice == '{') abort + 3472 (slice-equal? %ecx "{") # => eax + 3473 3d/compare-eax-and 0/imm32/false + 3474 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 + 3475 # if (word-slice == '->') abort + 3476 (slice-equal? %ecx "->") # => eax + 3477 3d/compare-eax-and 0/imm32/false + 3478 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 + 3479 # if (word-slice == '}') abort + 3480 (slice-equal? %ecx "}") # => eax + 3481 3d/compare-eax-and 0/imm32/false + 3482 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 + 3483 # save function name + 3484 (slice-to-string Heap %ecx %edi) # Function-name + 3485 # save function inouts + 3486 { + 3487 $populate-mu-function-header:check-for-inout: + 3488 (next-mu-token *(ebp+8) %ecx) + 3489 # if (word-slice == '{') goto done + 3490 (slice-equal? %ecx "{") # => eax + 3491 3d/compare-eax-and 0/imm32/false + 3492 0f 85/jump-if-!= $populate-mu-function-header:done/disp32 + 3493 # if (word-slice == '->') break + 3494 (slice-equal? %ecx "->") # => eax + 3495 3d/compare-eax-and 0/imm32/false + 3496 0f 85/jump-if-!= break/disp32 + 3497 # if (word-slice == '}') abort + 3498 (slice-equal? %ecx "}") # => eax + 3499 3d/compare-eax-and 0/imm32/false + 3500 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 + 3501 # v = parse-var-with-type(word-slice, first-line) + 3502 (parse-var-with-type %ecx *(ebp+8) %ebx) + 3503 # assert(v->register == null) + 3504 # . eax: (addr var) = lookup(v) + 3505 (lookup *ebx *(ebx+4)) # => eax + 3506 81 7/subop/compare *(eax+0x18) 0/imm32 # Var-register + 3507 0f 85/jump-if-!= $populate-mu-function-header:error2/disp32 + 3508 # v->block-depth is implicitly 0 + 3509 # + 3510 # out->inouts = append(v, out->inouts) + 3511 8d/copy-address *(edi+8) 0/r32/eax # Function-inouts + 3512 (append-list Heap *ebx *(ebx+4) *(edi+8) *(edi+0xc) %eax) # Function-inouts, Function-inouts + 3513 # push(vars, v) + 3514 (push *(ebp+0x10) *ebx) + 3515 (push *(ebp+0x10) *(ebx+4)) + 3516 # + 3517 e9/jump loop/disp32 + 3518 } + 3519 # save function outputs + 3520 { + 3521 $populate-mu-function-header:check-for-out: + 3522 (next-mu-token *(ebp+8) %ecx) + 3523 # if (word-slice == '{') break + 3524 (slice-equal? %ecx "{") # => eax + 3525 3d/compare-eax-and 0/imm32/false + 3526 0f 85/jump-if-!= break/disp32 + 3527 # if (word-slice == '->') abort + 3528 (slice-equal? %ecx "->") # => eax + 3529 3d/compare-eax-and 0/imm32/false + 3530 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 + 3531 # if (word-slice == '}') abort + 3532 (slice-equal? %ecx "}") # => eax + 3533 3d/compare-eax-and 0/imm32/false + 3534 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 + 3535 # v = parse-var-with-type(word-slice, first-line) + 3536 (parse-var-with-type %ecx *(ebp+8) %ebx) + 3537 # assert(var->register != null) + 3538 # . eax: (addr var) = lookup(v) + 3539 (lookup *ebx *(ebx+4)) # => eax + 3540 81 7/subop/compare *(eax+0x18) 0/imm32 # Var-register + 3541 0f 84/jump-if-= $populate-mu-function-header:error3/disp32 + 3542 # out->outputs = append(v, out->outputs) + 3543 8d/copy-address *(edi+0x10) 0/r32/eax # Function-outputs + 3544 (append-list Heap *ebx *(ebx+4) *(edi+0x10) *(edi+0x14) %eax) # Function-outputs, Function-outputs + 3545 # + 3546 e9/jump loop/disp32 + 3547 } + 3548 $populate-mu-function-header:done: + 3549 (check-no-tokens-left *(ebp+8)) + 3550 $populate-mu-function-header:end: + 3551 # . reclaim locals + 3552 81 0/subop/add %esp 0x10/imm32 + 3553 # . restore registers + 3554 5f/pop-to-edi + 3555 5b/pop-to-ebx + 3556 5a/pop-to-edx + 3557 59/pop-to-ecx + 3558 58/pop-to-eax + 3559 # . epilogue + 3560 89/<- %esp 5/r32/ebp + 3561 5d/pop-to-ebp + 3562 c3/return + 3563 + 3564 $populate-mu-function-header:error1: + 3565 # error("function header not in form 'fn <name> {'") + 3566 (write-buffered Stderr "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '") + 3567 (flush Stderr) + 3568 (rewind-stream *(ebp+8)) + 3569 (write-stream 2 *(ebp+8)) + 3570 (write-buffered Stderr "'\n") + 3571 (flush Stderr) + 3572 # . syscall(exit, 1) + 3573 bb/copy-to-ebx 1/imm32 + 3574 b8/copy-to-eax 1/imm32/exit + 3575 cd/syscall 0x80/imm8 + 3576 # never gets here + 3577 + 3578 $populate-mu-function-header:error2: + 3579 # error("function input '" var "' cannot be in a register") + 3580 (write-buffered Stderr "function input '") + 3581 (write-buffered Stderr *ebx) # Var-name + 3582 (write-buffered Stderr "' cannot be in a register") + 3583 (flush Stderr) + 3584 # . syscall(exit, 1) + 3585 bb/copy-to-ebx 1/imm32 + 3586 b8/copy-to-eax 1/imm32/exit + 3587 cd/syscall 0x80/imm8 + 3588 # never gets here + 3589 + 3590 $populate-mu-function-header:error3: + 3591 # error("function input '" var "' must be in a register") + 3592 (write-buffered Stderr "function input '") + 3593 (lookup *ebx *(ebx+4)) # => eax + 3594 (lookup *eax *(eax+4)) # Var-name Var-name => eax + 3595 (write-buffered Stderr %eax) + 3596 (write-buffered Stderr "' must be in a register, in instruction '") + 3597 (flush Stderr) + 3598 (rewind-stream *(ebp+8)) + 3599 (write-stream 2 *(ebp+8)) + 3600 (write-buffered Stderr "'\n") + 3601 (flush Stderr) + 3602 # . syscall(exit, 1) + 3603 bb/copy-to-ebx 1/imm32 + 3604 b8/copy-to-eax 1/imm32/exit + 3605 cd/syscall 0x80/imm8 + 3606 # never gets here + 3607 + 3608 test-function-header-with-arg: + 3609 # . prologue + 3610 55/push-ebp + 3611 89/<- %ebp 4/r32/esp + 3612 # setup + 3613 (clear-stream _test-input-stream) + 3614 (write _test-input-stream "foo n: int {\n") + 3615 # var result/ecx: function + 3616 2b/subtract *Function-size 4/r32/esp + 3617 89/<- %ecx 4/r32/esp + 3618 (zero-out %ecx *Function-size) + 3619 # var vars/ebx: (stack (handle var) 16) + 3620 81 5/subop/subtract %esp 0x80/imm32 + 3621 68/push 0x80/imm32/size + 3622 68/push 0/imm32/top + 3623 89/<- %ebx 4/r32/esp + 3624 # convert + 3625 (populate-mu-function-header _test-input-stream %ecx %ebx) + 3626 # check result->name + 3627 (lookup *ecx *(ecx+4)) # Function-name Function-name => eax + 3628 (check-strings-equal %eax "foo" "F - test-function-header-with-arg/name") + 3629 # var v/edx: (addr var) = result->inouts->value + 3630 (lookup *(ecx+8) *(ecx+0xc)) # Function-inouts Function-inouts => eax + 3631 (lookup *eax *(eax+4)) # List-value List-value => eax + 3632 89/<- %edx 0/r32/eax + 3633 # check v->name + 3634 (lookup *edx *(edx+4)) # Var-name Var-name => eax + 3635 (check-strings-equal %eax "n" "F - test-function-header-with-arg/inout:0") + 3636 # check v->type + 3637 (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + 3638 (check-ints-equal *eax 1 "F - test-function-header-with-arg/inout:0/type:0") # Tree-is-atom + 3639 (check-ints-equal *(eax+4) 1 "F - test-function-header-with-arg/inout:0/type:1") # Tree-value + 3640 (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-arg/inout:0/type:2") # Tree-right + 3641 # . epilogue + 3642 89/<- %esp 5/r32/ebp + 3643 5d/pop-to-ebp + 3644 c3/return + 3645 + 3646 test-function-header-with-multiple-args: + 3647 # . prologue + 3648 55/push-ebp + 3649 89/<- %ebp 4/r32/esp + 3650 # setup + 3651 (clear-stream _test-input-stream) + 3652 (write _test-input-stream "foo a: int, b: int c: int {\n") + 3653 # result/ecx: function + 3654 2b/subtract *Function-size 4/r32/esp + 3655 89/<- %ecx 4/r32/esp + 3656 (zero-out %ecx *Function-size) + 3657 # var vars/ebx: (stack (handle var) 16) + 3658 81 5/subop/subtract %esp 0x80/imm32 + 3659 68/push 0x80/imm32/size + 3660 68/push 0/imm32/top + 3661 89/<- %ebx 4/r32/esp + 3662 # convert + 3663 (populate-mu-function-header _test-input-stream %ecx %ebx) + 3664 # check result->name + 3665 (lookup *ecx *(ecx+4)) # Function-name Function-name => eax + 3666 (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args/name") + 3667 # var inouts/edx: (addr list var) = lookup(result->inouts) + 3668 (lookup *(ecx+8) *(ecx+0xc)) # Function-inouts Function-inouts => eax + 3669 89/<- %edx 0/r32/eax + 3670 $test-function-header-with-multiple-args:inout0: + 3671 # var v/ebx: (addr var) = lookup(inouts->value) + 3672 (lookup *edx *(edx+4)) # List-value List-value => eax + 3673 89/<- %ebx 0/r32/eax + 3674 # check v->name + 3675 (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + 3676 (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args/inout:0") # Var-name + 3677 # check v->type + 3678 (lookup *(ebx+8) *(ebx+0xc)) # Var-type Var-type => eax + 3679 (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:0/type:0") # Tree-is-atom + 3680 (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:0/type:1") # Tree-value + 3681 (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:0/type:2") # Tree-right + 3682 $test-function-header-with-multiple-args:inout1: + 3683 # inouts = lookup(inouts->next) + 3684 (lookup *(edx+8) *(edx+0xc)) # List-next List-next => eax + 3685 89/<- %edx 0/r32/eax + 3686 # v = lookup(inouts->value) + 3687 (lookup *edx *(edx+4)) # List-value List-value => eax + 3688 89/<- %ebx 0/r32/eax + 3689 # check v->name + 3690 (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + 3691 (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args/inout:1") # Var-name + 3692 # check v->type + 3693 (lookup *(ebx+8) *(ebx+0xc)) # Var-type Var-type => eax + 3694 (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:1/type:0") # Tree-is-atom + 3695 (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:1/type:1") # Tree-value + 3696 (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:1/type:2") # Tree-right + 3697 $test-function-header-with-multiple-args:inout2: + 3698 # inouts = lookup(inouts->next) + 3699 (lookup *(edx+8) *(edx+0xc)) # List-next List-next => eax + 3700 89/<- %edx 0/r32/eax + 3701 # v = lookup(inouts->value) + 3702 (lookup *edx *(edx+4)) # List-value List-value => eax + 3703 89/<- %ebx 0/r32/eax + 3704 # check v->name + 3705 (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + 3706 (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args/inout:2") # Var-name + 3707 # check v->type + 3708 (lookup *(ebx+8) *(ebx+0xc)) # Var-type Var-type => eax + 3709 (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:2/type:0") # Tree-is-atom + 3710 (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:2/type:1") # Tree-value + 3711 (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:2/type:2") # Tree-right + 3712 # . epilogue + 3713 89/<- %esp 5/r32/ebp + 3714 5d/pop-to-ebp + 3715 c3/return + 3716 + 3717 test-function-header-with-multiple-args-and-outputs: + 3718 # . prologue + 3719 55/push-ebp + 3720 89/<- %ebp 4/r32/esp + 3721 # setup + 3722 (clear-stream _test-input-stream) + 3723 (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n") + 3724 # result/ecx: function + 3725 2b/subtract *Function-size 4/r32/esp + 3726 89/<- %ecx 4/r32/esp + 3727 (zero-out %ecx *Function-size) + 3728 # var vars/ebx: (stack (handle var) 16) + 3729 81 5/subop/subtract %esp 0x80/imm32 + 3730 68/push 0x80/imm32/size + 3731 68/push 0/imm32/top + 3732 89/<- %ebx 4/r32/esp + 3733 # convert + 3734 (populate-mu-function-header _test-input-stream %ecx %ebx) + 3735 # check result->name + 3736 (lookup *ecx *(ecx+4)) # Function-name Function-name => eax + 3737 (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args-and-outputs/name") + 3738 # var inouts/edx: (addr list var) = lookup(result->inouts) + 3739 (lookup *(ecx+8) *(ecx+0xc)) # Function-inouts Function-inouts => eax + 3740 89/<- %edx 0/r32/eax + 3741 $test-function-header-with-multiple-args-and-outputs:inout0: + 3742 # var v/ebx: (addr var) = lookup(inouts->value) + 3743 (lookup *edx *(edx+4)) # List-value List-value => eax + 3744 89/<- %ebx 0/r32/eax + 3745 # check v->name + 3746 (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + 3747 (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0") + 3748 # check v->type + 3749 (lookup *(ebx+8) *(ebx+0xc)) # Var-type Var-type => eax + 3750 (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0") # Tree-is-atom + 3751 (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1") # Tree-value + 3752 (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:2") # Tree-right + 3753 $test-function-header-with-multiple-args-and-outputs:inout1: + 3754 # inouts = lookup(inouts->next) + 3755 (lookup *(edx+8) *(edx+0xc)) # List-next List-next => eax + 3756 89/<- %edx 0/r32/eax + 3757 # v = lookup(inouts->value) + 3758 (lookup *edx *(edx+4)) # List-value List-value => eax + 3759 89/<- %ebx 0/r32/eax + 3760 # check v->name + 3761 (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + 3762 (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1") + 3763 # check v->type + 3764 (lookup *(ebx+8) *(ebx+0xc)) # Var-type Var-type => eax + 3765 (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0") # Tree-is-atom + 3766 (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1") # Tree-value + 3767 (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:2") # Tree-right + 3768 $test-function-header-with-multiple-args-and-outputs:inout2: + 3769 # inouts = lookup(inouts->next) + 3770 (lookup *(edx+8) *(edx+0xc)) # List-next List-next => eax + 3771 89/<- %edx 0/r32/eax + 3772 # v = lookup(inouts->value) + 3773 (lookup *edx *(edx+4)) # List-value List-value => eax + 3774 89/<- %ebx 0/r32/eax + 3775 # check v->name + 3776 (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + 3777 (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2") + 3778 # check v->type + 3779 (lookup *(ebx+8) *(ebx+0xc)) # Var-type Var-type => eax + 3780 (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0") # Tree-is-atom + 3781 (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1") # Tree-value + 3782 (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:2") # Tree-right + 3783 $test-function-header-with-multiple-args-and-outputs:out0: + 3784 # var outputs/edx: (addr list var) = lookup(result->outputs) + 3785 (lookup *(ecx+0x10) *(ecx+0x14)) # Function-outputs Function-outputs => eax + 3786 89/<- %edx 0/r32/eax + 3787 # v = lookup(outputs->value) + 3788 (lookup *edx *(edx+4)) # List-value List-value => eax + 3789 89/<- %ebx 0/r32/eax + 3790 # check v->name + 3791 (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + 3792 (check-strings-equal %eax "x" "F - test-function-header-with-multiple-args-and-outputs/output:0") + 3793 # check v->register + 3794 (lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax + 3795 (check-strings-equal %eax "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") + 3796 # check v->type + 3797 (lookup *(ebx+8) *(ebx+0xc)) # Var-type Var-type => eax + 3798 (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:0") # Tree-is-atom + 3799 (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Tree-value + 3800 (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:2") # Tree-right + 3801 $test-function-header-with-multiple-args-and-outputs:out1: + 3802 # outputs = lookup(outputs->next) + 3803 (lookup *(edx+8) *(edx+0xc)) # List-next List-next => eax + 3804 89/<- %edx 0/r32/eax + 3805 # v = lookup(inouts->value) + 3806 (lookup *edx *(edx+4)) # List-value List-value => eax + 3807 89/<- %ebx 0/r32/eax + 3808 # check v->name + 3809 (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + 3810 (check-strings-equal %eax "y" "F - test-function-header-with-multiple-args-and-outputs/output:1") + 3811 # check v->register + 3812 (lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax + 3813 (check-strings-equal %eax "edx" "F - test-function-header-with-multiple-args-and-outputs/output:1/register") + 3814 # check v->type + 3815 (lookup *(ebx+8) *(ebx+0xc)) # Var-type Var-type => eax + 3816 (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:0") # Tree-is-atom + 3817 (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Tree-value + 3818 (check-ints-equal *(eax+0c) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:2") # Tree-right + 3819 # . epilogue + 3820 89/<- %esp 5/r32/ebp + 3821 5d/pop-to-ebp + 3822 c3/return + 3823 + 3824 # format for variables with types + 3825 # x: int + 3826 # x: int, + 3827 # x/eax: int + 3828 # x/eax: int, + 3829 # ignores at most one trailing comma + 3830 # WARNING: modifies name + 3831 parse-var-with-type: # name: (addr slice), first-line: (addr stream byte), out: (addr handle var) + 3832 # pseudocode: + 3833 # var s: slice + 3834 # if (!slice-ends-with(name, ":")) + 3835 # abort + 3836 # --name->end to skip ':' + 3837 # next-token-from-slice(name->start, name->end, '/', s) + 3838 # new-var-from-slice(s, out) + 3839 # ## register + 3840 # next-token-from-slice(s->end, name->end, '/', s) + 3841 # if (!slice-empty?(s)) + 3842 # out->register = slice-to-string(s) + 3843 # ## type + 3844 # var type: (handle tree type-id) = parse-type(first-line) + 3845 # out->type = type + 3846 # + 3847 # . prologue + 3848 55/push-ebp + 3849 89/<- %ebp 4/r32/esp + 3850 # . save registers + 3851 50/push-eax + 3852 51/push-ecx + 3853 52/push-edx + 3854 53/push-ebx + 3855 56/push-esi + 3856 57/push-edi + 3857 # esi = name + 3858 8b/-> *(ebp+8) 6/r32/esi + 3859 # if (!slice-ends-with?(name, ":")) abort + 3860 8b/-> *(esi+4) 1/r32/ecx # Slice-end + 3861 49/decrement-ecx + 3862 8a/copy-byte *ecx 1/r32/CL + 3863 81 4/subop/and %ecx 0xff/imm32 + 3864 81 7/subop/compare %ecx 0x3a/imm32/colon + 3865 0f 85/jump-if-!= $parse-var-with-type:abort/disp32 + 3866 # --name->end to skip ':' + 3867 ff 1/subop/decrement *(esi+4) + 3868 # var s/ecx: slice + 3869 68/push 0/imm32/end + 3870 68/push 0/imm32/start + 3871 89/<- %ecx 4/r32/esp + 3872 $parse-var-with-type:parse-name: + 3873 (next-token-from-slice *esi *(esi+4) 0x2f %ecx) # Slice-start, Slice-end, '/' + 3874 $parse-var-with-type:create-var: + 3875 # new-var-from-slice(s, out) + 3876 (new-var-from-slice Heap %ecx *(ebp+0x10)) + 3877 # save out->register + 3878 $parse-var-with-type:save-register: + 3879 # . var out-addr/edi: (addr var) = lookup(*out) + 3880 8b/-> *(ebp+0x10) 7/r32/edi + 3881 (lookup *edi *(edi+4)) # => eax + 3882 89/<- %edi 0/r32/eax + 3883 # . s = next-token(...) + 3884 (next-token-from-slice *(ecx+4) *(esi+4) 0x2f %ecx) # s->end, name->end, '/' + 3885 # . if (!slice-empty?(s)) out->register = slice-to-string(s) + 3886 { + 3887 $parse-var-with-type:write-register: + 3888 (slice-empty? %ecx) # => eax + 3889 3d/compare-eax-and 0/imm32/false + 3890 75/jump-if-!= break/disp8 + 3891 # out->register = slice-to-string(s) + 3892 8d/copy-address *(edi+0x18) 0/r32/eax # Var-register + 3893 (slice-to-string Heap %ecx %eax) + 3894 } + 3895 $parse-var-with-type:save-type: + 3896 8d/copy-address *(edi+8) 0/r32/eax # Var-type + 3897 (parse-type Heap *(ebp+0xc) %eax) + 3898 $parse-var-with-type:end: + 3899 # . reclaim locals + 3900 81 0/subop/add %esp 8/imm32 3901 # . restore registers - 3902 5a/pop-to-edx - 3903 59/pop-to-ecx - 3904 # . epilogue - 3905 89/<- %esp 5/r32/ebp - 3906 5d/pop-to-ebp - 3907 c3/return - 3908 - 3909 next-mu-token: # in: (addr stream byte), out: (addr slice) - 3910 # pseudocode: - 3911 # start: - 3912 # skip-chars-matching-whitespace(in) - 3913 # if in->read >= in->write # end of in - 3914 # out = {0, 0} - 3915 # return - 3916 # out->start = &in->data[in->read] - 3917 # var curr-byte/eax: byte = in->data[in->read] - 3918 # if curr->byte == ',' # comment token - 3919 # ++in->read - 3920 # goto start - 3921 # if curr-byte == '#' # comment - 3922 # goto done # treat as eof - 3923 # if curr-byte == '"' # string literal - 3924 # skip-string(in) - 3925 # goto done # no metadata - 3926 # if curr-byte == '(' - 3927 # ++in->read - 3928 # goto done - 3929 # if curr-byte == ')' - 3930 # ++in->read - 3931 # goto done - 3932 # # read a word - 3933 # while true - 3934 # if in->read >= in->write - 3935 # break - 3936 # curr-byte = in->data[in->read] - 3937 # if curr-byte == ' ' - 3938 # break - 3939 # if curr-byte == '\r' - 3940 # break - 3941 # if curr-byte == '\n' - 3942 # break - 3943 # if curr-byte == '(' - 3944 # break - 3945 # if curr-byte == ')' - 3946 # break - 3947 # if curr-byte == ',' - 3948 # break - 3949 # ++in->read - 3950 # done: - 3951 # out->end = &in->data[in->read] - 3952 # - 3953 # . prologue - 3954 55/push-ebp - 3955 89/<- %ebp 4/r32/esp - 3956 # . save registers - 3957 50/push-eax - 3958 51/push-ecx - 3959 56/push-esi - 3960 57/push-edi - 3961 # esi = in - 3962 8b/-> *(ebp+8) 6/r32/esi - 3963 # edi = out - 3964 8b/-> *(ebp+0xc) 7/r32/edi - 3965 $next-mu-token:start: - 3966 (skip-chars-matching-whitespace %esi) - 3967 $next-mu-token:check0: - 3968 # if (in->read >= in->write) return out = {0, 0} - 3969 # . ecx = in->read - 3970 8b/-> *(esi+4) 1/r32/ecx - 3971 # . if (ecx >= in->write) return out = {0, 0} - 3972 3b/compare<- *esi 1/r32/ecx - 3973 c7 0/subop/copy *edi 0/imm32 - 3974 c7 0/subop/copy *(edi+4) 0/imm32 - 3975 0f 8d/jump-if->= $next-mu-token:end/disp32 - 3976 # out->start = &in->data[in->read] - 3977 8d/copy-address *(esi+ecx+0xc) 0/r32/eax - 3978 89/<- *edi 0/r32/eax - 3979 # var curr-byte/eax: byte = in->data[in->read] - 3980 31/xor-with %eax 0/r32/eax - 3981 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL - 3982 { - 3983 $next-mu-token:check-for-comma: - 3984 # if (curr-byte != ',') break - 3985 3d/compare-eax-and 0x2c/imm32/comma - 3986 75/jump-if-!= break/disp8 - 3987 # ++in->read - 3988 ff 0/subop/increment *(esi+4) - 3989 # restart - 3990 e9/jump $next-mu-token:start/disp32 - 3991 } - 3992 { - 3993 $next-mu-token:check-for-comment: - 3994 # if (curr-byte != '#') break - 3995 3d/compare-eax-and 0x23/imm32/pound - 3996 75/jump-if-!= break/disp8 - 3997 # return eof - 3998 e9/jump $next-mu-token:done/disp32 - 3999 } - 4000 { - 4001 $next-mu-token:check-for-string-literal: - 4002 # if (curr-byte != '"') break - 4003 3d/compare-eax-and 0x22/imm32/dquote - 4004 75/jump-if-!= break/disp8 - 4005 (skip-string %esi) - 4006 # return - 4007 e9/jump $next-mu-token:done/disp32 - 4008 } - 4009 { - 4010 $next-mu-token:check-for-open-paren: - 4011 # if (curr-byte != '(') break - 4012 3d/compare-eax-and 0x28/imm32/open-paren - 4013 75/jump-if-!= break/disp8 - 4014 # ++in->read - 4015 ff 0/subop/increment *(esi+4) - 4016 # return - 4017 e9/jump $next-mu-token:done/disp32 - 4018 } - 4019 { - 4020 $next-mu-token:check-for-close-paren: - 4021 # if (curr-byte != ')') break - 4022 3d/compare-eax-and 0x29/imm32/close-paren - 4023 75/jump-if-!= break/disp8 - 4024 # ++in->read - 4025 ff 0/subop/increment *(esi+4) - 4026 # return - 4027 e9/jump $next-mu-token:done/disp32 - 4028 } - 4029 { - 4030 $next-mu-token:regular-word-without-metadata: - 4031 # if (in->read >= in->write) break - 4032 # . ecx = in->read - 4033 8b/-> *(esi+4) 1/r32/ecx - 4034 # . if (ecx >= in->write) break - 4035 3b/compare<- *esi 1/r32/ecx - 4036 7d/jump-if->= break/disp8 - 4037 # var c/eax: byte = in->data[in->read] - 4038 31/xor-with %eax 0/r32/eax - 4039 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL - 4040 # if (c == ' ') break - 4041 3d/compare-eax-and 0x20/imm32/space - 4042 74/jump-if-= break/disp8 - 4043 # if (c == '\r') break - 4044 3d/compare-eax-and 0xd/imm32/carriage-return - 4045 74/jump-if-= break/disp8 - 4046 # if (c == '\n') break - 4047 3d/compare-eax-and 0xa/imm32/newline - 4048 74/jump-if-= break/disp8 - 4049 # if (c == '(') break - 4050 3d/compare-eax-and 0x28/imm32/open-paren - 4051 0f 84/jump-if-= break/disp32 - 4052 # if (c == ')') break - 4053 3d/compare-eax-and 0x29/imm32/close-paren - 4054 0f 84/jump-if-= break/disp32 - 4055 # if (c == ',') break - 4056 3d/compare-eax-and 0x2c/imm32/comma - 4057 0f 84/jump-if-= break/disp32 - 4058 # ++in->read - 4059 ff 0/subop/increment *(esi+4) - 4060 # - 4061 e9/jump loop/disp32 - 4062 } - 4063 $next-mu-token:done: - 4064 # out->end = &in->data[in->read] - 4065 8b/-> *(esi+4) 1/r32/ecx - 4066 8d/copy-address *(esi+ecx+0xc) 0/r32/eax - 4067 89/<- *(edi+4) 0/r32/eax - 4068 $next-mu-token:end: - 4069 # . restore registers - 4070 5f/pop-to-edi - 4071 5e/pop-to-esi - 4072 59/pop-to-ecx - 4073 58/pop-to-eax - 4074 # . epilogue - 4075 89/<- %esp 5/r32/ebp - 4076 5d/pop-to-ebp - 4077 c3/return - 4078 - 4079 pos-or-insert-slice: # arr: (addr stream (handle array byte)), s: (addr slice) -> index/eax: int - 4080 # . prologue - 4081 55/push-ebp - 4082 89/<- %ebp 4/r32/esp - 4083 # if (pos-slice(arr, s) != -1) return it - 4084 (pos-slice *(ebp+8) *(ebp+0xc)) # => eax - 4085 3d/compare-eax-and -1/imm32 - 4086 75/jump-if-!= $pos-or-insert-slice:end/disp8 - 4087 $pos-or-insert-slice:insert: - 4088 (slice-to-string Heap *(ebp+0xc)) # => eax - 4089 (write-int *(ebp+8) %eax) - 4090 (pos-slice *(ebp+8) *(ebp+0xc)) # => eax - 4091 $pos-or-insert-slice:end: - 4092 # . epilogue - 4093 89/<- %esp 5/r32/ebp - 4094 5d/pop-to-ebp - 4095 c3/return - 4096 - 4097 # return the index in an array of strings matching 's', -1 if not found - 4098 # index is denominated in elements, not bytes - 4099 pos-slice: # arr: (addr stream (handle array byte)), s: (addr slice) -> index/eax: int - 4100 # . prologue - 4101 55/push-ebp - 4102 89/<- %ebp 4/r32/esp - 4103 # . save registers - 4104 51/push-ecx - 4105 52/push-edx - 4106 53/push-ebx - 4107 56/push-esi - 4108 #? (write-buffered Stderr "pos-slice: ") - 4109 #? (write-slice-buffered Stderr *(ebp+0xc)) - 4110 #? (write-buffered Stderr "\n") - 4111 #? (flush Stderr) - 4112 # esi = arr - 4113 8b/-> *(ebp+8) 6/r32/esi - 4114 # var index/ecx: int = 0 - 4115 b9/copy-to-ecx 0/imm32 - 4116 # var curr/edx: (addr (addr array byte)) = arr->data - 4117 8d/copy-address *(esi+0xc) 2/r32/edx - 4118 # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write] - 4119 8b/-> *esi 3/r32/ebx - 4120 8d/copy-address *(esi+ebx+0xc) 3/r32/ebx - 4121 { - 4122 #? (write-buffered Stderr " ") - 4123 #? (print-int32-buffered Stderr %ecx) - 4124 #? (write-buffered Stderr "\n") - 4125 #? (flush Stderr) - 4126 # if (curr >= max) return -1 - 4127 39/compare %edx 3/r32/ebx - 4128 b8/copy-to-eax -1/imm32 - 4129 73/jump-if-addr>= $pos-slice:end/disp8 - 4130 # if (slice-equal?(s, *curr)) break - 4131 (slice-equal? *(ebp+0xc) *edx) # => eax - 4132 3d/compare-eax-and 0/imm32/false - 4133 75/jump-if-!= break/disp8 - 4134 # ++index - 4135 41/increment-ecx - 4136 # curr += 4 - 4137 81 0/subop/add %edx 4/imm32 - 4138 # - 4139 eb/jump loop/disp8 - 4140 } - 4141 # return index - 4142 89/<- %eax 1/r32/ecx - 4143 $pos-slice:end: - 4144 #? (write-buffered Stderr "=> ") - 4145 #? (print-int32-buffered Stderr %eax) - 4146 #? (write-buffered Stderr "\n") - 4147 # . restore registers - 4148 5e/pop-to-esi - 4149 5b/pop-to-ebx - 4150 5a/pop-to-edx - 4151 59/pop-to-ecx - 4152 # . epilogue - 4153 89/<- %esp 5/r32/ebp - 4154 5d/pop-to-ebp - 4155 c3/return - 4156 - 4157 test-parse-var-with-type: - 4158 # . prologue - 4159 55/push-ebp - 4160 89/<- %ebp 4/r32/esp - 4161 # (eax..ecx) = "x:" - 4162 b8/copy-to-eax "x:"/imm32 - 4163 8b/-> *eax 1/r32/ecx - 4164 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 4165 05/add-to-eax 4/imm32 - 4166 # var slice/ecx: slice = {eax, ecx} - 4167 51/push-ecx - 4168 50/push-eax - 4169 89/<- %ecx 4/r32/esp - 4170 # _test-input-stream contains "int" - 4171 (clear-stream _test-input-stream) - 4172 (write _test-input-stream "int") - 4173 # - 4174 (parse-var-with-type %ecx _test-input-stream) - 4175 8b/-> *eax 2/r32/edx # Var-name - 4176 (check-strings-equal %edx "x" "F - test-parse-var-with-type/name") - 4177 8b/-> *(eax+4) 2/r32/edx # Var-type - 4178 (check-ints-equal *edx 1 "F - test-parse-var-with-type/type:0") # Tree-is-atom - 4179 (check-ints-equal *(edx+4) 1 "F - test-parse-var-with-type/type:1") # Tree-value - 4180 (check-ints-equal *(edx+8) 0 "F - test-parse-var-with-type/type:2") # Tree-right - 4181 # . epilogue - 4182 89/<- %esp 5/r32/ebp - 4183 5d/pop-to-ebp - 4184 c3/return - 4185 - 4186 test-parse-var-with-type-and-register: - 4187 # . prologue - 4188 55/push-ebp - 4189 89/<- %ebp 4/r32/esp - 4190 # (eax..ecx) = "x/eax:" - 4191 b8/copy-to-eax "x/eax:"/imm32 - 4192 8b/-> *eax 1/r32/ecx - 4193 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 4194 05/add-to-eax 4/imm32 - 4195 # var slice/ecx: slice = {eax, ecx} - 4196 51/push-ecx - 4197 50/push-eax - 4198 89/<- %ecx 4/r32/esp - 4199 # _test-input-stream contains "int" - 4200 (clear-stream _test-input-stream) - 4201 (write _test-input-stream "int") - 4202 # - 4203 (parse-var-with-type %ecx _test-input-stream) - 4204 8b/-> *eax 2/r32/edx # Var-name - 4205 (check-strings-equal %edx "x" "F - test-parse-var-with-type-and-register/name") - 4206 8b/-> *(eax+0x10) 2/r32/edx # Var-register - 4207 (check-strings-equal %edx "eax" "F - test-parse-var-with-type-and-register/register") - 4208 8b/-> *(eax+4) 2/r32/edx # Var-type - 4209 (check-ints-equal *edx 1 "F - test-parse-var-with-type-and-register/type:0") # Tree-is-atom - 4210 (check-ints-equal *(edx+4) 1 "F - test-parse-var-with-type-and-register/type:1") # Tree-left - 4211 (check-ints-equal *(edx+8) 0 "F - test-parse-var-with-type-and-register/type:2") # Tree-right - 4212 # . epilogue - 4213 89/<- %esp 5/r32/ebp - 4214 5d/pop-to-ebp - 4215 c3/return - 4216 - 4217 test-parse-var-with-trailing-characters: - 4218 # . prologue - 4219 55/push-ebp - 4220 89/<- %ebp 4/r32/esp - 4221 # (eax..ecx) = "x:" - 4222 b8/copy-to-eax "x:"/imm32 - 4223 8b/-> *eax 1/r32/ecx - 4224 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 4225 05/add-to-eax 4/imm32 - 4226 # var slice/ecx: slice = {eax, ecx} - 4227 51/push-ecx - 4228 50/push-eax - 4229 89/<- %ecx 4/r32/esp - 4230 # _test-input-stream contains "int," - 4231 (clear-stream _test-input-stream) - 4232 (write _test-input-stream "int,") - 4233 # - 4234 (parse-var-with-type %ecx _test-input-stream) - 4235 8b/-> *eax 2/r32/edx # Var-name - 4236 (check-strings-equal %edx "x" "F - test-parse-var-with-trailing-characters/name") - 4237 8b/-> *(eax+0x10) 2/r32/edx # Var-register - 4238 (check-ints-equal %edx 0 "F - test-parse-var-with-trailing-characters/register") - 4239 8b/-> *(eax+4) 2/r32/edx # Var-type - 4240 (check-ints-equal *edx 1 "F - test-parse-var-with-trailing-characters/type:0") # Tree-is-atom - 4241 (check-ints-equal *(edx+4) 1 "F - test-parse-var-with-trailing-characters/type:1") # Tree-left - 4242 (check-ints-equal *(edx+8) 0 "F - test-parse-var-with-trailing-characters/type:1") # Tree-right - 4243 # . epilogue - 4244 89/<- %esp 5/r32/ebp - 4245 5d/pop-to-ebp - 4246 c3/return - 4247 - 4248 test-parse-var-with-register-and-trailing-characters: - 4249 # . prologue - 4250 55/push-ebp - 4251 89/<- %ebp 4/r32/esp - 4252 # (eax..ecx) = "x/eax:" - 4253 b8/copy-to-eax "x/eax:"/imm32 - 4254 8b/-> *eax 1/r32/ecx - 4255 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 4256 05/add-to-eax 4/imm32 - 4257 # var slice/ecx: slice = {eax, ecx} - 4258 51/push-ecx - 4259 50/push-eax - 4260 89/<- %ecx 4/r32/esp - 4261 # _test-input-stream contains "int," - 4262 (clear-stream _test-input-stream) - 4263 (write _test-input-stream "int,") - 4264 # - 4265 (parse-var-with-type %ecx _test-input-stream) - 4266 8b/-> *eax 2/r32/edx # Var-name - 4267 (check-strings-equal %edx "x" "F - test-parse-var-with-register-and-trailing-characters/name") - 4268 8b/-> *(eax+0x10) 2/r32/edx # Var-register - 4269 (check-strings-equal %edx "eax" "F - test-parse-var-with-register-and-trailing-characters/register") - 4270 8b/-> *(eax+4) 2/r32/edx # Var-type - 4271 (check-ints-equal *edx 1 "F - test-parse-var-with-register-and-trailing-characters/type:0") # Tree-is-atom - 4272 (check-ints-equal *(edx+4) 1 "F - test-parse-var-with-register-and-trailing-characters/type:1") # Tree-left - 4273 (check-ints-equal *(edx+8) 0 "F - test-parse-var-with-register-and-trailing-characters/type:2") # Tree-right - 4274 # . epilogue - 4275 89/<- %esp 5/r32/ebp - 4276 5d/pop-to-ebp - 4277 c3/return - 4278 - 4279 test-parse-var-with-compound-type: - 4280 # . prologue - 4281 55/push-ebp - 4282 89/<- %ebp 4/r32/esp - 4283 # (eax..ecx) = "x:" - 4284 b8/copy-to-eax "x:"/imm32 - 4285 8b/-> *eax 1/r32/ecx - 4286 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 4287 05/add-to-eax 4/imm32 - 4288 # var slice/ecx: slice = {eax, ecx} - 4289 51/push-ecx - 4290 50/push-eax - 4291 89/<- %ecx 4/r32/esp - 4292 # _test-input-stream contains "(addr int)" - 4293 (clear-stream _test-input-stream) - 4294 (write _test-input-stream "(addr int)") - 4295 # - 4296 (parse-var-with-type %ecx _test-input-stream) - 4297 8b/-> *eax 2/r32/edx # Var-name - 4298 (check-strings-equal %edx "x" "F - test-parse-var-with-compound-type/name") - 4299 8b/-> *(eax+0x10) 2/r32/edx # Var-register - 4300 (check-ints-equal %edx 0 "F - test-parse-var-with-compound-type/register") - 4301 # var type/edx: (handle tree type-id) = var->type - 4302 8b/-> *(eax+4) 2/r32/edx # Var-type - 4303 # type is a non-atom - 4304 (check-ints-equal *edx 0 "F - test-parse-var-with-compound-type/type:0") # Tree-is-atom - 4305 # type->left == atom(addr) - 4306 8b/-> *(edx+4) 0/r32/eax # Tree-left - 4307 (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:1") # Tree-is-atom - 4308 (check-ints-equal *(eax+4) 2 "F - test-parse-var-with-compound-type/type:2") # Tree-value - 4309 # type->right->left == atom(int) - 4310 8b/-> *(edx+8) 2/r32/edx # Tree-right - 4311 8b/-> *(edx+4) 0/r32/eax # Tree-left - 4312 (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:3") # Tree-is-atom - 4313 (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-compound-type/type:4") # Tree-value - 4314 # type->right->right == null - 4315 (check-ints-equal *(edx+8) 0 "F - test-parse-var-with-compound-type/type:5") # Tree-right - 4316 # . epilogue - 4317 89/<- %esp 5/r32/ebp - 4318 5d/pop-to-ebp - 4319 c3/return - 4320 - 4321 # identifier starts with a letter or '$' or '_' - 4322 # no constraints at the moment on later letters - 4323 # all we really want to do so far is exclude '{', '}' and '->' - 4324 is-identifier?: # in: (addr slice) -> result/eax: boolean - 4325 # . prologue - 4326 55/push-ebp - 4327 89/<- %ebp 4/r32/esp - 4328 # if (slice-empty?(in)) return false - 4329 (slice-empty? *(ebp+8)) # => eax - 4330 3d/compare-eax-and 0/imm32/false - 4331 75/jump-if-!= $is-identifier?:false/disp8 - 4332 # var c/eax: byte = *in->start - 4333 8b/-> *(ebp+8) 0/r32/eax - 4334 8b/-> *eax 0/r32/eax - 4335 8a/copy-byte *eax 0/r32/AL - 4336 81 4/subop/and %eax 0xff/imm32 - 4337 # if (c == '$') return true - 4338 3d/compare-eax-and 0x24/imm32/$ - 4339 74/jump-if-= $is-identifier?:true/disp8 - 4340 # if (c == '_') return true - 4341 3d/compare-eax-and 0x5f/imm32/_ - 4342 74/jump-if-= $is-identifier?:true/disp8 - 4343 # drop case - 4344 25/and-eax-with 0x5f/imm32 - 4345 # if (c < 'A') return false - 4346 3d/compare-eax-and 0x41/imm32/A - 4347 7c/jump-if-< $is-identifier?:false/disp8 - 4348 # if (c > 'Z') return false - 4349 3d/compare-eax-and 0x5a/imm32/Z - 4350 7f/jump-if-> $is-identifier?:false/disp8 - 4351 # otherwise return true - 4352 $is-identifier?:true: - 4353 b8/copy-to-eax 1/imm32/true - 4354 eb/jump $is-identifier?:end/disp8 - 4355 $is-identifier?:false: - 4356 b8/copy-to-eax 0/imm32/false - 4357 $is-identifier?:end: - 4358 # . epilogue - 4359 89/<- %esp 5/r32/ebp - 4360 5d/pop-to-ebp - 4361 c3/return - 4362 - 4363 test-is-identifier-dollar: - 4364 # . prologue - 4365 55/push-ebp - 4366 89/<- %ebp 4/r32/esp - 4367 # (eax..ecx) = "$a" - 4368 b8/copy-to-eax "$a"/imm32 - 4369 8b/-> *eax 1/r32/ecx - 4370 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 4371 05/add-to-eax 4/imm32 - 4372 # var slice/ecx: slice = {eax, ecx} - 4373 51/push-ecx - 4374 50/push-eax - 4375 89/<- %ecx 4/r32/esp - 4376 # - 4377 (is-identifier? %ecx) - 4378 (check-ints-equal %eax 1 "F - test-is-identifier-dollar") - 4379 # . epilogue - 4380 89/<- %esp 5/r32/ebp - 4381 5d/pop-to-ebp - 4382 c3/return - 4383 - 4384 test-is-identifier-underscore: - 4385 # . prologue - 4386 55/push-ebp - 4387 89/<- %ebp 4/r32/esp - 4388 # (eax..ecx) = "_a" - 4389 b8/copy-to-eax "_a"/imm32 - 4390 8b/-> *eax 1/r32/ecx - 4391 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 4392 05/add-to-eax 4/imm32 - 4393 # var slice/ecx: slice = {eax, ecx} - 4394 51/push-ecx - 4395 50/push-eax - 4396 89/<- %ecx 4/r32/esp - 4397 # - 4398 (is-identifier? %ecx) - 4399 (check-ints-equal %eax 1 "F - test-is-identifier-underscore") - 4400 # . epilogue - 4401 89/<- %esp 5/r32/ebp - 4402 5d/pop-to-ebp - 4403 c3/return - 4404 - 4405 test-is-identifier-a: - 4406 # . prologue - 4407 55/push-ebp - 4408 89/<- %ebp 4/r32/esp - 4409 # (eax..ecx) = "a$" - 4410 b8/copy-to-eax "a$"/imm32 - 4411 8b/-> *eax 1/r32/ecx - 4412 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 4413 05/add-to-eax 4/imm32 - 4414 # var slice/ecx: slice = {eax, ecx} - 4415 51/push-ecx - 4416 50/push-eax - 4417 89/<- %ecx 4/r32/esp - 4418 # - 4419 (is-identifier? %ecx) - 4420 (check-ints-equal %eax 1 "F - test-is-identifier-a") - 4421 # . epilogue - 4422 89/<- %esp 5/r32/ebp - 4423 5d/pop-to-ebp - 4424 c3/return - 4425 - 4426 test-is-identifier-z: - 4427 # . prologue - 4428 55/push-ebp - 4429 89/<- %ebp 4/r32/esp - 4430 # (eax..ecx) = "z$" - 4431 b8/copy-to-eax "z$"/imm32 - 4432 8b/-> *eax 1/r32/ecx - 4433 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 4434 05/add-to-eax 4/imm32 - 4435 # var slice/ecx: slice = {eax, ecx} - 4436 51/push-ecx - 4437 50/push-eax - 4438 89/<- %ecx 4/r32/esp - 4439 # - 4440 (is-identifier? %ecx) - 4441 (check-ints-equal %eax 1 "F - test-is-identifier-z") - 4442 # . epilogue - 4443 89/<- %esp 5/r32/ebp - 4444 5d/pop-to-ebp - 4445 c3/return - 4446 - 4447 test-is-identifier-A: - 4448 # . prologue - 4449 55/push-ebp - 4450 89/<- %ebp 4/r32/esp - 4451 # (eax..ecx) = "A$" - 4452 b8/copy-to-eax "A$"/imm32 - 4453 8b/-> *eax 1/r32/ecx - 4454 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 4455 05/add-to-eax 4/imm32 - 4456 # var slice/ecx: slice = {eax, ecx} - 4457 51/push-ecx - 4458 50/push-eax - 4459 89/<- %ecx 4/r32/esp - 4460 # - 4461 (is-identifier? %ecx) - 4462 (check-ints-equal %eax 1 "F - test-is-identifier-A") - 4463 # . epilogue - 4464 89/<- %esp 5/r32/ebp - 4465 5d/pop-to-ebp - 4466 c3/return - 4467 - 4468 test-is-identifier-Z: - 4469 # . prologue - 4470 55/push-ebp - 4471 89/<- %ebp 4/r32/esp - 4472 # (eax..ecx) = "Z$" - 4473 b8/copy-to-eax "Z$"/imm32 - 4474 8b/-> *eax 1/r32/ecx - 4475 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 4476 05/add-to-eax 4/imm32 - 4477 # var slice/ecx: slice = {eax, ecx} - 4478 51/push-ecx - 4479 50/push-eax - 4480 89/<- %ecx 4/r32/esp - 4481 # - 4482 (is-identifier? %ecx) - 4483 (check-ints-equal %eax 1 "F - test-is-identifier-Z") - 4484 # . epilogue - 4485 89/<- %esp 5/r32/ebp - 4486 5d/pop-to-ebp - 4487 c3/return - 4488 - 4489 test-is-identifier-@: - 4490 # character before 'A' is invalid - 4491 # . prologue - 4492 55/push-ebp - 4493 89/<- %ebp 4/r32/esp - 4494 # (eax..ecx) = "@a" - 4495 b8/copy-to-eax "@a"/imm32 - 4496 8b/-> *eax 1/r32/ecx - 4497 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 4498 05/add-to-eax 4/imm32 - 4499 # var slice/ecx: slice = {eax, ecx} - 4500 51/push-ecx - 4501 50/push-eax - 4502 89/<- %ecx 4/r32/esp - 4503 # - 4504 (is-identifier? %ecx) - 4505 (check-ints-equal %eax 0 "F - test-is-identifier-@") - 4506 # . epilogue - 4507 89/<- %esp 5/r32/ebp - 4508 5d/pop-to-ebp - 4509 c3/return - 4510 - 4511 test-is-identifier-square-bracket: - 4512 # character after 'Z' is invalid - 4513 # . prologue - 4514 55/push-ebp - 4515 89/<- %ebp 4/r32/esp - 4516 # (eax..ecx) = "[a" - 4517 b8/copy-to-eax "[a"/imm32 - 4518 8b/-> *eax 1/r32/ecx - 4519 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 4520 05/add-to-eax 4/imm32 - 4521 # var slice/ecx: slice = {eax, ecx} - 4522 51/push-ecx - 4523 50/push-eax - 4524 89/<- %ecx 4/r32/esp - 4525 # - 4526 (is-identifier? %ecx) - 4527 (check-ints-equal %eax 0 "F - test-is-identifier-@") - 4528 # . epilogue - 4529 89/<- %esp 5/r32/ebp - 4530 5d/pop-to-ebp - 4531 c3/return - 4532 - 4533 test-is-identifier-backtick: - 4534 # character before 'a' is invalid - 4535 # . prologue - 4536 55/push-ebp - 4537 89/<- %ebp 4/r32/esp - 4538 # (eax..ecx) = "`a" - 4539 b8/copy-to-eax "`a"/imm32 - 4540 8b/-> *eax 1/r32/ecx - 4541 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 4542 05/add-to-eax 4/imm32 - 4543 # var slice/ecx: slice = {eax, ecx} - 4544 51/push-ecx - 4545 50/push-eax - 4546 89/<- %ecx 4/r32/esp - 4547 # - 4548 (is-identifier? %ecx) - 4549 (check-ints-equal %eax 0 "F - test-is-identifier-backtick") - 4550 # . epilogue - 4551 89/<- %esp 5/r32/ebp - 4552 5d/pop-to-ebp - 4553 c3/return - 4554 - 4555 test-is-identifier-curly-brace-open: - 4556 # character after 'z' is invalid; also used for blocks - 4557 # . prologue - 4558 55/push-ebp - 4559 89/<- %ebp 4/r32/esp - 4560 # (eax..ecx) = "{a" - 4561 b8/copy-to-eax "{a"/imm32 - 4562 8b/-> *eax 1/r32/ecx - 4563 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 4564 05/add-to-eax 4/imm32 - 4565 # var slice/ecx: slice = {eax, ecx} - 4566 51/push-ecx - 4567 50/push-eax - 4568 89/<- %ecx 4/r32/esp - 4569 # - 4570 (is-identifier? %ecx) - 4571 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open") - 4572 # . epilogue - 4573 89/<- %esp 5/r32/ebp - 4574 5d/pop-to-ebp - 4575 c3/return - 4576 - 4577 test-is-identifier-curly-brace-close: - 4578 # . prologue - 4579 55/push-ebp - 4580 89/<- %ebp 4/r32/esp - 4581 # (eax..ecx) = "}a" - 4582 b8/copy-to-eax "}a"/imm32 - 4583 8b/-> *eax 1/r32/ecx - 4584 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 4585 05/add-to-eax 4/imm32 - 4586 # var slice/ecx: slice = {eax, ecx} - 4587 51/push-ecx - 4588 50/push-eax - 4589 89/<- %ecx 4/r32/esp - 4590 # - 4591 (is-identifier? %ecx) - 4592 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close") - 4593 # . epilogue - 4594 89/<- %esp 5/r32/ebp - 4595 5d/pop-to-ebp - 4596 c3/return - 4597 - 4598 test-is-identifier-hyphen: - 4599 # disallow leading '-' since '->' has special meaning - 4600 # . prologue - 4601 55/push-ebp - 4602 89/<- %ebp 4/r32/esp - 4603 # (eax..ecx) = "-a" - 4604 b8/copy-to-eax "-a"/imm32 - 4605 8b/-> *eax 1/r32/ecx - 4606 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 4607 05/add-to-eax 4/imm32 - 4608 # var slice/ecx: slice = {eax, ecx} - 4609 51/push-ecx - 4610 50/push-eax - 4611 89/<- %ecx 4/r32/esp - 4612 # - 4613 (is-identifier? %ecx) - 4614 (check-ints-equal %eax 0 "F - test-is-identifier-hyphen") - 4615 # . epilogue - 4616 89/<- %esp 5/r32/ebp - 4617 5d/pop-to-ebp - 4618 c3/return - 4619 - 4620 populate-mu-function-body: # in: (addr buffered-file), out: (handle function), vars: (addr stack (handle var)) - 4621 # . prologue - 4622 55/push-ebp - 4623 89/<- %ebp 4/r32/esp - 4624 # . save registers - 4625 50/push-eax - 4626 56/push-esi - 4627 57/push-edi - 4628 # esi = in - 4629 8b/-> *(ebp+8) 6/r32/esi - 4630 # edi = out - 4631 8b/-> *(ebp+0xc) 7/r32/edi - 4632 # var eax: (handle block) = parse-mu-block(in, vars, fn) - 4633 (parse-mu-block %esi *(ebp+0x10) %edi) # => eax - 4634 # out->body = eax - 4635 89/<- *(edi+0x10) 0/r32/eax # Function-body - 4636 $populate-mu-function-body:end: - 4637 # . restore registers - 4638 5f/pop-to-edi - 4639 5e/pop-to-esi - 4640 58/pop-to-eax - 4641 # . epilogue - 4642 89/<- %esp 5/r32/ebp - 4643 5d/pop-to-ebp - 4644 c3/return - 4645 - 4646 # parses a block, assuming that the leading '{' has already been read by the caller - 4647 parse-mu-block: # in: (addr buffered-file), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle block) - 4648 # pseudocode: - 4649 # var line: (stream byte 512) - 4650 # var word-slice: slice - 4651 # result/eax = allocate(Heap, Stmt-size) - 4652 # result->tag = 0/block - 4653 # result->name = some unique name - 4654 # while true # line loop - 4655 # clear-stream(line) - 4656 # read-line-buffered(in, line) - 4657 # if (line->write == 0) break # end of file - 4658 # word-slice = next-mu-token(line) - 4659 # if slice-empty?(word-slice) # end of line - 4660 # continue - 4661 # else if slice-starts-with?(word-slice, "#") - 4662 # continue - 4663 # else if slice-equal?(word-slice, "{") - 4664 # assert(no-tokens-in(line)) - 4665 # block = parse-mu-block(in, vars, fn) - 4666 # append-to-block(result, block) - 4667 # else if slice-equal?(word-slice, "}") - 4668 # break - 4669 # else if slice-ends-with?(word-slice, ":") - 4670 # # TODO: error-check the rest of 'line' - 4671 # --word-slice->end to skip ':' - 4672 # named-block = parse-mu-named-block(word-slice, in, vars, fn) - 4673 # append-to-block(result, named-block) - 4674 # else if slice-equal?(word-slice, "var") - 4675 # var-def = parse-mu-var-def(line, vars) - 4676 # append-to-block(result, var-def) - 4677 # else - 4678 # stmt = parse-mu-stmt(line, vars, fn) - 4679 # append-to-block(result, stmt) - 4680 # return result - 4681 # - 4682 # . prologue - 4683 55/push-ebp - 4684 89/<- %ebp 4/r32/esp - 4685 # . save registers - 4686 51/push-ecx - 4687 52/push-edx - 4688 53/push-ebx - 4689 57/push-edi - 4690 # var line/ecx: (stream byte 512) - 4691 81 5/subop/subtract %esp 0x200/imm32 - 4692 68/push 0x200/imm32/size - 4693 68/push 0/imm32/read - 4694 68/push 0/imm32/write - 4695 89/<- %ecx 4/r32/esp - 4696 # var word-slice/edx: slice - 4697 68/push 0/imm32/end - 4698 68/push 0/imm32/start - 4699 89/<- %edx 4/r32/esp - 4700 # edi = result - 4701 (allocate Heap *Stmt-size) # => eax - 4702 89/<- %edi 0/r32/eax - 4703 # set result->tag - 4704 c7 0/subop/copy *edi 0/imm32/block # Stmt-tag - 4705 # set result->var - 4706 (new-block-name *(ebp+0x10)) # => eax - 4707 89/<- *(edi+8) 0/r32/eax # Block-var - 4708 # push result->var to vars - 4709 (push *(ebp+0xc) %eax) - 4710 { - 4711 $parse-mu-block:line-loop: - 4712 # line = read-line-buffered(in) - 4713 (clear-stream %ecx) - 4714 (read-line-buffered *(ebp+8) %ecx) - 4715 #? (write-buffered Stderr "line: ") - 4716 #? (write-stream-data Stderr %ecx) - 4717 #? (write-buffered Stderr Newline) - 4718 #? (flush Stderr) - 4719 # if (line->write == 0) break - 4720 81 7/subop/compare *ecx 0/imm32 - 4721 0f 84/jump-if-= break/disp32 - 4722 # word-slice = next-mu-token(line) - 4723 (next-mu-token %ecx %edx) - 4724 #? (write-buffered Stderr "word: ") - 4725 #? (write-slice-buffered Stderr %edx) - 4726 #? (write-buffered Stderr Newline) - 4727 #? (flush Stderr) - 4728 # if slice-empty?(word-slice) continue - 4729 (slice-empty? %edx) - 4730 3d/compare-eax-and 0/imm32/false - 4731 0f 85/jump-if-!= loop/disp32 - 4732 # if (slice-starts-with?(word-slice, '#') continue - 4733 # . eax = *word-slice->start - 4734 8b/-> *edx 0/r32/eax - 4735 8a/copy-byte *eax 0/r32/AL - 4736 81 4/subop/and %eax 0xff/imm32 - 4737 # . if (eax == '#') continue - 4738 3d/compare-eax-and 0x23/imm32/hash - 4739 0f 84/jump-if-= loop/disp32 - 4740 # if slice-equal?(word-slice, "{") - 4741 { - 4742 $parse-mu-block:check-for-block: - 4743 (slice-equal? %edx "{") - 4744 3d/compare-eax-and 0/imm32/false - 4745 74/jump-if-= break/disp8 - 4746 (check-no-tokens-left %ecx) - 4747 # parse new block and append - 4748 (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax - 4749 (append-to-block Heap %edi %eax) - 4750 e9/jump $parse-mu-block:line-loop/disp32 - 4751 } - 4752 # if slice-equal?(word-slice, "}") break - 4753 $parse-mu-block:check-for-end: - 4754 (slice-equal? %edx "}") - 4755 3d/compare-eax-and 0/imm32/false - 4756 0f 85/jump-if-!= break/disp32 - 4757 # if slice-ends-with?(word-slice, ":") parse named block and append - 4758 { - 4759 $parse-mu-block:check-for-named-block: - 4760 # . eax = *(word-slice->end-1) - 4761 8b/-> *(edx+4) 0/r32/eax - 4762 48/decrement-eax - 4763 8a/copy-byte *eax 0/r32/AL - 4764 81 4/subop/and %eax 0xff/imm32 - 4765 # . if (eax != ':') break - 4766 3d/compare-eax-and 0x3a/imm32/colon - 4767 0f 85/jump-if-!= break/disp32 - 4768 # TODO: error-check the rest of 'line' - 4769 # - 4770 # skip ':' - 4771 ff 1/subop/decrement *(edx+4) # Slice-end - 4772 # - 4773 (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax - 4774 (append-to-block Heap %edi %eax) - 4775 e9/jump $parse-mu-block:line-loop/disp32 - 4776 } - 4777 # if slice-equal?(word-slice, "var") - 4778 { - 4779 $parse-mu-block:check-for-var: - 4780 (slice-equal? %edx "var") - 4781 3d/compare-eax-and 0/imm32/false - 4782 74/jump-if-= break/disp8 - 4783 # - 4784 (parse-mu-var-def %ecx *(ebp+0xc)) # => eax - 4785 (append-to-block Heap %edi %eax) - 4786 e9/jump $parse-mu-block:line-loop/disp32 - 4787 } - 4788 $parse-mu-block:regular-stmt: - 4789 # otherwise - 4790 (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10)) # => eax - 4791 (append-to-block Heap %edi %eax) - 4792 e9/jump loop/disp32 - 4793 } # end line loop - 4794 # - 4795 (pop *(ebp+0xc)) # => eax - 4796 # return result - 4797 89/<- %eax 7/r32/edi - 4798 $parse-mu-block:end: - 4799 # . reclaim locals - 4800 81 0/subop/add %esp 0x214/imm32 - 4801 # . restore registers - 4802 5f/pop-to-edi - 4803 5b/pop-to-ebx - 4804 5a/pop-to-edx - 4805 59/pop-to-ecx - 4806 # . epilogue - 4807 89/<- %esp 5/r32/ebp - 4808 5d/pop-to-ebp - 4809 c3/return - 4810 - 4811 $parse-mu-block:abort: - 4812 # error("'{' or '}' should be on its own line, but got '") - 4813 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") - 4814 (rewind-stream %ecx) - 4815 (write-stream 2 %ecx) - 4816 (write-buffered Stderr "'\n") - 4817 (flush Stderr) - 4818 # . syscall(exit, 1) - 4819 bb/copy-to-ebx 1/imm32 - 4820 b8/copy-to-eax 1/imm32/exit - 4821 cd/syscall 0x80/imm8 - 4822 # never gets here - 4823 - 4824 new-block-name: # fn: (handle function) -> result/eax: (handle var) - 4825 # . prologue - 4826 55/push-ebp - 4827 89/<- %ebp 4/r32/esp - 4828 # . save registers - 4829 51/push-ecx - 4830 52/push-edx - 4831 # var n/ecx: int = len(fn->name) + 10 for an int + 2 for '$:' - 4832 8b/-> *(ebp+8) 0/r32/eax - 4833 8b/-> *eax 0/r32/eax # Function-name - 4834 8b/-> *eax 0/r32/eax # String-size - 4835 05/add-to-eax 0xd/imm32 # 10 + 2 for '$:' - 4836 89/<- %ecx 0/r32/eax - 4837 # var name/edx: (stream byte n) - 4838 29/subtract-from %esp 1/r32/ecx - 4839 ff 6/subop/push %ecx - 4840 68/push 0/imm32/read - 4841 68/push 0/imm32/write - 4842 89/<- %edx 4/r32/esp - 4843 (clear-stream %edx) - 4844 # eax = fn->name - 4845 8b/-> *(ebp+8) 0/r32/eax - 4846 8b/-> *eax 0/r32/eax # Function-name - 4847 # construct result using Next-block-index (and increment it) - 4848 (write %edx "$") - 4849 (write %edx %eax) - 4850 (write %edx ":") - 4851 (print-int32 %edx *Next-block-index) - 4852 ff 0/subop/increment *Next-block-index - 4853 # var s/eax: slice = {name->data, name->data + name->write} (clobbering edx) - 4854 # . eax = name->write - 4855 8b/-> *edx 0/r32/eax - 4856 # . edx = name->data - 4857 8d/copy-address *(edx+0xc) 2/r32/edx - 4858 # . eax = name->write + name->data - 4859 01/add-to %eax 2/r32/edx - 4860 # . push {edx, eax} - 4861 ff 6/subop/push %eax - 4862 ff 6/subop/push %edx - 4863 89/<- %eax 4/r32/esp - 4864 # result->var = new literal(s) - 4865 (new-literal Heap %eax) # => eax - 4866 $new-block-name:end: - 4867 # . reclaim locals - 4868 81 0/subop/add %ecx 0xc/imm32 # name.{read/write/len} - 4869 81 0/subop/add %ecx 8/imm32 # slice - 4870 01/add-to %esp 1/r32/ecx - 4871 # . restore registers - 4872 5a/pop-to-edx - 4873 59/pop-to-ecx - 4874 # . epilogue - 4875 89/<- %esp 5/r32/ebp - 4876 5d/pop-to-ebp - 4877 c3/return - 4878 - 4879 == data - 4880 - 4881 # Global state added to each var record when parsing a function - 4882 Next-block-index: # (addr int) - 4883 1/imm32 - 4884 - 4885 == code - 4886 - 4887 check-no-tokens-left: # line: (addr stream byte) - 4888 # . prologue - 4889 55/push-ebp - 4890 89/<- %ebp 4/r32/esp - 4891 # . save registers - 4892 50/push-eax - 4893 51/push-ecx - 4894 # var s/ecx: slice - 4895 68/push 0/imm32/end - 4896 68/push 0/imm32/start - 4897 89/<- %ecx 4/r32/esp - 4898 # - 4899 (next-mu-token *(ebp+8) %ecx) - 4900 # if slice-empty?(s) return - 4901 (slice-empty? %ecx) - 4902 3d/compare-eax-and 0/imm32/false - 4903 75/jump-if-!= $check-no-tokens-left:end/disp8 - 4904 # if (slice-starts-with?(s, '#') return - 4905 # . eax = *s->start - 4906 8b/-> *edx 0/r32/eax - 4907 8a/copy-byte *eax 0/r32/AL - 4908 81 4/subop/and %eax 0xff/imm32 - 4909 # . if (eax == '#') continue - 4910 3d/compare-eax-and 0x23/imm32/hash - 4911 74/jump-if-= $check-no-tokens-left:end/disp8 - 4912 # abort - 4913 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") - 4914 (rewind-stream %ecx) - 4915 (write-stream 2 %ecx) - 4916 (write-buffered Stderr "'\n") - 4917 (flush Stderr) - 4918 # . syscall(exit, 1) - 4919 bb/copy-to-ebx 1/imm32 - 4920 b8/copy-to-eax 1/imm32/exit - 4921 cd/syscall 0x80/imm8 - 4922 # never gets here - 4923 $check-no-tokens-left:end: - 4924 # . reclaim locals - 4925 81 0/subop/add %esp 8/imm32 - 4926 # . restore registers - 4927 59/pop-to-ecx - 4928 58/pop-to-eax - 4929 # . epilogue - 4930 89/<- %esp 5/r32/ebp - 4931 5d/pop-to-ebp - 4932 c3/return - 4933 - 4934 parse-mu-named-block: # name: (addr slice), in: (addr buffered-file), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle stmt) - 4935 # pseudocode: - 4936 # var v: (handle var) = new-literal(name) - 4937 # push(vars, v) - 4938 # result = parse-mu-block(in, vars, fn) - 4939 # pop(vars) - 4940 # result->name = s - 4941 # return result - 4942 # - 4943 # . prologue - 4944 55/push-ebp - 4945 89/<- %ebp 4/r32/esp - 4946 # . save registers - 4947 51/push-ecx - 4948 # var v/ecx: (handle var) - 4949 (new-literal Heap *(ebp+8)) # => eax - 4950 89/<- %ecx 0/r32/eax - 4951 # push(vars, v) - 4952 (push *(ebp+0x10) %ecx) - 4953 # eax = result - 4954 (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) # => eax - 4955 # pop the var - 4956 50/push-eax - 4957 (pop *(ebp+0x10)) # => eax - 4958 58/pop-to-eax - 4959 # result->tag = named-block - 4960 c7 0/subop/copy *eax 0/imm32/block # Stmt-tag - 4961 # result->var = v - 4962 89/<- *(eax+8) 1/r32/ecx # Block-var - 4963 $parse-mu-named-block:end: - 4964 # . restore registers - 4965 59/pop-to-ecx - 4966 # . epilogue - 4967 89/<- %esp 5/r32/ebp - 4968 5d/pop-to-ebp - 4969 c3/return - 4970 - 4971 parse-mu-var-def: # line: (addr stream byte), vars: (addr stack (handle var)) -> result/eax: (handle stmt) - 4972 # . prologue - 4973 55/push-ebp - 4974 89/<- %ebp 4/r32/esp - 4975 # . save registers - 4976 51/push-ecx - 4977 52/push-edx - 4978 # var word-slice/ecx: slice - 4979 68/push 0/imm32/end - 4980 68/push 0/imm32/start - 4981 89/<- %ecx 4/r32/esp - 4982 # var v/edx: (handle var) = parse-var-with-type(line) - 4983 (next-mu-token *(ebp+8) %ecx) - 4984 (parse-var-with-type %ecx *(ebp+8)) # => eax - 4985 89/<- %edx 0/r32/eax - 4986 # - 4987 (push *(ebp+0xc) %edx) - 4988 # either v has no register and there's no more to this line - 4989 8b/-> *(edx+0x10) 0/r32/eax # Var-register - 4990 3d/compare-eax-and 0/imm32 - 4991 { - 4992 75/jump-if-!= break/disp8 - 4993 # TODO: ensure that there's nothing else on this line - 4994 (new-var-def Heap %edx) # => eax - 4995 eb/jump $parse-mu-var-def:end/disp8 - 4996 } - 4997 # or v has a register and there's more to this line - 4998 { - 4999 74/jump-if-= break/disp8 - 5000 # ensure that the next word is '<-' - 5001 (next-mu-token *(ebp+8) %ecx) - 5002 (slice-equal? %ecx "<-") # => eax - 5003 3d/compare-eax-and 0/imm32/false - 5004 74/jump-if-= $parse-mu-var-def:abort/disp8 - 5005 # - 5006 (new-reg-var-def Heap %edx) # => eax - 5007 (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc)) - 5008 } - 5009 $parse-mu-var-def:end: - 5010 # . reclaim locals - 5011 81 0/subop/add %esp 8/imm32 - 5012 # . restore registers - 5013 5a/pop-to-edx - 5014 59/pop-to-ecx - 5015 # . epilogue - 5016 89/<- %esp 5/r32/ebp - 5017 5d/pop-to-ebp - 5018 c3/return - 5019 - 5020 $parse-mu-var-def:abort: - 5021 (rewind-stream *(ebp+8)) - 5022 # error("register variable requires a valid instruction to initialize but got '" line "'\n") - 5023 (write-buffered Stderr "register variable requires a valid instruction to initialize but got '") - 5024 (flush Stderr) - 5025 (write-stream 2 *(ebp+8)) - 5026 (write-buffered Stderr "'\n") - 5027 (flush Stderr) - 5028 # . syscall(exit, 1) - 5029 bb/copy-to-ebx 1/imm32 - 5030 b8/copy-to-eax 1/imm32/exit - 5031 cd/syscall 0x80/imm8 - 5032 # never gets here - 5033 - 5034 test-parse-mu-var-def: - 5035 # 'var n: int' - 5036 # . prologue - 5037 55/push-ebp - 5038 89/<- %ebp 4/r32/esp - 5039 # setup - 5040 (clear-stream _test-input-stream) - 5041 (write _test-input-stream "n: int\n") # caller has consumed the 'var' - 5042 # var vars/ecx: (stack (addr var) 4) - 5043 81 5/subop/subtract %esp 0x10/imm32 - 5044 68/push 0x10/imm32/size - 5045 68/push 0/imm32/top - 5046 89/<- %ecx 4/r32/esp - 5047 (clear-stack %ecx) - 5048 # convert - 5049 (parse-mu-var-def _test-input-stream %ecx) # => eax - 5050 # check result - 5051 (check-ints-equal *eax 2 "F - test-parse-mu-var-def/tag") # Stmt-tag is var-def - 5052 8b/-> *(eax+4) 0/r32/eax # Vardef-var - 5053 (check-strings-equal *eax "n" "F - test-parse-mu-var-def/var-name") # Var-name - 5054 (check-ints-equal *(eax+0x10) 0 "F - test-parse-mu-var-def/var-register") # Var-register - 5055 # ensure type is int - 5056 8b/-> *(eax+4) 0/r32/eax # Var-type - 5057 (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0") # Tree-is-atom - 5058 (check-ints-equal *(eax+4) 1 "F - test-parse-mu-var-def/var-type:1") # Tree-value - 5059 (check-ints-equal *(eax+8) 0 "F - test-parse-mu-var-def/var-type:2") # Tree-right - 5060 # . epilogue - 5061 89/<- %esp 5/r32/ebp - 5062 5d/pop-to-ebp - 5063 c3/return - 5064 - 5065 test-parse-mu-reg-var-def: - 5066 # 'var n/eax: int <- copy 0' - 5067 # . prologue - 5068 55/push-ebp - 5069 89/<- %ebp 4/r32/esp - 5070 # setup - 5071 (clear-stream _test-input-stream) - 5072 (write _test-input-stream "n/eax: int <- copy 0\n") # caller has consumed the 'var' - 5073 # var vars/ecx: (stack (addr var) 4) - 5074 81 5/subop/subtract %esp 0x10/imm32 - 5075 68/push 0x10/imm32/size - 5076 68/push 0/imm32/top - 5077 89/<- %ecx 4/r32/esp - 5078 (clear-stack %ecx) - 5079 # convert - 5080 (parse-mu-var-def _test-input-stream %ecx) # => eax - 5081 # check result - 5082 (check-ints-equal *eax 3 "F - test-parse-mu-reg-var-def/tag") # Stmt-tag is reg-var-def - 5083 8b/-> *(eax+0xc) 0/r32/eax # Regvardef-outputs - 5084 (check-ints-equal *(eax+4) 0 "F - test-parse-mu-reg-var-def/single-output") # List-next - 5085 8b/-> *eax 0/r32/eax # Stmt-var-value - 5086 (check-strings-equal *eax "n" "F - test-parse-mu-reg-var-def/output-name") # Var-name - 5087 (check-strings-equal *(eax+0x10) "eax" "F - test-parse-mu-reg-var-def/output-register") # Var-register - 5088 # ensure type is int - 5089 8b/-> *(eax+4) 0/r32/eax # Var-type - 5090 (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/var-type:0") # Tree-is-atom - 5091 (check-ints-equal *(eax+4) 1 "F - test-parse-mu-reg-var-def/output-type:0") # Tree-value - 5092 (check-ints-equal *(eax+8) 0 "F - test-parse-mu-reg-var-def/output-type:0") # Tree-right - 5093 # . epilogue - 5094 89/<- %esp 5/r32/ebp - 5095 5d/pop-to-ebp - 5096 c3/return - 5097 - 5098 parse-mu-stmt: # line: (addr stream byte), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle stmt) - 5099 # pseudocode: - 5100 # var name: slice - 5101 # result = allocate(Heap, Stmt-size) - 5102 # if stmt-has-outputs?(line) - 5103 # while true - 5104 # name = next-mu-token(line) - 5105 # if (name == '<-') break - 5106 # assert(is-identifier?(name)) - 5107 # var v: (handle var) = lookup-or-define-var(name, vars, fn) # regular stmts may define vars in fn outputs - 5108 # result->outputs = append(result->outputs, v) - 5109 # add-operation-and-inputs-to-stmt(result, line, vars) - 5110 # - 5111 # . prologue - 5112 55/push-ebp - 5113 89/<- %ebp 4/r32/esp - 5114 # . save registers - 5115 51/push-ecx - 5116 52/push-edx - 5117 57/push-edi - 5118 # var name/ecx: slice - 5119 68/push 0/imm32/end - 5120 68/push 0/imm32/start - 5121 89/<- %ecx 4/r32/esp - 5122 # var is-deref?/edx: boolean = false - 5123 ba/copy-to-edx 0/imm32/false - 5124 # result/edi: (handle stmt) - 5125 (allocate Heap *Stmt-size) # => eax - 5126 89/<- %edi 0/r32/eax - 5127 # result->tag = 1/stmt - 5128 c7 0/subop/copy *edi 1/imm32/stmt1 # Stmt-tag - 5129 { - 5130 (stmt-has-outputs? *(ebp+8)) - 5131 3d/compare-eax-and 0/imm32/false - 5132 0f 84/jump-if-= break/disp32 - 5133 { - 5134 $parse-mu-stmt:read-outputs: - 5135 # name = next-mu-token(line) - 5136 (next-mu-token *(ebp+8) %ecx) - 5137 # if slice-empty?(word-slice) break - 5138 (slice-empty? %ecx) # => eax - 5139 3d/compare-eax-and 0/imm32/false - 5140 0f 85/jump-if-!= break/disp32 - 5141 # if (name == "<-") break - 5142 (slice-equal? %ecx "<-") # => eax - 5143 3d/compare-eax-and 0/imm32/false - 5144 0f 85/jump-if-!= break/disp32 - 5145 # is-deref? = false - 5146 ba/copy-to-edx 0/imm32/false - 5147 # if (slice-starts-with?(name, '*')) ++name->start and set is-deref? - 5148 8b/-> *ecx 0/r32/eax # Slice-start - 5149 8a/copy-byte *eax 0/r32/AL - 5150 81 4/subop/and %eax 0xff/imm32 - 5151 3d/compare-eax-and 0x2a/imm32/asterisk - 5152 { - 5153 75/jump-if-!= break/disp8 - 5154 ff 0/subop/increment *ecx - 5155 ba/copy-to-edx 1/imm32/true - 5156 } - 5157 # assert(is-identifier?(name)) - 5158 (is-identifier? %ecx) # => eax - 5159 3d/compare-eax-and 0/imm32/false - 5160 0f 84/jump-if-= $parse-mu-stmt:abort/disp32 - 5161 # result->outputs = new stmt-var(lookup(name, vars, fn), result->outputs, is-deref?) - 5162 (lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10)) # => eax - 5163 (append-stmt-var Heap %eax *(edi+0xc) %edx) # Stmt1-outputs => eax - 5164 89/<- *(edi+0xc) 0/r32/eax # Stmt1-outputs - 5165 e9/jump loop/disp32 - 5166 } - 5167 } - 5168 (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc)) - 5169 $parse-mu-stmt:end: - 5170 # return result - 5171 89/<- %eax 7/r32/edi - 5172 # . reclaim locals - 5173 81 0/subop/add %esp 8/imm32 - 5174 # . restore registers - 5175 5f/pop-to-edi - 5176 5a/pop-to-edx - 5177 59/pop-to-ecx - 5178 # . epilogue - 5179 89/<- %esp 5/r32/ebp - 5180 5d/pop-to-ebp - 5181 c3/return - 5182 - 5183 $parse-mu-stmt:abort: - 5184 # error("invalid identifier '" name "'\n") - 5185 (write-buffered Stderr "invalid identifier '") - 5186 (write-slice-buffered Stderr %ecx) - 5187 (write-buffered Stderr "'\n") - 5188 (flush Stderr) - 5189 # . syscall(exit, 1) - 5190 bb/copy-to-ebx 1/imm32 - 5191 b8/copy-to-eax 1/imm32/exit - 5192 cd/syscall 0x80/imm8 - 5193 # never gets here - 5194 - 5195 add-operation-and-inputs-to-stmt: # stmt: (handle stmt), line: (addr stream byte), vars: (addr stack (handle var)) - 5196 # pseudocode: - 5197 # stmt->name = slice-to-string(next-mu-token(line)) - 5198 # while true - 5199 # name = next-mu-token(line) - 5200 # v = lookup-var-or-literal(name) - 5201 # stmt->inouts = append(stmt->inouts, v) - 5202 # - 5203 # . prologue - 5204 55/push-ebp - 5205 89/<- %ebp 4/r32/esp - 5206 # . save registers - 5207 50/push-eax - 5208 51/push-ecx - 5209 52/push-edx - 5210 53/push-ebx - 5211 57/push-edi - 5212 # edi = stmt - 5213 8b/-> *(ebp+8) 7/r32/edi - 5214 # var name/ecx: slice - 5215 68/push 0/imm32/end - 5216 68/push 0/imm32/start - 5217 89/<- %ecx 4/r32/esp - 5218 # var is-deref?/edx: boolean = false - 5219 ba/copy-to-edx 0/imm32/false - 5220 $add-operation-and-inputs-to-stmt:read-operation: - 5221 (next-mu-token *(ebp+0xc) %ecx) - 5222 (slice-to-string Heap %ecx) # => eax - 5223 89/<- *(edi+4) 0/r32/eax # Stmt1-operation or Regvardef-operation - 5224 # var is-get?/ebx: boolean = (name == "get") - 5225 (slice-equal? %ecx "get") # => eax - 5226 89/<- %ebx 0/r32/eax - 5227 { - 5228 $add-operation-and-inputs-to-stmt:read-inouts: - 5229 # name = next-mu-token(line) - 5230 (next-mu-token *(ebp+0xc) %ecx) - 5231 # if slice-empty?(word-slice) break - 5232 (slice-empty? %ecx) # => eax - 5233 3d/compare-eax-and 0/imm32/false - 5234 0f 85/jump-if-!= break/disp32 - 5235 # if (name == "<-") abort - 5236 (slice-equal? %ecx "<-") - 5237 3d/compare-eax-and 0/imm32/false - 5238 0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32 - 5239 # if (is-get? && second operand) lookup or create offset - 5240 { - 5241 81 7/subop/compare %ebx 0/imm32/false - 5242 74/jump-if-= break/disp8 - 5243 81 7/subop/compare *(edi+8) 0/imm32 # Stmt1-inouts or Regvardef-inouts - 5244 74/jump-if-= break/disp8 - 5245 (lookup-or-create-constant *(edi+8) %ecx) # Stmt1-inouts => eax - 5246 #? (write-buffered Stderr "creating new output var ") - 5247 #? (print-int32-buffered Stderr %eax) - 5248 #? (write-buffered Stderr " for field called ") - 5249 #? (write-slice-buffered Stderr %ecx) - 5250 #? (write-buffered Stderr Newline) - 5251 #? (flush Stderr) - 5252 e9/jump $add-operation-and-inputs-to-stmt:save-var/disp32 - 5253 } - 5254 # is-deref? = false - 5255 ba/copy-to-edx 0/imm32/false - 5256 # if (slice-starts-with?(name, '*')) ++name->start and set is-deref? - 5257 8b/-> *ecx 0/r32/eax # Slice-start - 5258 8a/copy-byte *eax 0/r32/AL - 5259 81 4/subop/and %eax 0xff/imm32 - 5260 3d/compare-eax-and 0x2a/imm32/asterisk - 5261 { - 5262 75/jump-if-!= break/disp8 - 5263 $add-operation-and-inputs-to-stmt:inout-is-deref: - 5264 ff 0/subop/increment *ecx - 5265 ba/copy-to-edx 1/imm32/true - 5266 } - 5267 (lookup-var-or-literal %ecx *(ebp+0x10)) # => eax - 5268 $add-operation-and-inputs-to-stmt:save-var: - 5269 (append-stmt-var Heap %eax *(edi+8) %edx) # Stmt1-inouts or Regvardef-inouts => eax - 5270 89/<- *(edi+8) 0/r32/eax # Stmt1-inouts or Regvardef-inouts - 5271 e9/jump loop/disp32 - 5272 } - 5273 $add-operation-and-inputs-to-stmt:end: - 5274 # . reclaim locals - 5275 81 0/subop/add %esp 8/imm32 - 5276 # . restore registers - 5277 5f/pop-to-edi - 5278 5b/pop-to-ebx - 5279 5a/pop-to-edx - 5280 59/pop-to-ecx - 5281 58/pop-to-eax - 5282 # . epilogue - 5283 89/<- %esp 5/r32/ebp - 5284 5d/pop-to-ebp - 5285 c3/return - 5286 - 5287 $add-operation-and-inputs-to-stmt:abort: - 5288 # error("invalid statement '" line "'\n") - 5289 (rewind-stream *(ebp+8)) - 5290 (write-buffered Stderr "invalid identifier '") - 5291 (flush Stderr) - 5292 (write-stream 2 *(ebp+8)) - 5293 (write-buffered Stderr "'\n") - 5294 (flush Stderr) - 5295 # . syscall(exit, 1) - 5296 bb/copy-to-ebx 1/imm32 - 5297 b8/copy-to-eax 1/imm32/exit - 5298 cd/syscall 0x80/imm8 - 5299 # never gets here - 5300 - 5301 stmt-has-outputs?: # line: (addr stream byte) -> result/eax: boolean - 5302 # . prologue - 5303 55/push-ebp - 5304 89/<- %ebp 4/r32/esp - 5305 # . save registers - 5306 51/push-ecx - 5307 # var word-slice/ecx: slice - 5308 68/push 0/imm32/end - 5309 68/push 0/imm32/start - 5310 89/<- %ecx 4/r32/esp - 5311 # result = false - 5312 b8/copy-to-eax 0/imm32/false - 5313 (rewind-stream *(ebp+8)) + 3902 5f/pop-to-edi + 3903 5e/pop-to-esi + 3904 5b/pop-to-ebx + 3905 5a/pop-to-edx + 3906 59/pop-to-ecx + 3907 58/pop-to-eax + 3908 # . epilogue + 3909 89/<- %esp 5/r32/ebp + 3910 5d/pop-to-ebp + 3911 c3/return + 3912 + 3913 $parse-var-with-type:abort: + 3914 # error("var should have form 'name: type' in '" line "'\n") + 3915 (write-buffered Stderr "var should have form 'name: type' in '") + 3916 (flush Stderr) + 3917 (rewind-stream *(ebp+0xc)) + 3918 (write-stream 2 *(ebp+0xc)) + 3919 (write-buffered Stderr "'\n") + 3920 (flush Stderr) + 3921 # . syscall(exit, 1) + 3922 bb/copy-to-ebx 1/imm32 + 3923 b8/copy-to-eax 1/imm32/exit + 3924 cd/syscall 0x80/imm8 + 3925 # never gets here + 3926 + 3927 parse-type: # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle tree type-id) + 3928 # pseudocode: + 3929 # var s: slice = next-mu-token(in) + 3930 # assert s != "" + 3931 # assert s != "->" + 3932 # assert s != "{" + 3933 # assert s != "}" + 3934 # if s == ")" + 3935 # return + 3936 # out = allocate(Tree) + 3937 # if s != "(" + 3938 # HACK: if s is an int, parse and return it + 3939 # out->left-is-atom? = true + 3940 # out->value = pos-or-insert-slice(Type-id, s) + 3941 # return + 3942 # out->left = parse-type(ad, in) + 3943 # out->right = parse-type-tree(ad, in) + 3944 # + 3945 # . prologue + 3946 55/push-ebp + 3947 89/<- %ebp 4/r32/esp + 3948 # . save registers + 3949 50/push-eax + 3950 51/push-ecx + 3951 52/push-edx + 3952 # clear out + 3953 (zero-out *(ebp+0x10) *Handle-size) + 3954 # var s/ecx: slice + 3955 68/push 0/imm32 + 3956 68/push 0/imm32 + 3957 89/<- %ecx 4/r32/esp + 3958 # s = next-mu-token(in) + 3959 (next-mu-token *(ebp+0xc) %ecx) + 3960 #? (write-buffered Stderr "tok: ") + 3961 #? (write-slice-buffered Stderr %ecx) + 3962 #? (write-buffered Stderr "$\n") + 3963 #? (flush Stderr) + 3964 # assert s != "" + 3965 (slice-equal? %ecx "") # => eax + 3966 3d/compare-eax-and 0/imm32/false + 3967 0f 85/jump-if-!= $parse-type:abort/disp32 + 3968 # assert s != "{" + 3969 (slice-equal? %ecx "{") # => eax + 3970 3d/compare-eax-and 0/imm32/false + 3971 0f 85/jump-if-!= $parse-type:abort/disp32 + 3972 # assert s != "}" + 3973 (slice-equal? %ecx "}") # => eax + 3974 3d/compare-eax-and 0/imm32/false + 3975 0f 85/jump-if-!= $parse-type:abort/disp32 + 3976 # assert s != "->" + 3977 (slice-equal? %ecx "->") # => eax + 3978 3d/compare-eax-and 0/imm32/false + 3979 0f 85/jump-if-!= $parse-type:abort/disp32 + 3980 # if (s == ")") return + 3981 (slice-equal? %ecx ")") # => eax + 3982 3d/compare-eax-and 0/imm32/false + 3983 0f 85/jump-if-!= $parse-type:end/disp32 + 3984 # out = new tree + 3985 (allocate *(ebp+8) *Tree-size *(ebp+0x10)) + 3986 # var out-addr/edx: (addr tree type-id) = lookup(*out) + 3987 8b/-> *(ebp+0x10) 2/r32/edx + 3988 (lookup *edx *(edx+4)) # => eax + 3989 89/<- %edx 0/r32/eax + 3990 { + 3991 # if (s != "(") break + 3992 (slice-equal? %ecx "(") # => eax + 3993 3d/compare-eax-and 0/imm32/false + 3994 75/jump-if-!= break/disp8 + 3995 # EGREGIOUS HACK for static array sizes: if s is a number, parse it + 3996 { + 3997 $parse-type:check-for-int: + 3998 (is-hex-int? %ecx) # => eax + 3999 3d/compare-eax-and 0/imm32/false + 4000 74/jump-if-= break/disp8 + 4001 $parse-type:int: + 4002 (parse-hex-int-from-slice %ecx) # => eax + 4003 89/<- *(edx+4) 0/r32/eax # Tree-value + 4004 e9/jump $parse-type:end/disp32 + 4005 } + 4006 $parse-type:atom: + 4007 # out->left-is-atom? = true + 4008 c7 0/subop/copy *edx 1/imm32/true # Tree-is-atom + 4009 # out->value = pos-or-insert-slice(Type-id, s) + 4010 (pos-or-insert-slice Type-id %ecx) # => eax + 4011 89/<- *(edx+4) 0/r32/eax # Tree-value + 4012 e9/jump $parse-type:end/disp32 + 4013 } + 4014 $parse-type:non-atom: + 4015 # otherwise s == "(" + 4016 # out->left = parse-type(ad, in) + 4017 8d/copy-address *(edx+4) 0/r32/eax # Tree-left + 4018 (parse-type *(ebp+8) *(ebp+0xc) %eax) + 4019 # out->right = parse-type-tree(ad, in) + 4020 8d/copy-address *(edx+0xc) 0/r32/eax # Tree-right + 4021 (parse-type-tree *(ebp+8) *(ebp+0xc) %eax) + 4022 $parse-type:end: + 4023 # . reclaim locals + 4024 81 0/subop/add %esp 8/imm32 + 4025 # . restore registers + 4026 5a/pop-to-edx + 4027 59/pop-to-ecx + 4028 58/pop-to-eax + 4029 # . epilogue + 4030 89/<- %esp 5/r32/ebp + 4031 5d/pop-to-ebp + 4032 c3/return + 4033 + 4034 $parse-type:abort: + 4035 # error("unexpected token when parsing type: '" s "'\n") + 4036 (write-buffered Stderr "unexpected token when parsing type: '") + 4037 (write-slice-buffered Stderr %ecx) + 4038 (write-buffered Stderr "'\n") + 4039 (flush Stderr) + 4040 # . syscall(exit, 1) + 4041 bb/copy-to-ebx 1/imm32 + 4042 b8/copy-to-eax 1/imm32/exit + 4043 cd/syscall 0x80/imm8 + 4044 # never gets here + 4045 + 4046 parse-type-tree: # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle tree type-id) + 4047 # pseudocode: + 4048 # var tmp: (handle tree type-id) = parse-type(ad, in) + 4049 # if tmp == 0 + 4050 # return 0 + 4051 # out = allocate(Tree) + 4052 # out->left = tmp + 4053 # out->right = parse-type-tree(ad, in) + 4054 # + 4055 # . prologue + 4056 55/push-ebp + 4057 89/<- %ebp 4/r32/esp + 4058 # . save registers + 4059 50/push-eax + 4060 51/push-ecx + 4061 52/push-edx + 4062 # + 4063 (zero-out *(ebp+0x10) *Handle-size) + 4064 # var tmp/ecx: (handle tree type-id) + 4065 68/push 0/imm32 + 4066 68/push 0/imm32 + 4067 89/<- %ecx 4/r32/esp + 4068 # tmp = parse-type(ad, in) + 4069 (parse-type *(ebp+8) *(ebp+0xc) %ecx) + 4070 # if (tmp == 0) return + 4071 81 7/subop/compare *ecx 0/imm32 + 4072 74/jump-if-= $parse-type-tree:end/disp8 + 4073 # out = new tree + 4074 (allocate *(ebp+8) *Tree-size *(ebp+0x10)) + 4075 # var out-addr/edx: (addr tree) = lookup(*out) + 4076 8b/-> *(ebp+0x10) 2/r32/edx + 4077 (lookup *edx *(edx+4)) # => eax + 4078 89/<- %edx 0/r32/eax + 4079 # out->left = tmp + 4080 8b/-> *ecx 0/r32/eax + 4081 89/<- *(edx+4) 0/r32/eax # Tree-left + 4082 8b/-> *(ecx+4) 0/r32/eax + 4083 89/<- *(edx+8) 0/r32/eax # Tree-left + 4084 # out->right = parse-type-tree(ad, in) + 4085 8d/copy-address *(edx+0xc) 0/r32/eax # Tree-right + 4086 (parse-type-tree *(ebp+8) *(ebp+0xc) %eax) + 4087 $parse-type-tree:end: + 4088 # . reclaim locals + 4089 81 0/subop/add %esp 8/imm32 + 4090 # . restore registers + 4091 5a/pop-to-edx + 4092 59/pop-to-ecx + 4093 58/pop-to-eax + 4094 # . epilogue + 4095 89/<- %esp 5/r32/ebp + 4096 5d/pop-to-ebp + 4097 c3/return + 4098 + 4099 next-mu-token: # in: (addr stream byte), out: (addr slice) + 4100 # pseudocode: + 4101 # start: + 4102 # skip-chars-matching-whitespace(in) + 4103 # if in->read >= in->write # end of in + 4104 # out = {0, 0} + 4105 # return + 4106 # out->start = &in->data[in->read] + 4107 # var curr-byte/eax: byte = in->data[in->read] + 4108 # if curr->byte == ',' # comment token + 4109 # ++in->read + 4110 # goto start + 4111 # if curr-byte == '#' # comment + 4112 # goto done # treat as eof + 4113 # if curr-byte == '"' # string literal + 4114 # skip-string(in) + 4115 # goto done # no metadata + 4116 # if curr-byte == '(' + 4117 # ++in->read + 4118 # goto done + 4119 # if curr-byte == ')' + 4120 # ++in->read + 4121 # goto done + 4122 # # read a word + 4123 # while true + 4124 # if in->read >= in->write + 4125 # break + 4126 # curr-byte = in->data[in->read] + 4127 # if curr-byte == ' ' + 4128 # break + 4129 # if curr-byte == '\r' + 4130 # break + 4131 # if curr-byte == '\n' + 4132 # break + 4133 # if curr-byte == '(' + 4134 # break + 4135 # if curr-byte == ')' + 4136 # break + 4137 # if curr-byte == ',' + 4138 # break + 4139 # ++in->read + 4140 # done: + 4141 # out->end = &in->data[in->read] + 4142 # + 4143 # . prologue + 4144 55/push-ebp + 4145 89/<- %ebp 4/r32/esp + 4146 # . save registers + 4147 50/push-eax + 4148 51/push-ecx + 4149 56/push-esi + 4150 57/push-edi + 4151 # esi = in + 4152 8b/-> *(ebp+8) 6/r32/esi + 4153 # edi = out + 4154 8b/-> *(ebp+0xc) 7/r32/edi + 4155 $next-mu-token:start: + 4156 (skip-chars-matching-whitespace %esi) + 4157 $next-mu-token:check0: + 4158 # if (in->read >= in->write) return out = {0, 0} + 4159 # . ecx = in->read + 4160 8b/-> *(esi+4) 1/r32/ecx + 4161 # . if (ecx >= in->write) return out = {0, 0} + 4162 3b/compare<- *esi 1/r32/ecx + 4163 c7 0/subop/copy *edi 0/imm32 + 4164 c7 0/subop/copy *(edi+4) 0/imm32 + 4165 0f 8d/jump-if->= $next-mu-token:end/disp32 + 4166 # out->start = &in->data[in->read] + 4167 8d/copy-address *(esi+ecx+0xc) 0/r32/eax + 4168 89/<- *edi 0/r32/eax + 4169 # var curr-byte/eax: byte = in->data[in->read] + 4170 31/xor-with %eax 0/r32/eax + 4171 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL + 4172 { + 4173 $next-mu-token:check-for-comma: + 4174 # if (curr-byte != ',') break + 4175 3d/compare-eax-and 0x2c/imm32/comma + 4176 75/jump-if-!= break/disp8 + 4177 # ++in->read + 4178 ff 0/subop/increment *(esi+4) + 4179 # restart + 4180 e9/jump $next-mu-token:start/disp32 + 4181 } + 4182 { + 4183 $next-mu-token:check-for-comment: + 4184 # if (curr-byte != '#') break + 4185 3d/compare-eax-and 0x23/imm32/pound + 4186 75/jump-if-!= break/disp8 + 4187 # return eof + 4188 e9/jump $next-mu-token:done/disp32 + 4189 } + 4190 { + 4191 $next-mu-token:check-for-string-literal: + 4192 # if (curr-byte != '"') break + 4193 3d/compare-eax-and 0x22/imm32/dquote + 4194 75/jump-if-!= break/disp8 + 4195 (skip-string %esi) + 4196 # return + 4197 e9/jump $next-mu-token:done/disp32 + 4198 } + 4199 { + 4200 $next-mu-token:check-for-open-paren: + 4201 # if (curr-byte != '(') break + 4202 3d/compare-eax-and 0x28/imm32/open-paren + 4203 75/jump-if-!= break/disp8 + 4204 # ++in->read + 4205 ff 0/subop/increment *(esi+4) + 4206 # return + 4207 e9/jump $next-mu-token:done/disp32 + 4208 } + 4209 { + 4210 $next-mu-token:check-for-close-paren: + 4211 # if (curr-byte != ')') break + 4212 3d/compare-eax-and 0x29/imm32/close-paren + 4213 75/jump-if-!= break/disp8 + 4214 # ++in->read + 4215 ff 0/subop/increment *(esi+4) + 4216 # return + 4217 e9/jump $next-mu-token:done/disp32 + 4218 } + 4219 { + 4220 $next-mu-token:regular-word-without-metadata: + 4221 # if (in->read >= in->write) break + 4222 # . ecx = in->read + 4223 8b/-> *(esi+4) 1/r32/ecx + 4224 # . if (ecx >= in->write) break + 4225 3b/compare<- *esi 1/r32/ecx + 4226 7d/jump-if->= break/disp8 + 4227 # var c/eax: byte = in->data[in->read] + 4228 31/xor-with %eax 0/r32/eax + 4229 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL + 4230 # if (c == ' ') break + 4231 3d/compare-eax-and 0x20/imm32/space + 4232 74/jump-if-= break/disp8 + 4233 # if (c == '\r') break + 4234 3d/compare-eax-and 0xd/imm32/carriage-return + 4235 74/jump-if-= break/disp8 + 4236 # if (c == '\n') break + 4237 3d/compare-eax-and 0xa/imm32/newline + 4238 74/jump-if-= break/disp8 + 4239 # if (c == '(') break + 4240 3d/compare-eax-and 0x28/imm32/open-paren + 4241 0f 84/jump-if-= break/disp32 + 4242 # if (c == ')') break + 4243 3d/compare-eax-and 0x29/imm32/close-paren + 4244 0f 84/jump-if-= break/disp32 + 4245 # if (c == ',') break + 4246 3d/compare-eax-and 0x2c/imm32/comma + 4247 0f 84/jump-if-= break/disp32 + 4248 # ++in->read + 4249 ff 0/subop/increment *(esi+4) + 4250 # + 4251 e9/jump loop/disp32 + 4252 } + 4253 $next-mu-token:done: + 4254 # out->end = &in->data[in->read] + 4255 8b/-> *(esi+4) 1/r32/ecx + 4256 8d/copy-address *(esi+ecx+0xc) 0/r32/eax + 4257 89/<- *(edi+4) 0/r32/eax + 4258 $next-mu-token:end: + 4259 # . restore registers + 4260 5f/pop-to-edi + 4261 5e/pop-to-esi + 4262 59/pop-to-ecx + 4263 58/pop-to-eax + 4264 # . epilogue + 4265 89/<- %esp 5/r32/ebp + 4266 5d/pop-to-ebp + 4267 c3/return + 4268 + 4269 pos-or-insert-slice: # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int + 4270 # . prologue + 4271 55/push-ebp + 4272 89/<- %ebp 4/r32/esp + 4273 # if (pos-slice(arr, s) != -1) return it + 4274 (pos-slice *(ebp+8) *(ebp+0xc)) # => eax + 4275 3d/compare-eax-and -1/imm32 + 4276 75/jump-if-!= $pos-or-insert-slice:end/disp8 + 4277 $pos-or-insert-slice:insert: + 4278 # var s2/eax: (handle array byte) + 4279 68/push 0/imm32 + 4280 68/push 0/imm32 + 4281 89/<- %eax 4/r32/esp + 4282 (slice-to-string Heap *(ebp+0xc) %eax) + 4283 # throw away alloc-id + 4284 (lookup *eax *(eax+4)) # => eax + 4285 (write-int *(ebp+8) %eax) + 4286 (pos-slice *(ebp+8) *(ebp+0xc)) # => eax + 4287 $pos-or-insert-slice:end: + 4288 # . reclaim locals + 4289 81 0/subop/add %esp 8/imm32 + 4290 # . epilogue + 4291 89/<- %esp 5/r32/ebp + 4292 5d/pop-to-ebp + 4293 c3/return + 4294 + 4295 # return the index in an array of strings matching 's', -1 if not found + 4296 # index is denominated in elements, not bytes + 4297 pos-slice: # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int + 4298 # . prologue + 4299 55/push-ebp + 4300 89/<- %ebp 4/r32/esp + 4301 # . save registers + 4302 51/push-ecx + 4303 52/push-edx + 4304 53/push-ebx + 4305 56/push-esi + 4306 #? (write-buffered Stderr "pos-slice: ") + 4307 #? (write-slice-buffered Stderr *(ebp+0xc)) + 4308 #? (write-buffered Stderr "\n") + 4309 #? (flush Stderr) + 4310 # esi = arr + 4311 8b/-> *(ebp+8) 6/r32/esi + 4312 # var index/ecx: int = 0 + 4313 b9/copy-to-ecx 0/imm32 + 4314 # var curr/edx: (addr (addr array byte)) = arr->data + 4315 8d/copy-address *(esi+0xc) 2/r32/edx + 4316 # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write] + 4317 8b/-> *esi 3/r32/ebx + 4318 8d/copy-address *(esi+ebx+0xc) 3/r32/ebx + 4319 { + 4320 #? (write-buffered Stderr " ") + 4321 #? (print-int32-buffered Stderr %ecx) + 4322 #? (write-buffered Stderr "\n") + 4323 #? (flush Stderr) + 4324 # if (curr >= max) return -1 + 4325 39/compare %edx 3/r32/ebx + 4326 b8/copy-to-eax -1/imm32 + 4327 73/jump-if-addr>= $pos-slice:end/disp8 + 4328 # if (slice-equal?(s, *curr)) break + 4329 (slice-equal? *(ebp+0xc) *edx) # => eax + 4330 3d/compare-eax-and 0/imm32/false + 4331 75/jump-if-!= break/disp8 + 4332 # ++index + 4333 41/increment-ecx + 4334 # curr += 4 + 4335 81 0/subop/add %edx 4/imm32 + 4336 # + 4337 eb/jump loop/disp8 + 4338 } + 4339 # return index + 4340 89/<- %eax 1/r32/ecx + 4341 $pos-slice:end: + 4342 #? (write-buffered Stderr "=> ") + 4343 #? (print-int32-buffered Stderr %eax) + 4344 #? (write-buffered Stderr "\n") + 4345 # . restore registers + 4346 5e/pop-to-esi + 4347 5b/pop-to-ebx + 4348 5a/pop-to-edx + 4349 59/pop-to-ecx + 4350 # . epilogue + 4351 89/<- %esp 5/r32/ebp + 4352 5d/pop-to-ebp + 4353 c3/return + 4354 + 4355 test-parse-var-with-type: + 4356 # . prologue + 4357 55/push-ebp + 4358 89/<- %ebp 4/r32/esp + 4359 # (eax..ecx) = "x:" + 4360 b8/copy-to-eax "x:"/imm32 + 4361 8b/-> *eax 1/r32/ecx + 4362 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 4363 05/add-to-eax 4/imm32 + 4364 # var slice/ecx: slice = {eax, ecx} + 4365 51/push-ecx + 4366 50/push-eax + 4367 89/<- %ecx 4/r32/esp + 4368 # _test-input-stream contains "int" + 4369 (clear-stream _test-input-stream) + 4370 (write _test-input-stream "int") + 4371 # var v/edx: (handle var) + 4372 68/push 0/imm32 + 4373 68/push 0/imm32 + 4374 89/<- %edx 4/r32/esp + 4375 # + 4376 (parse-var-with-type %ecx _test-input-stream %edx) + 4377 # var v-addr/edx: (addr var) = lookup(v) + 4378 (lookup *edx *(edx+4)) # => eax + 4379 89/<- %edx 0/r32/eax + 4380 # check v-addr->name + 4381 (lookup *edx *(edx+4)) # Var-name Var-name => eax + 4382 (check-strings-equal %eax "x" "F - test-parse-var-with-type/name") + 4383 # check v-addr->type + 4384 (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + 4385 (check-ints-equal *eax 1 "F - test-parse-var-with-type/type:0") # Tree-is-atom + 4386 (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type/type:1") # Tree-value + 4387 (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type/type:2") # Tree-right + 4388 # . epilogue + 4389 89/<- %esp 5/r32/ebp + 4390 5d/pop-to-ebp + 4391 c3/return + 4392 + 4393 test-parse-var-with-type-and-register: + 4394 # . prologue + 4395 55/push-ebp + 4396 89/<- %ebp 4/r32/esp + 4397 # (eax..ecx) = "x/eax:" + 4398 b8/copy-to-eax "x/eax:"/imm32 + 4399 8b/-> *eax 1/r32/ecx + 4400 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 4401 05/add-to-eax 4/imm32 + 4402 # var slice/ecx: slice = {eax, ecx} + 4403 51/push-ecx + 4404 50/push-eax + 4405 89/<- %ecx 4/r32/esp + 4406 # _test-input-stream contains "int" + 4407 (clear-stream _test-input-stream) + 4408 (write _test-input-stream "int") + 4409 # var v/edx: (handle var) + 4410 68/push 0/imm32 + 4411 68/push 0/imm32 + 4412 89/<- %edx 4/r32/esp + 4413 # + 4414 (parse-var-with-type %ecx _test-input-stream %edx) + 4415 # var v-addr/edx: (addr var) = lookup(v) + 4416 (lookup *edx *(edx+4)) # => eax + 4417 89/<- %edx 0/r32/eax + 4418 # check v-addr->name + 4419 (lookup *edx *(edx+4)) # Var-name Var-name => eax + 4420 (check-strings-equal %eax "x" "F - test-parse-var-with-type-and-register/name") + 4421 # check v-addr->register + 4422 (lookup *(edx+0x18) *(edx+0x1c)) # Var-register Var-register => eax + 4423 (check-strings-equal %eax "eax" "F - test-parse-var-with-type-and-register/register") + 4424 # check v-addr->type + 4425 (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + 4426 (check-ints-equal *eax 1 "F - test-parse-var-with-type-and-register/type:0") # Tree-is-atom + 4427 (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type-and-register/type:1") # Tree-left + 4428 (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type-and-register/type:2") # Tree-right + 4429 # . epilogue + 4430 89/<- %esp 5/r32/ebp + 4431 5d/pop-to-ebp + 4432 c3/return + 4433 + 4434 test-parse-var-with-trailing-characters: + 4435 # . prologue + 4436 55/push-ebp + 4437 89/<- %ebp 4/r32/esp + 4438 # (eax..ecx) = "x:" + 4439 b8/copy-to-eax "x:"/imm32 + 4440 8b/-> *eax 1/r32/ecx + 4441 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 4442 05/add-to-eax 4/imm32 + 4443 # var slice/ecx: slice = {eax, ecx} + 4444 51/push-ecx + 4445 50/push-eax + 4446 89/<- %ecx 4/r32/esp + 4447 # _test-input-stream contains "int," + 4448 (clear-stream _test-input-stream) + 4449 (write _test-input-stream "int,") + 4450 # var v/edx: (handle var) + 4451 68/push 0/imm32 + 4452 68/push 0/imm32 + 4453 89/<- %edx 4/r32/esp + 4454 # + 4455 (parse-var-with-type %ecx _test-input-stream %edx) + 4456 # var v-addr/edx: (addr var) = lookup(v) + 4457 (lookup *edx *(edx+4)) # => eax + 4458 89/<- %edx 0/r32/eax + 4459 # check v-addr->name + 4460 (lookup *edx *(edx+4)) # Var-name Var-name => eax + 4461 (check-strings-equal %eax "x" "F - test-parse-var-with-trailing-characters/name") + 4462 # check v-addr->register + 4463 (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-trailing-characters/register") # Var-register + 4464 # check v-addr->type + 4465 (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + 4466 (check-ints-equal *eax 1 "F - test-parse-var-with-trailing-characters/type:0") # Tree-is-atom + 4467 (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-trailing-characters/type:1") # Tree-left + 4468 (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-trailing-characters/type:1") # Tree-right + 4469 # . epilogue + 4470 89/<- %esp 5/r32/ebp + 4471 5d/pop-to-ebp + 4472 c3/return + 4473 + 4474 test-parse-var-with-register-and-trailing-characters: + 4475 # . prologue + 4476 55/push-ebp + 4477 89/<- %ebp 4/r32/esp + 4478 # (eax..ecx) = "x/eax:" + 4479 b8/copy-to-eax "x/eax:"/imm32 + 4480 8b/-> *eax 1/r32/ecx + 4481 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 4482 05/add-to-eax 4/imm32 + 4483 # var slice/ecx: slice = {eax, ecx} + 4484 51/push-ecx + 4485 50/push-eax + 4486 89/<- %ecx 4/r32/esp + 4487 # _test-input-stream contains "int," + 4488 (clear-stream _test-input-stream) + 4489 (write _test-input-stream "int,") + 4490 # var v/edx: (handle var) + 4491 68/push 0/imm32 + 4492 68/push 0/imm32 + 4493 89/<- %edx 4/r32/esp + 4494 # + 4495 (parse-var-with-type %ecx _test-input-stream %edx) + 4496 # var v-addr/edx: (addr var) = lookup(v) + 4497 (lookup *edx *(edx+4)) # => eax + 4498 89/<- %edx 0/r32/eax + 4499 # check v-addr->name + 4500 (lookup *edx *(edx+4)) # Var-name Var-name => eax + 4501 (check-strings-equal %eax "x" "F - test-parse-var-with-register-and-trailing-characters/name") + 4502 # check v-addr->register + 4503 (lookup *(edx+0x18) *(edx+0x1c)) # Var-register Var-register => eax + 4504 (check-strings-equal %eax "eax" "F - test-parse-var-with-register-and-trailing-characters/register") + 4505 # check v-addr->type + 4506 (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + 4507 (check-ints-equal *eax 1 "F - test-parse-var-with-register-and-trailing-characters/type:0") # Tree-is-atom + 4508 (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-register-and-trailing-characters/type:1") # Tree-left + 4509 (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-register-and-trailing-characters/type:2") # Tree-right + 4510 # . epilogue + 4511 89/<- %esp 5/r32/ebp + 4512 5d/pop-to-ebp + 4513 c3/return + 4514 + 4515 test-parse-var-with-compound-type: + 4516 # . prologue + 4517 55/push-ebp + 4518 89/<- %ebp 4/r32/esp + 4519 # (eax..ecx) = "x:" + 4520 b8/copy-to-eax "x:"/imm32 + 4521 8b/-> *eax 1/r32/ecx + 4522 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 4523 05/add-to-eax 4/imm32 + 4524 # var slice/ecx: slice = {eax, ecx} + 4525 51/push-ecx + 4526 50/push-eax + 4527 89/<- %ecx 4/r32/esp + 4528 # _test-input-stream contains "(addr int)" + 4529 (clear-stream _test-input-stream) + 4530 (write _test-input-stream "(addr int)") + 4531 # var v/edx: (handle var) + 4532 68/push 0/imm32 + 4533 68/push 0/imm32 + 4534 89/<- %edx 4/r32/esp + 4535 # + 4536 (parse-var-with-type %ecx _test-input-stream %edx) + 4537 # var v-addr/edx: (addr var) = lookup(v) + 4538 (lookup *edx *(edx+4)) # => eax + 4539 89/<- %edx 0/r32/eax + 4540 # check v-addr->name + 4541 (lookup *edx *(edx+4)) # Var-name Var-name => eax + 4542 (check-strings-equal %eax "x" "F - test-parse-var-with-compound-type/name") + 4543 # check v-addr->register + 4544 (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-compound-type/register") # Var-register + 4545 # - check v-addr->type + 4546 # var type/edx: (addr tree type-id) = var->type + 4547 (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + 4548 89/<- %edx 0/r32/eax + 4549 # type is a non-atom + 4550 (check-ints-equal *edx 0 "F - test-parse-var-with-compound-type/type:0") # Tree-is-atom + 4551 # type->left == atom(addr) + 4552 (lookup *(edx+4) *(edx+8)) # Tree-left Tree-left => eax + 4553 (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:1") # Tree-is-atom + 4554 (check-ints-equal *(eax+4) 2 "F - test-parse-var-with-compound-type/type:2") # Tree-value + 4555 # type->right->left == atom(int) + 4556 (lookup *(edx+0xc) *(edx+0x10)) # Tree-right Tree-right => eax + 4557 (lookup *(eax+4) *(eax+8)) # Tree-left Tree-left => eax + 4558 (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:3") # Tree-is-atom + 4559 (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-compound-type/type:4") # Tree-value + 4560 # type->right->right == null + 4561 (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-compound-type/type:5") # Tree-right + 4562 # . epilogue + 4563 89/<- %esp 5/r32/ebp + 4564 5d/pop-to-ebp + 4565 c3/return + 4566 + 4567 # identifier starts with a letter or '$' or '_' + 4568 # no constraints at the moment on later letters + 4569 # all we really want to do so far is exclude '{', '}' and '->' + 4570 is-identifier?: # in: (addr slice) -> result/eax: boolean + 4571 # . prologue + 4572 55/push-ebp + 4573 89/<- %ebp 4/r32/esp + 4574 # if (slice-empty?(in)) return false + 4575 (slice-empty? *(ebp+8)) # => eax + 4576 3d/compare-eax-and 0/imm32/false + 4577 75/jump-if-!= $is-identifier?:false/disp8 + 4578 # var c/eax: byte = *in->start + 4579 8b/-> *(ebp+8) 0/r32/eax + 4580 8b/-> *eax 0/r32/eax + 4581 8a/copy-byte *eax 0/r32/AL + 4582 81 4/subop/and %eax 0xff/imm32 + 4583 # if (c == '$') return true + 4584 3d/compare-eax-and 0x24/imm32/$ + 4585 74/jump-if-= $is-identifier?:true/disp8 + 4586 # if (c == '_') return true + 4587 3d/compare-eax-and 0x5f/imm32/_ + 4588 74/jump-if-= $is-identifier?:true/disp8 + 4589 # drop case + 4590 25/and-eax-with 0x5f/imm32 + 4591 # if (c < 'A') return false + 4592 3d/compare-eax-and 0x41/imm32/A + 4593 7c/jump-if-< $is-identifier?:false/disp8 + 4594 # if (c > 'Z') return false + 4595 3d/compare-eax-and 0x5a/imm32/Z + 4596 7f/jump-if-> $is-identifier?:false/disp8 + 4597 # otherwise return true + 4598 $is-identifier?:true: + 4599 b8/copy-to-eax 1/imm32/true + 4600 eb/jump $is-identifier?:end/disp8 + 4601 $is-identifier?:false: + 4602 b8/copy-to-eax 0/imm32/false + 4603 $is-identifier?:end: + 4604 # . epilogue + 4605 89/<- %esp 5/r32/ebp + 4606 5d/pop-to-ebp + 4607 c3/return + 4608 + 4609 test-is-identifier-dollar: + 4610 # . prologue + 4611 55/push-ebp + 4612 89/<- %ebp 4/r32/esp + 4613 # (eax..ecx) = "$a" + 4614 b8/copy-to-eax "$a"/imm32 + 4615 8b/-> *eax 1/r32/ecx + 4616 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 4617 05/add-to-eax 4/imm32 + 4618 # var slice/ecx: slice = {eax, ecx} + 4619 51/push-ecx + 4620 50/push-eax + 4621 89/<- %ecx 4/r32/esp + 4622 # + 4623 (is-identifier? %ecx) + 4624 (check-ints-equal %eax 1 "F - test-is-identifier-dollar") + 4625 # . epilogue + 4626 89/<- %esp 5/r32/ebp + 4627 5d/pop-to-ebp + 4628 c3/return + 4629 + 4630 test-is-identifier-underscore: + 4631 # . prologue + 4632 55/push-ebp + 4633 89/<- %ebp 4/r32/esp + 4634 # (eax..ecx) = "_a" + 4635 b8/copy-to-eax "_a"/imm32 + 4636 8b/-> *eax 1/r32/ecx + 4637 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 4638 05/add-to-eax 4/imm32 + 4639 # var slice/ecx: slice = {eax, ecx} + 4640 51/push-ecx + 4641 50/push-eax + 4642 89/<- %ecx 4/r32/esp + 4643 # + 4644 (is-identifier? %ecx) + 4645 (check-ints-equal %eax 1 "F - test-is-identifier-underscore") + 4646 # . epilogue + 4647 89/<- %esp 5/r32/ebp + 4648 5d/pop-to-ebp + 4649 c3/return + 4650 + 4651 test-is-identifier-a: + 4652 # . prologue + 4653 55/push-ebp + 4654 89/<- %ebp 4/r32/esp + 4655 # (eax..ecx) = "a$" + 4656 b8/copy-to-eax "a$"/imm32 + 4657 8b/-> *eax 1/r32/ecx + 4658 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 4659 05/add-to-eax 4/imm32 + 4660 # var slice/ecx: slice = {eax, ecx} + 4661 51/push-ecx + 4662 50/push-eax + 4663 89/<- %ecx 4/r32/esp + 4664 # + 4665 (is-identifier? %ecx) + 4666 (check-ints-equal %eax 1 "F - test-is-identifier-a") + 4667 # . epilogue + 4668 89/<- %esp 5/r32/ebp + 4669 5d/pop-to-ebp + 4670 c3/return + 4671 + 4672 test-is-identifier-z: + 4673 # . prologue + 4674 55/push-ebp + 4675 89/<- %ebp 4/r32/esp + 4676 # (eax..ecx) = "z$" + 4677 b8/copy-to-eax "z$"/imm32 + 4678 8b/-> *eax 1/r32/ecx + 4679 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 4680 05/add-to-eax 4/imm32 + 4681 # var slice/ecx: slice = {eax, ecx} + 4682 51/push-ecx + 4683 50/push-eax + 4684 89/<- %ecx 4/r32/esp + 4685 # + 4686 (is-identifier? %ecx) + 4687 (check-ints-equal %eax 1 "F - test-is-identifier-z") + 4688 # . epilogue + 4689 89/<- %esp 5/r32/ebp + 4690 5d/pop-to-ebp + 4691 c3/return + 4692 + 4693 test-is-identifier-A: + 4694 # . prologue + 4695 55/push-ebp + 4696 89/<- %ebp 4/r32/esp + 4697 # (eax..ecx) = "A$" + 4698 b8/copy-to-eax "A$"/imm32 + 4699 8b/-> *eax 1/r32/ecx + 4700 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 4701 05/add-to-eax 4/imm32 + 4702 # var slice/ecx: slice = {eax, ecx} + 4703 51/push-ecx + 4704 50/push-eax + 4705 89/<- %ecx 4/r32/esp + 4706 # + 4707 (is-identifier? %ecx) + 4708 (check-ints-equal %eax 1 "F - test-is-identifier-A") + 4709 # . epilogue + 4710 89/<- %esp 5/r32/ebp + 4711 5d/pop-to-ebp + 4712 c3/return + 4713 + 4714 test-is-identifier-Z: + 4715 # . prologue + 4716 55/push-ebp + 4717 89/<- %ebp 4/r32/esp + 4718 # (eax..ecx) = "Z$" + 4719 b8/copy-to-eax "Z$"/imm32 + 4720 8b/-> *eax 1/r32/ecx + 4721 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 4722 05/add-to-eax 4/imm32 + 4723 # var slice/ecx: slice = {eax, ecx} + 4724 51/push-ecx + 4725 50/push-eax + 4726 89/<- %ecx 4/r32/esp + 4727 # + 4728 (is-identifier? %ecx) + 4729 (check-ints-equal %eax 1 "F - test-is-identifier-Z") + 4730 # . epilogue + 4731 89/<- %esp 5/r32/ebp + 4732 5d/pop-to-ebp + 4733 c3/return + 4734 + 4735 test-is-identifier-at: + 4736 # character before 'A' is invalid + 4737 # . prologue + 4738 55/push-ebp + 4739 89/<- %ebp 4/r32/esp + 4740 # (eax..ecx) = "@a" + 4741 b8/copy-to-eax "@a"/imm32 + 4742 8b/-> *eax 1/r32/ecx + 4743 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 4744 05/add-to-eax 4/imm32 + 4745 # var slice/ecx: slice = {eax, ecx} + 4746 51/push-ecx + 4747 50/push-eax + 4748 89/<- %ecx 4/r32/esp + 4749 # + 4750 (is-identifier? %ecx) + 4751 (check-ints-equal %eax 0 "F - test-is-identifier-@") + 4752 # . epilogue + 4753 89/<- %esp 5/r32/ebp + 4754 5d/pop-to-ebp + 4755 c3/return + 4756 + 4757 test-is-identifier-square-bracket: + 4758 # character after 'Z' is invalid + 4759 # . prologue + 4760 55/push-ebp + 4761 89/<- %ebp 4/r32/esp + 4762 # (eax..ecx) = "[a" + 4763 b8/copy-to-eax "[a"/imm32 + 4764 8b/-> *eax 1/r32/ecx + 4765 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 4766 05/add-to-eax 4/imm32 + 4767 # var slice/ecx: slice = {eax, ecx} + 4768 51/push-ecx + 4769 50/push-eax + 4770 89/<- %ecx 4/r32/esp + 4771 # + 4772 (is-identifier? %ecx) + 4773 (check-ints-equal %eax 0 "F - test-is-identifier-@") + 4774 # . epilogue + 4775 89/<- %esp 5/r32/ebp + 4776 5d/pop-to-ebp + 4777 c3/return + 4778 + 4779 test-is-identifier-backtick: + 4780 # character before 'a' is invalid + 4781 # . prologue + 4782 55/push-ebp + 4783 89/<- %ebp 4/r32/esp + 4784 # (eax..ecx) = "`a" + 4785 b8/copy-to-eax "`a"/imm32 + 4786 8b/-> *eax 1/r32/ecx + 4787 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 4788 05/add-to-eax 4/imm32 + 4789 # var slice/ecx: slice = {eax, ecx} + 4790 51/push-ecx + 4791 50/push-eax + 4792 89/<- %ecx 4/r32/esp + 4793 # + 4794 (is-identifier? %ecx) + 4795 (check-ints-equal %eax 0 "F - test-is-identifier-backtick") + 4796 # . epilogue + 4797 89/<- %esp 5/r32/ebp + 4798 5d/pop-to-ebp + 4799 c3/return + 4800 + 4801 test-is-identifier-curly-brace-open: + 4802 # character after 'z' is invalid; also used for blocks + 4803 # . prologue + 4804 55/push-ebp + 4805 89/<- %ebp 4/r32/esp + 4806 # (eax..ecx) = "{a" + 4807 b8/copy-to-eax "{a"/imm32 + 4808 8b/-> *eax 1/r32/ecx + 4809 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 4810 05/add-to-eax 4/imm32 + 4811 # var slice/ecx: slice = {eax, ecx} + 4812 51/push-ecx + 4813 50/push-eax + 4814 89/<- %ecx 4/r32/esp + 4815 # + 4816 (is-identifier? %ecx) + 4817 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open") + 4818 # . epilogue + 4819 89/<- %esp 5/r32/ebp + 4820 5d/pop-to-ebp + 4821 c3/return + 4822 + 4823 test-is-identifier-curly-brace-close: + 4824 # . prologue + 4825 55/push-ebp + 4826 89/<- %ebp 4/r32/esp + 4827 # (eax..ecx) = "}a" + 4828 b8/copy-to-eax "}a"/imm32 + 4829 8b/-> *eax 1/r32/ecx + 4830 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 4831 05/add-to-eax 4/imm32 + 4832 # var slice/ecx: slice = {eax, ecx} + 4833 51/push-ecx + 4834 50/push-eax + 4835 89/<- %ecx 4/r32/esp + 4836 # + 4837 (is-identifier? %ecx) + 4838 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close") + 4839 # . epilogue + 4840 89/<- %esp 5/r32/ebp + 4841 5d/pop-to-ebp + 4842 c3/return + 4843 + 4844 test-is-identifier-hyphen: + 4845 # disallow leading '-' since '->' has special meaning + 4846 # . prologue + 4847 55/push-ebp + 4848 89/<- %ebp 4/r32/esp + 4849 # (eax..ecx) = "-a" + 4850 b8/copy-to-eax "-a"/imm32 + 4851 8b/-> *eax 1/r32/ecx + 4852 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 4853 05/add-to-eax 4/imm32 + 4854 # var slice/ecx: slice = {eax, ecx} + 4855 51/push-ecx + 4856 50/push-eax + 4857 89/<- %ecx 4/r32/esp + 4858 # + 4859 (is-identifier? %ecx) + 4860 (check-ints-equal %eax 0 "F - test-is-identifier-hyphen") + 4861 # . epilogue + 4862 89/<- %esp 5/r32/ebp + 4863 5d/pop-to-ebp + 4864 c3/return + 4865 + 4866 populate-mu-function-body: # in: (addr buffered-file), out: (addr function), vars: (addr stack (handle var)) + 4867 # . prologue + 4868 55/push-ebp + 4869 89/<- %ebp 4/r32/esp + 4870 # . save registers + 4871 50/push-eax + 4872 56/push-esi + 4873 57/push-edi + 4874 # esi = in + 4875 8b/-> *(ebp+8) 6/r32/esi + 4876 # edi = out + 4877 8b/-> *(ebp+0xc) 7/r32/edi + 4878 # parse-mu-block(in, vars, out, out->body) + 4879 8d/copy-address *(edi+0x18) 0/r32/eax # Function-body + 4880 (parse-mu-block %esi *(ebp+0x10) %edi %eax) + 4881 $populate-mu-function-body:end: + 4882 # . restore registers + 4883 5f/pop-to-edi + 4884 5e/pop-to-esi + 4885 58/pop-to-eax + 4886 # . epilogue + 4887 89/<- %esp 5/r32/ebp + 4888 5d/pop-to-ebp + 4889 c3/return + 4890 + 4891 # parses a block, assuming that the leading '{' has already been read by the caller + 4892 parse-mu-block: # in: (addr buffered-file), vars: (addr stack (handle var)), fn: (addr function), out: (addr handle block) + 4893 # pseudocode: + 4894 # var line: (stream byte 512) + 4895 # var word-slice: slice + 4896 # allocate(Heap, Stmt-size, out) + 4897 # var out-addr: (addr block) = lookup(*out) + 4898 # out-addr->tag = 0/block + 4899 # out-addr->var = some unique name + 4900 # push(vars, out-addr->var) + 4901 # while true # line loop + 4902 # clear-stream(line) + 4903 # read-line-buffered(in, line) + 4904 # if (line->write == 0) break # end of file + 4905 # word-slice = next-mu-token(line) + 4906 # if slice-empty?(word-slice) # end of line + 4907 # continue + 4908 # else if slice-starts-with?(word-slice, "#") + 4909 # continue + 4910 # else if slice-equal?(word-slice, "{") + 4911 # assert(no-tokens-in(line)) + 4912 # block = parse-mu-block(in, vars, fn) + 4913 # append-to-block(out-addr, block) + 4914 # else if slice-equal?(word-slice, "}") + 4915 # break + 4916 # else if slice-ends-with?(word-slice, ":") + 4917 # # TODO: error-check the rest of 'line' + 4918 # --word-slice->end to skip ':' + 4919 # named-block = parse-mu-named-block(word-slice, in, vars, fn) + 4920 # append-to-block(out-addr, named-block) + 4921 # else if slice-equal?(word-slice, "var") + 4922 # var-def = parse-mu-var-def(line, vars) + 4923 # append-to-block(out-addr, var-def) + 4924 # else + 4925 # stmt = parse-mu-stmt(line, vars, fn) + 4926 # append-to-block(out-addr, stmt) + 4927 # pop(vars) + 4928 # + 4929 # . prologue + 4930 55/push-ebp + 4931 89/<- %ebp 4/r32/esp + 4932 # . save registers + 4933 50/push-eax + 4934 51/push-ecx + 4935 52/push-edx + 4936 53/push-ebx + 4937 57/push-edi + 4938 # var line/ecx: (stream byte 512) + 4939 81 5/subop/subtract %esp 0x200/imm32 + 4940 68/push 0x200/imm32/size + 4941 68/push 0/imm32/read + 4942 68/push 0/imm32/write + 4943 89/<- %ecx 4/r32/esp + 4944 # var word-slice/edx: slice + 4945 68/push 0/imm32/end + 4946 68/push 0/imm32/start + 4947 89/<- %edx 4/r32/esp + 4948 # allocate into out + 4949 (allocate Heap *Stmt-size *(ebp+0x14)) + 4950 # var out-addr/edi: (addr block) = lookup(*out) + 4951 8b/-> *(ebp+0x14) 7/r32/edi + 4952 (lookup *edi *(edi+4)) # => eax + 4953 89/<- %edi 0/r32/eax + 4954 # out-addr->tag is 0 (block) by default + 4955 # set out-addr->var + 4956 8d/copy-address *(edi+0xc) 0/r32/eax # Block-var + 4957 (new-block-name *(ebp+0x10) %eax) + 4958 # push(vars, out-addr->var) + 4959 (push *(ebp+0xc) *(edi+0xc)) # Block-var + 4960 (push *(ebp+0xc) *(edi+0x10)) # Block-var + 4961 { + 4962 $parse-mu-block:line-loop: + 4963 # line = read-line-buffered(in) + 4964 (clear-stream %ecx) + 4965 (read-line-buffered *(ebp+8) %ecx) + 4966 #? (write-buffered Stderr "line: ") + 4967 #? (write-stream-data Stderr %ecx) + 4968 #? (write-buffered Stderr Newline) + 4969 #? (flush Stderr) + 4970 # if (line->write == 0) break + 4971 81 7/subop/compare *ecx 0/imm32 + 4972 0f 84/jump-if-= break/disp32 + 4973 # word-slice = next-mu-token(line) + 4974 (next-mu-token %ecx %edx) + 4975 #? (write-buffered Stderr "word: ") + 4976 #? (write-slice-buffered Stderr %edx) + 4977 #? (write-buffered Stderr Newline) + 4978 #? (flush Stderr) + 4979 # if slice-empty?(word-slice) continue + 4980 (slice-empty? %edx) + 4981 3d/compare-eax-and 0/imm32/false + 4982 0f 85/jump-if-!= loop/disp32 + 4983 # if (slice-starts-with?(word-slice, '#') continue + 4984 # . eax = *word-slice->start + 4985 8b/-> *edx 0/r32/eax + 4986 8a/copy-byte *eax 0/r32/AL + 4987 81 4/subop/and %eax 0xff/imm32 + 4988 # . if (eax == '#') continue + 4989 3d/compare-eax-and 0x23/imm32/hash + 4990 0f 84/jump-if-= loop/disp32 + 4991 # if slice-equal?(word-slice, "{") + 4992 { + 4993 $parse-mu-block:check-for-block: + 4994 (slice-equal? %edx "{") + 4995 3d/compare-eax-and 0/imm32/false + 4996 74/jump-if-= break/disp8 + 4997 (check-no-tokens-left %ecx) + 4998 # parse new block and append + 4999 # . var tmp/eax: (handle block) + 5000 68/push 0/imm32 + 5001 68/push 0/imm32 + 5002 89/<- %eax 4/r32/esp + 5003 # . + 5004 (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax) + 5005 (append-to-block Heap %edi *eax *(eax+4)) + 5006 # . reclaim tmp + 5007 81 0/subop/add %esp 8/imm32 + 5008 # . + 5009 e9/jump $parse-mu-block:line-loop/disp32 + 5010 } + 5011 # if slice-equal?(word-slice, "}") break + 5012 $parse-mu-block:check-for-end: + 5013 (slice-equal? %edx "}") + 5014 3d/compare-eax-and 0/imm32/false + 5015 0f 85/jump-if-!= break/disp32 + 5016 # if slice-ends-with?(word-slice, ":") parse named block and append + 5017 { + 5018 $parse-mu-block:check-for-named-block: + 5019 # . eax = *(word-slice->end-1) + 5020 8b/-> *(edx+4) 0/r32/eax + 5021 48/decrement-eax + 5022 8a/copy-byte *eax 0/r32/AL + 5023 81 4/subop/and %eax 0xff/imm32 + 5024 # . if (eax != ':') break + 5025 3d/compare-eax-and 0x3a/imm32/colon + 5026 0f 85/jump-if-!= break/disp32 + 5027 # TODO: error-check the rest of 'line' + 5028 # + 5029 # skip ':' + 5030 ff 1/subop/decrement *(edx+4) # Slice-end + 5031 # var tmp/eax: (handle block) + 5032 68/push 0/imm32 + 5033 68/push 0/imm32 + 5034 89/<- %eax 4/r32/esp + 5035 # + 5036 (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax) + 5037 (append-to-block Heap %edi *eax *(eax+4)) + 5038 # reclaim tmp + 5039 81 0/subop/add %esp 8/imm32 + 5040 # + 5041 e9/jump $parse-mu-block:line-loop/disp32 + 5042 } + 5043 # if slice-equal?(word-slice, "var") + 5044 { + 5045 $parse-mu-block:check-for-var: + 5046 (slice-equal? %edx "var") + 5047 3d/compare-eax-and 0/imm32/false + 5048 74/jump-if-= break/disp8 + 5049 # var tmp/eax: (handle block) + 5050 68/push 0/imm32 + 5051 68/push 0/imm32 + 5052 89/<- %eax 4/r32/esp + 5053 # + 5054 (parse-mu-var-def %ecx *(ebp+0xc) %eax) + 5055 (append-to-block Heap %edi *eax *(eax+4)) + 5056 # reclaim tmp + 5057 81 0/subop/add %esp 8/imm32 + 5058 # + 5059 e9/jump $parse-mu-block:line-loop/disp32 + 5060 } + 5061 $parse-mu-block:regular-stmt: + 5062 # otherwise + 5063 # var tmp/eax: (handle block) + 5064 68/push 0/imm32 + 5065 68/push 0/imm32 + 5066 89/<- %eax 4/r32/esp + 5067 # + 5068 (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10) %eax) + 5069 (append-to-block Heap %edi *eax *(eax+4)) + 5070 # reclaim tmp + 5071 81 0/subop/add %esp 8/imm32 + 5072 # + 5073 e9/jump loop/disp32 + 5074 } # end line loop + 5075 # pop(vars) + 5076 (pop *(ebp+0xc)) # => eax + 5077 (pop *(ebp+0xc)) # => eax + 5078 $parse-mu-block:end: + 5079 # . reclaim locals + 5080 81 0/subop/add %esp 0x214/imm32 + 5081 # . restore registers + 5082 5f/pop-to-edi + 5083 5b/pop-to-ebx + 5084 5a/pop-to-edx + 5085 59/pop-to-ecx + 5086 58/pop-to-eax + 5087 # . epilogue + 5088 89/<- %esp 5/r32/ebp + 5089 5d/pop-to-ebp + 5090 c3/return + 5091 + 5092 $parse-mu-block:abort: + 5093 # error("'{' or '}' should be on its own line, but got '") + 5094 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") + 5095 (rewind-stream %ecx) + 5096 (write-stream 2 %ecx) + 5097 (write-buffered Stderr "'\n") + 5098 (flush Stderr) + 5099 # . syscall(exit, 1) + 5100 bb/copy-to-ebx 1/imm32 + 5101 b8/copy-to-eax 1/imm32/exit + 5102 cd/syscall 0x80/imm8 + 5103 # never gets here + 5104 + 5105 new-block-name: # fn: (addr function), out: (addr handle var) + 5106 # . prologue + 5107 55/push-ebp + 5108 89/<- %ebp 4/r32/esp + 5109 # . save registers + 5110 50/push-eax + 5111 51/push-ecx + 5112 52/push-edx + 5113 # var n/ecx: int = len(fn->name) + 10 for an int + 2 for '$:' + 5114 8b/-> *(ebp+8) 0/r32/eax + 5115 (lookup *eax *(eax+4)) # Function-name Function-name => eax + 5116 8b/-> *eax 0/r32/eax # String-size + 5117 05/add-to-eax 0xd/imm32 # 10 + 2 for '$:' + 5118 89/<- %ecx 0/r32/eax + 5119 # var name/edx: (stream byte n) + 5120 29/subtract-from %esp 1/r32/ecx + 5121 ff 6/subop/push %ecx + 5122 68/push 0/imm32/read + 5123 68/push 0/imm32/write + 5124 89/<- %edx 4/r32/esp + 5125 (clear-stream %edx) + 5126 # eax = fn->name + 5127 8b/-> *(ebp+8) 0/r32/eax + 5128 (lookup *eax *(eax+4)) # Function-name Function-name => eax + 5129 # construct result using Next-block-index (and increment it) + 5130 (write %edx "$") + 5131 (write %edx %eax) + 5132 (write %edx ":") + 5133 (print-int32 %edx *Next-block-index) + 5134 ff 0/subop/increment *Next-block-index + 5135 # var s/eax: slice = {name->data, name->data + name->write} (clobbering edx) + 5136 # . eax = name->write + 5137 8b/-> *edx 0/r32/eax + 5138 # . edx = name->data + 5139 8d/copy-address *(edx+0xc) 2/r32/edx + 5140 # . eax = name->write + name->data + 5141 01/add-to %eax 2/r32/edx + 5142 # . push {edx, eax} + 5143 ff 6/subop/push %eax + 5144 ff 6/subop/push %edx + 5145 89/<- %eax 4/r32/esp + 5146 # out = new literal(s) + 5147 (new-literal Heap %eax *(ebp+0xc)) + 5148 #? 8b/-> *(ebp+0xc) 0/r32/eax + 5149 #? (write-buffered Stderr "type allocid in caller after new-literal: ") + 5150 #? (print-int32-buffered Stderr *(eax+8)) + 5151 #? (write-buffered Stderr " for var ") + 5152 #? (print-int32-buffered Stderr %eax) + 5153 #? (write-buffered Stderr Newline) + 5154 #? (flush Stderr) + 5155 $new-block-name:end: + 5156 # . reclaim locals + 5157 81 0/subop/add %ecx 0xc/imm32 # name.{read/write/len} + 5158 81 0/subop/add %ecx 8/imm32 # slice + 5159 01/add-to %esp 1/r32/ecx + 5160 # . restore registers + 5161 5a/pop-to-edx + 5162 59/pop-to-ecx + 5163 58/pop-to-eax + 5164 # . epilogue + 5165 89/<- %esp 5/r32/ebp + 5166 5d/pop-to-ebp + 5167 c3/return + 5168 + 5169 == data + 5170 + 5171 # Global state added to each var record when parsing a function + 5172 Next-block-index: # (addr int) + 5173 1/imm32 + 5174 + 5175 == code + 5176 + 5177 check-no-tokens-left: # line: (addr stream byte) + 5178 # . prologue + 5179 55/push-ebp + 5180 89/<- %ebp 4/r32/esp + 5181 # . save registers + 5182 50/push-eax + 5183 51/push-ecx + 5184 # var s/ecx: slice + 5185 68/push 0/imm32/end + 5186 68/push 0/imm32/start + 5187 89/<- %ecx 4/r32/esp + 5188 # + 5189 (next-mu-token *(ebp+8) %ecx) + 5190 # if slice-empty?(s) return + 5191 (slice-empty? %ecx) + 5192 3d/compare-eax-and 0/imm32/false + 5193 75/jump-if-!= $check-no-tokens-left:end/disp8 + 5194 # if (slice-starts-with?(s, '#') return + 5195 # . eax = *s->start + 5196 8b/-> *edx 0/r32/eax + 5197 8a/copy-byte *eax 0/r32/AL + 5198 81 4/subop/and %eax 0xff/imm32 + 5199 # . if (eax == '#') continue + 5200 3d/compare-eax-and 0x23/imm32/hash + 5201 74/jump-if-= $check-no-tokens-left:end/disp8 + 5202 # abort + 5203 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") + 5204 (rewind-stream %ecx) + 5205 (write-stream 2 %ecx) + 5206 (write-buffered Stderr "'\n") + 5207 (flush Stderr) + 5208 # . syscall(exit, 1) + 5209 bb/copy-to-ebx 1/imm32 + 5210 b8/copy-to-eax 1/imm32/exit + 5211 cd/syscall 0x80/imm8 + 5212 # never gets here + 5213 $check-no-tokens-left:end: + 5214 # . reclaim locals + 5215 81 0/subop/add %esp 8/imm32 + 5216 # . restore registers + 5217 59/pop-to-ecx + 5218 58/pop-to-eax + 5219 # . epilogue + 5220 89/<- %esp 5/r32/ebp + 5221 5d/pop-to-ebp + 5222 c3/return + 5223 + 5224 parse-mu-named-block: # name: (addr slice), in: (addr buffered-file), vars: (addr stack (handle var)), fn: (addr function), out: (addr handle stmt) + 5225 # pseudocode: + 5226 # var v: (handle var) + 5227 # new-literal(name, v) + 5228 # push(vars, v) + 5229 # parse-mu-block(in, vars, fn, out) + 5230 # pop(vars) + 5231 # out->tag = block + 5232 # out->var = v + 5233 # + 5234 # . prologue + 5235 55/push-ebp + 5236 89/<- %ebp 4/r32/esp + 5237 # . save registers + 5238 50/push-eax + 5239 51/push-ecx + 5240 57/push-edi + 5241 # var v/ecx: (handle var) + 5242 68/push 0/imm32 + 5243 68/push 0/imm32 + 5244 89/<- %ecx 4/r32/esp + 5245 # + 5246 (new-literal Heap *(ebp+8) %ecx) + 5247 # push(vars, v) + 5248 (push *(ebp+0x10) *ecx) + 5249 (push *(ebp+0x10) *(ecx+4)) + 5250 # + 5251 (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18)) + 5252 # pop v off vars + 5253 (pop *(ebp+0x10)) # => eax + 5254 (pop *(ebp+0x10)) # => eax + 5255 # var out-addr/edi: (addr stmt) = lookup(*out) + 5256 8b/-> *(ebp+0x18) 7/r32/edi + 5257 (lookup *edi *(edi+4)) # => eax + 5258 89/<- %edi 0/r32/eax + 5259 # out-addr->tag = named-block + 5260 c7 0/subop/copy *edi 0/imm32/block # Stmt-tag + 5261 # out-addr->var = v + 5262 8b/-> *ecx 0/r32/eax + 5263 89/<- *(edi+0xc) 0/r32/eax # Block-var + 5264 8b/-> *(ecx+4) 0/r32/eax + 5265 89/<- *(edi+0x10) 0/r32/eax # Block-var + 5266 $parse-mu-named-block:end: + 5267 # . reclaim locals + 5268 81 0/subop/add %esp 8/imm32 + 5269 # . restore registers + 5270 5f/pop-to-edi + 5271 59/pop-to-ecx + 5272 58/pop-to-eax + 5273 # . epilogue + 5274 89/<- %esp 5/r32/ebp + 5275 5d/pop-to-ebp + 5276 c3/return + 5277 + 5278 parse-mu-var-def: # line: (addr stream byte), vars: (addr stack (handle var)), out: (addr handle stmt) + 5279 # . prologue + 5280 55/push-ebp + 5281 89/<- %ebp 4/r32/esp + 5282 # . save registers + 5283 50/push-eax + 5284 51/push-ecx + 5285 52/push-edx + 5286 57/push-edi + 5287 # edi = out + 5288 8b/-> *(ebp+0x10) 7/r32/edi + 5289 # var word-slice/ecx: slice + 5290 68/push 0/imm32/end + 5291 68/push 0/imm32/start + 5292 89/<- %ecx 4/r32/esp + 5293 # var v/edx: (handle var) + 5294 68/push 0/imm32 + 5295 68/push 0/imm32 + 5296 89/<- %edx 4/r32/esp + 5297 # v = parse-var-with-type(next-mu-token(line)) + 5298 (next-mu-token *(ebp+8) %ecx) + 5299 (parse-var-with-type %ecx *(ebp+8) %edx) + 5300 # + 5301 (push *(ebp+0xc) *edx) + 5302 (push *(ebp+0xc) *(edx+4)) + 5303 # either v has no register and there's no more to this line + 5304 (lookup *edx *(edx+4)) # => eax + 5305 8b/-> *(eax+0x18) 0/r32/eax # Var-register + 5306 3d/compare-eax-and 0/imm32 + 5307 { + 5308 75/jump-if-!= break/disp8 + 5309 # TODO: ensure that there's nothing else on this line + 5310 (new-var-def Heap *edx *(edx+4) %edi) + 5311 eb/jump $parse-mu-var-def:end/disp8 + 5312 } + 5313 # or v has a register and there's more to this line 5314 { - 5315 (next-mu-token *(ebp+8) %ecx) - 5316 # if slice-empty?(word-slice) break - 5317 (slice-empty? %ecx) - 5318 3d/compare-eax-and 0/imm32/false - 5319 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) - 5320 0f 85/jump-if-!= break/disp32 - 5321 # if slice-starts-with?(word-slice, '#') break - 5322 # . eax = *word-slice->start - 5323 8b/-> *ecx 0/r32/eax - 5324 8a/copy-byte *eax 0/r32/AL - 5325 81 4/subop/and %eax 0xff/imm32 - 5326 # . if (eax == '#') break - 5327 3d/compare-eax-and 0x23/imm32/hash - 5328 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) - 5329 0f 84/jump-if-= break/disp32 - 5330 # if slice-equal?(word-slice, '<-') return true - 5331 (slice-equal? %ecx "<-") - 5332 3d/compare-eax-and 0/imm32/false - 5333 74/jump-if-= loop/disp8 - 5334 b8/copy-to-eax 1/imm32/true - 5335 } - 5336 $stmt-has-outputs:end: - 5337 (rewind-stream *(ebp+8)) - 5338 # . reclaim locals - 5339 81 0/subop/add %esp 8/imm32 - 5340 # . restore registers - 5341 59/pop-to-ecx - 5342 # . epilogue - 5343 89/<- %esp 5/r32/ebp - 5344 5d/pop-to-ebp - 5345 c3/return - 5346 - 5347 # if 'name' starts with a digit, create a new literal var for it - 5348 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found - 5349 lookup-var-or-literal: # name: (addr slice), vars: (addr stack (handle var)) -> result/eax: (handle var) - 5350 # . prologue - 5351 55/push-ebp - 5352 89/<- %ebp 4/r32/esp - 5353 # . save registers - 5354 51/push-ecx - 5355 56/push-esi - 5356 # esi = name - 5357 8b/-> *(ebp+8) 6/r32/esi - 5358 # if slice-empty?(name) abort - 5359 (slice-empty? %esi) # => eax - 5360 3d/compare-eax-and 0/imm32/false - 5361 0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32 - 5362 # var c/ecx: byte = *name->start - 5363 8b/-> *esi 1/r32/ecx - 5364 8a/copy-byte *ecx 1/r32/CL - 5365 81 4/subop/and %ecx 0xff/imm32 - 5366 # if is-decimal-digit?(c) return new var(name) - 5367 { - 5368 (is-decimal-digit? %ecx) # => eax - 5369 3d/compare-eax-and 0/imm32/false - 5370 74/jump-if-= break/disp8 - 5371 (new-literal-integer Heap %esi) # => eax - 5372 eb/jump $lookup-var-or-literal:end/disp8 - 5373 } - 5374 # else if (c == '"') return new var(name) - 5375 { - 5376 81 7/subop/compare %ecx 0x22/imm32/dquote - 5377 75/jump-if-!= break/disp8 - 5378 (new-literal Heap %esi) # => eax - 5379 eb/jump $lookup-var-or-literal:end/disp8 - 5380 } - 5381 # otherwise return lookup-var(name, vars) - 5382 { - 5383 (lookup-var %esi *(ebp+0xc)) # => eax - 5384 } - 5385 $lookup-var-or-literal:end: - 5386 # . restore registers - 5387 5e/pop-to-esi - 5388 59/pop-to-ecx - 5389 # . epilogue - 5390 89/<- %esp 5/r32/ebp - 5391 5d/pop-to-ebp - 5392 c3/return - 5393 - 5394 $lookup-var-or-literal:abort: - 5395 (write-buffered Stderr "empty variable!") - 5396 (flush Stderr) - 5397 # . syscall(exit, 1) - 5398 bb/copy-to-ebx 1/imm32 - 5399 b8/copy-to-eax 1/imm32/exit - 5400 cd/syscall 0x80/imm8 - 5401 # never gets here - 5402 - 5403 # return first 'name' from the top (back) of 'vars' and abort if not found - 5404 lookup-var: # name: (addr slice), vars: (addr stack (handle var)) -> result/eax: (handle var) - 5405 # . prologue - 5406 55/push-ebp - 5407 89/<- %ebp 4/r32/esp - 5408 # var target/eax: (handle array byte) = slice-to-string(name) - 5409 (slice-to-string Heap *(ebp+8)) # => eax - 5410 # - 5411 (lookup-var-helper %eax *(ebp+0xc)) # => eax - 5412 # if (result == 0) abort - 5413 3d/compare-eax-and 0/imm32 - 5414 74/jump-if-= $lookup-var:abort/disp8 - 5415 $lookup-var:end: - 5416 # . epilogue - 5417 89/<- %esp 5/r32/ebp - 5418 5d/pop-to-ebp - 5419 c3/return - 5420 - 5421 $lookup-var:abort: - 5422 (write-buffered Stderr "unknown variable '") - 5423 (write-slice-buffered Stderr *(ebp+8)) - 5424 (write-buffered Stderr "'\n") - 5425 (flush Stderr) - 5426 # . syscall(exit, 1) - 5427 bb/copy-to-ebx 1/imm32 - 5428 b8/copy-to-eax 1/imm32/exit - 5429 cd/syscall 0x80/imm8 - 5430 # never gets here - 5431 - 5432 # return first 'name' from the top (back) of 'vars', and 0/null if not found - 5433 lookup-var-helper: # name: (addr array byte), vars: (addr stack (handle var)) -> result/eax: (handle var) - 5434 # pseudocode: - 5435 # var curr: (addr handle var) = &vars->data[vars->top - 4] - 5436 # var min = vars->data - 5437 # while curr >= min - 5438 # var v: (handle var) = *curr - 5439 # if v->name == name - 5440 # return v - 5441 # return 0 - 5442 # - 5443 # . prologue - 5444 55/push-ebp - 5445 89/<- %ebp 4/r32/esp - 5446 # . save registers - 5447 52/push-edx - 5448 53/push-ebx - 5449 56/push-esi - 5450 # esi = vars - 5451 8b/-> *(ebp+0xc) 6/r32/esi - 5452 # ebx = vars->top - 5453 8b/-> *esi 3/r32/ebx - 5454 # if (vars->top > vars->size) abort - 5455 3b/compare<- *(esi+4) 0/r32/eax - 5456 0f 8f/jump-if-> $lookup-var-helper:error1/disp32 - 5457 # var min/edx: (addr handle var) = vars->data - 5458 8d/copy-address *(esi+8) 2/r32/edx - 5459 # var curr/ebx: (addr handle var) = &vars->data[vars->top - 4] - 5460 81 5/subop/subtract %ebx 4/imm32 - 5461 8d/copy-address *(esi+ebx+8) 3/r32/ebx - 5462 { - 5463 # if (curr < min) return 0 - 5464 39/compare %ebx 2/r32/edx - 5465 b8/copy-to-eax 0/imm32 - 5466 0f 82/jump-if-addr< break/disp32 - 5467 # var v/eax: (handle var) = *curr - 5468 8b/-> *ebx 0/r32/eax - 5469 # if (v->name == name) return v - 5470 (string-equal? *eax *(ebp+8)) # Var-name - 5471 3d/compare-eax-and 0/imm32/false - 5472 8b/-> *ebx 0/r32/eax - 5473 75/jump-if-!= break/disp8 - 5474 # curr -= 4 - 5475 81 5/subop/subtract %ebx 4/imm32 - 5476 e9/jump loop/disp32 - 5477 } - 5478 $lookup-var-helper:end: - 5479 # . restore registers - 5480 5e/pop-to-esi - 5481 5b/pop-to-ebx - 5482 5a/pop-to-edx - 5483 # . epilogue - 5484 89/<- %esp 5/r32/ebp - 5485 5d/pop-to-ebp - 5486 c3/return - 5487 - 5488 $lookup-var-helper:error1: - 5489 (write-buffered Stderr "malformed stack when looking up '") - 5490 (write-slice-buffered Stderr *(ebp+8)) - 5491 (write-buffered Stderr "'\n") - 5492 (flush Stderr) - 5493 # . syscall(exit, 1) - 5494 bb/copy-to-ebx 1/imm32 - 5495 b8/copy-to-eax 1/imm32/exit - 5496 cd/syscall 0x80/imm8 - 5497 # never gets here - 5498 - 5499 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found - 5500 lookup-or-define-var: # name: (addr slice), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle var) - 5501 # . prologue - 5502 55/push-ebp - 5503 89/<- %ebp 4/r32/esp - 5504 # . save registers - 5505 51/push-ecx - 5506 # var target/ecx: (handle array byte) = slice-to-string(name) - 5507 (slice-to-string Heap *(ebp+8)) # => eax - 5508 89/<- %ecx 0/r32/eax - 5509 # - 5510 (lookup-var-helper %ecx *(ebp+0xc)) # => eax - 5511 { - 5512 # if (result != 0) return - 5513 3d/compare-eax-and 0/imm32 - 5514 75/jump-if-!= break/disp8 - 5515 # if name is one of fn's outputs, return it - 5516 { - 5517 (find-in-function-outputs *(ebp+0x10) %ecx) # => eax - 5518 3d/compare-eax-and 0/imm32 - 5519 # otherwise abort - 5520 0f 84/jump-if-!= $lookup-var:abort/disp32 - 5521 } - 5522 } - 5523 $lookup-or-define-var:end: - 5524 # . restore registers - 5525 59/pop-to-ecx - 5526 # . epilogue - 5527 89/<- %esp 5/r32/ebp - 5528 5d/pop-to-ebp - 5529 c3/return - 5530 - 5531 find-in-function-outputs: # fn: (handle function), name: (handle array byte) -> result/eax: (handle var) - 5532 # . prologue - 5533 55/push-ebp - 5534 89/<- %ebp 4/r32/esp - 5535 # . save registers - 5536 51/push-ecx - 5537 # var curr/ecx: (handle list var) = fn->outputs - 5538 8b/-> *(ebp+8) 1/r32/ecx - 5539 8b/-> *(ecx+0xc) 1/r32/ecx - 5540 # while curr != null - 5541 { - 5542 81 7/subop/compare %ecx 0/imm32 - 5543 74/jump-if-= break/disp8 - 5544 # var v: (handle var) = *curr - 5545 8b/-> *ecx 0/r32/eax # List-value - 5546 # if (curr->name == name) return curr - 5547 50/push-eax - 5548 (string-equal? *eax *(ebp+0xc)) - 5549 3d/compare-eax-and 0/imm32/false - 5550 58/pop-to-eax - 5551 75/jump-if-!= $find-in-function-outputs:end/disp8 - 5552 # curr = curr->next - 5553 8b/-> *(ecx+4) 1/r32/ecx # List-next - 5554 eb/jump loop/disp8 - 5555 } - 5556 b8/copy-to-eax 0/imm32 - 5557 $find-in-function-outputs:end: - 5558 # . restore registers - 5559 59/pop-to-ecx - 5560 # . epilogue - 5561 89/<- %esp 5/r32/ebp - 5562 5d/pop-to-ebp - 5563 c3/return - 5564 - 5565 test-parse-mu-stmt: - 5566 # . prologue - 5567 55/push-ebp - 5568 89/<- %ebp 4/r32/esp - 5569 # setup - 5570 (clear-stream _test-input-stream) - 5571 (write _test-input-stream "increment n\n") - 5572 # var vars/ecx: (stack (addr var) 4) - 5573 81 5/subop/subtract %esp 0x10/imm32 - 5574 68/push 0x10/imm32/size - 5575 68/push 0/imm32/top - 5576 89/<- %ecx 4/r32/esp - 5577 (clear-stack %ecx) - 5578 # var v/edx: var - 5579 81 5/subop/subtract %esp 0x14/imm32 # Var-size - 5580 89/<- %edx 4/r32/esp - 5581 (zero-out %edx 0x14) # Var-size - 5582 # v->name = "n" - 5583 c7 0/subop/copy *edx "n"/imm32 # Var-name - 5584 # - 5585 (push %ecx %edx) - 5586 # convert - 5587 (parse-mu-stmt _test-input-stream %ecx) # => eax - 5588 # check result - 5589 (check-ints-equal *eax 1 "F - test-parse-mu-stmt/tag") # Stmt-tag is Stmt1 - 5590 (check-strings-equal *(eax+4) "increment" "F - test-parse-mu-stmt/name") # Stmt1-operation - 5591 # edx: (handle list var) = result->inouts - 5592 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts - 5593 # ebx: (handle var) = result->inouts->value - 5594 8b/-> *edx 3/r32/ebx # Stmt-var-value - 5595 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt/inout:0") # Var-name - 5596 # . epilogue - 5597 89/<- %esp 5/r32/ebp - 5598 5d/pop-to-ebp - 5599 c3/return - 5600 - 5601 test-parse-mu-stmt-with-comma: - 5602 # . prologue - 5603 55/push-ebp - 5604 89/<- %ebp 4/r32/esp - 5605 # setup - 5606 (clear-stream _test-input-stream) - 5607 (write _test-input-stream "copy-to n, 3\n") - 5608 # var vars/ecx: (stack (addr var) 4) - 5609 81 5/subop/subtract %esp 0x10/imm32 - 5610 68/push 0x10/imm32/size - 5611 68/push 0/imm32/top - 5612 89/<- %ecx 4/r32/esp - 5613 (clear-stack %ecx) - 5614 # var v/edx: var - 5615 81 5/subop/subtract %esp 0x14/imm32 # Var-size - 5616 89/<- %edx 4/r32/esp - 5617 (zero-out %edx 0x14) # Var-size - 5618 # v->name = "n" - 5619 c7 0/subop/copy *edx "n"/imm32 # Var-name - 5620 # - 5621 (push %ecx %edx) - 5622 # convert - 5623 (parse-mu-stmt _test-input-stream %ecx) # => eax - 5624 # check result - 5625 (check-ints-equal *eax 1 "F - test-parse-mu-stmt-with-comma/tag") # Stmt-tag is Stmt1 - 5626 (check-strings-equal *(eax+4) "copy-to" "F - test-parse-mu-stmt-with-comma/name") # Stmt1-operation - 5627 # edx: (handle list var) = result->inouts - 5628 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts - 5629 # ebx: (handle var) = result->inouts->value - 5630 8b/-> *edx 3/r32/ebx # Stmt-var-value - 5631 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt-with-comma/inout:0") # Var-name - 5632 # . epilogue - 5633 89/<- %esp 5/r32/ebp - 5634 5d/pop-to-ebp - 5635 c3/return - 5636 - 5637 new-var: # ad: (addr allocation-descriptor), name: (addr array byte) -> result/eax: (handle var) - 5638 # . prologue - 5639 55/push-ebp - 5640 89/<- %ebp 4/r32/esp - 5641 # . save registers - 5642 51/push-ecx - 5643 # - 5644 (allocate *(ebp+8) *Var-size) # => eax - 5645 8b/-> *(ebp+0xc) 1/r32/ecx - 5646 89/<- *eax 1/r32/ecx # Var-name - 5647 $new-var:end: - 5648 # . restore registers - 5649 59/pop-to-ecx - 5650 # . epilogue - 5651 89/<- %esp 5/r32/ebp - 5652 5d/pop-to-ebp - 5653 c3/return - 5654 - 5655 new-literal-integer: # ad: (addr allocation-descriptor), name: (addr slice) -> result/eax: (handle var) - 5656 # . prologue - 5657 55/push-ebp - 5658 89/<- %ebp 4/r32/esp - 5659 # . save registers - 5660 51/push-ecx - 5661 # if (!is-hex-int?(name)) abort - 5662 (is-hex-int? *(ebp+0xc)) # => eax - 5663 3d/compare-eax-and 0/imm32/false - 5664 0f 84/jump-if-= $new-literal-integer:abort/disp32 - 5665 # var type/ecx: (handle tree type-id) = new type() - 5666 (allocate *(ebp+8) *Tree-size) # => eax - 5667 # nothing else to do; default type is 'literal' - 5668 c7 0/subop/copy *eax 1/imm32/true # Tree-is-atom - 5669 89/<- %ecx 0/r32/eax - 5670 # result = new var(s) - 5671 (new-var-from-slice *(ebp+8) *(ebp+0xc)) # => eax - 5672 89/<- *(eax+4) 1/r32/ecx - 5673 $new-literal-integer:end: - 5674 # . restore registers - 5675 59/pop-to-ecx - 5676 # . epilogue - 5677 89/<- %esp 5/r32/ebp - 5678 5d/pop-to-ebp - 5679 c3/return - 5680 - 5681 $new-literal-integer:abort: - 5682 (write-buffered Stderr "variable cannot begin with a digit '") - 5683 (write-slice-buffered Stderr *(ebp+0xc)) - 5684 (write-buffered Stderr "'\n") - 5685 (flush Stderr) - 5686 # . syscall(exit, 1) - 5687 bb/copy-to-ebx 1/imm32 - 5688 b8/copy-to-eax 1/imm32/exit - 5689 cd/syscall 0x80/imm8 - 5690 # never gets here - 5691 - 5692 new-literal: # ad: (addr allocation-descriptor), name: (addr slice) -> result/eax: (handle var) - 5693 # . prologue - 5694 55/push-ebp - 5695 89/<- %ebp 4/r32/esp - 5696 # . save registers - 5697 51/push-ecx - 5698 52/push-edx - 5699 # var s/ecx: (addr array byte) - 5700 (slice-to-string Heap *(ebp+0xc)) # => eax - 5701 89/<- %ecx 0/r32/eax - 5702 # type = new type() - 5703 (allocate *(ebp+8) *Tree-size) # => eax - 5704 # nothing else to do; default type is 'literal' - 5705 c7 0/subop/copy *eax 1/imm32/true # Tree-is-atom - 5706 89/<- %edx 0/r32/eax - 5707 # eax = result - 5708 (new-var *(ebp+8) %ecx) # => eax - 5709 # result->type = type - 5710 89/<- *(eax+4) 2/r32/edx # Var-type - 5711 $new-literal:end: - 5712 # . restore registers - 5713 5a/pop-to-edx - 5714 59/pop-to-ecx - 5715 # . epilogue - 5716 89/<- %esp 5/r32/ebp - 5717 5d/pop-to-ebp - 5718 c3/return - 5719 - 5720 new-var-from-slice: # ad: (addr allocation-descriptor), name: (addr slice) -> result/eax: (handle var) - 5721 # . prologue - 5722 55/push-ebp - 5723 89/<- %ebp 4/r32/esp - 5724 # . save registers - 5725 51/push-ecx - 5726 # result = new-var(slice-to-string(name)) - 5727 (slice-to-string Heap *(ebp+0xc)) # => eax - 5728 (new-var *(ebp+8) %eax) - 5729 $new-var-from-slice:end: - 5730 # . restore registers - 5731 59/pop-to-ecx - 5732 # . epilogue - 5733 89/<- %esp 5/r32/ebp - 5734 5d/pop-to-ebp - 5735 c3/return - 5736 - 5737 new-block: # ad: (addr allocation-descriptor), data: (handle list stmt) -> result/eax: (handle stmt) - 5738 # . prologue - 5739 55/push-ebp - 5740 89/<- %ebp 4/r32/esp - 5741 # . save registers - 5742 51/push-ecx - 5743 # - 5744 (allocate *(ebp+8) *Stmt-size) # => eax - 5745 c7 0/subop/copy *eax 0/imm32/tag/block # Stmt-tag - 5746 8b/-> *(ebp+0xc) 1/r32/ecx - 5747 89/<- *(eax+4) 1/r32/ecx # Block-stmts - 5748 $new-block:end: + 5315 74/jump-if-= break/disp8 + 5316 # ensure that the next word is '<-' + 5317 (next-mu-token *(ebp+8) %ecx) + 5318 (slice-equal? %ecx "<-") # => eax + 5319 3d/compare-eax-and 0/imm32/false + 5320 74/jump-if-= $parse-mu-var-def:abort/disp8 + 5321 # + 5322 (new-reg-var-def Heap *edx *(edx+4) %edi) + 5323 (lookup *edi *(edi+4)) # => eax + 5324 (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc)) + 5325 } + 5326 $parse-mu-var-def:end: + 5327 # . reclaim locals + 5328 81 0/subop/add %esp 0x10/imm32 + 5329 # . restore registers + 5330 5f/pop-to-edi + 5331 5a/pop-to-edx + 5332 59/pop-to-ecx + 5333 58/pop-to-eax + 5334 # . epilogue + 5335 89/<- %esp 5/r32/ebp + 5336 5d/pop-to-ebp + 5337 c3/return + 5338 + 5339 $parse-mu-var-def:abort: + 5340 (rewind-stream *(ebp+8)) + 5341 # error("register variable requires a valid instruction to initialize but got '" line "'\n") + 5342 (write-buffered Stderr "register variable requires a valid instruction to initialize but got '") + 5343 (flush Stderr) + 5344 (write-stream 2 *(ebp+8)) + 5345 (write-buffered Stderr "'\n") + 5346 (flush Stderr) + 5347 # . syscall(exit, 1) + 5348 bb/copy-to-ebx 1/imm32 + 5349 b8/copy-to-eax 1/imm32/exit + 5350 cd/syscall 0x80/imm8 + 5351 # never gets here + 5352 + 5353 test-parse-mu-var-def: + 5354 # 'var n: int' + 5355 # . prologue + 5356 55/push-ebp + 5357 89/<- %ebp 4/r32/esp + 5358 # setup + 5359 (clear-stream _test-input-stream) + 5360 (write _test-input-stream "n: int\n") # caller has consumed the 'var' + 5361 # var out/esi: (handle stmt) + 5362 68/push 0/imm32 + 5363 68/push 0/imm32 + 5364 89/<- %esi 4/r32/esp + 5365 # var vars/ecx: (stack (addr var) 16) + 5366 81 5/subop/subtract %esp 0x80/imm32 + 5367 68/push 0x80/imm32/size + 5368 68/push 0/imm32/top + 5369 89/<- %ecx 4/r32/esp + 5370 (clear-stack %ecx) + 5371 # convert + 5372 (parse-mu-var-def _test-input-stream %ecx %esi) + 5373 # var out-addr/esi: (addr stmt) + 5374 (lookup *esi *(esi+4)) # => eax + 5375 89/<- %esi 0/r32/eax + 5376 # + 5377 (check-ints-equal *esi 2 "F - test-parse-mu-var-def/tag") # Stmt-tag is var-def + 5378 # var v/ecx: (addr var) = lookup(out->var) + 5379 (lookup *(esi+4) *(esi+8)) # Vardef-var Vardef-var => eax + 5380 89/<- %ecx 0/r32/eax + 5381 # v->name + 5382 (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + 5383 (check-strings-equal %eax "n" "F - test-parse-mu-var-def/var-name") + 5384 # v->register + 5385 (check-ints-equal *(ecx+0x18) 0 "F - test-parse-mu-var-def/var-register") # Var-register + 5386 # v->type == int + 5387 (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + 5388 (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0") # Tree-is-atom + 5389 (check-ints-equal *(eax+4) 1 "F - test-parse-mu-var-def/var-type:1") # Tree-value + 5390 (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-var-def/var-type:2") # Tree-right + 5391 # . epilogue + 5392 89/<- %esp 5/r32/ebp + 5393 5d/pop-to-ebp + 5394 c3/return + 5395 + 5396 test-parse-mu-reg-var-def: + 5397 # 'var n/eax: int <- copy 0' + 5398 # . prologue + 5399 55/push-ebp + 5400 89/<- %ebp 4/r32/esp + 5401 # setup + 5402 (clear-stream _test-input-stream) + 5403 (write _test-input-stream "n/eax: int <- copy 0\n") # caller has consumed the 'var' + 5404 # var out/esi: (handle stmt) + 5405 68/push 0/imm32 + 5406 68/push 0/imm32 + 5407 89/<- %esi 4/r32/esp + 5408 # var vars/ecx: (stack (addr var) 16) + 5409 81 5/subop/subtract %esp 0x80/imm32 + 5410 68/push 0x80/imm32/size + 5411 68/push 0/imm32/top + 5412 89/<- %ecx 4/r32/esp + 5413 (clear-stack %ecx) + 5414 # convert + 5415 (parse-mu-var-def _test-input-stream %ecx %esi) + 5416 # var out-addr/esi: (addr stmt) + 5417 (lookup *esi *(esi+4)) # => eax + 5418 89/<- %esi 0/r32/eax + 5419 # + 5420 (check-ints-equal *esi 3 "F - test-parse-mu-reg-var-def/tag") # Stmt-tag is reg-var-def + 5421 # var v/ecx: (addr var) = lookup(out->outputs->value) + 5422 # . eax: (addr stmt-var) = lookup(out->outputs) + 5423 (lookup *(esi+0x14) *(esi+0x18)) # Regvardef-outputs Regvardef-outputs => eax + 5424 # . + 5425 (check-ints-equal *(eax+8) 0 "F - test-parse-mu-reg-var-def/single-output") # Stmt-var-next + 5426 # . eax: (addr var) = lookup(eax->value) + 5427 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 5428 # . ecx = eax + 5429 89/<- %ecx 0/r32/eax + 5430 # v->name + 5431 (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + 5432 (check-strings-equal %eax "n" "F - test-parse-mu-reg-var-def/output-name") # Var-name + 5433 # v->register + 5434 (lookup *(ecx+0x18) *(ecx+0x1c)) # Var-register Var-register => eax + 5435 (check-strings-equal %eax "eax" "F - test-parse-mu-reg-var-def/output-register") + 5436 # v->type == int + 5437 (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + 5438 (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0") # Tree-is-atom + 5439 (check-ints-equal *(eax+4) 1 "F - test-parse-mu-reg-var-def/output-type:1") # Tree-value + 5440 (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-reg-var-def/output-type:2") # Tree-right + 5441 # . epilogue + 5442 89/<- %esp 5/r32/ebp + 5443 5d/pop-to-ebp + 5444 c3/return + 5445 + 5446 parse-mu-stmt: # line: (addr stream byte), vars: (addr stack (handle var)), fn: (addr function), out: (addr handle stmt) + 5447 # pseudocode: + 5448 # var name: slice + 5449 # allocate(Heap, Stmt-size, out) + 5450 # var out-addr: (addr stmt) = lookup(*out) + 5451 # out-addr->tag = stmt + 5452 # if stmt-has-outputs?(line) + 5453 # while true + 5454 # name = next-mu-token(line) + 5455 # if (name == '<-') break + 5456 # assert(is-identifier?(name)) + 5457 # var v: (handle var) = lookup-or-define-var(name, vars, fn) # regular stmts may define vars in fn outputs + 5458 # out-addr->outputs = append(v, out-addr->outputs) + 5459 # add-operation-and-inputs-to-stmt(out-addr, line, vars) + 5460 # + 5461 # . prologue + 5462 55/push-ebp + 5463 89/<- %ebp 4/r32/esp + 5464 # . save registers + 5465 50/push-eax + 5466 51/push-ecx + 5467 52/push-edx + 5468 53/push-ebx + 5469 57/push-edi + 5470 # var name/ecx: slice + 5471 68/push 0/imm32/end + 5472 68/push 0/imm32/start + 5473 89/<- %ecx 4/r32/esp + 5474 # var is-deref?/edx: boolean = false + 5475 ba/copy-to-edx 0/imm32/false + 5476 # var v: (handle var) + 5477 68/push 0/imm32 + 5478 68/push 0/imm32 + 5479 89/<- %ebx 4/r32/esp + 5480 # + 5481 (allocate Heap *Stmt-size *(ebp+0x14)) + 5482 # var out-addr/edi: (addr stmt) = lookup(*out) + 5483 8b/-> *(ebp+0x14) 7/r32/edi + 5484 (lookup *edi *(edi+4)) # => eax + 5485 89/<- %edi 0/r32/eax + 5486 # out-addr->tag = 1/stmt + 5487 c7 0/subop/copy *edi 1/imm32/stmt1 # Stmt-tag + 5488 { + 5489 (stmt-has-outputs? *(ebp+8)) + 5490 3d/compare-eax-and 0/imm32/false + 5491 0f 84/jump-if-= break/disp32 + 5492 { + 5493 $parse-mu-stmt:read-outputs: + 5494 # name = next-mu-token(line) + 5495 (next-mu-token *(ebp+8) %ecx) + 5496 # if slice-empty?(word-slice) break + 5497 (slice-empty? %ecx) # => eax + 5498 3d/compare-eax-and 0/imm32/false + 5499 0f 85/jump-if-!= break/disp32 + 5500 # if (name == "<-") break + 5501 (slice-equal? %ecx "<-") # => eax + 5502 3d/compare-eax-and 0/imm32/false + 5503 0f 85/jump-if-!= break/disp32 + 5504 # is-deref? = false + 5505 ba/copy-to-edx 0/imm32/false + 5506 # if (slice-starts-with?(name, '*')) ++name->start and set is-deref? + 5507 8b/-> *ecx 0/r32/eax # Slice-start + 5508 8a/copy-byte *eax 0/r32/AL + 5509 81 4/subop/and %eax 0xff/imm32 + 5510 3d/compare-eax-and 0x2a/imm32/asterisk + 5511 { + 5512 75/jump-if-!= break/disp8 + 5513 ff 0/subop/increment *ecx + 5514 ba/copy-to-edx 1/imm32/true + 5515 } + 5516 # assert(is-identifier?(name)) + 5517 (is-identifier? %ecx) # => eax + 5518 3d/compare-eax-and 0/imm32/false + 5519 0f 84/jump-if-= $parse-mu-stmt:abort/disp32 + 5520 # + 5521 (lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10) %ebx) + 5522 8d/copy-address *(edi+0x14) 0/r32/eax # Stmt1-outputs + 5523 (append-stmt-var Heap *ebx *(ebx+4) *(edi+0x14) *(edi+0x18) %edx %eax) # Stmt1-outputs + 5524 # + 5525 e9/jump loop/disp32 + 5526 } + 5527 } + 5528 (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc)) + 5529 $parse-mu-stmt:end: + 5530 # . reclaim locals + 5531 81 0/subop/add %esp 0x10/imm32 + 5532 # . restore registers + 5533 5f/pop-to-edi + 5534 5b/pop-to-ebx + 5535 5a/pop-to-edx + 5536 59/pop-to-ecx + 5537 58/pop-to-eax + 5538 # . epilogue + 5539 89/<- %esp 5/r32/ebp + 5540 5d/pop-to-ebp + 5541 c3/return + 5542 + 5543 $parse-mu-stmt:abort: + 5544 # error("invalid identifier '" name "'\n") + 5545 (write-buffered Stderr "invalid identifier '") + 5546 (write-slice-buffered Stderr %ecx) + 5547 (write-buffered Stderr "'\n") + 5548 (flush Stderr) + 5549 # . syscall(exit, 1) + 5550 bb/copy-to-ebx 1/imm32 + 5551 b8/copy-to-eax 1/imm32/exit + 5552 cd/syscall 0x80/imm8 + 5553 # never gets here + 5554 + 5555 add-operation-and-inputs-to-stmt: # stmt: (addr stmt), line: (addr stream byte), vars: (addr stack (handle var)) + 5556 # pseudocode: + 5557 # stmt->name = slice-to-string(next-mu-token(line)) + 5558 # while true + 5559 # name = next-mu-token(line) + 5560 # v = lookup-var-or-literal(name) + 5561 # stmt->inouts = append(v, stmt->inouts) + 5562 # + 5563 # . prologue + 5564 55/push-ebp + 5565 89/<- %ebp 4/r32/esp + 5566 # . save registers + 5567 50/push-eax + 5568 51/push-ecx + 5569 52/push-edx + 5570 53/push-ebx + 5571 56/push-esi + 5572 57/push-edi + 5573 # edi = stmt + 5574 8b/-> *(ebp+8) 7/r32/edi + 5575 # var name/ecx: slice + 5576 68/push 0/imm32/end + 5577 68/push 0/imm32/start + 5578 89/<- %ecx 4/r32/esp + 5579 # var is-deref?/edx: boolean = false + 5580 ba/copy-to-edx 0/imm32/false + 5581 # var v/esi: (handle var) + 5582 68/push 0/imm32 + 5583 68/push 0/imm32 + 5584 89/<- %esi 4/r32/esp + 5585 $add-operation-and-inputs-to-stmt:read-operation: + 5586 (next-mu-token *(ebp+0xc) %ecx) + 5587 8d/copy-address *(edi+4) 0/r32/eax # Stmt1-operation or Regvardef-operationStmt1-operation or Regvardef-operation + 5588 (slice-to-string Heap %ecx %eax) + 5589 # var is-get?/ebx: boolean = (name == "get") + 5590 (slice-equal? %ecx "get") # => eax + 5591 89/<- %ebx 0/r32/eax + 5592 { + 5593 $add-operation-and-inputs-to-stmt:read-inouts: + 5594 # name = next-mu-token(line) + 5595 (next-mu-token *(ebp+0xc) %ecx) + 5596 # if slice-empty?(word-slice) break + 5597 (slice-empty? %ecx) # => eax + 5598 3d/compare-eax-and 0/imm32/false + 5599 0f 85/jump-if-!= break/disp32 + 5600 # if (name == "<-") abort + 5601 (slice-equal? %ecx "<-") + 5602 3d/compare-eax-and 0/imm32/false + 5603 0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32 + 5604 # if (is-get? && second operand) lookup or create offset + 5605 { + 5606 81 7/subop/compare %ebx 0/imm32/false + 5607 74/jump-if-= break/disp8 + 5608 (lookup *(edi+0xc) *(edi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 5609 3d/compare-eax-and 0/imm32 + 5610 74/jump-if-= break/disp8 + 5611 (lookup-or-create-constant %eax %ecx %esi) + 5612 e9/jump $add-operation-and-inputs-to-stmt:save-var/disp32 + 5613 } + 5614 # is-deref? = false + 5615 ba/copy-to-edx 0/imm32/false + 5616 # if (slice-starts-with?(name, '*')) ++name->start and set is-deref? + 5617 8b/-> *ecx 0/r32/eax # Slice-start + 5618 8a/copy-byte *eax 0/r32/AL + 5619 81 4/subop/and %eax 0xff/imm32 + 5620 3d/compare-eax-and 0x2a/imm32/asterisk + 5621 { + 5622 75/jump-if-!= break/disp8 + 5623 $add-operation-and-inputs-to-stmt:inout-is-deref: + 5624 ff 0/subop/increment *ecx + 5625 ba/copy-to-edx 1/imm32/true + 5626 } + 5627 (lookup-var-or-literal %ecx *(ebp+0x10) %esi) + 5628 $add-operation-and-inputs-to-stmt:save-var: + 5629 8d/copy-address *(edi+0xc) 0/r32/eax + 5630 (append-stmt-var Heap *esi *(esi+4) *(edi+0xc) *(edi+0x10) %edx %eax) # Stmt1-inouts or Regvardef-inouts + 5631 # + 5632 e9/jump loop/disp32 + 5633 } + 5634 $add-operation-and-inputs-to-stmt:end: + 5635 # . reclaim locals + 5636 81 0/subop/add %esp 0x10/imm32 + 5637 # . restore registers + 5638 5f/pop-to-edi + 5639 5e/pop-to-esi + 5640 5b/pop-to-ebx + 5641 5a/pop-to-edx + 5642 59/pop-to-ecx + 5643 58/pop-to-eax + 5644 # . epilogue + 5645 89/<- %esp 5/r32/ebp + 5646 5d/pop-to-ebp + 5647 c3/return + 5648 + 5649 $add-operation-and-inputs-to-stmt:abort: + 5650 # error("invalid statement '" line "'\n") + 5651 (rewind-stream *(ebp+8)) + 5652 (write-buffered Stderr "invalid identifier '") + 5653 (flush Stderr) + 5654 (write-stream 2 *(ebp+8)) + 5655 (write-buffered Stderr "'\n") + 5656 (flush Stderr) + 5657 # . syscall(exit, 1) + 5658 bb/copy-to-ebx 1/imm32 + 5659 b8/copy-to-eax 1/imm32/exit + 5660 cd/syscall 0x80/imm8 + 5661 # never gets here + 5662 + 5663 stmt-has-outputs?: # line: (addr stream byte) -> result/eax: boolean + 5664 # . prologue + 5665 55/push-ebp + 5666 89/<- %ebp 4/r32/esp + 5667 # . save registers + 5668 51/push-ecx + 5669 # var word-slice/ecx: slice + 5670 68/push 0/imm32/end + 5671 68/push 0/imm32/start + 5672 89/<- %ecx 4/r32/esp + 5673 # result = false + 5674 b8/copy-to-eax 0/imm32/false + 5675 (rewind-stream *(ebp+8)) + 5676 { + 5677 (next-mu-token *(ebp+8) %ecx) + 5678 # if slice-empty?(word-slice) break + 5679 (slice-empty? %ecx) + 5680 3d/compare-eax-and 0/imm32/false + 5681 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) + 5682 0f 85/jump-if-!= break/disp32 + 5683 # if slice-starts-with?(word-slice, '#') break + 5684 # . eax = *word-slice->start + 5685 8b/-> *ecx 0/r32/eax + 5686 8a/copy-byte *eax 0/r32/AL + 5687 81 4/subop/and %eax 0xff/imm32 + 5688 # . if (eax == '#') break + 5689 3d/compare-eax-and 0x23/imm32/hash + 5690 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) + 5691 0f 84/jump-if-= break/disp32 + 5692 # if slice-equal?(word-slice, '<-') return true + 5693 (slice-equal? %ecx "<-") + 5694 3d/compare-eax-and 0/imm32/false + 5695 74/jump-if-= loop/disp8 + 5696 b8/copy-to-eax 1/imm32/true + 5697 } + 5698 $stmt-has-outputs:end: + 5699 (rewind-stream *(ebp+8)) + 5700 # . reclaim locals + 5701 81 0/subop/add %esp 8/imm32 + 5702 # . restore registers + 5703 59/pop-to-ecx + 5704 # . epilogue + 5705 89/<- %esp 5/r32/ebp + 5706 5d/pop-to-ebp + 5707 c3/return + 5708 + 5709 # if 'name' starts with a digit, create a new literal var for it + 5710 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found + 5711 lookup-var-or-literal: # name: (addr slice), vars: (addr stack (handle var)), out: (addr handle var) + 5712 # . prologue + 5713 55/push-ebp + 5714 89/<- %ebp 4/r32/esp + 5715 # . save registers + 5716 50/push-eax + 5717 51/push-ecx + 5718 56/push-esi + 5719 # esi = name + 5720 8b/-> *(ebp+8) 6/r32/esi + 5721 # if slice-empty?(name) abort + 5722 (slice-empty? %esi) # => eax + 5723 3d/compare-eax-and 0/imm32/false + 5724 0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32 + 5725 # var c/ecx: byte = *name->start + 5726 8b/-> *esi 1/r32/ecx + 5727 8a/copy-byte *ecx 1/r32/CL + 5728 81 4/subop/and %ecx 0xff/imm32 + 5729 # if is-decimal-digit?(c) return new var(name) + 5730 { + 5731 (is-decimal-digit? %ecx) # => eax + 5732 3d/compare-eax-and 0/imm32/false + 5733 74/jump-if-= break/disp8 + 5734 (new-literal-integer Heap %esi *(ebp+0x10)) + 5735 eb/jump $lookup-var-or-literal:end/disp8 + 5736 } + 5737 # else if (c == '"') return new var(name) + 5738 { + 5739 81 7/subop/compare %ecx 0x22/imm32/dquote + 5740 75/jump-if-!= break/disp8 + 5741 (new-literal Heap %esi *(ebp+0x10)) + 5742 eb/jump $lookup-var-or-literal:end/disp8 + 5743 } + 5744 # otherwise return lookup-var(name, vars) + 5745 { + 5746 (lookup-var %esi *(ebp+0xc)) # => eax + 5747 } + 5748 $lookup-var-or-literal:end: 5749 # . restore registers - 5750 59/pop-to-ecx - 5751 # . epilogue - 5752 89/<- %esp 5/r32/ebp - 5753 5d/pop-to-ebp - 5754 c3/return - 5755 - 5756 new-var-def: # ad: (addr allocation-descriptor), var: (handle var) -> result/eax: (handle stmt) - 5757 # . prologue - 5758 55/push-ebp - 5759 89/<- %ebp 4/r32/esp - 5760 # . save registers - 5761 51/push-ecx - 5762 # - 5763 (allocate *(ebp+8) *Stmt-size) # => eax - 5764 c7 0/subop/copy *eax 2/imm32/tag/var-on-stack # Stmt-tag - 5765 # result->var = var - 5766 8b/-> *(ebp+0xc) 1/r32/ecx - 5767 89/<- *(eax+4) 1/r32/ecx # Vardef-var - 5768 $new-var-def:end: - 5769 # . restore registers - 5770 59/pop-to-ecx - 5771 # . epilogue - 5772 89/<- %esp 5/r32/ebp - 5773 5d/pop-to-ebp - 5774 c3/return - 5775 - 5776 new-reg-var-def: # ad: (addr allocation-descriptor), var: (handle var) -> result/eax: (handle stmt) - 5777 # . prologue - 5778 55/push-ebp - 5779 89/<- %ebp 4/r32/esp - 5780 # . save registers - 5781 51/push-ecx - 5782 57/push-edi - 5783 # ecx = var - 5784 8b/-> *(ebp+0xc) 1/r32/ecx - 5785 # edi = result - 5786 (allocate *(ebp+8) *Stmt-size) # => eax - 5787 89/<- %edi 0/r32/eax - 5788 # set tag - 5789 c7 0/subop/copy *edi 3/imm32/tag/var-in-register # Stmt-tag - 5790 # set output - 5791 (append-stmt-var Heap %ecx *(edi+0xc) 0) # Regvardef-outputs => eax - 5792 89/<- *(edi+0xc) 0/r32/eax # Regvardef-outputs - 5793 $new-reg-var-def:end: - 5794 89/<- %eax 7/r32/edi - 5795 # . restore registers - 5796 5f/pop-to-edi - 5797 59/pop-to-ecx - 5798 # . epilogue - 5799 89/<- %esp 5/r32/ebp - 5800 5d/pop-to-ebp - 5801 c3/return - 5802 - 5803 append-list: # ad: (addr allocation-descriptor), value: _type, list: (handle list _type) -> result/eax: (handle list _type) - 5804 # . prologue - 5805 55/push-ebp - 5806 89/<- %ebp 4/r32/esp - 5807 # . save registers - 5808 51/push-ecx + 5750 5e/pop-to-esi + 5751 59/pop-to-ecx + 5752 58/pop-to-eax + 5753 # . epilogue + 5754 89/<- %esp 5/r32/ebp + 5755 5d/pop-to-ebp + 5756 c3/return + 5757 + 5758 $lookup-var-or-literal:abort: + 5759 (write-buffered Stderr "empty variable!") + 5760 (flush Stderr) + 5761 # . syscall(exit, 1) + 5762 bb/copy-to-ebx 1/imm32 + 5763 b8/copy-to-eax 1/imm32/exit + 5764 cd/syscall 0x80/imm8 + 5765 # never gets here + 5766 + 5767 # return first 'name' from the top (back) of 'vars' and abort if not found + 5768 lookup-var: # name: (addr slice), vars: (addr stack (handle var)), out: (addr handle var) + 5769 # . prologue + 5770 55/push-ebp + 5771 89/<- %ebp 4/r32/esp + 5772 # . save registers + 5773 50/push-eax + 5774 # + 5775 (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x10)) + 5776 # if (*out == 0) abort + 5777 8b/-> *(ebp+0x10) 0/r32/eax + 5778 81 7/subop/compare *eax 0/imm32 + 5779 74/jump-if-= $lookup-var:abort/disp8 + 5780 $lookup-var:end: + 5781 # . restore registers + 5782 58/pop-to-eax + 5783 # . epilogue + 5784 89/<- %esp 5/r32/ebp + 5785 5d/pop-to-ebp + 5786 c3/return + 5787 + 5788 $lookup-var:abort: + 5789 (write-buffered Stderr "unknown variable '") + 5790 (write-slice-buffered Stderr *(ebp+8)) + 5791 (write-buffered Stderr "'\n") + 5792 (flush Stderr) + 5793 # . syscall(exit, 1) + 5794 bb/copy-to-ebx 1/imm32 + 5795 b8/copy-to-eax 1/imm32/exit + 5796 cd/syscall 0x80/imm8 + 5797 # never gets here + 5798 + 5799 # return first 'name' from the top (back) of 'vars', and 0/null if not found + 5800 lookup-var-helper: # name: (addr slice), vars: (addr stack (handle var)), out: (addr handle var) + 5801 # pseudocode: + 5802 # var curr: (addr handle var) = &vars->data[vars->top - 8] + 5803 # var min = vars->data + 5804 # while curr >= min + 5805 # var v: (handle var) = *curr + 5806 # if v->name == name + 5807 # return + 5808 # curr -= 8 5809 # - 5810 (allocate *(ebp+8) *List-size) # => eax - 5811 8b/-> *(ebp+0xc) 1/r32/ecx - 5812 89/<- *eax 1/r32/ecx # List-value - 5813 # if (list == null) return result - 5814 81 7/subop/compare *(ebp+0x10) 0/imm32 - 5815 74/jump-if-= $append-list:end/disp8 - 5816 # otherwise append - 5817 # var curr/ecx = list - 5818 8b/-> *(ebp+0x10) 1/r32/ecx - 5819 # while (curr->next != null) curr = curr->next - 5820 { - 5821 81 7/subop/compare *(ecx+4) 0/imm32 # List-next - 5822 74/jump-if-= break/disp8 - 5823 # curr = curr->next - 5824 8b/-> *(ecx+4) 1/r32/ecx - 5825 eb/jump loop/disp8 - 5826 } - 5827 # curr->next = result - 5828 89/<- *(ecx+4) 0/r32/eax - 5829 # return list - 5830 8b/-> *(ebp+0x10) 0/r32/eax - 5831 $append-list:end: - 5832 # . restore registers - 5833 59/pop-to-ecx - 5834 # . epilogue - 5835 89/<- %esp 5/r32/ebp - 5836 5d/pop-to-ebp - 5837 c3/return - 5838 - 5839 append-stmt-var: # ad: (addr allocation-descriptor), v: (handle var), vars: (handle stmt-var), is-deref?: boolean -> result/eax: (handle stmt-var) - 5840 # . prologue - 5841 55/push-ebp - 5842 89/<- %ebp 4/r32/esp - 5843 # . save registers - 5844 51/push-ecx - 5845 # - 5846 (allocate *(ebp+8) *Stmt-var-size) # => eax - 5847 8b/-> *(ebp+0xc) 1/r32/ecx - 5848 89/<- *eax 1/r32/ecx # Stmt-var-value - 5849 8b/-> *(ebp+0x14) 1/r32/ecx - 5850 89/<- *(eax+8) 1/r32/ecx # Stmt-var-is-deref - 5851 # if (list == null) return result - 5852 81 7/subop/compare *(ebp+0x10) 0/imm32 - 5853 74/jump-if-= $append-stmt-var:end/disp8 - 5854 # otherwise append - 5855 # var curr/ecx: (handle stmt-var) = vars - 5856 8b/-> *(ebp+0x10) 1/r32/ecx - 5857 # while (curr->next != null) curr = curr->next - 5858 { - 5859 81 7/subop/compare *(ecx+4) 0/imm32 # List-next - 5860 74/jump-if-= break/disp8 - 5861 # curr = curr->next - 5862 8b/-> *(ecx+4) 1/r32/ecx - 5863 eb/jump loop/disp8 - 5864 } - 5865 # curr->next = result - 5866 89/<- *(ecx+4) 0/r32/eax - 5867 # return vars - 5868 8b/-> *(ebp+0x10) 0/r32/eax - 5869 $append-stmt-var:end: - 5870 # . restore registers - 5871 59/pop-to-ecx - 5872 # . epilogue - 5873 89/<- %esp 5/r32/ebp - 5874 5d/pop-to-ebp - 5875 c3/return - 5876 - 5877 append-to-block: # ad: (addr allocation-descriptor), block: (handle block), x: (handle stmt) - 5878 # . prologue - 5879 55/push-ebp - 5880 89/<- %ebp 4/r32/esp - 5881 # . save registers - 5882 56/push-esi - 5883 # esi = block - 5884 8b/-> *(ebp+0xc) 6/r32/esi - 5885 (append-list *(ebp+8) *(ebp+0x10) *(esi+4)) # ad, x, Block-stmts - 5886 89/<- *(esi+4) 0/r32/eax # Block-stmts - 5887 $append-to-block:end: - 5888 # . restore registers - 5889 5e/pop-to-esi - 5890 # . epilogue - 5891 89/<- %esp 5/r32/ebp - 5892 5d/pop-to-ebp - 5893 c3/return - 5894 - 5895 ## Parsing types - 5896 # We need to create metadata on user-defined types, and we need to use this - 5897 # metadata as we parse instructions. - 5898 # However, we also want to allow types to be used before their definitions. - 5899 # This means we can't ever assume any type data structures exist. - 5900 - 5901 lookup-or-create-constant: # container: (handle stmt-var), field-name: (addr slice) -> result/eax: (handle var) - 5902 # . prologue - 5903 55/push-ebp - 5904 89/<- %ebp 4/r32/esp - 5905 # . save registers - 5906 56/push-esi - 5907 # var container-type/esi: type-id - 5908 (container-type *(ebp+8)) # => eax - 5909 #? (write-buffered Stderr "lookup-or-create-constant: container type-id: ") - 5910 #? (print-int32-buffered Stderr %eax) - 5911 #? (write-buffered Stderr Newline) - 5912 #? (flush Stderr) - 5913 89/<- %esi 0/r32/eax - 5914 # var typeinfo/eax: (addr typeinfo) - 5915 (find-or-create-typeinfo %esi) # => eax - 5916 #? (write-buffered Stderr "lookup-or-create-constant: typeinfo: ") - 5917 #? (print-int32-buffered Stderr %eax) - 5918 #? (write-buffered Stderr Newline) - 5919 #? (flush Stderr) - 5920 # result = find-or-create-typeinfo-output-var(typeinfo, field-name) - 5921 (find-or-create-typeinfo-output-var %eax *(ebp+0xc)) # => eax - 5922 $lookup-or-create-constant:end: - 5923 # . restore registers - 5924 5e/pop-to-esi - 5925 # . epilogue - 5926 89/<- %esp 5/r32/ebp - 5927 5d/pop-to-ebp - 5928 c3/return - 5929 - 5930 # if addr var: - 5931 # container->var->type->right->left->value - 5932 # otherwise - 5933 # container->var->type->value - 5934 container-type: # container: (handle stmt-var) -> result/eax: type-id - 5935 # . prologue - 5936 55/push-ebp - 5937 89/<- %ebp 4/r32/esp - 5938 # - 5939 8b/-> *(ebp+8) 0/r32/eax - 5940 8b/-> *eax 0/r32/eax # Stmt-var-value - 5941 8b/-> *(eax+4) 0/r32/eax # Var-type - 5942 { - 5943 81 7/subop/compare *(eax+8) 0/imm32 # Tree-right - 5944 74/jump-if-= break/disp8 - 5945 8b/-> *(eax+8) 0/r32/eax # Tree-right - 5946 8b/-> *(eax+4) 0/r32/eax # Tree-left - 5947 } - 5948 8b/-> *(eax+4) 0/r32/eax # Tree-value - 5949 $container-type:end: - 5950 # . epilogue - 5951 89/<- %esp 5/r32/ebp - 5952 5d/pop-to-ebp - 5953 c3/return - 5954 - 5955 find-or-create-typeinfo: # t: type-id -> result/eax: (handle typeinfo) - 5956 # . prologue - 5957 55/push-ebp - 5958 89/<- %ebp 4/r32/esp - 5959 # . save registers - 5960 51/push-ecx - 5961 # eax = find-typeinfo(t) - 5962 (find-typeinfo *(ebp+8)) # => eax - 5963 { - 5964 # if (curr != 0) break - 5965 3d/compare-eax-and 0/imm32 - 5966 75/jump-if-!= break/disp8 - 5967 $find-or-create-typeinfo:create: - 5968 (allocate Heap *Typeinfo-size) # => eax - 5969 # result->id = t - 5970 8b/-> *(ebp+8) 1/r32/ecx - 5971 89/<- *eax 1/r32/ecx # Typeinfo-id - 5972 # result->fields = new table - 5973 # . ecx = new table - 5974 50/push-eax - 5975 (new-stream Heap 0x40 *Typeinfo-fields-row-size) # => eax - 5976 89/<- %ecx 0/r32/eax - 5977 58/pop-to-eax - 5978 # . result->fields = ecx - 5979 89/<- *(eax+4) 1/r32/ecx # Typeinfo-fields - 5980 # result->next = Program->types - 5981 8b/-> *_Program-types 1/r32/ecx - 5982 89/<- *(eax+0xc) 1/r32/ecx # Typeinfo-next - 5983 # Program->types = result - 5984 89/<- *_Program-types 0/r32/eax - 5985 } - 5986 $find-or-create-typeinfo:end: - 5987 # . restore registers - 5988 59/pop-to-ecx - 5989 # . epilogue - 5990 89/<- %esp 5/r32/ebp - 5991 5d/pop-to-ebp - 5992 c3/return - 5993 - 5994 find-typeinfo: # t: type-id -> result/eax: (handle typeinfo) - 5995 # . prologue - 5996 55/push-ebp - 5997 89/<- %ebp 4/r32/esp - 5998 # . save registers - 5999 51/push-ecx - 6000 # ecx = t - 6001 8b/-> *(ebp+8) 1/r32/ecx - 6002 # var curr/eax: (handle typeinfo) = Program->types - 6003 8b/-> *_Program-types 0/r32/eax - 6004 { - 6005 # if (curr == 0) break - 6006 3d/compare-eax-and 0/imm32 - 6007 74/jump-if-= break/disp8 - 6008 # if (curr->id == t) return curr - 6009 39/compare *eax 1/r32/ecx # Typeinfo-id - 6010 0f 84/jump-if-= $find-or-create-typeinfo:end/disp32 - 6011 # curr = curr->next - 6012 8b/-> *(eax+0xc) 0/r32/eax # Typeinfo-next - 6013 # - 6014 eb/jump loop/disp8 - 6015 } - 6016 $find-typeinfo:end: - 6017 # . restore registers - 6018 59/pop-to-ecx - 6019 # . epilogue - 6020 89/<- %esp 5/r32/ebp - 6021 5d/pop-to-ebp - 6022 c3/return - 6023 - 6024 find-or-create-typeinfo-output-var: # T: (handle typeinfo), f: (addr slice) -> result/eax: (handle var) - 6025 # . prologue - 6026 55/push-ebp - 6027 89/<- %ebp 4/r32/esp - 6028 # . save registers - 6029 51/push-ecx - 6030 56/push-esi - 6031 # esi = find-or-create-typeinfo-fields(T, f) - 6032 (find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc)) # => eax - 6033 89/<- %esi 0/r32/eax - 6034 # if output var doesn't exist, create it - 6035 { - 6036 81 7/subop/compare *(esi+8) 0/imm32 # Typeinfo-entry-output-var - 6037 75/jump-if-!= break/disp8 - 6038 # var type/eax: (handle tree type-id) = new var("dummy name", constant type, -1 offset) - 6039 (allocate Heap *Tree-size) # => eax - 6040 c7 0/subop/copy *(eax+4) 6/imm32/constant # Tree-value - 6041 c7 0/subop/copy *(eax+8) 0/imm32 # Tree-right - 6042 89/<- %ecx 0/r32/eax - 6043 # eax = result - 6044 (new-var Heap "field") # => eax - 6045 # result->type = type - 6046 89/<- *(eax+4) 1/r32/ecx # Var-type - 6047 # result->offset isn't filled out yet - 6048 c7 0/subop/copy *(eax+0xc) -1/imm32/uninitialized # Var-offset - 6049 # save result as output var - 6050 89/<- *(esi+8) 0/r32/eax # Typeinfo-entry-output-var - 6051 } - 6052 # return the output var - 6053 8b/-> *(esi+8) 0/r32/eax # Typeinfo-entry-output-var - 6054 $find-or-create-typeinfo-output-var:end: - 6055 # . restore registers - 6056 5e/pop-to-esi - 6057 59/pop-to-ecx - 6058 # . epilogue - 6059 89/<- %esp 5/r32/ebp - 6060 5d/pop-to-ebp - 6061 c3/return - 6062 - 6063 find-or-create-typeinfo-fields: # T: (handle typeinfo), f: (addr slice) -> result/eax: (handle typeinfo-entry) - 6064 # . prologue - 6065 55/push-ebp - 6066 89/<- %ebp 4/r32/esp - 6067 # . save registers - 6068 56/push-esi - 6069 # esi = T->fields - 6070 8b/-> *(ebp+8) 6/r32/esi - 6071 8b/-> *(esi+4) 6/r32/esi # Typeinfo-fields - 6072 # esi = get-or-insert(T->fields, f) - 6073 (get-or-insert-slice %esi *(ebp+0xc) *Typeinfo-fields-row-size Heap) # => eax - 6074 89/<- %esi 0/r32/eax - 6075 # if typeinfo-entry doesn't exist, allocate it - 6076 { - 6077 81 7/subop/compare *esi 0/imm32 # output var - 6078 75/jump-if-!= break/disp8 - 6079 (allocate Heap *Typeinfo-entry-size) # => eax - 6080 89/<- *esi 0/r32/eax - 6081 } - 6082 # eax = T->fields[f]->entry - 6083 8b/-> *esi 0/r32/eax - 6084 $find-or-create-typeinfo-fields:end: - 6085 # . restore registers - 6086 5e/pop-to-esi - 6087 # . epilogue - 6088 89/<- %esp 5/r32/ebp - 6089 5d/pop-to-ebp - 6090 c3/return - 6091 - 6092 populate-mu-type: # in: (addr stream byte), t: (handle typeinfo) - 6093 # pseudocode: - 6094 # var line: (stream byte 512) - 6095 # curr-index = 0 - 6096 # while true - 6097 # clear-stream(line) - 6098 # read-line-buffered(in, line) - 6099 # if line->write == 0 - 6100 # abort - 6101 # word-slice = next-mu-token(line) - 6102 # if slice-empty?(word-slice) # end of line - 6103 # continue - 6104 # if slice-equal?(word-slice, "}") - 6105 # break - 6106 # var v: (handle var) = parse-var-with-type(word-slice, line) - 6107 # var r: (handle typeinfo-fields) = find-or-create-typeinfo-fields(t, word-slice/v->name) - 6108 # TODO: ensure that r->first is null - 6109 # r->index = curr-index - 6110 # curr-index++ - 6111 # r->input-var = v - 6112 # if r->output-var == 0 - 6113 # r->output-var = new literal - 6114 # TODO: ensure nothing else in line - 6115 # t->total-size-in-bytes = -2 (not yet initialized) - 6116 # - 6117 # . prologue - 6118 55/push-ebp - 6119 89/<- %ebp 4/r32/esp - 6120 # var curr-index: int at *(ebp-4) - 6121 68/push 0/imm32 - 6122 # . save registers - 6123 50/push-eax - 6124 51/push-ecx - 6125 52/push-edx - 6126 53/push-ebx - 6127 56/push-esi - 6128 57/push-edi - 6129 # edi = t - 6130 8b/-> *(ebp+0xc) 7/r32/edi - 6131 # var line/ecx: (stream byte 512) - 6132 81 5/subop/subtract %esp 0x200/imm32 - 6133 68/push 0x200/imm32/size - 6134 68/push 0/imm32/read - 6135 68/push 0/imm32/write - 6136 89/<- %ecx 4/r32/esp - 6137 # var word-slice/edx: slice - 6138 68/push 0/imm32/end - 6139 68/push 0/imm32/start - 6140 89/<- %edx 4/r32/esp - 6141 { - 6142 $populate-mu-type:line-loop: - 6143 (clear-stream %ecx) - 6144 (read-line-buffered *(ebp+8) %ecx) - 6145 # if (line->write == 0) abort - 6146 81 7/subop/compare *ecx 0/imm32 - 6147 0f 84/jump-if-= $populate-mu-type:abort/disp32 - 6148 +-- 6 lines: #? # dump line --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 6154 (next-mu-token %ecx %edx) - 6155 # if slice-empty?(word-slice) continue - 6156 (slice-empty? %edx) # => eax - 6157 3d/compare-eax-and 0/imm32 - 6158 0f 85/jump-if-!= loop/disp32 - 6159 # if slice-equal?(word-slice, "}") break - 6160 (slice-equal? %edx "}") - 6161 3d/compare-eax-and 0/imm32 - 6162 0f 85/jump-if-!= break/disp32 - 6163 $populate-mu-type:parse-element: - 6164 # var v/esi: (handle var) = parse-var-with-type(word-slice, first-line) - 6165 (parse-var-with-type %edx %ecx) # => eax - 6166 89/<- %esi 0/r32/eax - 6167 $populate-mu-type:create-typeinfo-fields: - 6168 # var r/ebx: (handle typeinfo-entry) - 6169 (find-or-create-typeinfo-fields %edi %edx) # => eax - 6170 89/<- %ebx 0/r32/eax - 6171 #? (write-buffered Stderr "var ") - 6172 #? (write-buffered Stderr *esi) # Var-name - 6173 #? (write-buffered Stderr " is at index ") - 6174 #? (print-int32-buffered Stderr *(ebp-4)) - 6175 #? (write-buffered Stderr Newline) - 6176 #? (flush Stderr) - 6177 # r->index = curr-index - 6178 8b/-> *(ebp-4) 0/r32/eax - 6179 89/<- *(ebx+4) 0/r32/eax # Typeinfo-entry-index - 6180 # ++curr-index - 6181 ff 0/subop/increment *(ebp-4) - 6182 $populate-mu-type:set-input-type: - 6183 # r->input-var = v - 6184 89/<- *ebx 6/r32/esi # Typeinfo-entry-input-var - 6185 { - 6186 $populate-mu-type:create-output-type: - 6187 # if (r->output-var == 0) create a new var with some placeholder data - 6188 81 7/subop/compare *(ebx+8) 0/imm32 # Typeinfo-entry-output-var - 6189 75/jump-if-!= break/disp8 - 6190 (new-literal Heap %edx) # => eax - 6191 89/<- *(ebx+8) 0/r32/eax # Typeinfo-entry-output-var - 6192 } - 6193 e9/jump loop/disp32 - 6194 } - 6195 $populate-mu-type:invalidate-total-size-in-bytes: - 6196 # Offsets and total size may not be accurate here since we may not yet - 6197 # have encountered the element types. - 6198 # We'll recompute them separately after parsing the entire program. - 6199 c7 0/subop/copy *(edi+8) -2/imm32/uninitialized # Typeinfo-total-size-in-bytes - 6200 $populate-mu-type:end: - 6201 # . reclaim locals - 6202 81 0/subop/add %esp 0x214/imm32 - 6203 # . restore registers - 6204 5f/pop-to-edi - 6205 5e/pop-to-esi - 6206 5b/pop-to-ebx - 6207 5a/pop-to-edx - 6208 59/pop-to-ecx - 6209 58/pop-to-eax - 6210 # reclaim curr-index - 6211 81 0/subop/add %esp 4/imm32 + 5810 # . prologue + 5811 55/push-ebp + 5812 89/<- %ebp 4/r32/esp + 5813 # . save registers + 5814 50/push-eax + 5815 51/push-ecx + 5816 52/push-edx + 5817 53/push-ebx + 5818 56/push-esi + 5819 # clear out + 5820 (zero-out *(ebp+0x10) *Handle-size) + 5821 # esi = vars + 5822 8b/-> *(ebp+0xc) 6/r32/esi + 5823 # ebx = vars->top + 5824 8b/-> *esi 3/r32/ebx + 5825 # if (vars->top > vars->size) abort + 5826 3b/compare<- *(esi+4) 0/r32/eax + 5827 0f 8f/jump-if-> $lookup-var-helper:error1/disp32 + 5828 # var min/edx: (addr handle var) = vars->data + 5829 8d/copy-address *(esi+8) 2/r32/edx + 5830 # var curr/ebx: (addr handle var) = &vars->data[vars->top - 8] + 5831 8d/copy-address *(esi+ebx) 3/r32/ebx + 5832 { + 5833 # if (curr < min) return + 5834 39/compare %ebx 2/r32/edx + 5835 0f 82/jump-if-addr< break/disp32 + 5836 # var v/ecx: (addr var) = lookup(*curr) + 5837 (lookup *ebx *(ebx+4)) # => eax + 5838 89/<- %ecx 0/r32/eax + 5839 # var vn/eax: (addr array byte) = lookup(v->name) + 5840 (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + 5841 # if (vn == name) return curr + 5842 (slice-equal? *(ebp+8) %eax) # => eax + 5843 3d/compare-eax-and 0/imm32/false + 5844 { + 5845 74/jump-if-= break/disp8 + 5846 # esi = out + 5847 8b/-> *(ebp+0x10) 6/r32/esi + 5848 # *out = *curr + 5849 8b/-> *ebx 0/r32/eax + 5850 89/<- *esi 0/r32/eax + 5851 8b/-> *(ebx+4) 0/r32/eax + 5852 89/<- *(esi+4) 0/r32/eax + 5853 # return + 5854 eb/jump $lookup-var-helper:end/disp8 + 5855 } + 5856 # curr -= 8 + 5857 81 5/subop/subtract %ebx 8/imm32 + 5858 e9/jump loop/disp32 + 5859 } + 5860 $lookup-var-helper:end: + 5861 # . restore registers + 5862 5e/pop-to-esi + 5863 5b/pop-to-ebx + 5864 5a/pop-to-edx + 5865 59/pop-to-ecx + 5866 58/pop-to-eax + 5867 # . epilogue + 5868 89/<- %esp 5/r32/ebp + 5869 5d/pop-to-ebp + 5870 c3/return + 5871 + 5872 $lookup-var-helper:error1: + 5873 (write-buffered Stderr "malformed stack when looking up '") + 5874 (write-slice-buffered Stderr *(ebp+8)) + 5875 (write-buffered Stderr "'\n") + 5876 (flush Stderr) + 5877 # . syscall(exit, 1) + 5878 bb/copy-to-ebx 1/imm32 + 5879 b8/copy-to-eax 1/imm32/exit + 5880 cd/syscall 0x80/imm8 + 5881 # never gets here + 5882 + 5883 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found + 5884 lookup-or-define-var: # name: (addr slice), vars: (addr stack (handle var)), fn: (addr function), out: (addr handle var) + 5885 # . prologue + 5886 55/push-ebp + 5887 89/<- %ebp 4/r32/esp + 5888 # . save registers + 5889 50/push-eax + 5890 # + 5891 (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x14)) + 5892 { + 5893 # if (out != 0) return + 5894 8b/-> *(ebp+0x14) 0/r32/eax + 5895 81 7/subop/compare *eax 0/imm32 + 5896 75/jump-if-!= break/disp8 + 5897 # if name is one of fn's outputs, return it + 5898 { + 5899 (find-in-function-outputs *(ebp+0x10) *(ebp+8) *(ebp+0x14)) + 5900 8b/-> *(ebp+0x14) 0/r32/eax + 5901 81 7/subop/compare *eax 0/imm32 + 5902 # otherwise abort + 5903 0f 84/jump-if-= $lookup-var:abort/disp32 + 5904 } + 5905 } + 5906 $lookup-or-define-var:end: + 5907 # . restore registers + 5908 58/pop-to-eax + 5909 # . epilogue + 5910 89/<- %esp 5/r32/ebp + 5911 5d/pop-to-ebp + 5912 c3/return + 5913 + 5914 find-in-function-outputs: # fn: (addr function), name: (addr slice), out: (addr handle var) + 5915 # . prologue + 5916 55/push-ebp + 5917 89/<- %ebp 4/r32/esp + 5918 # . save registers + 5919 50/push-eax + 5920 51/push-ecx + 5921 # var curr/ecx: (addr list var) = lookup(fn->outputs) + 5922 8b/-> *(ebp+8) 1/r32/ecx + 5923 (lookup *(ecx+0x10) *(ecx+0x14)) # Function-outputs Function-outputs => eax + 5924 89/<- %ecx 0/r32/eax + 5925 # while curr != null + 5926 { + 5927 81 7/subop/compare %ecx 0/imm32 + 5928 74/jump-if-= break/disp8 + 5929 # var v/eax: (addr var) = lookup(curr->value) + 5930 (lookup *ecx *(ecx+4)) # List-value List-value => eax + 5931 # var s/eax: (addr array byte) = lookup(v->name) + 5932 (lookup *eax *(eax+4)) # Var-name Var-name => eax + 5933 # if (s == name) return curr->value + 5934 (slice-equal? *(ebp+0xc) %eax) # => eax + 5935 3d/compare-eax-and 0/imm32/false + 5936 { + 5937 74/jump-if-= break/disp8 + 5938 # var edi = out + 5939 57/push-edi + 5940 8b/-> *(ebp+0x10) 7/r32/edi + 5941 # *out = curr->value + 5942 8b/-> *ecx 0/r32/eax + 5943 89/<- *edi 0/r32/eax + 5944 8b/-> *(ecx+4) 0/r32/eax + 5945 89/<- *(edi+4) 0/r32/eax + 5946 # + 5947 5f/pop-to-edi + 5948 eb/jump $find-in-function-outputs:end/disp8 + 5949 } + 5950 # curr = curr->next + 5951 (lookup *(ecx+8) *(ecx+0xc)) # List-next List-next => eax + 5952 89/<- %ecx 0/r32/eax + 5953 # + 5954 eb/jump loop/disp8 + 5955 } + 5956 b8/copy-to-eax 0/imm32 + 5957 $find-in-function-outputs:end: + 5958 # . restore registers + 5959 59/pop-to-ecx + 5960 58/pop-to-eax + 5961 # . epilogue + 5962 89/<- %esp 5/r32/ebp + 5963 5d/pop-to-ebp + 5964 c3/return + 5965 + 5966 test-parse-mu-stmt: + 5967 # . prologue + 5968 55/push-ebp + 5969 89/<- %ebp 4/r32/esp + 5970 # setup + 5971 (clear-stream _test-input-stream) + 5972 (write _test-input-stream "increment n\n") + 5973 # var vars/ecx: (stack (addr var) 16) + 5974 81 5/subop/subtract %esp 0x80/imm32 + 5975 68/push 0x80/imm32/size + 5976 68/push 0/imm32/top + 5977 89/<- %ecx 4/r32/esp + 5978 (clear-stack %ecx) + 5979 # var v/edx: (handle var) + 5980 68/push 0/imm32 + 5981 68/push 0/imm32 + 5982 89/<- %edx 4/r32/esp + 5983 # var s/eax: (handle array byte) + 5984 68/push 0/imm32 + 5985 68/push 0/imm32 + 5986 89/<- %eax 4/r32/esp + 5987 # v = new var("n") + 5988 (copy-array Heap "n" %eax) + 5989 (new-var Heap *eax *(eax+4) %edx) + 5990 # + 5991 (push %ecx *edx) + 5992 (push %ecx *(edx+4)) + 5993 # var out/eax: (handle stmt) + 5994 68/push 0/imm32 + 5995 68/push 0/imm32 + 5996 89/<- %eax 4/r32/esp + 5997 # convert + 5998 (parse-mu-stmt _test-input-stream %ecx 0 %eax) + 5999 # var out-addr/edx: (addr stmt) = lookup(*out) + 6000 (lookup *eax *(eax+4)) # => eax + 6001 89/<- %edx 0/r32/eax + 6002 # out->tag + 6003 (check-ints-equal *edx 1 "F - test-parse-mu-stmt/tag") # Stmt-tag is Stmt1 + 6004 # out->operation + 6005 (lookup *(edx+4) *(edx+8)) # Stmt1-operation Stmt1-operation => eax + 6006 (check-strings-equal %eax "increment" "F - test-parse-mu-stmt/name") # Stmt1-operation + 6007 # out->inouts->value->name + 6008 # . eax = out->inouts + 6009 (lookup *(edx+0xc) *(edx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 6010 # . eax = out->inouts->value + 6011 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 6012 # . eax = out->inouts->value->name + 6013 (lookup *eax *(eax+4)) # Var-name Var-name => eax + 6014 # . + 6015 (check-strings-equal %eax "n" "F - test-parse-mu-stmt/inout:0") + 6016 # . epilogue + 6017 89/<- %esp 5/r32/ebp + 6018 5d/pop-to-ebp + 6019 c3/return + 6020 + 6021 test-parse-mu-stmt-with-comma: + 6022 # . prologue + 6023 55/push-ebp + 6024 89/<- %ebp 4/r32/esp + 6025 # setup + 6026 (clear-stream _test-input-stream) + 6027 (write _test-input-stream "copy-to n, 3\n") + 6028 # var vars/ecx: (stack (addr var) 16) + 6029 81 5/subop/subtract %esp 0x80/imm32 + 6030 68/push 0x80/imm32/size + 6031 68/push 0/imm32/top + 6032 89/<- %ecx 4/r32/esp + 6033 (clear-stack %ecx) + 6034 # var v/edx: (handle var) + 6035 68/push 0/imm32 + 6036 68/push 0/imm32 + 6037 89/<- %edx 4/r32/esp + 6038 # var s/eax: (handle array byte) + 6039 68/push 0/imm32 + 6040 68/push 0/imm32 + 6041 89/<- %eax 4/r32/esp + 6042 # v = new var("n") + 6043 (copy-array Heap "n" %eax) + 6044 (new-var Heap *eax *(eax+4) %edx) + 6045 # + 6046 (push %ecx *edx) + 6047 (push %ecx *(edx+4)) + 6048 # var out/eax: (handle stmt) + 6049 68/push 0/imm32 + 6050 68/push 0/imm32 + 6051 89/<- %eax 4/r32/esp + 6052 # convert + 6053 (parse-mu-stmt _test-input-stream %ecx 0 %eax) + 6054 # var out-addr/edx: (addr stmt) = lookup(*out) + 6055 (lookup *eax *(eax+4)) # => eax + 6056 89/<- %edx 0/r32/eax + 6057 # out->tag + 6058 (check-ints-equal *edx 1 "F - test-parse-mu-stmt-with-comma/tag") # Stmt-tag is Stmt1 + 6059 # out->operation + 6060 (lookup *(edx+4) *(edx+8)) # Stmt1-operation Stmt1-operation => eax + 6061 (check-strings-equal %eax "copy-to" "F - test-parse-mu-stmt-with-comma/name") # Stmt1-operation + 6062 # out->inouts->value->name + 6063 # . eax = out->inouts + 6064 (lookup *(edx+0xc) *(edx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 6065 # . eax = out->inouts->value + 6066 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 6067 # . eax = out->inouts->value->name + 6068 (lookup *eax *(eax+4)) # Var-name Var-name => eax + 6069 # . + 6070 (check-strings-equal %eax "n" "F - test-parse-mu-stmt-with-comma/inout:0") + 6071 # . epilogue + 6072 89/<- %esp 5/r32/ebp + 6073 5d/pop-to-ebp + 6074 c3/return + 6075 + 6076 new-var: # ad: (addr allocation-descriptor), name: (handle array byte), out: (addr handle var) + 6077 # . prologue + 6078 55/push-ebp + 6079 89/<- %ebp 4/r32/esp + 6080 # . save registers + 6081 50/push-eax + 6082 51/push-ecx + 6083 # ecx = out + 6084 8b/-> *(ebp+0x14) 1/r32/ecx + 6085 # + 6086 (allocate *(ebp+8) *Var-size %ecx) + 6087 # var out-addr/eax: (addr var) + 6088 (lookup *ecx *(ecx+4)) # => eax + 6089 # out-addr->name = name + 6090 8b/-> *(ebp+0xc) 1/r32/ecx + 6091 89/<- *eax 1/r32/ecx # Var-name + 6092 8b/-> *(ebp+0x10) 1/r32/ecx + 6093 89/<- *(eax+4) 1/r32/ecx # Var-name + 6094 #? (write-buffered Stderr "var ") + 6095 #? (lookup *(ebp+0xc) *(ebp+0x10)) + 6096 #? (write-buffered Stderr %eax) + 6097 #? (write-buffered Stderr " at ") + 6098 #? 8b/-> *(ebp+0x14) 1/r32/ecx + 6099 #? (lookup *ecx *(ecx+4)) # => eax + 6100 #? (print-int32-buffered Stderr %eax) + 6101 #? (write-buffered Stderr Newline) + 6102 #? (flush Stderr) + 6103 $new-var:end: + 6104 # . restore registers + 6105 59/pop-to-ecx + 6106 58/pop-to-eax + 6107 # . epilogue + 6108 89/<- %esp 5/r32/ebp + 6109 5d/pop-to-ebp + 6110 c3/return + 6111 + 6112 new-literal-integer: # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var) + 6113 # . prologue + 6114 55/push-ebp + 6115 89/<- %ebp 4/r32/esp + 6116 # . save registers + 6117 50/push-eax + 6118 51/push-ecx + 6119 # if (!is-hex-int?(name)) abort + 6120 (is-hex-int? *(ebp+0xc)) # => eax + 6121 3d/compare-eax-and 0/imm32/false + 6122 0f 84/jump-if-= $new-literal-integer:abort/disp32 + 6123 # out = new var(s) + 6124 (new-var-from-slice *(ebp+8) *(ebp+0xc) *(ebp+0x10)) + 6125 # var out-addr/ecx: (addr var) = lookup(*out) + 6126 8b/-> *(ebp+0x10) 0/r32/eax + 6127 (lookup *eax *(eax+4)) # => eax + 6128 89/<- %ecx 0/r32/eax + 6129 # out-addr->type = new tree() + 6130 8d/copy-address *(ecx+8) 0/r32/eax # Var-type + 6131 (allocate *(ebp+8) *Tree-size %eax) + 6132 (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + 6133 c7 0/subop/copy *eax 1/imm32/true # Tree-is-atom + 6134 # nothing else to do; default type is 'literal' + 6135 $new-literal-integer:end: + 6136 # . reclaim locals + 6137 81 0/subop/add %esp 8/imm32 + 6138 # . restore registers + 6139 59/pop-to-ecx + 6140 58/pop-to-eax + 6141 # . epilogue + 6142 89/<- %esp 5/r32/ebp + 6143 5d/pop-to-ebp + 6144 c3/return + 6145 + 6146 $new-literal-integer:abort: + 6147 (write-buffered Stderr "variable cannot begin with a digit '") + 6148 (write-slice-buffered Stderr *(ebp+0xc)) + 6149 (write-buffered Stderr "'\n") + 6150 (flush Stderr) + 6151 # . syscall(exit, 1) + 6152 bb/copy-to-ebx 1/imm32 + 6153 b8/copy-to-eax 1/imm32/exit + 6154 cd/syscall 0x80/imm8 + 6155 # never gets here + 6156 + 6157 new-literal: # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var) + 6158 # . prologue + 6159 55/push-ebp + 6160 89/<- %ebp 4/r32/esp + 6161 # . save registers + 6162 50/push-eax + 6163 51/push-ecx + 6164 # var s/ecx: (handle array byte) + 6165 68/push 0/imm32 + 6166 68/push 0/imm32 + 6167 89/<- %ecx 0/r32/eax + 6168 # s = slice-to-string(name) + 6169 (slice-to-string Heap *(ebp+0xc) %ecx) + 6170 # allocate to out + 6171 (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10)) + 6172 # var out-addr/ecx: (addr var) = lookup(*out) + 6173 8b/-> *(ebp+0x10) 1/r32/ecx + 6174 (lookup *ecx *(ecx+4)) # => eax + 6175 89/<- %ecx 0/r32/eax + 6176 # out-addr->type/eax = new type + 6177 8d/copy-address *(ecx+8) 0/r32/eax # Var-type + 6178 (allocate *(ebp+8) *Tree-size %eax) + 6179 (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + 6180 # nothing else to do; default type is 'literal' + 6181 c7 0/subop/copy *eax 1/imm32/true # Tree-is-atom + 6182 $new-literal:end: + 6183 # . reclaim locals + 6184 81 0/subop/add %esp 8/imm32 + 6185 # . restore registers + 6186 59/pop-to-ecx + 6187 58/pop-to-eax + 6188 # . epilogue + 6189 89/<- %esp 5/r32/ebp + 6190 5d/pop-to-ebp + 6191 c3/return + 6192 + 6193 new-var-from-slice: # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var) + 6194 # . prologue + 6195 55/push-ebp + 6196 89/<- %ebp 4/r32/esp + 6197 # . save registers + 6198 51/push-ecx + 6199 # var tmp/ecx: (handle array byte) + 6200 68/push 0/imm32 + 6201 68/push 0/imm32 + 6202 89/<- %ecx 4/r32/esp + 6203 # tmp = slice-to-string(name) + 6204 (slice-to-string Heap *(ebp+0xc) %ecx) + 6205 # out = new-var(tmp) + 6206 (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10)) + 6207 $new-var-from-slice:end: + 6208 # . reclaim locals + 6209 81 0/subop/add %esp 8/imm32 + 6210 # . restore registers + 6211 59/pop-to-ecx 6212 # . epilogue 6213 89/<- %esp 5/r32/ebp 6214 5d/pop-to-ebp 6215 c3/return 6216 - 6217 $populate-mu-type:abort: - 6218 # error("unexpected top-level command: " word-slice "\n") - 6219 (write-buffered Stderr "incomplete type definition '") - 6220 (type-name *edi) # Typeinfo-id => eax - 6221 (write-buffered Stderr %eax) - 6222 (write-buffered Stderr "\n") - 6223 (flush Stderr) - 6224 # . syscall(exit, 1) - 6225 bb/copy-to-ebx 1/imm32 - 6226 b8/copy-to-eax 1/imm32/exit - 6227 cd/syscall 0x80/imm8 - 6228 # never gets here - 6229 - 6230 type-name: # index: int -> result/eax: (addr array byte) - 6231 # . prologue - 6232 55/push-ebp - 6233 89/<- %ebp 4/r32/esp - 6234 # - 6235 (index Type-id *(ebp+8)) - 6236 $type-name:end: - 6237 # . epilogue - 6238 89/<- %esp 5/r32/ebp - 6239 5d/pop-to-ebp - 6240 c3/return - 6241 - 6242 index: # arr: (addr stream (handle array byte)), index: int -> result/eax: (addr array byte) - 6243 # . prologue - 6244 55/push-ebp - 6245 89/<- %ebp 4/r32/esp - 6246 # . save registers - 6247 56/push-esi - 6248 # TODO: bounds-check index - 6249 # esi = arr - 6250 8b/-> *(ebp+8) 6/r32/esi - 6251 # eax = index - 6252 8b/-> *(ebp+0xc) 0/r32/eax - 6253 # eax = *(arr + 12 + index) - 6254 8b/-> *(esi+eax+0xc) 0/r32/eax - 6255 $index:end: - 6256 # . restore registers - 6257 5e/pop-to-esi - 6258 # . epilogue - 6259 89/<- %esp 5/r32/ebp - 6260 5d/pop-to-ebp - 6261 c3/return - 6262 - 6263 ####################################################### - 6264 # Compute type sizes - 6265 ####################################################### - 6266 - 6267 # Compute the sizes of all user-defined types. - 6268 # We'll need the sizes of their elements, which may be other user-defined - 6269 # types, which we will compute as needed. - 6270 - 6271 # Initially, all user-defined types have their sizes set to -2 (invalid) - 6272 populate-mu-type-sizes: - 6273 # . prologue - 6274 55/push-ebp - 6275 89/<- %ebp 4/r32/esp - 6276 # . save registers - 6277 51/push-ecx - 6278 $populate-mu-type-sizes:total-sizes: - 6279 # var curr/ecx: (handle typeinfo) = *Program->types - 6280 8b/-> *_Program-types 1/r32/ecx - 6281 { - 6282 # if (curr == null) break - 6283 81 7/subop/compare %ecx 0/imm32 - 6284 74/jump-if-= break/disp8 - 6285 (populate-mu-type-sizes-in-type %ecx) - 6286 # curr = curr->next - 6287 8b/-> *(ecx+0xc) 1/r32/ecx # Typeinfo-next - 6288 eb/jump loop/disp8 - 6289 } - 6290 $populate-mu-type-sizes:offsets: - 6291 # var curr/ecx: (handle typeinfo) = *Program->types - 6292 8b/-> *_Program-types 1/r32/ecx - 6293 { - 6294 # if (curr == null) break - 6295 81 7/subop/compare %ecx 0/imm32 - 6296 74/jump-if-= break/disp8 - 6297 (populate-mu-type-offsets %ecx) - 6298 # curr = curr->next - 6299 8b/-> *(ecx+0xc) 1/r32/ecx # Typeinfo-next - 6300 eb/jump loop/disp8 - 6301 } - 6302 $populate-mu-type-sizes:end: - 6303 # . restore registers - 6304 59/pop-to-ecx - 6305 # . epilogue - 6306 89/<- %esp 5/r32/ebp - 6307 5d/pop-to-ebp - 6308 c3/return - 6309 - 6310 # compute sizes of all fields, recursing as necessary - 6311 # sum up all their sizes to arrive at total size - 6312 # fields may be out of order, but that doesn't affect the answer - 6313 populate-mu-type-sizes-in-type: # T: (handle typeinfo) - 6314 # . prologue - 6315 55/push-ebp - 6316 89/<- %ebp 4/r32/esp - 6317 # . save registers - 6318 50/push-eax - 6319 51/push-ecx - 6320 52/push-edx - 6321 56/push-esi - 6322 57/push-edi - 6323 # esi = T - 6324 8b/-> *(ebp+8) 6/r32/esi - 6325 # if T is already computed, return - 6326 81 7/subop/compare *(esi+8) 0/imm32 # Typeinfo-total-size-in-bytes - 6327 7d/jump-if->= $populate-mu-type-sizes-in-type:end/disp8 - 6328 # if T is being computed, abort - 6329 81 7/subop/compare *(esi+8) -1/imm32/being-computed # Typeinfo-total-size-in-bytes - 6330 74/jump-if-= $populate-mu-type-sizes-in-type:abort/disp8 - 6331 # tag T (-2 to -1) to avoid infinite recursion - 6332 c7 0/subop/copy *(esi+8) -1/imm32/being-computed # Typeinfo-total-size-in-bytes - 6333 # var total-size/edi: int = 0 - 6334 bf/copy-to-edi 0/imm32 - 6335 # - for every field, if it's a user-defined type, compute its size - 6336 # var table/ecx: (handle table string_key (handle typeinfo-entry)) = T->fields - 6337 8b/-> *(esi+4) 1/r32/ecx # Typeinfo-fields - 6338 # var table-size/edx: int = table->write - 6339 8b/-> *ecx 2/r32/edx # stream-write - 6340 # var curr/ecx: (addr table_row) = table->data - 6341 8d/copy-address *(ecx+0xc) 1/r32/ecx - 6342 # var max/edx: (addr table_row) = table->data + table->write - 6343 8d/copy-address *(ecx+edx) 2/r32/edx - 6344 { - 6345 $populate-mu-type-sizes-in-type:loop: - 6346 # if (curr >= max) break - 6347 39/compare %ecx 2/r32/edx - 6348 73/jump-if-addr>= break/disp8 - 6349 # var t/eax: (handle typeinfo-entry) = curr->value - 6350 8b/-> *(ecx+4) 0/r32/eax - 6351 # compute size of t - 6352 (compute-size-of-var *eax) # Typeinfo-entry-input-var => eax - 6353 # result += eax - 6354 01/add-to %edi 0/r32/eax - 6355 # curr += row-size - 6356 81 0/subop/add %ecx 8/imm32 - 6357 # - 6358 eb/jump loop/disp8 - 6359 } - 6360 # - save result - 6361 89/<- *(esi+8) 7/r32/edi # Typeinfo-total-size-in-bytes - 6362 $populate-mu-type-sizes-in-type:end: - 6363 # . restore registers - 6364 5f/pop-to-edi - 6365 5e/pop-to-esi - 6366 5a/pop-to-edx - 6367 59/pop-to-ecx - 6368 58/pop-to-eax - 6369 # . epilogue - 6370 89/<- %esp 5/r32/ebp - 6371 5d/pop-to-ebp - 6372 c3/return - 6373 - 6374 $populate-mu-type-sizes-in-type:abort: - 6375 (write-buffered Stderr "cycle in type definitions\n") - 6376 (flush Stderr) - 6377 # . syscall(exit, 1) - 6378 bb/copy-to-ebx 1/imm32 - 6379 b8/copy-to-eax 1/imm32/exit - 6380 cd/syscall 0x80/imm8 - 6381 # never gets here - 6382 - 6383 # Analogous to size-of, except we need to compute what size-of can just read - 6384 # off the right data structures. - 6385 compute-size-of-var: # in: (handle var) -> result/eax: int - 6386 # . prologue - 6387 55/push-ebp - 6388 89/<- %ebp 4/r32/esp - 6389 # . push registers - 6390 51/push-ecx - 6391 # var t/ecx: (handle tree type-id) = v->type - 6392 8b/-> *(ebp+8) 1/r32/ecx - 6393 8b/-> *(ecx+4) 1/r32/ecx # Var-type - 6394 # if (t->left-is-atom == false) t = t->left - 6395 { - 6396 81 7/subop/compare *ecx 0/imm32/false # Tree-is-atom - 6397 75/jump-if-!= break/disp8 - 6398 8b/-> *(ecx+4) 1/r32/ecx # Tree-left - 6399 } - 6400 (compute-size-of-type-id *(ecx+4)) # Tree-left => eax - 6401 $compute-size-of-var:end: - 6402 # . restore registers - 6403 59/pop-to-ecx - 6404 # . epilogue - 6405 89/<- %esp 5/r32/ebp - 6406 5d/pop-to-ebp - 6407 c3/return - 6408 - 6409 compute-size-of-type-id: # t: type-id -> result/eax: int - 6410 # . prologue - 6411 55/push-ebp - 6412 89/<- %ebp 4/r32/esp - 6413 # - 6414 8b/-> *(ebp+8) 0/r32/eax - 6415 # if v is a literal, return 0 - 6416 3d/compare-eax-and 0/imm32 - 6417 74/jump-if-= $compute-size-of-type-id:end/disp8 # eax changes type from type-id to int - 6418 # if v has a user-defined type, compute its size - 6419 # TODO: support non-atom type - 6420 (find-typeinfo %eax) # => eax - 6421 { - 6422 3d/compare-eax-and 0/imm32 - 6423 74/jump-if-= break/disp8 - 6424 $compute-size-of-type-id:user-defined: - 6425 (populate-mu-type-sizes %eax) - 6426 8b/-> *(eax+8) 0/r32/eax # Typeinfo-total-size-in-bytes - 6427 eb/jump $compute-size-of-type-id:end/disp8 - 6428 } - 6429 # otherwise return the word size - 6430 b8/copy-to-eax 4/imm32 - 6431 $compute-size-of-type-id:end: - 6432 # . epilogue - 6433 89/<- %esp 5/r32/ebp - 6434 5d/pop-to-ebp - 6435 c3/return - 6436 - 6437 # at this point we have total sizes for all user-defined types - 6438 # compute offsets for each element - 6439 # complication: fields may be out of order - 6440 populate-mu-type-offsets: # in: (handle typeinfo) - 6441 # . prologue - 6442 55/push-ebp - 6443 89/<- %ebp 4/r32/esp - 6444 # . save registers - 6445 50/push-eax - 6446 51/push-ecx - 6447 52/push-edx - 6448 53/push-ebx - 6449 56/push-esi - 6450 57/push-edi - 6451 # var curr-offset/edi: int = 0 - 6452 bf/copy-to-edi 0/imm32 - 6453 # var table/ecx: (handle table string_key (handle typeinfo-entry)) = T->fields - 6454 8b/-> *(ebp+8) 1/r32/ecx - 6455 8b/-> *(ecx+4) 1/r32/ecx # Typeinfo-fields - 6456 # var num-elems/edx: int = table->write / 8 - 6457 8b/-> *ecx 2/r32/edx # stream-write - 6458 c1 5/subop/shift-right-logical %edx 3/imm8 - 6459 # var i/ebx: int = 0 - 6460 bb/copy-to-ebx 0/imm32 - 6461 { - 6462 $populate-mu-type-offsets:loop: - 6463 39/compare %ebx 2/r32/edx - 6464 7d/jump-if->= break/disp8 - 6465 # var v/esi: (handle typeinfo-entry) - 6466 (locate-typeinfo-entry-with-index %ecx %ebx) # => eax - 6467 89/<- %esi 0/r32/eax - 6468 # v->output-var->offset = curr-offset - 6469 8b/-> *(esi+8) 0/r32/eax # Typeinfo-entry-output-var - 6470 89/<- *(eax+0xc) 7/r32/edi # Var-offset - 6471 # curr-offset += size-of(v->input-var) - 6472 8b/-> *esi 0/r32/eax # Typeinfo-entry-input-var - 6473 (size-of %eax) # => eax - 6474 01/add-to %edi 0/r32/eax - 6475 # ++i - 6476 43/increment-ebx - 6477 eb/jump loop/disp8 - 6478 } - 6479 $populate-mu-type-offsets:end: - 6480 # . restore registers - 6481 5f/pop-to-edi - 6482 5e/pop-to-esi - 6483 5b/pop-to-ebx - 6484 5a/pop-to-edx - 6485 59/pop-to-ecx - 6486 58/pop-to-eax - 6487 # . epilogue - 6488 89/<- %esp 5/r32/ebp - 6489 5d/pop-to-ebp - 6490 c3/return - 6491 - 6492 locate-typeinfo-entry-with-index: # table: (handle table string_key (handle typeinfo-entry)), idx: int -> result/eax: (handle typeinfo-entry) - 6493 # . prologue - 6494 55/push-ebp - 6495 89/<- %ebp 4/r32/esp - 6496 # . save registers - 6497 51/push-ecx - 6498 52/push-edx - 6499 53/push-ebx - 6500 56/push-esi - 6501 57/push-edi - 6502 # esi = table - 6503 8b/-> *(ebp+8) 6/r32/esi - 6504 # var curr/ecx: (addr string_key) = table->data - 6505 8d/copy-address *(esi+0xc) 1/r32/ecx - 6506 # var max/edx: (addr byte) = &table->data[table->write] - 6507 8b/-> *esi 2/r32/edx - 6508 8d/copy-address *(ecx+edx) 2/r32/edx - 6509 { - 6510 $locate-typeinfo-entry-with-index:loop: - 6511 39/compare %ecx 2/r32/edx - 6512 73/jump-if-addr>= $locate-typeinfo-entry-with-index:abort/disp8 - 6513 # var v/ebx: (handle typeinfo-entry) - 6514 8b/-> *(ecx+4) 3/r32/ebx - 6515 # if (v->index == idx) return v - 6516 8b/-> *(ebx+4) 0/r32/eax # Typeinfo-entry-index - 6517 39/compare *(ebp+0xc) 0/r32/eax - 6518 89/<- %eax 3/r32/ebx - 6519 74/jump-if-= break/disp8 - 6520 # curr += 8 - 6521 81 0/subop/add %ecx 8/imm32 - 6522 eb/jump loop/disp8 - 6523 } - 6524 $locate-typeinfo-entry-with-index:end: + 6217 new-var-def: # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt) + 6218 # . prologue + 6219 55/push-ebp + 6220 89/<- %ebp 4/r32/esp + 6221 # . save registers + 6222 50/push-eax + 6223 51/push-ecx + 6224 # + 6225 (allocate *(ebp+8) *Stmt-size *(ebp+0x14)) + 6226 # var out-addr/eax: (addr stmt) = lookup(*out) + 6227 8b/-> *(ebp+0x14) 0/r32/eax + 6228 (lookup *eax *(eax+4)) # => eax + 6229 # out-addr->tag = stmt + 6230 c7 0/subop/copy *eax 2/imm32/tag/var-on-stack # Stmt-tag + 6231 # result->var = var + 6232 8b/-> *(ebp+0xc) 1/r32/ecx + 6233 89/<- *(eax+4) 1/r32/ecx # Vardef-var + 6234 8b/-> *(ebp+0x10) 1/r32/ecx + 6235 89/<- *(eax+8) 1/r32/ecx # Vardef-var + 6236 $new-var-def:end: + 6237 # . restore registers + 6238 59/pop-to-ecx + 6239 58/pop-to-eax + 6240 # . epilogue + 6241 89/<- %esp 5/r32/ebp + 6242 5d/pop-to-ebp + 6243 c3/return + 6244 + 6245 new-reg-var-def: # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt) + 6246 # . prologue + 6247 55/push-ebp + 6248 89/<- %ebp 4/r32/esp + 6249 # . save registers + 6250 50/push-eax + 6251 # eax = out + 6252 8b/-> *(ebp+0x14) 0/r32/eax + 6253 # + 6254 (allocate *(ebp+8) *Stmt-size %eax) + 6255 # var out-addr/eax: (addr stmt) = lookup(*out) + 6256 (lookup *eax *(eax+4)) # => eax + 6257 # set tag + 6258 c7 0/subop/copy *eax 3/imm32/tag/var-in-register # Stmt-tag + 6259 # set output + 6260 8d/copy-address *(eax+0x14) 0/r32/eax # Regvardef-outputs + 6261 (append-stmt-var Heap *(ebp+0xc) *(ebp+0x10) 0 0 0 %eax) + 6262 $new-reg-var-def:end: + 6263 # . restore registers + 6264 58/pop-to-eax + 6265 # . epilogue + 6266 89/<- %esp 5/r32/ebp + 6267 5d/pop-to-ebp + 6268 c3/return + 6269 + 6270 append-list: # ad: (addr allocation-descriptor), value: (handle _type), list: (handle list _type), out: (addr handle list _type) + 6271 # . prologue + 6272 55/push-ebp + 6273 89/<- %ebp 4/r32/esp + 6274 # . save registers + 6275 50/push-eax + 6276 51/push-ecx + 6277 57/push-edi + 6278 # edi = out + 6279 8b/-> *(ebp+0x1c) 7/r32/edi + 6280 # *out = new list + 6281 (allocate *(ebp+8) *List-size %edi) + 6282 # var out-addr/edi: (addr list _type) = lookup(*out) + 6283 (lookup *edi *(edi+4)) # => eax + 6284 89/<- %edi 0/r32/eax + 6285 # out-addr->value = value + 6286 8b/-> *(ebp+0xc) 0/r32/eax + 6287 89/<- *edi 0/r32/eax # List-value + 6288 8b/-> *(ebp+0x10) 0/r32/eax + 6289 89/<- *(edi+4) 0/r32/eax # List-value + 6290 # if (list == null) return + 6291 81 7/subop/compare *(ebp+0x14) 0/imm32 + 6292 74/jump-if-= $append-list:end/disp8 + 6293 # otherwise append + 6294 $append-list:non-empty-list: + 6295 # var curr/eax: (addr list _type) = lookup(list) + 6296 (lookup *(ebp+0x14) *(ebp+0x18)) # => eax + 6297 # while (curr->next != null) curr = curr->next + 6298 { + 6299 81 7/subop/compare *(eax+8) 0/imm32 # List-next + 6300 74/jump-if-= break/disp8 + 6301 # curr = lookup(curr->next) + 6302 (lookup *(eax+8) *(eax+0xc)) # List-next, List-next => eax + 6303 # + 6304 eb/jump loop/disp8 + 6305 } + 6306 # edi = out + 6307 8b/-> *(ebp+0x1c) 7/r32/edi + 6308 # curr->next = out + 6309 8b/-> *edi 1/r32/ecx + 6310 89/<- *(eax+8) 1/r32/ecx # List-next + 6311 8b/-> *(edi+4) 1/r32/ecx + 6312 89/<- *(eax+0xc) 1/r32/ecx # List-next + 6313 # out = list + 6314 8b/-> *(ebp+0x14) 1/r32/ecx + 6315 89/<- *edi 1/r32/ecx + 6316 8b/-> *(ebp+0x18) 1/r32/ecx + 6317 89/<- *(edi+4) 1/r32/ecx + 6318 $append-list:end: + 6319 # . restore registers + 6320 5f/pop-to-edi + 6321 59/pop-to-ecx + 6322 58/pop-to-eax + 6323 # . epilogue + 6324 89/<- %esp 5/r32/ebp + 6325 5d/pop-to-ebp + 6326 c3/return + 6327 + 6328 append-stmt-var: # ad: (addr allocation-descriptor), v: (handle var), vars: (handle stmt-var), is-deref?: boolean, out: (addr handle stmt-var) + 6329 # . prologue + 6330 55/push-ebp + 6331 89/<- %ebp 4/r32/esp + 6332 # . save registers + 6333 50/push-eax + 6334 51/push-ecx + 6335 57/push-edi + 6336 # edi = out + 6337 8b/-> *(ebp+0x20) 7/r32/edi + 6338 # out = new stmt-var + 6339 (allocate *(ebp+8) *Stmt-var-size %edi) + 6340 # var out-addr/ecx: (addr stmt-var) = lookup(*out) + 6341 (lookup *edi *(edi+4)) # => eax + 6342 89/<- %ecx 0/r32/eax + 6343 # out-addr->value = v + 6344 8b/-> *(ebp+0xc) 0/r32/eax + 6345 89/<- *ecx 0/r32/eax # Stmt-var-value + 6346 8b/-> *(ebp+0x10) 0/r32/eax + 6347 89/<- *(ecx+4) 0/r32/eax # Stmt-var-value + 6348 # out-addr->is-deref? = is-deref? + 6349 8b/-> *(ebp+0x1c) 0/r32/eax + 6350 89/<- *(ecx+0x10) 0/r32/eax # Stmt-var-is-deref + 6351 # if (vars == null) return result + 6352 81 7/subop/compare *(ebp+0x14) 0/imm32/null + 6353 74/jump-if-= $append-stmt-var:end/disp8 + 6354 # otherwise append + 6355 # var curr/eax: (addr stmt-var) = lookup(vars) + 6356 (lookup *(ebp+0x14) *(ebp+0x18)) # => eax + 6357 # while (curr->next != null) curr = curr->next + 6358 { + 6359 81 7/subop/compare *(eax+8) 0/imm32 # Stmt-var-next + 6360 74/jump-if-= break/disp8 + 6361 # curr = lookup(curr->next) + 6362 (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next, Stmt-var-next => eax + 6363 # + 6364 eb/jump loop/disp8 + 6365 } + 6366 # curr->next = out + 6367 8b/-> *edi 1/r32/ecx + 6368 89/<- *(eax+8) 1/r32/ecx # Stmt-var-next + 6369 8b/-> *(edi+4) 1/r32/ecx + 6370 89/<- *(eax+0xc) 1/r32/ecx # Stmt-var-next + 6371 # out = vars + 6372 8b/-> *(ebp+0x14) 1/r32/ecx + 6373 89/<- *edi 1/r32/ecx + 6374 8b/-> *(ebp+0x18) 1/r32/ecx + 6375 89/<- *(edi+4) 1/r32/ecx + 6376 $append-stmt-var:end: + 6377 # . restore registers + 6378 5f/pop-to-edi + 6379 59/pop-to-ecx + 6380 58/pop-to-eax + 6381 # . epilogue + 6382 89/<- %esp 5/r32/ebp + 6383 5d/pop-to-ebp + 6384 c3/return + 6385 + 6386 append-to-block: # ad: (addr allocation-descriptor), block: (addr block), x: (handle stmt) + 6387 # . prologue + 6388 55/push-ebp + 6389 89/<- %ebp 4/r32/esp + 6390 # . save registers + 6391 50/push-eax + 6392 56/push-esi + 6393 # esi = block + 6394 8b/-> *(ebp+0xc) 6/r32/esi + 6395 # block->stmts = append(x, block->stmts) + 6396 8d/copy-address *(esi+4) 0/r32/eax # Block-stmts + 6397 (append-list *(ebp+8) *(ebp+0x10) *(ebp+0x14) *(esi+4) *(esi+8) %eax) # ad, x, x, Block-stmts, Block-stmts + 6398 $append-to-block:end: + 6399 # . restore registers + 6400 5e/pop-to-esi + 6401 58/pop-to-eax + 6402 # . epilogue + 6403 89/<- %esp 5/r32/ebp + 6404 5d/pop-to-ebp + 6405 c3/return + 6406 + 6407 ## Parsing types + 6408 # We need to create metadata on user-defined types, and we need to use this + 6409 # metadata as we parse instructions. + 6410 # However, we also want to allow types to be used before their definitions. + 6411 # This means we can't ever assume any type data structures exist. + 6412 + 6413 lookup-or-create-constant: # container: (addr stmt-var), field-name: (addr slice), out: (addr handle var) + 6414 # . prologue + 6415 55/push-ebp + 6416 89/<- %ebp 4/r32/esp + 6417 # . save registers + 6418 50/push-eax + 6419 56/push-esi + 6420 # var container-type/esi: type-id + 6421 (container-type *(ebp+8)) # => eax + 6422 89/<- %esi 0/r32/eax + 6423 # var tmp/eax: (handle typeinfo) = find-or-create-typeinfo(container-type) + 6424 68/push 0/imm32 + 6425 68/push 0/imm32 + 6426 89/<- %eax 4/r32/esp + 6427 (find-or-create-typeinfo %esi %eax) + 6428 # var tmp-addr/eax: (addr typeinfo) = lookup(tmp) + 6429 (lookup *eax *(eax+4)) # => eax + 6430 # result = find-or-create-typeinfo-output-var(typeinfo, field-name) + 6431 (find-or-create-typeinfo-output-var %eax *(ebp+0xc) *(ebp+0x10)) + 6432 $lookup-or-create-constant:end: + 6433 # . reclaim locals + 6434 81 0/subop/add %esp 8/imm32 + 6435 # . restore registers + 6436 5e/pop-to-esi + 6437 58/pop-to-eax + 6438 # . epilogue + 6439 89/<- %esp 5/r32/ebp + 6440 5d/pop-to-ebp + 6441 c3/return + 6442 + 6443 # if addr var: + 6444 # container->var->type->right->left->value + 6445 # otherwise + 6446 # container->var->type->value + 6447 container-type: # container: (addr stmt-var) -> result/eax: type-id + 6448 # . prologue + 6449 55/push-ebp + 6450 89/<- %ebp 4/r32/esp + 6451 # + 6452 8b/-> *(ebp+8) 0/r32/eax + 6453 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 6454 (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 6455 { + 6456 81 7/subop/compare *(eax+8) 0/imm32 # Tree-right + 6457 74/jump-if-= break/disp8 + 6458 (lookup *(eax+0xc) *(eax+0x10)) # Tree-right Tree-right => eax + 6459 (lookup *(eax+4) *(eax+8)) # Tree-left Tree-left => eax + 6460 } + 6461 8b/-> *(eax+4) 0/r32/eax # Tree-value + 6462 $container-type:end: + 6463 # . epilogue + 6464 89/<- %esp 5/r32/ebp + 6465 5d/pop-to-ebp + 6466 c3/return + 6467 + 6468 find-or-create-typeinfo: # t: type-id, out: (addr handle typeinfo) + 6469 # . prologue + 6470 55/push-ebp + 6471 89/<- %ebp 4/r32/esp + 6472 # . save registers + 6473 50/push-eax + 6474 51/push-ecx + 6475 52/push-edx + 6476 57/push-edi + 6477 # edi = out + 6478 8b/-> *(ebp+0xc) 7/r32/edi + 6479 # var fields/ecx: (handle table (handle array byte) (handle typeinfo-entry)) + 6480 68/push 0/imm32 + 6481 68/push 0/imm32 + 6482 89/<- %ecx 4/r32/esp + 6483 # find-typeinfo(t, out) + 6484 (find-typeinfo *(ebp+8) %edi) + 6485 { + 6486 # if (*out != 0) break + 6487 81 7/subop/compare *edi 0/imm32 + 6488 0f 85/jump-if-!= break/disp32 + 6489 $find-or-create-typeinfo:create: + 6490 # *out = allocate + 6491 (allocate Heap *Typeinfo-size %edi) + 6492 # var tmp/eax: (addr typeinfo) = lookup(*out) + 6493 (lookup *edi *(edi+4)) # => eax + 6494 #? (write-buffered Stderr "created typeinfo at ") + 6495 #? (print-int32-buffered Stderr %eax) + 6496 #? (write-buffered Stderr " for type-id ") + 6497 #? (print-int32-buffered Stderr *(ebp+8)) + 6498 #? (write-buffered Stderr Newline) + 6499 #? (flush Stderr) + 6500 # tmp->id = t + 6501 8b/-> *(ebp+8) 2/r32/edx + 6502 89/<- *eax 2/r32/edx # Typeinfo-id + 6503 # tmp->fields = new table + 6504 # . fields = new table + 6505 (new-stream Heap 0x40 *Typeinfo-fields-row-size %ecx) + 6506 # . tmp->fields = fields + 6507 8b/-> *ecx 2/r32/edx + 6508 89/<- *(eax+4) 2/r32/edx # Typeinfo-fields + 6509 8b/-> *(ecx+4) 2/r32/edx + 6510 89/<- *(eax+8) 2/r32/edx # Typeinfo-fields + 6511 # tmp->next = Program->types + 6512 8b/-> *_Program-types 1/r32/ecx + 6513 89/<- *(eax+0x10) 1/r32/ecx # Typeinfo-next + 6514 8b/-> *_Program-types->payload 1/r32/ecx + 6515 89/<- *(eax+0x14) 1/r32/ecx # Typeinfo-next + 6516 # Program->types = out + 6517 8b/-> *edi 1/r32/ecx + 6518 89/<- *_Program-types 1/r32/ecx + 6519 8b/-> *(edi+4) 1/r32/ecx + 6520 89/<- *_Program-types->payload 1/r32/ecx + 6521 } + 6522 $find-or-create-typeinfo:end: + 6523 # . reclaim locals + 6524 81 0/subop/add %esp 8/imm32 6525 # . restore registers 6526 5f/pop-to-edi - 6527 5e/pop-to-esi - 6528 5b/pop-to-ebx - 6529 5a/pop-to-edx - 6530 59/pop-to-ecx - 6531 # . epilogue - 6532 89/<- %esp 5/r32/ebp - 6533 5d/pop-to-ebp - 6534 c3/return - 6535 - 6536 $locate-typeinfo-entry-with-index:abort: - 6537 (write-buffered Stderr "overflowing typeinfo-entry->index ") - 6538 (print-int32-buffered Stderr %ecx) - 6539 (write-buffered Stderr "\n") - 6540 (flush Stderr) - 6541 # . syscall(exit, 1) - 6542 bb/copy-to-ebx 1/imm32 - 6543 b8/copy-to-eax 1/imm32/exit - 6544 cd/syscall 0x80/imm8 - 6545 # never gets here - 6546 - 6547 ####################################################### - 6548 # Type-checking - 6549 ####################################################### - 6550 - 6551 check-mu-types: - 6552 # . prologue - 6553 55/push-ebp - 6554 89/<- %ebp 4/r32/esp - 6555 # - 6556 $check-mu-types:end: - 6557 # . epilogue - 6558 89/<- %esp 5/r32/ebp - 6559 5d/pop-to-ebp - 6560 c3/return - 6561 - 6562 size-of: # v: (handle var) -> result/eax: int - 6563 # . prologue - 6564 55/push-ebp - 6565 89/<- %ebp 4/r32/esp - 6566 # . save registers - 6567 51/push-ecx - 6568 # var t/ecx: (handle tree type-id) = v->type - 6569 8b/-> *(ebp+8) 1/r32/ecx - 6570 8b/-> *(ecx+4) 1/r32/ecx # Var-type - 6571 # if is-mu-array?(t) return size-of-array(t) - 6572 { - 6573 (is-mu-array? %ecx) # => eax - 6574 3d/compare-eax-and 0/imm32/false - 6575 74/jump-if-= break/disp8 - 6576 (size-of-array %ecx) # => eax - 6577 eb/jump $size-of:end/disp8 - 6578 } - 6579 # if (t->left-is-atom == false) t = t->left - 6580 { - 6581 81 7/subop/compare *ecx 0/imm32/false # Tree-is-atom - 6582 75/jump-if-!= break/disp8 - 6583 8b/-> *(ecx+4) 1/r32/ecx # Tree-left - 6584 } - 6585 (size-of-type-id *(ecx+4)) # Tree-left => eax - 6586 $size-of:end: - 6587 # . restore registers - 6588 59/pop-to-ecx - 6589 # . epilogue - 6590 89/<- %esp 5/r32/ebp - 6591 5d/pop-to-ebp - 6592 c3/return - 6593 - 6594 size-of-deref: # v: (handle var) -> result/eax: int - 6595 # . prologue - 6596 55/push-ebp - 6597 89/<- %ebp 4/r32/esp - 6598 # . save registers - 6599 51/push-ecx - 6600 # var t/ecx: (handle tree type-id) = v->type - 6601 8b/-> *(ebp+8) 1/r32/ecx - 6602 8b/-> *(ecx+4) 1/r32/ecx # Var-type - 6603 # TODO: assert(t is an addr) - 6604 8b/-> *(ecx+8) 1/r32/ecx # Tree-right - 6605 # if is-mu-array?(t) return size-of-array(t) - 6606 { - 6607 (is-mu-array? %ecx) # => eax - 6608 3d/compare-eax-and 0/imm32/false - 6609 74/jump-if-= break/disp8 - 6610 (size-of-array %ecx) # => eax - 6611 eb/jump $size-of:end/disp8 - 6612 } - 6613 # if (t->left-is-atom == false) t = t->left - 6614 { - 6615 81 7/subop/compare *ecx 0/imm32/false # Tree-is-atom - 6616 75/jump-if-!= break/disp8 - 6617 8b/-> *(ecx+4) 1/r32/ecx # Tree-left - 6618 } - 6619 (size-of-type-id *(ecx+4)) # Tree-left => eax - 6620 $size-of-deref:end: - 6621 # . restore registers - 6622 59/pop-to-ecx - 6623 # . epilogue - 6624 89/<- %esp 5/r32/ebp - 6625 5d/pop-to-ebp - 6626 c3/return - 6627 - 6628 is-mu-array?: # t: (handle tree type-id) -> result/eax: boolean - 6629 # . prologue - 6630 55/push-ebp - 6631 89/<- %ebp 4/r32/esp - 6632 # . save registers - 6633 51/push-ecx - 6634 # ecx = t - 6635 8b/-> *(ebp+8) 1/r32/ecx - 6636 # result = false - 6637 b8/copy-to-eax 0/imm32/false - 6638 # if t->left-is-atom, return false - 6639 81 7/subop/compare *ecx 0/imm32/false # Tree-is-atom - 6640 75/jump-if-!= $is-mu-array?:end/disp8 - 6641 # if !t->left->left-is-atom, return false - 6642 8b/-> *(ecx+4) 1/r32/ecx # Tree-left - 6643 81 7/subop/compare *ecx 0/imm32/false # Tree-is-atom - 6644 74/jump-if-= $is-mu-array?:end/disp8 - 6645 # return t->left->value == array - 6646 81 7/subop/compare *(ecx+4) 3/imm32/array-type-id # Tree-value - 6647 0f 94/set-if-= %al - 6648 $is-mu-array?:end: - 6649 # . restore registers - 6650 59/pop-to-ecx - 6651 # . epilogue - 6652 89/<- %esp 5/r32/ebp - 6653 5d/pop-to-ebp - 6654 c3/return - 6655 - 6656 size-of-array: # a: (handle tree type-id) -> result/eax: int - 6657 # . prologue - 6658 55/push-ebp - 6659 89/<- %ebp 4/r32/esp - 6660 # . save registers - 6661 51/push-ecx - 6662 52/push-edx - 6663 # - 6664 8b/-> *(ebp+8) 1/r32/ecx - 6665 # TODO: assert that a->left is 'array' - 6666 8b/-> *(ecx+8) 1/r32/ecx # Tree-right - 6667 # var elem-type/edx: type-id = a->right->value - 6668 8b/-> *(ecx+4) 2/r32/edx # Tree-value - 6669 8b/-> *(edx+4) 2/r32/edx # Tree-value - 6670 # var array-size/ecx: int = a->right->right->left->value - 6671 8b/-> *(ecx+8) 1/r32/ecx # Tree-right - 6672 8b/-> *(ecx+4) 1/r32/ecx # Tree-left - 6673 8b/-> *(ecx+4) 1/r32/ecx # Tree-value - 6674 # return array-size * size-of(elem-type) - 6675 (size-of-type-id %edx) # => eax - 6676 f7 4/subop/multiply-into-eax %ecx - 6677 05/add-to-eax 4/imm32 # for array size - 6678 $size-of-array:end: - 6679 # . restore registers - 6680 5a/pop-to-edx - 6681 59/pop-to-ecx - 6682 # . epilogue - 6683 89/<- %esp 5/r32/ebp - 6684 5d/pop-to-ebp - 6685 c3/return - 6686 - 6687 size-of-type-id: # t: type-id -> result/eax: int - 6688 # . prologue - 6689 55/push-ebp - 6690 89/<- %ebp 4/r32/esp - 6691 # - 6692 8b/-> *(ebp+8) 0/r32/eax - 6693 # if v is a literal, return 0 - 6694 3d/compare-eax-and 0/imm32 - 6695 74/jump-if-= $size-of-type-id:end/disp8 # eax changes type from type-id to int - 6696 # if v has a user-defined type, return its size - 6697 # TODO: support non-atom type - 6698 (find-typeinfo %eax) # => eax - 6699 { - 6700 3d/compare-eax-and 0/imm32 - 6701 74/jump-if-= break/disp8 - 6702 $size-of-type-id:user-defined: - 6703 8b/-> *(eax+8) 0/r32/eax # Typeinfo-total-size-in-bytes - 6704 eb/jump $size-of-type-id:end/disp8 - 6705 } - 6706 # otherwise return the word size - 6707 b8/copy-to-eax 4/imm32 - 6708 $size-of-type-id:end: - 6709 # . epilogue - 6710 89/<- %esp 5/r32/ebp - 6711 5d/pop-to-ebp - 6712 c3/return - 6713 - 6714 type-equal?: # a: (handle tree type-id), b: (handle tree type-id) -> result/eax: boolean - 6715 # . prologue - 6716 55/push-ebp - 6717 89/<- %ebp 4/r32/esp - 6718 # . save registers - 6719 51/push-ecx - 6720 52/push-edx - 6721 # ecx = a - 6722 8b/-> *(ebp+8) 1/r32/ecx - 6723 # edx = b - 6724 8b/-> *(ebp+0xc) 2/r32/edx - 6725 # if (a == b) return true - 6726 8b/-> %ecx 0/r32/eax # Var-type - 6727 39/compare %edx 0/r32/eax # Var-type - 6728 b8/copy-to-eax 1/imm32/true - 6729 74/jump-if-= $type-equal?:end/disp8 - 6730 # if (a < MAX_TYPE_ID) return false - 6731 81 7/subop/compare %ecx 0x10000/imm32 - 6732 b8/copy-to-eax 0/imm32/false - 6733 72/jump-if-addr< $type-equal?:end/disp8 - 6734 # if (b < MAX_TYPE_ID) return false - 6735 81 7/subop/compare %edx 0x10000/imm32 - 6736 b8/copy-to-eax 0/imm32/false - 6737 72/jump-if-addr< $type-equal?:end/disp8 - 6738 # if (!type-equal?(a->left, b->left)) return false - 6739 (type-equal? *(ecx+4) *(edx+4)) # Tree-left, Tree-left => eax - 6740 3d/compare-eax-and 0/imm32/false - 6741 74/jump-if-= $type-equal?:end/disp8 - 6742 # return type-equal?(a->right, b->right) - 6743 (type-equal? *(ecx+8) *(edx+8)) # Tree-right, Tree-right => eax - 6744 $type-equal?:end: - 6745 # . restore registers - 6746 5a/pop-to-edx - 6747 59/pop-to-ecx - 6748 # . epilogue - 6749 89/<- %esp 5/r32/ebp - 6750 5d/pop-to-ebp - 6751 c3/return - 6752 - 6753 ####################################################### - 6754 # Code-generation - 6755 ####################################################### - 6756 - 6757 == data - 6758 - 6759 Curr-block-depth: # (addr int) - 6760 0/imm32 - 6761 Curr-local-stack-offset: # (addr int) - 6762 0/imm32 - 6763 - 6764 == code - 6765 - 6766 emit-subx: # out: (addr buffered-file) - 6767 # . prologue - 6768 55/push-ebp - 6769 89/<- %ebp 4/r32/esp - 6770 # . save registers - 6771 50/push-eax - 6772 51/push-ecx - 6773 57/push-edi - 6774 # edi = out - 6775 8b/-> *(ebp+8) 7/r32/edi - 6776 # var curr/ecx: (handle function) = *Program->functions - 6777 8b/-> *_Program-functions 1/r32/ecx - 6778 { - 6779 # if (curr == null) break - 6780 81 7/subop/compare %ecx 0/imm32 - 6781 0f 84/jump-if-= break/disp32 - 6782 (emit-subx-function %edi %ecx) - 6783 # curr = curr->next - 6784 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next - 6785 e9/jump loop/disp32 - 6786 } - 6787 $emit-subx:end: - 6788 # . restore registers - 6789 5f/pop-to-edi - 6790 59/pop-to-ecx - 6791 58/pop-to-eax - 6792 # . epilogue - 6793 89/<- %esp 5/r32/ebp - 6794 5d/pop-to-ebp - 6795 c3/return - 6796 - 6797 emit-subx-function: # out: (addr buffered-file), f: (handle function) - 6798 # . prologue - 6799 55/push-ebp - 6800 89/<- %ebp 4/r32/esp - 6801 # some preprocessing - 6802 (populate-mu-type-offsets-in-inouts *(ebp+0xc)) - 6803 # . save registers - 6804 50/push-eax - 6805 51/push-ecx - 6806 52/push-edx - 6807 57/push-edi - 6808 # edi = out - 6809 8b/-> *(ebp+8) 7/r32/edi - 6810 # ecx = f - 6811 8b/-> *(ebp+0xc) 1/r32/ecx - 6812 # var vars/edx: (stack (addr var) 256) - 6813 81 5/subop/subtract %esp 0x400/imm32 - 6814 68/push 0x400/imm32/size - 6815 68/push 0/imm32/top - 6816 89/<- %edx 4/r32/esp - 6817 # - 6818 (write-buffered %edi *ecx) - 6819 (write-buffered %edi ":\n") - 6820 # initialize some global state - 6821 c7 0/subop/copy *Curr-block-depth 1/imm32 - 6822 c7 0/subop/copy *Curr-local-stack-offset 0/imm32 - 6823 # - 6824 (emit-subx-prologue %edi) - 6825 (emit-subx-block %edi *(ecx+0x10) %edx) # Function-body - 6826 (emit-subx-epilogue %edi) - 6827 # TODO: validate that *Curr-block-depth and *Curr-local-stack-offset have - 6828 # been cleaned up - 6829 $emit-subx-function:end: - 6830 # . reclaim locals - 6831 81 0/subop/add %esp 408/imm32 - 6832 # . restore registers - 6833 5f/pop-to-edi - 6834 5a/pop-to-edx - 6835 59/pop-to-ecx - 6836 58/pop-to-eax - 6837 # . epilogue - 6838 89/<- %esp 5/r32/ebp - 6839 5d/pop-to-ebp - 6840 c3/return - 6841 - 6842 populate-mu-type-offsets-in-inouts: # f: (handle function) - 6843 # . prologue - 6844 55/push-ebp - 6845 89/<- %ebp 4/r32/esp - 6846 # . save registers - 6847 50/push-eax - 6848 51/push-ecx - 6849 52/push-edx - 6850 53/push-ebx - 6851 57/push-edi - 6852 # var next-offset/edx: int = 8 - 6853 ba/copy-to-edx 8/imm32 - 6854 # var curr/ecx: (handle list var) = f->inouts - 6855 8b/-> *(ebp+8) 1/r32/ecx - 6856 8b/-> *(ecx+8) 1/r32/ecx # Function-inouts - 6857 { - 6858 $populate-mu-type-offsets-in-inouts:loop: - 6859 81 7/subop/compare %ecx 0/imm32 - 6860 74/jump-if-= break/disp8 - 6861 # var v/ebx: (handle var) = curr->value - 6862 8b/-> *ecx 3/r32/ebx # List-value - 6863 # v->offset = next-offset - 6864 89/<- *(ebx+0xc) 2/r32/edx # Var-offset - 6865 # next-offset += size-of(v) - 6866 (size-of %ebx) # => eax - 6867 01/add-to %edx 0/r32/eax - 6868 # curr = curr->next - 6869 8b/-> *(ecx+4) 1/r32/ecx # List-next - 6870 eb/jump loop/disp8 - 6871 } - 6872 $populate-mu-type-offsets-in-inouts:end: - 6873 # . restore registers - 6874 5f/pop-to-edi - 6875 5b/pop-to-ebx - 6876 5a/pop-to-edx - 6877 59/pop-to-ecx - 6878 58/pop-to-eax - 6879 # . epilogue - 6880 89/<- %esp 5/r32/ebp - 6881 5d/pop-to-ebp - 6882 c3/return - 6883 - 6884 emit-subx-stmt-list: # out: (addr buffered-file), stmts: (handle list stmt), vars: (addr stack (handle var)) - 6885 # . prologue - 6886 55/push-ebp - 6887 89/<- %ebp 4/r32/esp - 6888 # . save registers - 6889 50/push-eax - 6890 51/push-ecx - 6891 52/push-edx - 6892 53/push-ebx - 6893 56/push-esi - 6894 # esi = stmts - 6895 8b/-> *(ebp+0xc) 6/r32/esi - 6896 # var var-seen?/edx: boolean <- copy false - 6897 ba/copy-to-edx 0/imm32/false - 6898 # - 6899 { - 6900 $emit-subx-stmt-list:loop: - 6901 81 7/subop/compare %esi 0/imm32 - 6902 0f 84/jump-if-= break/disp32 - 6903 # var curr-stmt/ecx = stmts->value - 6904 8b/-> *esi 1/r32/ecx # List-value - 6905 { - 6906 $emit-subx-stmt-list:check-for-block: - 6907 81 7/subop/compare *ecx 0/imm32/block # Stmt-tag - 6908 75/jump-if-!= break/disp8 - 6909 $emit-subx-stmt-list:block: - 6910 (emit-subx-block *(ebp+8) %ecx *(ebp+0x10)) - 6911 } - 6912 { - 6913 $emit-subx-stmt-list:check-for-stmt: - 6914 81 7/subop/compare *ecx 1/imm32/stmt1 # Stmt-tag - 6915 0f 85/jump-if-!= break/disp32 - 6916 $emit-subx-stmt-list:stmt1: - 6917 { - 6918 (is-mu-branch? %ecx) # => eax - 6919 3d/compare-eax-and 0/imm32/false - 6920 0f 84/jump-if-= break/disp32 - 6921 $emit-subx-stmt-list:branch-stmt: - 6922 # if !var-seen? break - 6923 81 7/subop/compare %edx 0/imm32/false - 6924 0f 84/jump-if-= break/disp32 - 6925 $emit-subx-stmt-list:branch-stmt-and-var-seen: - 6926 +-- 26 lines: # unconditional loops -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 6952 +-- 15 lines: # unconditional breaks ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 6967 +-- 37 lines: # simple conditional branches without a target ------------------------------------------------------------------------------------------------------------------------------------------------------- - 7004 +-- 19 lines: # conditional branches with an explicit target ------------------------------------------------------------------------------------------------------------------------------------------------------- - 7023 } - 7024 $emit-subx-stmt-list:1-to-1: - 7025 (emit-subx-stmt *(ebp+8) %ecx Primitives) - 7026 } - 7027 { - 7028 $emit-subx-stmt-list:check-for-var-def: - 7029 81 7/subop/compare *ecx 2/imm32/var-def # Stmt-tag - 7030 75/jump-if-!= break/disp8 - 7031 $emit-subx-stmt-list:var-def: - 7032 (emit-subx-var-def *(ebp+8) %ecx) - 7033 (push *(ebp+0x10) *(ecx+4)) # Vardef-var - 7034 # var-seen? = true - 7035 ba/copy-to-edx 1/imm32/true - 7036 } - 7037 { - 7038 $emit-subx-stmt-list:check-for-reg-var-def: - 7039 81 7/subop/compare *ecx 3/imm32/reg-var-def # Stmt-tag - 7040 0f 85/jump-if-!= break/disp32 - 7041 $emit-subx-stmt-list:reg-var-def: - 7042 # TODO: ensure that there's exactly one output - 7043 (compute-reg-and-maybe-emit-spill *(ebp+8) %ecx *(ebp+0x10)) - 7044 # register variable definition - 7045 (push *(ebp+0x10) %eax) - 7046 # emit the instruction as usual - 7047 (emit-subx-stmt *(ebp+8) %ecx Primitives) - 7048 # var-seen? = true - 7049 ba/copy-to-edx 1/imm32/true - 7050 } - 7051 $emit-subx-stmt-list:continue: - 7052 # TODO: raise an error on unrecognized Stmt-tag - 7053 8b/-> *(esi+4) 6/r32/esi # List-next - 7054 e9/jump loop/disp32 - 7055 } - 7056 $emit-subx-stmt-list:emit-cleanup: - 7057 (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth) - 7058 $emit-subx-stmt-list:cleanup: - 7059 (clean-up-blocks *(ebp+0x10) *Curr-block-depth) - 7060 $emit-subx-stmt-list:end: - 7061 # . restore registers - 7062 5e/pop-to-esi - 7063 5b/pop-to-ebx - 7064 5a/pop-to-edx - 7065 59/pop-to-ecx - 7066 58/pop-to-eax + 6527 5a/pop-to-edx + 6528 59/pop-to-ecx + 6529 58/pop-to-eax + 6530 # . epilogue + 6531 89/<- %esp 5/r32/ebp + 6532 5d/pop-to-ebp + 6533 c3/return + 6534 + 6535 find-typeinfo: # t: type-id, out: (addr handle typeinfo) + 6536 # . prologue + 6537 55/push-ebp + 6538 89/<- %ebp 4/r32/esp + 6539 # . save registers + 6540 50/push-eax + 6541 51/push-ecx + 6542 52/push-edx + 6543 57/push-edi + 6544 # ecx = t + 6545 8b/-> *(ebp+8) 1/r32/ecx + 6546 # edi = out + 6547 8b/-> *(ebp+0xc) 7/r32/edi + 6548 # *out = Program->types + 6549 8b/-> *_Program-types 0/r32/eax + 6550 89/<- *edi 0/r32/eax + 6551 8b/-> *_Program-types->payload 0/r32/eax + 6552 89/<- *(edi+4) 0/r32/eax + 6553 { + 6554 # if (*out == 0) break + 6555 81 7/subop/compare *edi 0/imm32 + 6556 74/jump-if-= break/disp8 + 6557 # var tmp/eax: (addr typeinfo) = lookup(*out) + 6558 (lookup *edi *(edi+4)) # => eax + 6559 # if (tmp->id == t) break + 6560 39/compare *eax 1/r32/ecx # Typeinfo-id + 6561 74/jump-if-= break/disp8 + 6562 # *out = tmp->next + 6563 8b/-> *(eax+0x10) 2/r32/edx # Typeinfo-next + 6564 89/<- *edi 2/r32/edx + 6565 8b/-> *(eax+0x14) 2/r32/edx # Typeinfo-next + 6566 89/<- *(edi+4) 2/r32/edx + 6567 # + 6568 eb/jump loop/disp8 + 6569 } + 6570 $find-typeinfo:end: + 6571 # . restore registers + 6572 5f/pop-to-edi + 6573 5a/pop-to-edx + 6574 59/pop-to-ecx + 6575 58/pop-to-eax + 6576 # . epilogue + 6577 89/<- %esp 5/r32/ebp + 6578 5d/pop-to-ebp + 6579 c3/return + 6580 + 6581 find-or-create-typeinfo-output-var: # T: (addr typeinfo), f: (addr slice), out: (addr handle var) + 6582 # . prologue + 6583 55/push-ebp + 6584 89/<- %ebp 4/r32/esp + 6585 # . save registers + 6586 50/push-eax + 6587 52/push-edx + 6588 57/push-edi + 6589 # var tmp-addr/edi: (addr typeinfo-entry) = find-or-create-typeinfo-fields(T, f) + 6590 # . var tmp/edi: (handle typeinfo-entry) + 6591 68/push 0/imm32 + 6592 68/push 0/imm32 + 6593 89/<- %edi 4/r32/esp + 6594 # . find-or-create-typeinfo-fields(T, f, tmp) + 6595 (find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc) %edi) + 6596 # . tmp-addr = lookup(tmp) + 6597 (lookup *edi *(edi+4)) # => eax + 6598 89/<- %edi 0/r32/eax + 6599 # if output var doesn't exist, create it + 6600 { + 6601 81 7/subop/compare *(edi+8) 0/imm32 # Typeinfo-entry-output-var + 6602 0f 85/jump-if-!= break/disp32 + 6603 # out/edx = new var(dummy name, type, -1 offset) + 6604 # . var name/eax: (handle array byte) = "field" + 6605 68/push 0/imm32 + 6606 68/push 0/imm32 + 6607 89/<- %eax 4/r32/esp + 6608 (copy-array Heap "field" %eax) + 6609 # . new var + 6610 (new-var Heap *eax *(eax+4) *(ebp+0x10)) + 6611 # . reclaim name + 6612 81 0/subop/add %esp 8/imm32 + 6613 # save out in typeinfo + 6614 8b/-> *(ebp+0x10) 2/r32/edx + 6615 8b/-> *edx 0/r32/eax + 6616 89/<- *(edi+0xc) 0/r32/eax # Typeinfo-entry-output-var + 6617 8b/-> *(edx+4) 0/r32/eax + 6618 89/<- *(edi+0x10) 0/r32/eax # Typeinfo-entry-output-var + 6619 # initialize out + 6620 # . var out-addr/edx: (addr var) = lookup(*out) + 6621 (lookup *edx *(edx+4)) # => eax + 6622 89/<- %edx 0/r32/eax + 6623 # . out->type = new constant type + 6624 8d/copy-address *(edx+8) 0/r32/eax # Var-type + 6625 (allocate Heap *Tree-size %eax) + 6626 (lookup *(edx+8) *(edx+0xc)) # => eax + 6627 c7 0/subop/copy *eax 1/imm32/true # Tree-is-atom + 6628 c7 0/subop/copy *(eax+4) 6/imm32/constant # Tree-value + 6629 c7 0/subop/copy *(eax+8) 0/imm32 # Tree-left + 6630 c7 0/subop/copy *(eax+0xc) 0/imm32 # Tree-right + 6631 c7 0/subop/copy *(eax+0x10) 0/imm32 # Tree-right + 6632 # . out-addr->offset isn't filled out yet + 6633 c7 0/subop/copy *(edx+0x14) -1/imm32/uninitialized # Var-offset + 6634 } + 6635 $find-or-create-typeinfo-output-var:end: + 6636 # . reclaim locals + 6637 81 0/subop/add %esp 8/imm32 + 6638 # . restore registers + 6639 5f/pop-to-edi + 6640 5a/pop-to-edx + 6641 58/pop-to-eax + 6642 # . epilogue + 6643 89/<- %esp 5/r32/ebp + 6644 5d/pop-to-ebp + 6645 c3/return + 6646 + 6647 find-or-create-typeinfo-fields: # T: (addr typeinfo), f: (addr slice), out: (addr handle typeinfo-entry) + 6648 # . prologue + 6649 55/push-ebp + 6650 89/<- %ebp 4/r32/esp + 6651 # . save registers + 6652 50/push-eax + 6653 56/push-esi + 6654 57/push-edi + 6655 # eax = lookup(T->fields) + 6656 8b/-> *(ebp+8) 0/r32/eax + 6657 (lookup *(eax+4) *(eax+8)) # Typeinfo-fields Typeinfo-fields => eax + 6658 # edi = out + 6659 8b/-> *(ebp+0x10) 7/r32/edi + 6660 # var src/esi: (addr handle typeinfo-entry) = get-or-insert-slice(T->fields, f) + 6661 (get-or-insert-slice %eax *(ebp+0xc) *Typeinfo-fields-row-size Heap) # => eax + 6662 89/<- %esi 0/r32/eax + 6663 # if src doesn't exist, allocate it + 6664 { + 6665 81 7/subop/compare *esi 0/imm32 + 6666 75/jump-if-!= break/disp8 + 6667 (allocate Heap *Typeinfo-entry-size %esi) + 6668 #? (write-buffered Stderr "handle at ") + 6669 #? (print-int32-buffered Stderr %esi) + 6670 #? (write-buffered Stderr ": ") + 6671 #? (print-int32-buffered Stderr *esi) + 6672 #? (write-buffered Stderr " ") + 6673 #? (print-int32-buffered Stderr *(esi+4)) + 6674 #? (write-buffered Stderr Newline) + 6675 #? (flush Stderr) + 6676 #? (lookup *esi *(esi+4)) + 6677 #? (write-buffered Stderr "created typeinfo fields at ") + 6678 #? (print-int32-buffered Stderr %esi) + 6679 #? (write-buffered Stderr " for ") + 6680 #? (print-int32-buffered Stderr *(ebp+8)) + 6681 #? (write-buffered Stderr Newline) + 6682 #? (flush Stderr) + 6683 } + 6684 # *out = src + 6685 # . *edi = *src + 6686 8b/-> *esi 0/r32/eax + 6687 89/<- *edi 0/r32/eax + 6688 8b/-> *(esi+4) 0/r32/eax + 6689 89/<- *(edi+4) 0/r32/eax + 6690 $find-or-create-typeinfo-fields:end: + 6691 # . restore registers + 6692 5f/pop-to-edi + 6693 5e/pop-to-esi + 6694 58/pop-to-eax + 6695 # . epilogue + 6696 89/<- %esp 5/r32/ebp + 6697 5d/pop-to-ebp + 6698 c3/return + 6699 + 6700 populate-mu-type: # in: (addr stream byte), t: (addr typeinfo) + 6701 # pseudocode: + 6702 # var line: (stream byte 512) + 6703 # curr-index = 0 + 6704 # while true + 6705 # clear-stream(line) + 6706 # read-line-buffered(in, line) + 6707 # if line->write == 0 + 6708 # abort + 6709 # word-slice = next-mu-token(line) + 6710 # if slice-empty?(word-slice) # end of line + 6711 # continue + 6712 # if slice-equal?(word-slice, "}") + 6713 # break + 6714 # var v: (handle var) = parse-var-with-type(word-slice, line) + 6715 # var r: (handle typeinfo-fields) = find-or-create-typeinfo-fields(t, word-slice/v->name) + 6716 # TODO: ensure that r->first is null + 6717 # r->index = curr-index + 6718 # curr-index++ + 6719 # r->input-var = v + 6720 # if r->output-var == 0 + 6721 # r->output-var = new literal + 6722 # TODO: ensure nothing else in line + 6723 # t->total-size-in-bytes = -2 (not yet initialized) + 6724 # + 6725 # . prologue + 6726 55/push-ebp + 6727 89/<- %ebp 4/r32/esp + 6728 # var curr-index: int at *(ebp-4) + 6729 68/push 0/imm32 + 6730 # . save registers + 6731 50/push-eax + 6732 51/push-ecx + 6733 52/push-edx + 6734 53/push-ebx + 6735 56/push-esi + 6736 57/push-edi + 6737 # edi = t + 6738 8b/-> *(ebp+0xc) 7/r32/edi + 6739 # var line/ecx: (stream byte 512) + 6740 81 5/subop/subtract %esp 0x200/imm32 + 6741 68/push 0x200/imm32/size + 6742 68/push 0/imm32/read + 6743 68/push 0/imm32/write + 6744 89/<- %ecx 4/r32/esp + 6745 # var word-slice/edx: slice + 6746 68/push 0/imm32/end + 6747 68/push 0/imm32/start + 6748 89/<- %edx 4/r32/esp + 6749 # var v/esi: (handle var) + 6750 68/push 0/imm32 + 6751 68/push 0/imm32 + 6752 89/<- %esi 4/r32/esp + 6753 # var r/ebx: (handle typeinfo-entry) + 6754 68/push 0/imm32 + 6755 68/push 0/imm32 + 6756 89/<- %ebx 4/r32/esp + 6757 { + 6758 $populate-mu-type:line-loop: + 6759 (clear-stream %ecx) + 6760 (read-line-buffered *(ebp+8) %ecx) + 6761 # if (line->write == 0) abort + 6762 81 7/subop/compare *ecx 0/imm32 + 6763 0f 84/jump-if-= $populate-mu-type:abort/disp32 + 6764 +-- 6 lines: #? # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------ + 6770 (next-mu-token %ecx %edx) + 6771 # if slice-empty?(word-slice) continue + 6772 (slice-empty? %edx) # => eax + 6773 3d/compare-eax-and 0/imm32 + 6774 0f 85/jump-if-!= loop/disp32 + 6775 # if slice-equal?(word-slice, "}") break + 6776 (slice-equal? %edx "}") + 6777 3d/compare-eax-and 0/imm32 + 6778 0f 85/jump-if-!= break/disp32 + 6779 $populate-mu-type:parse-element: + 6780 # v = parse-var-with-type(word-slice, first-line) + 6781 # must do this first to strip the trailing ':' from word-slice before + 6782 # using it in find-or-create-typeinfo-fields below + 6783 # TODO: clean up that mutation in parse-var-with-type + 6784 (parse-var-with-type %edx %ecx %esi) # => eax + 6785 # var tmp/ecx + 6786 51/push-ecx + 6787 $populate-mu-type:create-typeinfo-fields: + 6788 # var r/ebx: (handle typeinfo-entry) + 6789 (find-or-create-typeinfo-fields %edi %edx %ebx) + 6790 # r->index = curr-index + 6791 (lookup *ebx *(ebx+4)) # => eax + 6792 8b/-> *(ebp-4) 1/r32/ecx + 6793 #? (write-buffered Stderr "saving index ") + 6794 #? (print-int32-buffered Stderr %ecx) + 6795 #? (write-buffered Stderr " at ") + 6796 #? (print-int32-buffered Stderr %edi) + 6797 #? (write-buffered Stderr Newline) + 6798 #? (flush Stderr) + 6799 89/<- *(eax+8) 1/r32/ecx # Typeinfo-entry-index + 6800 # ++curr-index + 6801 ff 0/subop/increment *(ebp-4) + 6802 $populate-mu-type:set-input-type: + 6803 # r->input-var = v + 6804 8b/-> *esi 1/r32/ecx + 6805 89/<- *eax 1/r32/ecx # Typeinfo-entry-input-var + 6806 8b/-> *(esi+4) 1/r32/ecx + 6807 89/<- *(eax+4) 1/r32/ecx # Typeinfo-entry-input-var + 6808 59/pop-to-ecx + 6809 { + 6810 $populate-mu-type:create-output-type: + 6811 # if (r->output-var == 0) create a new var with some placeholder data + 6812 81 7/subop/compare *(eax+0xc) 0/imm32 # Typeinfo-entry-output-var + 6813 75/jump-if-!= break/disp8 + 6814 8d/copy-address *(eax+0xc) 0/r32/eax # Typeinfo-entry-output-var + 6815 (new-literal Heap %edx %eax) + 6816 } + 6817 e9/jump loop/disp32 + 6818 } + 6819 $populate-mu-type:invalidate-total-size-in-bytes: + 6820 # Offsets and total size may not be accurate here since we may not yet + 6821 # have encountered the element types. + 6822 # We'll recompute them separately after parsing the entire program. + 6823 c7 0/subop/copy *(edi+0xc) -2/imm32/uninitialized # Typeinfo-total-size-in-bytes + 6824 $populate-mu-type:end: + 6825 # . reclaim locals + 6826 81 0/subop/add %esp 0x224/imm32 + 6827 # . restore registers + 6828 5f/pop-to-edi + 6829 5e/pop-to-esi + 6830 5b/pop-to-ebx + 6831 5a/pop-to-edx + 6832 59/pop-to-ecx + 6833 58/pop-to-eax + 6834 # reclaim curr-index + 6835 81 0/subop/add %esp 4/imm32 + 6836 # . epilogue + 6837 89/<- %esp 5/r32/ebp + 6838 5d/pop-to-ebp + 6839 c3/return + 6840 + 6841 $populate-mu-type:abort: + 6842 # error("unexpected top-level command: " word-slice "\n") + 6843 (write-buffered Stderr "incomplete type definition '") + 6844 (type-name *edi) # Typeinfo-id => eax + 6845 (write-buffered Stderr %eax) + 6846 (write-buffered Stderr "\n") + 6847 (flush Stderr) + 6848 # . syscall(exit, 1) + 6849 bb/copy-to-ebx 1/imm32 + 6850 b8/copy-to-eax 1/imm32/exit + 6851 cd/syscall 0x80/imm8 + 6852 # never gets here + 6853 + 6854 type-name: # index: int -> result/eax: (addr array byte) + 6855 # . prologue + 6856 55/push-ebp + 6857 89/<- %ebp 4/r32/esp + 6858 # + 6859 (index Type-id *(ebp+8)) + 6860 $type-name:end: + 6861 # . epilogue + 6862 89/<- %esp 5/r32/ebp + 6863 5d/pop-to-ebp + 6864 c3/return + 6865 + 6866 index: # arr: (addr stream (handle array byte)), index: int -> result/eax: (addr array byte) + 6867 # . prologue + 6868 55/push-ebp + 6869 89/<- %ebp 4/r32/esp + 6870 # . save registers + 6871 56/push-esi + 6872 # TODO: bounds-check index + 6873 # esi = arr + 6874 8b/-> *(ebp+8) 6/r32/esi + 6875 # eax = index + 6876 8b/-> *(ebp+0xc) 0/r32/eax + 6877 # eax = *(arr + 12 + index) + 6878 8b/-> *(esi+eax+0xc) 0/r32/eax + 6879 $index:end: + 6880 # . restore registers + 6881 5e/pop-to-esi + 6882 # . epilogue + 6883 89/<- %esp 5/r32/ebp + 6884 5d/pop-to-ebp + 6885 c3/return + 6886 + 6887 ####################################################### + 6888 # Compute type sizes + 6889 ####################################################### + 6890 + 6891 # Compute the sizes of all user-defined types. + 6892 # We'll need the sizes of their elements, which may be other user-defined + 6893 # types, which we will compute as needed. + 6894 + 6895 # Initially, all user-defined types have their sizes set to -2 (invalid) + 6896 populate-mu-type-sizes: + 6897 # . prologue + 6898 55/push-ebp + 6899 89/<- %ebp 4/r32/esp + 6900 $populate-mu-type-sizes:total-sizes: + 6901 # var curr/eax: (addr typeinfo) = lookup(Program->types) + 6902 (lookup *_Program-types *_Program-types->payload) # => eax + 6903 { + 6904 # if (curr == null) break + 6905 3d/compare-eax-and 0/imm32/null + 6906 74/jump-if-= break/disp8 + 6907 (populate-mu-type-sizes-in-type %eax) + 6908 # curr = lookup(curr->next) + 6909 (lookup *(eax+0x10) *(eax+0x14)) # Typeinfo-next Typeinfo-next => eax + 6910 eb/jump loop/disp8 + 6911 } + 6912 $populate-mu-type-sizes:offsets: + 6913 # curr = *Program->types + 6914 (lookup *_Program-types *_Program-types->payload) # => eax + 6915 { + 6916 # if (curr == null) break + 6917 3d/compare-eax-and 0/imm32/null + 6918 74/jump-if-= break/disp8 + 6919 (populate-mu-type-offsets %eax) + 6920 # curr = curr->next + 6921 (lookup *(eax+0x10) *(eax+0x14)) # Typeinfo-next Typeinfo-next => eax + 6922 eb/jump loop/disp8 + 6923 } + 6924 $populate-mu-type-sizes:end: + 6925 # . epilogue + 6926 89/<- %esp 5/r32/ebp + 6927 5d/pop-to-ebp + 6928 c3/return + 6929 + 6930 # compute sizes of all fields, recursing as necessary + 6931 # sum up all their sizes to arrive at total size + 6932 # fields may be out of order, but that doesn't affect the answer + 6933 populate-mu-type-sizes-in-type: # T: (addr typeinfo) + 6934 # . prologue + 6935 55/push-ebp + 6936 89/<- %ebp 4/r32/esp + 6937 # . save registers + 6938 50/push-eax + 6939 51/push-ecx + 6940 52/push-edx + 6941 56/push-esi + 6942 57/push-edi + 6943 # esi = T + 6944 8b/-> *(ebp+8) 6/r32/esi + 6945 # if T is already computed, return + 6946 81 7/subop/compare *(esi+0xc) 0/imm32 # Typeinfo-total-size-in-bytes + 6947 0f 8d/jump-if->= $populate-mu-type-sizes-in-type:end/disp32 + 6948 # if T is being computed, abort + 6949 81 7/subop/compare *(esi+0xc) -1/imm32/being-computed # Typeinfo-total-size-in-bytes + 6950 0f 84/jump-if-= $populate-mu-type-sizes-in-type:abort/disp32 + 6951 # tag T (-2 to -1) to avoid infinite recursion + 6952 c7 0/subop/copy *(esi+0xc) -1/imm32/being-computed # Typeinfo-total-size-in-bytes + 6953 # var total-size/edi: int = 0 + 6954 bf/copy-to-edi 0/imm32 + 6955 # - for every field, if it's a user-defined type, compute its size + 6956 # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields) + 6957 (lookup *(esi+4) *(esi+8)) # Typeinfo-fields Typeinfo-fields => eax + 6958 89/<- %ecx 0/r32/eax + 6959 # var table-size/edx: int = table->write + 6960 8b/-> *ecx 2/r32/edx # stream-write + 6961 # var curr/ecx: (addr table_row) = table->data + 6962 8d/copy-address *(ecx+0xc) 1/r32/ecx + 6963 # var max/edx: (addr table_row) = table->data + table->write + 6964 8d/copy-address *(ecx+edx) 2/r32/edx + 6965 { + 6966 $populate-mu-type-sizes-in-type:loop: + 6967 # if (curr >= max) break + 6968 39/compare %ecx 2/r32/edx + 6969 73/jump-if-addr>= break/disp8 + 6970 # var t/eax: (addr typeinfo-entry) = lookup(curr->value) + 6971 (lookup *(ecx+8) *(ecx+0xc)) # => eax + 6972 # compute size of t->input-var + 6973 (lookup *eax *(eax+4)) # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax + 6974 (compute-size-of-var %eax) # => eax + 6975 # result += eax + 6976 01/add-to %edi 0/r32/eax + 6977 # curr += row-size + 6978 81 0/subop/add %ecx 0x10/imm32 # Typeinfo-fields-row-size + 6979 # + 6980 eb/jump loop/disp8 + 6981 } + 6982 # - save result + 6983 89/<- *(esi+0xc) 7/r32/edi # Typeinfo-total-size-in-bytes + 6984 $populate-mu-type-sizes-in-type:end: + 6985 # . restore registers + 6986 5f/pop-to-edi + 6987 5e/pop-to-esi + 6988 5a/pop-to-edx + 6989 59/pop-to-ecx + 6990 58/pop-to-eax + 6991 # . epilogue + 6992 89/<- %esp 5/r32/ebp + 6993 5d/pop-to-ebp + 6994 c3/return + 6995 + 6996 $populate-mu-type-sizes-in-type:abort: + 6997 (write-buffered Stderr "cycle in type definitions\n") + 6998 (flush Stderr) + 6999 # . syscall(exit, 1) + 7000 bb/copy-to-ebx 1/imm32 + 7001 b8/copy-to-eax 1/imm32/exit + 7002 cd/syscall 0x80/imm8 + 7003 # never gets here + 7004 + 7005 # Analogous to size-of, except we need to compute what size-of can just read + 7006 # off the right data structures. + 7007 compute-size-of-var: # in: (addr var) -> result/eax: int + 7008 # . prologue + 7009 55/push-ebp + 7010 89/<- %ebp 4/r32/esp + 7011 # . push registers + 7012 51/push-ecx + 7013 # var t/ecx: (addr tree type-id) = lookup(v->type) + 7014 8b/-> *(ebp+8) 1/r32/ecx + 7015 (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + 7016 89/<- %ecx 0/r32/eax + 7017 # if (t->is-atom == false) t = lookup(t->left) + 7018 { + 7019 81 7/subop/compare *ecx 0/imm32/false # Tree-is-atom + 7020 75/jump-if-!= break/disp8 + 7021 (lookup *(ecx+4) *(ecx+8)) # Tree-left Tree-left => eax + 7022 89/<- %ecx 0/r32/eax + 7023 } + 7024 # TODO: ensure t is an atom + 7025 (compute-size-of-type-id *(ecx+4)) # Tree-value => eax + 7026 $compute-size-of-var:end: + 7027 # . restore registers + 7028 59/pop-to-ecx + 7029 # . epilogue + 7030 89/<- %esp 5/r32/ebp + 7031 5d/pop-to-ebp + 7032 c3/return + 7033 + 7034 compute-size-of-type-id: # t: type-id -> result/eax: int + 7035 # . prologue + 7036 55/push-ebp + 7037 89/<- %ebp 4/r32/esp + 7038 # . save registers + 7039 51/push-ecx + 7040 # var out/ecx: (handle typeinfo) + 7041 68/push 0/imm32 + 7042 68/push 0/imm32 + 7043 89/<- %ecx 4/r32/esp + 7044 # eax = t + 7045 8b/-> *(ebp+8) 0/r32/eax + 7046 # if v is a literal, return 0 + 7047 3d/compare-eax-and 0/imm32 + 7048 74/jump-if-= $compute-size-of-type-id:end/disp8 # eax changes type from type-id to int + 7049 # if v has a user-defined type, compute its size + 7050 # TODO: support non-atom type + 7051 (find-typeinfo %eax %ecx) + 7052 { + 7053 81 7/subop/compare *ecx 0/imm32 + 7054 74/jump-if-= break/disp8 + 7055 $compute-size-of-type-id:user-defined: + 7056 (populate-mu-type-sizes %eax) + 7057 8b/-> *(eax+0xc) 0/r32/eax # Typeinfo-total-size-in-bytes + 7058 eb/jump $compute-size-of-type-id:end/disp8 + 7059 } + 7060 # otherwise return the word size + 7061 b8/copy-to-eax 4/imm32 + 7062 $compute-size-of-type-id:end: + 7063 # . reclaim locals + 7064 81 0/subop/add %esp 8/imm32 + 7065 # . restore registers + 7066 59/pop-to-ecx 7067 # . epilogue 7068 89/<- %esp 5/r32/ebp 7069 5d/pop-to-ebp 7070 c3/return 7071 - 7072 compute-reg-and-maybe-emit-spill: # out: (addr buffered-file), stmt: (handle reg-var-def), vars: (addr stack (handle var)) -> result/eax: (handle var) - 7073 # . prologue - 7074 55/push-ebp - 7075 89/<- %ebp 4/r32/esp - 7076 # . save registers - 7077 51/push-ecx - 7078 # ecx = stmt - 7079 8b/-> *(ebp+0xc) 1/r32/ecx - 7080 # var output/ecx: (handle var) = curr-stmt->outputs->value - 7081 8b/-> *(ecx+0xc) 1/r32/ecx # Regvardef-inouts - 7082 8b/-> *ecx 1/r32/ecx # List-value - 7083 # v->block-depth = *Curr-block-depth - 7084 8b/-> *Curr-block-depth 0/r32/eax - 7085 89/<- *(ecx+8) 0/r32/eax # Var-block-depth - 7086 # var reg/eax: (handle array byte) = output->register - 7087 8b/-> *(ecx+0x10) 0/r32/eax # Var-register - 7088 # ensure that output is in a register - 7089 3d/compare-eax-and 0/imm32 - 7090 0f 84/jump-if-= $compute-reg-and-maybe-emit-spill:abort/disp32 - 7091 # if already-spilled-this-block?(reg, vars) return - 7092 (already-spilled-this-block? %ecx *(ebp+0x10)) # => eax - 7093 3d/compare-eax-and 0/imm32/false - 7094 75/jump-if-!= $compute-reg-and-maybe-emit-spill:end/disp8 - 7095 # TODO: assert(size-of(output) == 4) - 7096 # *Curr-local-stack-offset -= 4 - 7097 81 5/subop/subtract *Curr-local-stack-offset 4/imm32 - 7098 # emit spill - 7099 (emit-indent *(ebp+8) *Curr-block-depth) - 7100 (write-buffered *(ebp+8) "ff 6/subop/push %") - 7101 (write-buffered *(ebp+8) *(ecx+0x10)) # Var-register - 7102 (write-buffered *(ebp+8) Newline) - 7103 $compute-reg-and-maybe-emit-spill:end: - 7104 # return output - 7105 89/<- %eax 1/r32/ecx - 7106 # . restore registers - 7107 59/pop-to-ecx - 7108 # . epilogue - 7109 89/<- %esp 5/r32/ebp - 7110 5d/pop-to-ebp - 7111 c3/return - 7112 - 7113 $compute-reg-and-maybe-emit-spill:abort: - 7114 # error("var '" var->name "' initialized from an instruction must live in a register\n") - 7115 (write-buffered Stderr "var '") - 7116 (write-buffered Stderr *eax) # Var-name - 7117 (write-buffered Stderr "' initialized from an instruction must live in a register\n") - 7118 (flush Stderr) - 7119 # . syscall(exit, 1) - 7120 bb/copy-to-ebx 1/imm32 - 7121 b8/copy-to-eax 1/imm32/exit - 7122 cd/syscall 0x80/imm8 - 7123 # never gets here - 7124 - 7125 emit-subx-cleanup-and-unconditional-nonlocal-branch: # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack (handle var)) - 7126 # . prologue - 7127 55/push-ebp - 7128 89/<- %ebp 4/r32/esp - 7129 # . save registers - 7130 50/push-eax - 7131 51/push-ecx - 7132 52/push-edx - 7133 # ecx = stmt - 7134 8b/-> *(ebp+0xc) 1/r32/ecx - 7135 # var target/edx: (addr array byte) = curr-stmt->inouts->value->name - 7136 8b/-> *(ecx+8) 2/r32/edx # Stmt1-inouts - 7137 8b/-> *edx 2/r32/edx # Stmt-var-value - 7138 8b/-> *edx 2/r32/edx # Var-name - 7139 # clean up until target block - 7140 (emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %edx) - 7141 # emit jump to target block - 7142 (emit-indent *(ebp+8) *Curr-block-depth) - 7143 (write-buffered *(ebp+8) "e9/jump ") - 7144 (write-buffered *(ebp+8) %edx) - 7145 (string-starts-with? *(ecx+4) "break") - 7146 3d/compare-eax-and 0/imm32/false - 7147 { - 7148 74/jump-if-= break/disp8 - 7149 (write-buffered *(ebp+8) ":break/disp32\n") - 7150 } - 7151 3d/compare-eax-and 0/imm32/false # just in case the function call modified flags - 7152 { - 7153 75/jump-if-!= break/disp8 - 7154 (write-buffered *(ebp+8) ":loop/disp32\n") - 7155 } - 7156 $emit-subx-cleanup-and-unconditional-nonlocal-branch:end: - 7157 # . restore registers - 7158 5a/pop-to-edx - 7159 59/pop-to-ecx - 7160 58/pop-to-eax - 7161 # . epilogue - 7162 89/<- %esp 5/r32/ebp - 7163 5d/pop-to-ebp - 7164 c3/return - 7165 - 7166 is-mu-branch?: # stmt: (addr stmt1) -> result/eax: boolean - 7167 # . prologue - 7168 55/push-ebp - 7169 89/<- %ebp 4/r32/esp - 7170 # . save registers - 7171 51/push-ecx - 7172 # ecx = stmt - 7173 8b/-> *(ebp+8) 1/r32/ecx - 7174 # if (stmt->operation starts with "loop") return true - 7175 (string-starts-with? *(ecx+4) "loop") # Stmt1-operation => eax - 7176 3d/compare-eax-and 0/imm32/false - 7177 75/jump-if-not-equal $is-mu-branch?:end/disp8 - 7178 # otherwise return (stmt->operation starts with "break") - 7179 (string-starts-with? *(ecx+4) "break") # Stmt1-operation => eax - 7180 $is-mu-branch?:end: + 7072 # at this point we have total sizes for all user-defined types + 7073 # compute offsets for each element + 7074 # complication: fields may be out of order + 7075 populate-mu-type-offsets: # in: (addr typeinfo) + 7076 # . prologue + 7077 55/push-ebp + 7078 89/<- %ebp 4/r32/esp + 7079 # . save registers + 7080 50/push-eax + 7081 51/push-ecx + 7082 52/push-edx + 7083 53/push-ebx + 7084 56/push-esi + 7085 57/push-edi + 7086 #? (dump-typeinfos "aaa\n") + 7087 # var curr-offset/edi: int = 0 + 7088 bf/copy-to-edi 0/imm32 + 7089 # var table/ecx: (addr table string_key (handle typeinfo-entry)) = lookup(in->fields) + 7090 8b/-> *(ebp+8) 1/r32/ecx + 7091 (lookup *(ecx+4) *(ecx+8)) # Typeinfo-fields Typeinfo-fields => eax + 7092 89/<- %ecx 0/r32/eax + 7093 # var num-elems/edx: int = table->write / Typeinfo-fields-row-size + 7094 8b/-> *ecx 2/r32/edx # stream-write + 7095 c1 5/subop/shift-right-logical %edx 4/imm8 + 7096 # var i/ebx: int = 0 + 7097 bb/copy-to-ebx 0/imm32 + 7098 { + 7099 $populate-mu-type-offsets:loop: + 7100 39/compare %ebx 2/r32/edx + 7101 7d/jump-if->= break/disp8 + 7102 #? (write-buffered Stderr "looking up index ") + 7103 #? (print-int32-buffered Stderr %ebx) + 7104 #? (write-buffered Stderr " in ") + 7105 #? (print-int32-buffered Stderr *(ebp+8)) + 7106 #? (write-buffered Stderr Newline) + 7107 #? (flush Stderr) + 7108 # var v/esi: (addr typeinfo-entry) + 7109 (locate-typeinfo-entry-with-index %ecx %ebx) # => eax + 7110 89/<- %esi 0/r32/eax + 7111 # v->output-var->offset = curr-offset + 7112 # . eax: (addr var) + 7113 (lookup *(esi+0xc) *(esi+0x10)) # Typeinfo-entry-output-var Typeinfo-entry-output-var => eax + 7114 89/<- *(eax+0x14) 7/r32/edi # Var-offset + 7115 # curr-offset += size-of(v->input-var) + 7116 (lookup *esi *(esi+4)) # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax + 7117 (size-of %eax) # => eax + 7118 01/add-to %edi 0/r32/eax + 7119 # ++i + 7120 43/increment-ebx + 7121 eb/jump loop/disp8 + 7122 } + 7123 $populate-mu-type-offsets:end: + 7124 # . restore registers + 7125 5f/pop-to-edi + 7126 5e/pop-to-esi + 7127 5b/pop-to-ebx + 7128 5a/pop-to-edx + 7129 59/pop-to-ecx + 7130 58/pop-to-eax + 7131 # . epilogue + 7132 89/<- %esp 5/r32/ebp + 7133 5d/pop-to-ebp + 7134 c3/return + 7135 + 7136 locate-typeinfo-entry-with-index: # table: (addr table (handle array byte) (handle typeinfo-entry)), idx: int -> result/eax: (addr typeinfo-entry) + 7137 # . prologue + 7138 55/push-ebp + 7139 89/<- %ebp 4/r32/esp + 7140 # . save registers + 7141 51/push-ecx + 7142 52/push-edx + 7143 53/push-ebx + 7144 56/push-esi + 7145 57/push-edi + 7146 # esi = table + 7147 8b/-> *(ebp+8) 6/r32/esi + 7148 # var curr/ecx: (addr row (handle array byte) (handle typeinfo-entry)) = table->data + 7149 8d/copy-address *(esi+0xc) 1/r32/ecx + 7150 # var max/edx: (addr byte) = &table->data[table->write] + 7151 8b/-> *esi 2/r32/edx + 7152 8d/copy-address *(ecx+edx) 2/r32/edx + 7153 { + 7154 $locate-typeinfo-entry-with-index:loop: + 7155 39/compare %ecx 2/r32/edx + 7156 73/jump-if-addr>= $locate-typeinfo-entry-with-index:abort/disp8 + 7157 # var v/eax: (addr typeinfo-entry) + 7158 (lookup *(ecx+8) *(ecx+0xc)) # => eax + 7159 # if (v->index == idx) return v + 7160 8b/-> *(eax+8) 3/r32/ebx # Typeinfo-entry-index + 7161 #? (write-buffered Stderr "comparing ") + 7162 #? (print-int32-buffered Stderr %ebx) + 7163 #? (write-buffered Stderr " and ") + 7164 #? (print-int32-buffered Stderr *(ebp+0xc)) + 7165 #? (write-buffered Stderr Newline) + 7166 #? (flush Stderr) + 7167 39/compare *(ebp+0xc) 3/r32/ebx + 7168 74/jump-if-= $locate-typeinfo-entry-with-index:end/disp8 + 7169 # curr += Typeinfo-entry-size + 7170 81 0/subop/add %ecx 0x10/imm32 # Typeinfo-entry-size + 7171 # + 7172 eb/jump loop/disp8 + 7173 } + 7174 # return 0 + 7175 b8/copy-to-eax 0/imm32 + 7176 $locate-typeinfo-entry-with-index:end: + 7177 #? (write-buffered Stderr "returning ") + 7178 #? (print-int32-buffered Stderr %eax) + 7179 #? (write-buffered Stderr Newline) + 7180 #? (flush Stderr) 7181 # . restore registers - 7182 59/pop-to-ecx - 7183 # . epilogue - 7184 89/<- %esp 5/r32/ebp - 7185 5d/pop-to-ebp - 7186 c3/return - 7187 - 7188 emit-reverse-break: # out: (addr buffered-file), stmt: (addr stmt1) - 7189 # . prologue - 7190 55/push-ebp - 7191 89/<- %ebp 4/r32/esp - 7192 # . save registers - 7193 50/push-eax - 7194 # eax = stmt - 7195 8b/-> *(ebp+0xc) 0/r32/eax - 7196 # - 7197 (get Reverse-branch *(eax+4) 8 "reverse-branch: ") # Stmt1-operation => eax: (addr addr array byte) - 7198 (emit-indent *(ebp+8) *Curr-block-depth) - 7199 (write-buffered *(ebp+8) *eax) - 7200 (write-buffered *(ebp+8) " break/disp32\n") - 7201 $emit-reverse-break:end: - 7202 # . restore registers - 7203 58/pop-to-eax - 7204 # . epilogue - 7205 89/<- %esp 5/r32/ebp - 7206 5d/pop-to-ebp - 7207 c3/return - 7208 - 7209 == data - 7210 - 7211 Reverse-branch: # (table string string) - 7212 # a table is a stream - 7213 0xa0/imm32/write - 7214 0/imm32/read - 7215 0xa0/imm32/size - 7216 # data - 7217 "break-if-="/imm32 "0f 85/jump-if-!="/imm32 - 7218 "loop-if-="/imm32 "0f 85/jump-if-!="/imm32 - 7219 "break-if-!="/imm32 "0f 84/jump-if-="/imm32 - 7220 "loop-if-!="/imm32 "0f 84/jump-if-="/imm32 - 7221 "break-if-<"/imm32 "0f 8d/jump-if->="/imm32 - 7222 "loop-if-<"/imm32 "0f 8d/jump-if->="/imm32 - 7223 "break-if->"/imm32 "0f 8e/jump-if-<="/imm32 - 7224 "loop-if->"/imm32 "0f 8e/jump-if-<="/imm32 - 7225 "break-if-<="/imm32 "0f 87/jump-if->"/imm32 - 7226 "loop-if-<="/imm32 "0f 87/jump-if->"/imm32 - 7227 "break-if->="/imm32 "0f 8c/jump-if-<"/imm32 - 7228 "loop-if->="/imm32 "0f 8c/jump-if-<"/imm32 - 7229 "break-if-addr<"/imm32 "0f 83/jump-if-addr>="/imm32 - 7230 "loop-if-addr<"/imm32 "0f 83/jump-if-addr>="/imm32 - 7231 "break-if-addr>"/imm32 "0f 86/jump-if-addr<="/imm32 - 7232 "loop-if-addr>"/imm32 "0f 86/jump-if-addr<="/imm32 - 7233 "break-if-addr<="/imm32 "0f 87/jump-if-addr>"/imm32 - 7234 "loop-if-addr<="/imm32 "0f 87/jump-if-addr>"/imm32 - 7235 "break-if-addr>="/imm32 "0f 82/jump-if-addr<"/imm32 - 7236 "loop-if-addr>="/imm32 "0f 82/jump-if-addr<"/imm32 - 7237 - 7238 == code - 7239 - 7240 emit-unconditional-jump-to-depth: # out: (addr buffered-file), vars: (addr stack (handle var)), depth: int, label-suffix: (addr array byte) - 7241 # . prologue - 7242 55/push-ebp - 7243 89/<- %ebp 4/r32/esp - 7244 # . save registers - 7245 50/push-eax - 7246 51/push-ecx - 7247 52/push-edx - 7248 53/push-ebx - 7249 # ecx = vars - 7250 8b/-> *(ebp+0xc) 1/r32/ecx - 7251 # var eax: int = vars->top - 7252 8b/-> *ecx 0/r32/eax - 7253 # var min/ecx: (address (handle var)) = vars->data - 7254 81 0/subop/add %ecx 8/imm32 - 7255 # var curr/eax: (address (handle var)) = &vars->data[vars->top - 4] - 7256 81 5/subop/subtract %eax 4/imm32 - 7257 8d/copy-address *(ecx+eax) 0/r32/eax - 7258 # edx = depth - 7259 8b/-> *(ebp+0x10) 2/r32/edx - 7260 { - 7261 $emit-unconditional-jump-to-depth:loop: - 7262 # if (curr < min) break - 7263 39/compare %eax 1/r32/ecx - 7264 0f 82/jump-if-addr< break/disp32 - 7265 # var v/ebx: (handle var) = *curr - 7266 8b/-> *eax 3/r32/ebx - 7267 # if (v->block-depth < until-block-depth) break - 7268 39/compare *(ebx+8) 2/r32/edx # Var-block-depth - 7269 0f 8c/jump-if-< break/disp32 - 7270 { - 7271 $emit-unconditional-jump-to-depth:check: - 7272 # if v->block-depth != until-block-depth, continue - 7273 39/compare *(ebx+8) 2/r32/edx # Var-block-depth - 7274 0f 85/jump-if-!= break/disp32 - 7275 $emit-unconditional-jump-to-depth:depth-found: - 7276 # if v is not a literal, continue - 7277 # . var eax: int = size-of(v) - 7278 50/push-eax - 7279 (size-of %ebx) # => eax - 7280 # . if (eax != 0) continue - 7281 3d/compare-eax-and 0/imm32 - 7282 58/pop-to-eax - 7283 # - 7284 0f 85/jump-if-!= break/disp32 - 7285 $emit-unconditional-jump-to-depth:label-found: - 7286 # emit unconditional jump, then return - 7287 (emit-indent *(ebp+8) *Curr-block-depth) - 7288 (write-buffered *(ebp+8) "e9/jump ") - 7289 (write-buffered *(ebp+8) *ebx) # Var-name - 7290 (write-buffered *(ebp+8) ":") - 7291 (write-buffered *(ebp+8) *(ebp+0x14)) - 7292 (write-buffered *(ebp+8) "/disp32\n") - 7293 eb/jump $emit-unconditional-jump-to-depth:end/disp8 - 7294 } - 7295 # curr -= 4 - 7296 2d/subtract-from-eax 4/imm32 - 7297 e9/jump loop/disp32 - 7298 } - 7299 # TODO: error if no label at 'depth' was found - 7300 $emit-unconditional-jump-to-depth:end: - 7301 # . restore registers - 7302 5b/pop-to-ebx - 7303 5a/pop-to-edx - 7304 59/pop-to-ecx - 7305 58/pop-to-eax - 7306 # . epilogue - 7307 89/<- %esp 5/r32/ebp - 7308 5d/pop-to-ebp - 7309 c3/return - 7310 - 7311 # emit clean-up code for 'vars' until some block depth - 7312 # doesn't actually modify 'vars' so we need traverse manually inside the stack - 7313 emit-cleanup-code-until-depth: # out: (addr buffered-file), vars: (addr stack (handle var)), until-block-depth: int - 7314 # . prologue - 7315 55/push-ebp - 7316 89/<- %ebp 4/r32/esp - 7317 # . save registers - 7318 50/push-eax - 7319 51/push-ecx - 7320 52/push-edx - 7321 53/push-ebx - 7322 # ecx = vars - 7323 8b/-> *(ebp+0xc) 1/r32/ecx - 7324 # var eax: int = vars->top - 7325 8b/-> *ecx 0/r32/eax - 7326 # var min/ecx: (address (handle var)) = vars->data - 7327 81 0/subop/add %ecx 8/imm32 - 7328 # var curr/eax: (address (handle var)) = &vars->data[vars->top - 4] - 7329 81 5/subop/subtract %eax 4/imm32 - 7330 8d/copy-address *(ecx+eax) 0/r32/eax - 7331 # edx = until-block-depth - 7332 8b/-> *(ebp+0x10) 2/r32/edx - 7333 { - 7334 $emit-cleanup-code-until-depth:loop: - 7335 # if (curr < min) break - 7336 39/compare %eax 1/r32/ecx - 7337 0f 82/jump-if-addr< break/disp32 - 7338 # var v/ebx: (handle var) = *curr - 7339 8b/-> *eax 3/r32/ebx - 7340 # if (v->block-depth < until-block-depth) break - 7341 39/compare *(ebx+8) 2/r32/edx # Var-block-depth - 7342 0f 8c/jump-if-< break/disp32 - 7343 # if v is in a register - 7344 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register - 7345 { - 7346 0f 84/jump-if-= break/disp32 - 7347 50/push-eax - 7348 { - 7349 $emit-cleanup-code-until-depth:check-for-previous-spill: - 7350 (same-register-spilled-before? %ebx *(ebp+0xc) %eax) # => eax - 7351 3d/compare-eax-and 0/imm32/false - 7352 0f 85/jump-if-!= break/disp32 - 7353 $emit-cleanup-code-until-depth:reclaim-var-in-register: - 7354 (emit-indent *(ebp+8) *Curr-block-depth) - 7355 (write-buffered *(ebp+8) "8f 0/subop/pop %") - 7356 (write-buffered *(ebp+8) *(ebx+0x10)) - 7357 (write-buffered *(ebp+8) Newline) - 7358 } - 7359 58/pop-to-eax - 7360 eb/jump $emit-cleanup-code-until-depth:continue/disp8 - 7361 } - 7362 # otherwise v is on the stack - 7363 { - 7364 75/jump-if-!= break/disp8 - 7365 $emit-cleanup-code-until-depth:reclaim-var-on-stack: - 7366 50/push-eax - 7367 (size-of %ebx) # => eax - 7368 # don't emit code for labels - 7369 3d/compare-eax-and 0/imm32 - 7370 74/jump-if-= break/disp8 - 7371 # - 7372 (emit-indent *(ebp+8) *Curr-block-depth) - 7373 (write-buffered *(ebp+8) "81 0/subop/add %esp ") - 7374 (print-int32-buffered *(ebp+8) %eax) - 7375 (write-buffered *(ebp+8) "/imm32\n") - 7376 58/pop-to-eax - 7377 } - 7378 $emit-cleanup-code-until-depth:continue: - 7379 # curr -= 4 - 7380 2d/subtract-from-eax 4/imm32 - 7381 e9/jump loop/disp32 - 7382 } - 7383 $emit-cleanup-code-until-depth:end: - 7384 # . restore registers - 7385 5b/pop-to-ebx - 7386 5a/pop-to-edx - 7387 59/pop-to-ecx - 7388 58/pop-to-eax - 7389 # . epilogue - 7390 89/<- %esp 5/r32/ebp - 7391 5d/pop-to-ebp - 7392 c3/return - 7393 - 7394 # emit clean-up code for 'vars' until a given label is encountered - 7395 # doesn't actually modify 'vars' so we need traverse manually inside the stack - 7396 emit-cleanup-code-until-target: # out: (addr buffered-file), vars: (addr stack (handle var)), until-block-label: (addr array byte) + 7182 5f/pop-to-edi + 7183 5e/pop-to-esi + 7184 5b/pop-to-ebx + 7185 5a/pop-to-edx + 7186 59/pop-to-ecx + 7187 # . epilogue + 7188 89/<- %esp 5/r32/ebp + 7189 5d/pop-to-ebp + 7190 c3/return + 7191 + 7192 $locate-typeinfo-entry-with-index:abort: + 7193 (write-buffered Stderr "overflowing typeinfo-entry->index ") + 7194 (print-int32-buffered Stderr %ecx) + 7195 (write-buffered Stderr "\n") + 7196 (flush Stderr) + 7197 # . syscall(exit, 1) + 7198 bb/copy-to-ebx 1/imm32 + 7199 b8/copy-to-eax 1/imm32/exit + 7200 cd/syscall 0x80/imm8 + 7201 # never gets here + 7202 + 7203 dump-typeinfos: # hdr: (addr array byte) + 7204 # . prologue + 7205 55/push-ebp + 7206 89/<- %ebp 4/r32/esp + 7207 # . save registers + 7208 50/push-eax + 7209 # + 7210 (write-buffered Stderr *(ebp+8)) + 7211 (flush Stderr) + 7212 # var curr/eax: (addr typeinfo) = lookup(Program->types) + 7213 (lookup *_Program-types *_Program-types->payload) # => eax + 7214 { + 7215 # if (curr == null) break + 7216 3d/compare-eax-and 0/imm32 + 7217 74/jump-if-= break/disp8 + 7218 (write-buffered Stderr "---\n") + 7219 (flush Stderr) + 7220 (dump-typeinfo %eax) + 7221 # curr = lookup(curr->next) + 7222 (lookup *(eax+0x10) *(eax+0x14)) # Typeinfo-next Typeinfo-next => eax + 7223 eb/jump loop/disp8 + 7224 } + 7225 $dump-typeinfos:end: + 7226 # . restore registers + 7227 58/pop-to-eax + 7228 # . epilogue + 7229 89/<- %esp 5/r32/ebp + 7230 5d/pop-to-ebp + 7231 c3/return + 7232 + 7233 dump-typeinfo: # in: (addr typeinfo) + 7234 # . prologue + 7235 55/push-ebp + 7236 89/<- %ebp 4/r32/esp + 7237 # . save registers + 7238 50/push-eax + 7239 51/push-ecx + 7240 52/push-edx + 7241 53/push-ebx + 7242 56/push-esi + 7243 57/push-edi + 7244 # esi = in + 7245 8b/-> *(ebp+8) 6/r32/esi + 7246 # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields) + 7247 (lookup *(esi+4) *(esi+8)) # Typeinfo-fields Typeinfo-fields => eax + 7248 89/<- %ecx 0/r32/eax + 7249 (write-buffered Stderr "id:") + 7250 (print-int32-buffered Stderr *esi) + 7251 (write-buffered Stderr "\n") + 7252 (write-buffered Stderr "fields @ ") + 7253 (print-int32-buffered Stderr %ecx) + 7254 (write-buffered Stderr Newline) + 7255 (flush Stderr) + 7256 (write-buffered Stderr " write: ") + 7257 (print-int32-buffered Stderr *ecx) + 7258 (write-buffered Stderr Newline) + 7259 (flush Stderr) + 7260 (write-buffered Stderr " read: ") + 7261 (print-int32-buffered Stderr *(ecx+4)) + 7262 (write-buffered Stderr Newline) + 7263 (flush Stderr) + 7264 (write-buffered Stderr " size: ") + 7265 (print-int32-buffered Stderr *(ecx+8)) + 7266 (write-buffered Stderr Newline) + 7267 (flush Stderr) + 7268 # var table-size/edx: int = table->write + 7269 8b/-> *ecx 2/r32/edx # stream-write + 7270 # var curr/ecx: (addr table_row) = table->data + 7271 8d/copy-address *(ecx+0xc) 1/r32/ecx + 7272 # var max/edx: (addr table_row) = table->data + table->write + 7273 8d/copy-address *(ecx+edx) 2/r32/edx + 7274 { + 7275 $dump-typeinfo:loop: + 7276 # if (curr >= max) break + 7277 39/compare %ecx 2/r32/edx + 7278 0f 83/jump-if-addr>= break/disp32 + 7279 (write-buffered Stderr " row:\n") + 7280 (write-buffered Stderr " key: ") + 7281 (print-int32-buffered Stderr *ecx) + 7282 (write-buffered Stderr ",") + 7283 (print-int32-buffered Stderr *(ecx+4)) + 7284 (write-buffered Stderr " = '") + 7285 (lookup *ecx *(ecx+4)) + 7286 (write-buffered Stderr %eax) + 7287 (write-buffered Stderr "' @ ") + 7288 (print-int32-buffered Stderr %eax) + 7289 (write-buffered Stderr Newline) + 7290 (flush Stderr) + 7291 (write-buffered Stderr " value: ") + 7292 (print-int32-buffered Stderr *(ecx+8)) + 7293 (write-buffered Stderr ",") + 7294 (print-int32-buffered Stderr *(ecx+0xc)) + 7295 (write-buffered Stderr " = typeinfo-entry@") + 7296 (lookup *(ecx+8) *(ecx+0xc)) + 7297 (print-int32-buffered Stderr %eax) + 7298 (write-buffered Stderr Newline) + 7299 (flush Stderr) + 7300 (write-buffered Stderr " input var@") + 7301 (print-int32-buffered Stderr *eax) + 7302 (write-buffered Stderr ",") + 7303 (print-int32-buffered Stderr *(eax+4)) + 7304 (write-buffered Stderr "->") + 7305 (lookup *eax *(eax+4)) # Typeinfo-entry-input-var + 7306 (print-int32-buffered Stderr %eax) + 7307 { + 7308 3d/compare-eax-and 0/imm32 + 7309 74/jump-if-= break/disp8 + 7310 (write-buffered Stderr " ") + 7311 # TODO + 7312 } + 7313 (write-buffered Stderr Newline) + 7314 (flush Stderr) + 7315 (lookup *(ecx+8) *(ecx+0xc)) + 7316 (write-buffered Stderr " index: ") + 7317 (print-int32-buffered Stderr *(eax+8)) + 7318 (write-buffered Stderr Newline) + 7319 (flush Stderr) + 7320 (write-buffered Stderr " output var@") + 7321 (print-int32-buffered Stderr *(eax+0xc)) + 7322 (write-buffered Stderr ",") + 7323 (print-int32-buffered Stderr *(eax+0x10)) + 7324 (write-buffered Stderr "->") + 7325 (lookup *(eax+0xc) *(eax+0x10)) # Typeinfo-entry-output-var + 7326 (print-int32-buffered Stderr %eax) + 7327 (write-buffered Stderr Newline) + 7328 (flush Stderr) + 7329 { + 7330 3d/compare-eax-and 0/imm32 + 7331 0f 84/jump-if-= break/disp32 + 7332 (write-buffered Stderr " name: ") + 7333 89/<- %ebx 0/r32/eax + 7334 (print-int32-buffered Stderr *ebx) # Var-name + 7335 (write-buffered Stderr ",") + 7336 (print-int32-buffered Stderr *(ebx+4)) # Var-name + 7337 (write-buffered Stderr "->") + 7338 (lookup *ebx *(ebx+4)) # Var-name + 7339 (print-int32-buffered Stderr %eax) + 7340 { + 7341 3d/compare-eax-and 0/imm32 + 7342 74/jump-if-= break/disp8 + 7343 (write-buffered Stderr Space) + 7344 (write-buffered Stderr %eax) + 7345 } + 7346 (write-buffered Stderr Newline) + 7347 (flush Stderr) + 7348 (write-buffered Stderr " block depth: ") + 7349 (print-int32-buffered Stderr *(ebx+0x10)) # Var-block-depth + 7350 (write-buffered Stderr Newline) + 7351 (flush Stderr) + 7352 (write-buffered Stderr " stack offset: ") + 7353 (print-int32-buffered Stderr *(ebx+0x14)) # Var-offset + 7354 (write-buffered Stderr Newline) + 7355 (flush Stderr) + 7356 (write-buffered Stderr " reg: ") + 7357 (print-int32-buffered Stderr *(ebx+0x18)) # Var-register + 7358 (write-buffered Stderr ",") + 7359 (print-int32-buffered Stderr *(ebx+0x1c)) # Var-register + 7360 (write-buffered Stderr "->") + 7361 (flush Stderr) + 7362 (lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register + 7363 (print-int32-buffered Stderr %eax) + 7364 { + 7365 3d/compare-eax-and 0/imm32 + 7366 74/jump-if-= break/disp8 + 7367 (write-buffered Stderr Space) + 7368 (write-buffered Stderr %eax) + 7369 } + 7370 (write-buffered Stderr Newline) + 7371 (flush Stderr) + 7372 } + 7373 (flush Stderr) + 7374 # curr += row-size + 7375 81 0/subop/add %ecx 0x10/imm32 # Typeinfo-fields-row-size + 7376 # + 7377 e9/jump loop/disp32 + 7378 } + 7379 $dump-typeinfo:end: + 7380 # . restore registers + 7381 5f/pop-to-edi + 7382 5e/pop-to-esi + 7383 5b/pop-to-ebx + 7384 5a/pop-to-edx + 7385 59/pop-to-ecx + 7386 58/pop-to-eax + 7387 # . epilogue + 7388 89/<- %esp 5/r32/ebp + 7389 5d/pop-to-ebp + 7390 c3/return + 7391 + 7392 ####################################################### + 7393 # Type-checking + 7394 ####################################################### + 7395 + 7396 check-mu-types: 7397 # . prologue 7398 55/push-ebp 7399 89/<- %ebp 4/r32/esp - 7400 # . save registers - 7401 50/push-eax - 7402 51/push-ecx - 7403 52/push-edx - 7404 53/push-ebx - 7405 # ecx = vars - 7406 8b/-> *(ebp+0xc) 1/r32/ecx - 7407 # var eax: int = vars->top - 7408 8b/-> *ecx 0/r32/eax - 7409 # var min/ecx: (address (handle var)) = vars->data - 7410 81 0/subop/add %ecx 8/imm32 - 7411 # var curr/edx: (address (handle var)) = &vars->data[vars->top - 4] - 7412 81 5/subop/subtract %eax 4/imm32 - 7413 8d/copy-address *(ecx+eax) 2/r32/edx - 7414 { - 7415 $emit-cleanup-code-until-target:loop: - 7416 # if (curr < min) break - 7417 39/compare %edx 1/r32/ecx - 7418 0f 82/jump-if-addr< break/disp32 - 7419 # var v/ebx: (handle var) = *curr - 7420 8b/-> *edx 3/r32/ebx - 7421 # if (v->name == until-block-label) break - 7422 (string-equal? *ebx *(ebp+0x10)) # => eax - 7423 3d/compare-eax-and 0/imm32/false - 7424 0f 85/jump-if-!= break/disp32 - 7425 # if v is in a register - 7426 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register - 7427 { - 7428 74/jump-if-= break/disp8 - 7429 50/push-eax - 7430 { - 7431 $emit-cleanup-code-until-target:check-for-previous-spill: - 7432 (same-register-spilled-before? %ebx *(ebp+0xc) %edx) # => eax - 7433 3d/compare-eax-and 0/imm32/false - 7434 75/jump-if-!= break/disp8 - 7435 $emit-cleanup-code-until-target:reclaim-var-in-register: - 7436 (emit-indent *(ebp+8) *Curr-block-depth) - 7437 (write-buffered *(ebp+8) "8f 0/subop/pop %") - 7438 (write-buffered *(ebp+8) *(ebx+0x10)) - 7439 (write-buffered *(ebp+8) Newline) - 7440 } - 7441 58/pop-to-eax - 7442 eb/jump $emit-cleanup-code-until-target:continue/disp8 - 7443 } - 7444 # otherwise v is on the stack - 7445 { - 7446 75/jump-if-!= break/disp8 - 7447 $emit-cleanup-code-until-target:reclaim-var-on-stack: - 7448 (size-of %ebx) # => eax - 7449 # don't emit code for labels - 7450 3d/compare-eax-and 0/imm32 - 7451 74/jump-if-= break/disp8 - 7452 # - 7453 (emit-indent *(ebp+8) *Curr-block-depth) - 7454 (write-buffered *(ebp+8) "81 0/subop/add %esp ") - 7455 (print-int32-buffered *(ebp+8) %eax) - 7456 (write-buffered *(ebp+8) "/imm32\n") - 7457 } - 7458 $emit-cleanup-code-until-target:continue: - 7459 # curr -= 4 - 7460 81 5/subop/subtract %edx 4/imm32 - 7461 e9/jump loop/disp32 - 7462 } - 7463 $emit-cleanup-code-until-target:end: - 7464 # . restore registers - 7465 5b/pop-to-ebx - 7466 5a/pop-to-edx - 7467 59/pop-to-ecx - 7468 58/pop-to-eax - 7469 # . epilogue - 7470 89/<- %esp 5/r32/ebp - 7471 5d/pop-to-ebp - 7472 c3/return - 7473 - 7474 # is there already a var with the same block-depth and register as 'v' on the 'vars' stack? - 7475 # v is guaranteed not to be within vars - 7476 already-spilled-this-block?: # v: (handle var), vars: (addr stack (handle var)) -> result/eax: boolean - 7477 # . prologue - 7478 55/push-ebp - 7479 89/<- %ebp 4/r32/esp - 7480 # . save registers - 7481 51/push-ecx - 7482 52/push-edx - 7483 53/push-ebx - 7484 56/push-esi - 7485 57/push-edi - 7486 # ecx = vars - 7487 8b/-> *(ebp+0xc) 1/r32/ecx - 7488 # var eax: int = vars->top - 7489 8b/-> *ecx 0/r32/eax - 7490 # var min/ecx: (address (handle var)) = vars->data - 7491 81 0/subop/add %ecx 8/imm32 - 7492 # var curr/edx: (address (handle var)) = &vars->data[vars->top - 4] - 7493 81 5/subop/subtract %eax 4/imm32 - 7494 8d/copy-address *(ecx+eax) 2/r32/edx - 7495 # var depth/ebx: int = v->block-depth - 7496 8b/-> *(ebp+8) 3/r32/ebx - 7497 8b/-> *(ebx+8) 3/r32/ebx # Var-block-depth - 7498 # var needle/esi: (handle array byte) = v->register - 7499 8b/-> *(ebp+8) 6/r32/esi - 7500 8b/-> *(esi+0x10) 6/r32/esi # Var-register - 7501 { - 7502 $already-spilled-this-block?:loop: - 7503 # if (curr < min) break - 7504 39/compare %edx 1/r32/ecx - 7505 0f 82/jump-if-addr< break/disp32 - 7506 # var cand/edi: (handle var) = *curr - 7507 8b/-> *edx 7/r32/edi - 7508 # if (cand->block-depth < depth) break - 7509 39/compare *(edi+8) 3/r32/ebx # Var-block-depth - 7510 0f 8c/jump-if-< break/disp32 - 7511 # var cand-reg/edi: (handle array byte) = cand->reg - 7512 8b/-> *(edi+0x10) 7/r32/edi - 7513 # if (cand-reg == null) continue - 7514 { - 7515 $already-spilled-this-block?:check-reg: - 7516 81 7/subop/compare %edi 0/imm32 - 7517 74/jump-if-= break/disp8 - 7518 # if (cand-reg == needle) return true - 7519 (string-equal? %esi %edi) # => eax - 7520 3d/compare-eax-and 0/imm32/false - 7521 74/jump-if-= break/disp8 - 7522 b8/copy-to-eax 1/imm32/true - 7523 eb/jump $already-spilled-this-block?:end/disp8 - 7524 } - 7525 $already-spilled-this-block?:continue: - 7526 # curr -= 4 - 7527 81 5/subop/subtract %edx 4/imm32 - 7528 e9/jump loop/disp32 - 7529 } - 7530 # return false - 7531 b8/copy-to-eax 0/imm32/false - 7532 $already-spilled-this-block?:end: - 7533 # . restore registers - 7534 5f/pop-to-edi - 7535 5e/pop-to-esi - 7536 5b/pop-to-ebx - 7537 5a/pop-to-edx - 7538 59/pop-to-ecx - 7539 # . epilogue - 7540 89/<- %esp 5/r32/ebp - 7541 5d/pop-to-ebp - 7542 c3/return - 7543 - 7544 # is there a var before 'v' with the same block-depth and register on the 'vars' stack? - 7545 # v is guaranteed to be within vars - 7546 # 'start' is provided as an optimization, a pointer within vars - 7547 # *start == v - 7548 same-register-spilled-before?: # v: (handle var), vars: (addr stack (handle var)), start: (addr (handle var)) -> result/eax: boolean - 7549 # . prologue - 7550 55/push-ebp - 7551 89/<- %ebp 4/r32/esp - 7552 # . save registers - 7553 51/push-ecx - 7554 52/push-edx - 7555 53/push-ebx - 7556 56/push-esi - 7557 57/push-edi - 7558 # ecx = v - 7559 8b/-> *(ebp+8) 1/r32/ecx - 7560 # var reg/edx: (handle array byte) = v->register - 7561 8b/-> *(ecx+0x10) 2/r32/edx # Var-register - 7562 # var depth/ebx: int = v->block-depth - 7563 8b/-> *(ecx+8) 3/r32/ebx # Var-block-depth - 7564 # var min/ecx: (address (handle var)) = vars->data - 7565 8b/-> *(ebp+0xc) 1/r32/ecx - 7566 81 0/subop/add %ecx 8/imm32 - 7567 # TODO: check that start >= min and start < &vars->data[top] - 7568 # TODO: check that *start == v - 7569 # var curr/esi: (address (handle var)) = start - 7570 8b/-> *(ebp+0x10) 6/r32/esi - 7571 # curr -= 4 - 7572 81 5/subop/subtract %esi 4/imm32 - 7573 { - 7574 $same-register-spilled-before?:loop: - 7575 # if (curr < min) break - 7576 39/compare %esi 1/r32/ecx - 7577 0f 82/jump-if-addr< break/disp32 - 7578 # var x/eax: (handle var) = *curr - 7579 8b/-> *esi 0/r32/eax - 7580 # if (x->block-depth < depth) break - 7581 39/compare *(eax+8) 3/r32/ebx # Var-block-depth - 7582 0f 8c/jump-if-< break/disp32 - 7583 # if (x->register == 0) continue - 7584 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register - 7585 74/jump-if-= $same-register-spilled-before?:continue/disp8 - 7586 # if (x->register == reg) return true - 7587 (string-equal? *(eax+0x10) %edx) # Var-register => eax - 7588 3d/compare-eax-and 0/imm32/false - 7589 75/jump-if-!= $same-register-spilled-before?:end/disp8 - 7590 $same-register-spilled-before?:continue: - 7591 # curr -= 4 - 7592 81 5/subop/subtract %esi 4/imm32 - 7593 e9/jump loop/disp32 - 7594 } - 7595 $same-register-spilled-before?:false: - 7596 b8/copy-to-eax 0/imm32/false - 7597 $same-register-spilled-before?:end: - 7598 # . restore registers - 7599 5f/pop-to-edi - 7600 5e/pop-to-esi - 7601 5b/pop-to-ebx - 7602 5a/pop-to-edx - 7603 59/pop-to-ecx - 7604 # . epilogue - 7605 89/<- %esp 5/r32/ebp - 7606 5d/pop-to-ebp - 7607 c3/return - 7608 - 7609 # clean up global state for 'vars' until some block depth - 7610 clean-up-blocks: # vars: (addr stack (handle var)), until-block-depth: int - 7611 # . prologue - 7612 55/push-ebp - 7613 89/<- %ebp 4/r32/esp - 7614 # . save registers - 7615 50/push-eax - 7616 51/push-ecx - 7617 56/push-esi - 7618 # esi = vars - 7619 8b/-> *(ebp+8) 6/r32/esi - 7620 # ecx = until-block-depth - 7621 8b/-> *(ebp+0xc) 1/r32/ecx - 7622 { - 7623 $clean-up-blocks:reclaim-loop: - 7624 # if (vars->top <= 0) break - 7625 81 7/subop/compare *esi 0/imm32 # Stack-top - 7626 7e/jump-if-<= break/disp8 - 7627 # var v/eax: (handle var) = top(vars) - 7628 (top %esi) # => eax - 7629 # if (v->block-depth < until-block-depth) break - 7630 39/compare *(eax+8) 1/r32/ecx # Var-block-depth - 7631 7c/jump-if-< break/disp8 - 7632 # if v is on the stack, update Curr-local-stack-offset - 7633 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register - 7634 { - 7635 75/jump-if-!= break/disp8 - 7636 $clean-up-blocks:reclaim-var-on-stack: - 7637 (size-of %eax) # => eax - 7638 01/add-to *Curr-local-stack-offset 0/r32/eax - 7639 } - 7640 (pop %esi) - 7641 e9/jump loop/disp32 - 7642 } - 7643 $clean-up-blocks:end: - 7644 # . restore registers - 7645 5e/pop-to-esi - 7646 59/pop-to-ecx - 7647 58/pop-to-eax - 7648 # . epilogue - 7649 89/<- %esp 5/r32/ebp - 7650 5d/pop-to-ebp - 7651 c3/return - 7652 - 7653 emit-subx-var-def: # out: (addr buffered-file), stmt: (handle stmt) - 7654 # . prologue - 7655 55/push-ebp - 7656 89/<- %ebp 4/r32/esp - 7657 # . save registers - 7658 50/push-eax - 7659 51/push-ecx - 7660 52/push-edx - 7661 # eax = stmt - 7662 8b/-> *(ebp+0xc) 0/r32/eax - 7663 # var v/ecx: (handle var) - 7664 8b/-> *(eax+4) 1/r32/ecx # Vardef-var - 7665 # v->block-depth = *Curr-block-depth - 7666 8b/-> *Curr-block-depth 0/r32/eax - 7667 89/<- *(ecx+8) 0/r32/eax # Var-block-depth - 7668 # var n/edx: int = size-of(stmt->var) - 7669 (size-of %ecx) # => eax - 7670 89/<- %edx 0/r32/eax - 7671 # *Curr-local-stack-offset -= n - 7672 29/subtract-from *Curr-local-stack-offset 2/r32/edx - 7673 # v->offset = *Curr-local-stack-offset - 7674 8b/-> *Curr-local-stack-offset 0/r32/eax - 7675 89/<- *(ecx+0xc) 0/r32/eax # Var-offset - 7676 # if v is an array, do something special - 7677 { - 7678 (is-mu-array? *(ecx+4)) # Var-type => eax - 7679 3d/compare-eax-and 0/imm32/false - 7680 0f 84/jump-if-= break/disp32 - 7681 # var array-size-without-size/edx: int = n-4 - 7682 81 5/subop/subtract %edx 4/imm32 - 7683 (emit-indent *(ebp+8) *Curr-block-depth) - 7684 (write-buffered *(ebp+8) "(push-n-zero-bytes ") - 7685 (print-int32-buffered *(ebp+8) %edx) - 7686 (write-buffered *(ebp+8) ")\n") - 7687 (emit-indent *(ebp+8) *Curr-block-depth) - 7688 (write-buffered *(ebp+8) "68/push ") - 7689 (print-int32-buffered *(ebp+8) %edx) - 7690 (write-buffered *(ebp+8) "/imm32\n") - 7691 eb/jump $emit-subx-var-def:end/disp8 - 7692 } - 7693 # while n > 0 - 7694 { - 7695 81 7/subop/compare %edx 0/imm32 - 7696 7e/jump-if-<= break/disp8 - 7697 (emit-indent *(ebp+8) *Curr-block-depth) - 7698 (write-buffered *(ebp+8) "68/push 0/imm32\n") - 7699 # n -= 4 - 7700 81 5/subop/subtract %edx 4/imm32 - 7701 # - 7702 eb/jump loop/disp8 - 7703 } - 7704 $emit-subx-var-def:end: - 7705 # . restore registers - 7706 5a/pop-to-edx - 7707 59/pop-to-ecx - 7708 58/pop-to-eax - 7709 # . epilogue - 7710 89/<- %esp 5/r32/ebp - 7711 5d/pop-to-ebp - 7712 c3/return - 7713 - 7714 emit-subx-stmt: # out: (addr buffered-file), stmt: (handle stmt), primitives: (handle primitive) - 7715 # . prologue - 7716 55/push-ebp - 7717 89/<- %ebp 4/r32/esp - 7718 # . save registers - 7719 50/push-eax - 7720 51/push-ecx - 7721 # - some special-case primitives that don't actually use the 'primitives' data structure - 7722 # ecx = stmt - 7723 8b/-> *(ebp+0xc) 1/r32/ecx - 7724 # array size - 7725 { - 7726 # if (!string-equal?(stmt->operation, "length")) break - 7727 (string-equal? *(ecx+4) "length") # Stmt1-operation => eax - 7728 3d/compare-eax-and 0/imm32 - 7729 0f 84/jump-if-= break/disp32 - 7730 (translate-mu-length-stmt *(ebp+8) *(ebp+0xc)) - 7731 e9/jump $emit-subx-stmt:end/disp32 - 7732 } - 7733 # index into array - 7734 { - 7735 # if (!string-equal?(var->operation, "index")) break - 7736 (string-equal? *(ecx+4) "index") # Stmt1-operation => eax - 7737 3d/compare-eax-and 0/imm32 - 7738 0f 84/jump-if-= break/disp32 - 7739 (translate-mu-index-stmt *(ebp+8) *(ebp+0xc)) - 7740 e9/jump $emit-subx-stmt:end/disp32 - 7741 } - 7742 # compute-offset for index into array - 7743 { - 7744 # if (!string-equal?(var->operation, "compute-offset")) break - 7745 (string-equal? *(ecx+4) "compute-offset") # Stmt1-operation => eax - 7746 3d/compare-eax-and 0/imm32 - 7747 0f 84/jump-if-= break/disp32 - 7748 (translate-mu-compute-index-stmt *(ebp+8) *(ebp+0xc)) - 7749 e9/jump $emit-subx-stmt:end/disp32 - 7750 } - 7751 # get field from record - 7752 { - 7753 # if (!string-equal?(var->operation, "get")) break - 7754 (string-equal? *(ecx+4) "get") # Stmt1-operation => eax - 7755 3d/compare-eax-and 0/imm32 - 7756 0f 84/jump-if-= break/disp32 - 7757 (translate-mu-get-stmt *(ebp+8) *(ebp+0xc)) - 7758 e9/jump $emit-subx-stmt:end/disp32 - 7759 } - 7760 # - if stmt matches a primitive, emit it - 7761 { - 7762 $emit-subx-stmt:check-for-primitive: - 7763 (find-matching-primitive *(ebp+0x10) *(ebp+0xc)) # primitives, stmt => curr/eax - 7764 3d/compare-eax-and 0/imm32 - 7765 74/jump-if-= break/disp8 - 7766 $emit-subx-stmt:primitive: - 7767 (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr - 7768 e9/jump $emit-subx-stmt:end/disp32 - 7769 } - 7770 # - otherwise emit a call - 7771 # TODO: type-checking - 7772 $emit-subx-stmt:call: - 7773 (emit-call *(ebp+8) *(ebp+0xc)) - 7774 $emit-subx-stmt:end: - 7775 # . restore registers - 7776 59/pop-to-ecx - 7777 58/pop-to-eax - 7778 # . epilogue - 7779 89/<- %esp 5/r32/ebp - 7780 5d/pop-to-ebp - 7781 c3/return - 7782 - 7783 translate-mu-length-stmt: # out: (address buffered-file), stmt: (handle stmt) - 7784 # . prologue - 7785 55/push-ebp - 7786 89/<- %ebp 4/r32/esp - 7787 # . save registers - 7788 50/push-eax - 7789 51/push-ecx - 7790 # ecx = stmt - 7791 8b/-> *(ebp+0xc) 1/r32/ecx - 7792 # - 7793 (emit-indent *(ebp+8) *Curr-block-depth) - 7794 (write-buffered *(ebp+8) "8b/-> *") - 7795 # var base/eax: (handle var) = inouts[0] - 7796 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts or Regvardef-inouts - 7797 8b/-> *eax 0/r32/eax # Stmt-var-value - 7798 # if base is an (address array ...) in a register - 7799 { - 7800 81 7/subop/compare *(eax+0x10)) 0/imm32 # Var-register - 7801 74/jump-if-= break/disp8 - 7802 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register - 7803 eb/jump $translate-mu-length-stmt:emit-output/disp8 - 7804 } - 7805 # otherwise if base is an (array ...) on the stack - 7806 { - 7807 81 7/subop/compare *(eax+0xc)) 0/imm32 # Var-offset - 7808 74/jump-if-= break/disp8 - 7809 (write-buffered *(ebp+8) "(ebp+") - 7810 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-offset - 7811 (write-buffered *(ebp+8) ")") - 7812 } - 7813 $translate-mu-length-stmt:emit-output: - 7814 (write-buffered *(ebp+8) " ") - 7815 # outputs[0] "/r32" - 7816 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs - 7817 8b/-> *eax 0/r32/eax # Stmt-var-value - 7818 (get Registers *(eax+0x10) 8 "Registers") # Var-register => eax - 7819 (print-int32-buffered *(ebp+8) *eax) - 7820 (write-buffered *(ebp+8) "/r32\n") - 7821 $translate-mu-length-stmt:end: - 7822 # . restore registers - 7823 59/pop-to-ecx - 7824 58/pop-to-eax - 7825 # . epilogue - 7826 89/<- %esp 5/r32/ebp - 7827 5d/pop-to-ebp - 7828 c3/return - 7829 - 7830 translate-mu-index-stmt: # out: (address buffered-file), stmt: (handle stmt) - 7831 # . prologue - 7832 55/push-ebp - 7833 89/<- %ebp 4/r32/esp - 7834 # . save registers - 7835 51/push-ecx - 7836 # var base/ecx: (handle var) = stmt->inouts[0] - 7837 8b/-> *(ebp+0xc) 1/r32/ecx - 7838 8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts - 7839 8b/-> *ecx 1/r32/ecx # Stmt-var-value - 7840 # if (var->register) do one thing - 7841 { - 7842 81 7/subop/compare *(ecx+0x10) 0/imm32 # Var-register - 7843 74/jump-if-= break/disp8 - 7844 # TODO: ensure there's no dereference - 7845 (translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc)) - 7846 eb/jump $translate-mu-index-stmt:end/disp8 - 7847 } - 7848 # if (var->offset) do a different thing - 7849 { - 7850 81 7/subop/compare *(ecx+0xc) 0/imm32 # Var-offset - 7851 74/jump-if-= break/disp8 - 7852 # TODO: ensure there's no dereference - 7853 (translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc)) - 7854 eb/jump $translate-mu-index-stmt:end/disp8 - 7855 } - 7856 $translate-mu-index-stmt:end: - 7857 # . restore registers - 7858 59/pop-to-ecx - 7859 # . epilogue - 7860 89/<- %esp 5/r32/ebp - 7861 5d/pop-to-ebp - 7862 c3/return - 7863 - 7864 $translate-mu-index-stmt-with-array:error1: - 7865 (write-buffered Stderr "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n") - 7866 (flush Stderr) - 7867 # . syscall(exit, 1) - 7868 bb/copy-to-ebx 1/imm32 - 7869 b8/copy-to-eax 1/imm32/exit - 7870 cd/syscall 0x80/imm8 - 7871 # never gets here - 7872 - 7873 $translate-mu-index-stmt-with-array:error2: - 7874 (write-buffered Stderr "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n") - 7875 (flush Stderr) - 7876 # . syscall(exit, 1) - 7877 bb/copy-to-ebx 1/imm32 - 7878 b8/copy-to-eax 1/imm32/exit - 7879 cd/syscall 0x80/imm8 - 7880 # never gets here - 7881 - 7882 translate-mu-index-stmt-with-array-in-register: # out: (address buffered-file), stmt: (handle stmt) - 7883 # . prologue - 7884 55/push-ebp - 7885 89/<- %ebp 4/r32/esp - 7886 # . save registers - 7887 50/push-eax - 7888 51/push-ecx - 7889 52/push-edx - 7890 53/push-ebx - 7891 # - 7892 (emit-indent *(ebp+8) *Curr-block-depth) - 7893 (write-buffered *(ebp+8) "8d/copy-address *(") - 7894 # TODO: ensure inouts[0] is in a register and not dereferenced - 7895 $translate-mu-index-stmt-with-array-in-register:emit-base: - 7896 # ecx = stmt - 7897 8b/-> *(ebp+0xc) 1/r32/ecx - 7898 # var base/ebx: (handle var) = inouts[0] - 7899 8b/-> *(ecx+8) 3/r32/ebx # Stmt1-inouts - 7900 8b/-> *ebx 3/r32/ebx # Stmt-var-value - 7901 # print base->register " + " - 7902 (write-buffered *(ebp+8) *(ebx+0x10)) # Var-register - 7903 # - 7904 (write-buffered *(ebp+8) " + ") - 7905 # var index/edx: (handle var) = inouts[1] - 7906 8b/-> *(ecx+8) 2/r32/edx # Stmt1-inouts - 7907 8b/-> *(edx+4) 2/r32/edx # Stmt-var-next - 7908 8b/-> *edx 2/r32/edx # Stmt-var-value - 7909 # if index->register - 7910 81 7/subop/compare *(edx+0x10) 0/imm32 # Var-register - 7911 { - 7912 0f 84/jump-if-= break/disp32 - 7913 $translate-mu-index-stmt-with-array-in-register:emit-register-index: - 7914 # if index is an int - 7915 (is-simple-mu-type? *(edx+4) 1) # Var-type, int => eax - 7916 3d/compare-eax-and 0/imm32/false - 7917 { - 7918 0f 84/jump-if-= break/disp32 - 7919 $translate-mu-index-stmt-with-array-in-register:emit-int-register-index: - 7920 # print index->register "<<" log2(size-of(element(base->type))) " + 4) " - 7921 # . index->register "<<" - 7922 (write-buffered *(ebp+8) *(edx+0x10)) # Var-register - 7923 (write-buffered *(ebp+8) "<<") - 7924 # . log2(size-of(element(base->type))) - 7925 # TODO: ensure size is a power of 2 - 7926 (array-element-type-id %ebx) # => eax - 7927 (size-of-type-id %eax) # => eax - 7928 (num-shift-rights %eax) # => eax - 7929 (print-int32-buffered *(ebp+8) %eax) - 7930 e9/jump $translate-mu-index-stmt-with-array-in-register:emit-register-index-done/disp32 - 7931 } - 7932 # if index->type is any other atom, abort - 7933 8b/-> *(edx+4) 0/r32/eax # Var-type - 7934 81 7/subop/compare *eax 0/imm32/false # Tree-is-atom - 7935 0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32 - 7936 # if index has type (offset ...) - 7937 (is-simple-mu-type? *(eax+4) 7) # Tree-left, offset => eax - 7938 3d/compare-eax-and 0/imm32/false - 7939 { - 7940 0f 84/jump-if-= break/disp32 - 7941 # print index->register " + 4) " - 7942 $translate-mu-index-stmt-with-array-in-register:emit-offset-register-index: - 7943 (write-buffered *(ebp+8) *(edx+0x10)) # Var-register - 7944 } - 7945 $translate-mu-index-stmt-with-array-in-register:emit-register-index-done: - 7946 (write-buffered *(ebp+8) " + 4) ") - 7947 e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32 - 7948 } - 7949 # otherwise if index is a literal - 7950 (is-simple-mu-type? *(edx+4) 0) # Var-type => eax - 7951 3d/compare-eax-and 0/imm32/false - 7952 { - 7953 0f 84/jump-if-= break/disp32 - 7954 $translate-mu-index-stmt-with-array-in-register:emit-literal-index: - 7955 # var index-value/edx: int = parse-hex-int(index->name) - 7956 (parse-hex-int *edx) # Var-name => eax - 7957 89/<- %edx 0/r32/eax - 7958 # offset = idx-value * size-of(element(base->type)) - 7959 (array-element-type-id %ebx) # => eax - 7960 (size-of-type-id %eax) # => eax - 7961 f7 4/subop/multiply-into-eax %edx # clobbers edx - 7962 # offset += 4 for array size - 7963 05/add-to-eax 4/imm32 - 7964 # TODO: check edx for overflow - 7965 # print offset - 7966 (print-int32-buffered *(ebp+8) %eax) - 7967 (write-buffered *(ebp+8) ") ") - 7968 e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32 - 7969 } - 7970 # otherwise abort - 7971 e9/jump $translate-mu-index-stmt-with-array:error1/disp32 - 7972 $translate-mu-index-stmt-with-array-in-register:emit-output: - 7973 # outputs[0] "/r32" - 7974 8b/-> *(ebp+0xc) 1/r32/ecx - 7975 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs - 7976 8b/-> *eax 0/r32/eax # Stmt-var-value - 7977 (get Registers *(eax+0x10) 8 "Registers") # Var-register => eax - 7978 (print-int32-buffered *(ebp+8) *eax) - 7979 (write-buffered *(ebp+8) "/r32\n") - 7980 $translate-mu-index-stmt-with-array-in-register:end: - 7981 # . restore registers - 7982 5b/pop-to-ebx - 7983 5a/pop-to-edx - 7984 59/pop-to-ecx - 7985 58/pop-to-eax - 7986 # . epilogue - 7987 89/<- %esp 5/r32/ebp - 7988 5d/pop-to-ebp - 7989 c3/return - 7990 - 7991 translate-mu-index-stmt-with-array-on-stack: # out: (address buffered-file), stmt: (handle stmt) - 7992 # . prologue - 7993 55/push-ebp - 7994 89/<- %ebp 4/r32/esp - 7995 # . save registers - 7996 50/push-eax - 7997 51/push-ecx - 7998 52/push-edx - 7999 53/push-ebx - 8000 # - 8001 (emit-indent *(ebp+8) *Curr-block-depth) - 8002 (write-buffered *(ebp+8) "8d/copy-address *(ebp + ") - 8003 # var curr/eax = stmt->inouts - 8004 8b/-> *(ebp+0xc) 0/r32/eax - 8005 # var base/ecx: (handle var) = stmt->inouts[0] - 8006 8b/-> *(eax+8) 0/r32/eax # Stmt1-inouts - 8007 8b/-> *eax 1/r32/ecx # Stmt-var-value - 8008 # curr = curr->next - 8009 8b/-> *(eax+4) 0/r32/eax # Stmt-var-next - 8010 # var index/edx: (handle var) = stmt->inouts[1] - 8011 8b/-> *eax 2/r32/edx # Stmt-var-value - 8012 # if index->register - 8013 81 7/subop/compare *(edx+0x10) 0/imm32 # Var-register - 8014 { - 8015 0f 84/jump-if-= break/disp32 - 8016 $translate-mu-index-stmt-with-array-on-stack:emit-register-index: - 8017 # if index is an int - 8018 (is-simple-mu-type? *(edx+4) 1) # Var-type, int => eax - 8019 3d/compare-eax-and 0/imm32/false - 8020 { - 8021 0f 84/jump-if-= break/disp32 - 8022 $translate-mu-index-stmt-with-array-on-stack:emit-int-register-index: - 8023 # print index->register "<<" log2(size-of(element-type(base))) " + " base->offset+4 - 8024 # . inouts[1]->register "<<" - 8025 (write-buffered *(ebp+8) *(edx+0x10)) # Var-register - 8026 (write-buffered *(ebp+8) "<<") - 8027 # . log2(size-of(element(base))) - 8028 # TODO: ensure size is a power of 2 - 8029 (array-element-type-id %ecx) # => eax - 8030 (size-of-type-id %eax) # => eax - 8031 (num-shift-rights %eax) # => eax - 8032 (print-int32-buffered *(ebp+8) %eax) - 8033 # - 8034 (write-buffered *(ebp+8) " + ") - 8035 # - 8036 8b/-> *(ecx+0xc) 0/r32/eax # Var-offset - 8037 05/add-to-eax 4/imm32 - 8038 (print-int32-buffered *(ebp+8) %eax) - 8039 e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done/disp32 - 8040 } - 8041 # if index->type is any other atom, abort - 8042 8b/-> *(edx+4) 0/r32/eax # Var-type - 8043 81 7/subop/compare *eax 0/imm32/false # Tree-is-atom - 8044 0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32 - 8045 # if index has type (offset ...) - 8046 (is-simple-mu-type? *(eax+4) 7) # Tree-left, offset => eax - 8047 3d/compare-eax-and 0/imm32/false - 8048 { - 8049 0f 84/jump-if-= break/disp32 - 8050 # print index->register - 8051 $translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index: - 8052 (write-buffered *(ebp+8) *(edx+0x10)) # Var-register - 8053 } - 8054 $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done: - 8055 (write-buffered *(ebp+8) ") ") - 8056 e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32 - 8057 } - 8058 # otherwise if index is a literal - 8059 (is-simple-mu-type? *(edx+4) 0) # Var-type => eax - 8060 3d/compare-eax-and 0/imm32/false - 8061 { - 8062 0f 84/jump-if-= break/disp32 - 8063 $translate-mu-index-stmt-with-array-on-stack:emit-literal-index: - 8064 # var idx-value/edx: int = parse-hex-int(index->name) - 8065 (parse-hex-int *edx) # Var-name => eax - 8066 89/<- %ebx 0/r32/eax - 8067 # offset = idx-value * size-of(element-type(base->type)) - 8068 (array-element-type-id %ecx) # => eax - 8069 (size-of-type-id %eax) # => eax - 8070 f7 4/subop/multiply-into-eax %ebx # clobbers edx - 8071 # offset += base->offset - 8072 03/add *(ecx+0xc) 0/r32/eax # Var-offset - 8073 # offset += 4 for array size - 8074 05/add-to-eax 4/imm32 - 8075 # TODO: check edx for overflow - 8076 # print offset - 8077 (print-int32-buffered *(ebp+8) %eax) - 8078 (write-buffered *(ebp+8) ") ") - 8079 e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32 - 8080 } - 8081 # otherwise abort - 8082 e9/jump $translate-mu-index-stmt-with-array:error1/disp32 - 8083 $translate-mu-index-stmt-with-array-on-stack:emit-output: - 8084 # outputs[0] "/r32" - 8085 8b/-> *(ebp+0xc) 0/r32/eax - 8086 8b/-> *(eax+0xc) 0/r32/eax # Stmt1-outputs - 8087 8b/-> *eax 0/r32/eax # Stmt-var-value - 8088 (get Registers *(eax+0x10) 8 "Registers") # Var-register => eax - 8089 (print-int32-buffered *(ebp+8) *eax) - 8090 (write-buffered *(ebp+8) "/r32\n") - 8091 $translate-mu-index-stmt-with-array-on-stack:end: - 8092 # . restore registers - 8093 5b/pop-to-ebx - 8094 5a/pop-to-edx - 8095 59/pop-to-ecx - 8096 58/pop-to-eax - 8097 # . epilogue - 8098 89/<- %esp 5/r32/ebp - 8099 5d/pop-to-ebp - 8100 c3/return - 8101 - 8102 translate-mu-compute-index-stmt: # out: (address buffered-file), stmt: (handle stmt) - 8103 # . prologue - 8104 55/push-ebp - 8105 89/<- %ebp 4/r32/esp - 8106 # . save registers - 8107 50/push-eax - 8108 51/push-ecx - 8109 52/push-edx - 8110 53/push-ebx - 8111 # - 8112 (emit-indent *(ebp+8) *Curr-block-depth) - 8113 (write-buffered *(ebp+8) "69/multiply") - 8114 # ecx = stmt - 8115 8b/-> *(ebp+0xc) 1/r32/ecx - 8116 # var first-inout/edx: (handle stmt-var) = stmt->inouts[0] - 8117 8b/-> *(ecx+8) 2/r32/edx # Stmt1-inouts - 8118 $translate-mu-compute-index-stmt:emit-index: - 8119 (emit-subx-var-as-rm32 *(ebp+8) *(edx+4)) # Stmt-var-next - 8120 (write-buffered *(ebp+8) Space) - 8121 $translate-mu-compute-index-stmt:emit-elem-size: - 8122 # var base/ebx: (handle var) - 8123 8b/-> *edx 3/r32/ebx # Stmt-var-value - 8124 # print size-of(element(base->type)) - 8125 (array-element-type-id %ebx) # => eax - 8126 (size-of-type-id %eax) # => eax - 8127 (print-int32-buffered *(ebp+8) %eax) - 8128 (write-buffered *(ebp+8) "/imm32 ") - 8129 $translate-mu-compute-index-stmt:emit-output: - 8130 # outputs[0] "/r32" - 8131 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs - 8132 8b/-> *eax 0/r32/eax # Stmt-var-value - 8133 (get Registers *(eax+0x10) 8 "Registers") # Var-register => eax - 8134 (print-int32-buffered *(ebp+8) *eax) - 8135 (write-buffered *(ebp+8) "/r32\n") - 8136 $translate-mu-compute-index-stmt:end: - 8137 # . restore registers - 8138 5b/pop-to-ebx - 8139 5a/pop-to-edx - 8140 59/pop-to-ecx - 8141 58/pop-to-eax - 8142 # . epilogue - 8143 89/<- %esp 5/r32/ebp - 8144 5d/pop-to-ebp - 8145 c3/return - 8146 - 8147 translate-mu-get-stmt: # out: (address buffered-file), stmt: (handle stmt) - 8148 # . prologue - 8149 55/push-ebp - 8150 89/<- %ebp 4/r32/esp - 8151 # . save registers - 8152 50/push-eax - 8153 51/push-ecx - 8154 52/push-edx - 8155 # - 8156 (emit-indent *(ebp+8) *Curr-block-depth) - 8157 (write-buffered *(ebp+8) "8d/copy-address ") - 8158 # ecx = stmt - 8159 8b/-> *(ebp+0xc) 1/r32/ecx - 8160 # var offset/edx: int = get offset of stmt - 8161 (mu-get-offset %ecx) # => eax - 8162 89/<- %edx 0/r32/eax - 8163 # var base/eax: (handle var) = stmt->inouts[0] - 8164 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts - 8165 8b/-> *eax 0/r32/eax # Stmt-var-value - 8166 # if base is in a register - 8167 81 7/subop/compare *(eax+0x10) 0/imm32 - 8168 { - 8169 0f 84/jump-if-= break/disp32 - 8170 $translate-mu-get-stmt:emit-register-input: - 8171 # "*(" inouts[0]->register " + " offset ")" - 8172 (write-buffered *(ebp+8) "*(") - 8173 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register - 8174 (write-buffered *(ebp+8) " + ") - 8175 (print-int32-buffered *(ebp+8) %edx) - 8176 (write-buffered *(ebp+8) ") ") - 8177 e9/jump $translate-mu-get-stmt:emit-output/disp32 - 8178 } - 8179 # otherwise base is on the stack - 8180 { - 8181 $translate-mu-get-stmt:emit-stack-input: - 8182 # "*(ebp + " inouts[0]->offset + offset ")" - 8183 (write-buffered *(ebp+8) "*(ebp+") - 8184 03/add *(eax+0xc) 2/r32/edx # Var-offset - 8185 (print-int32-buffered *(ebp+8) %edx) - 8186 (write-buffered *(ebp+8) ") ") - 8187 eb/jump $translate-mu-get-stmt:emit-output/disp8 - 8188 } - 8189 $translate-mu-get-stmt:emit-output: - 8190 # outputs[0] "/r32" - 8191 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs - 8192 8b/-> *eax 0/r32/eax # Stmt-var-value - 8193 (get Registers *(eax+0x10) 8 "Registers") # Var-register => eax - 8194 (print-int32-buffered *(ebp+8) *eax) - 8195 (write-buffered *(ebp+8) "/r32\n") - 8196 $translate-mu-get-stmt:end: - 8197 # . restore registers - 8198 5a/pop-to-edx - 8199 59/pop-to-ecx - 8200 58/pop-to-eax - 8201 # . epilogue - 8202 89/<- %esp 5/r32/ebp - 8203 5d/pop-to-ebp - 8204 c3/return - 8205 - 8206 array-element-type-id: # v: (handle var) -> result/eax: type-id - 8207 # precondition: n is positive - 8208 # . prologue - 8209 55/push-ebp - 8210 89/<- %ebp 4/r32/esp - 8211 # - 8212 8b/-> *(ebp+8) 0/r32/eax - 8213 8b/-> *(eax+4) 0/r32/eax # Var-type - 8214 # TODO: ensure type->left is 'addr' - 8215 8b/-> *(eax+8) 0/r32/eax # Tree-right - 8216 # TODO: ensure that type->right is non-null - 8217 # TODO: ensure that type->right->left is 'array' - 8218 8b/-> *(eax+8) 0/r32/eax # Tree-right - 8219 # TODO: ensure that type->right->right is non-null - 8220 8b/-> *(eax+4) 0/r32/eax # Tree-left - 8221 8b/-> *(eax+4) 0/r32/eax # Tree-value - 8222 $array-element-type-id:end: - 8223 # . epilogue - 8224 89/<- %esp 5/r32/ebp - 8225 5d/pop-to-ebp - 8226 c3/return - 8227 - 8228 num-shift-rights: # n: int -> result/eax: int - 8229 # precondition: n is a positive power of 2 - 8230 # . prologue - 8231 55/push-ebp - 8232 89/<- %ebp 4/r32/esp - 8233 # . save registers - 8234 51/push-ecx - 8235 # var curr/ecx: int = n - 8236 8b/-> *(ebp+8) 1/r32/ecx - 8237 # result = 0 - 8238 b8/copy-to-eax 0/imm32 - 8239 { - 8240 # if (curr <= 1) break - 8241 81 7/subop/compare %ecx 1/imm32 - 8242 7e/jump-if-<= break/disp8 - 8243 40/increment-eax - 8244 c1/shift 5/subop/arithmetic-right %ecx 1/imm8 - 8245 eb/jump loop/disp8 - 8246 } - 8247 $num-shift-rights:end: - 8248 # . restore registers - 8249 59/pop-to-ecx - 8250 # . epilogue - 8251 89/<- %esp 5/r32/ebp - 8252 5d/pop-to-ebp - 8253 c3/return - 8254 - 8255 mu-get-offset: # stmt: (handle stmt) -> result/eax: int - 8256 # . prologue - 8257 55/push-ebp - 8258 89/<- %ebp 4/r32/esp - 8259 # var second-inout/eax: (handle stmt-var) = stmt->inouts->next - 8260 8b/-> *(ebp+8) 0/r32/eax - 8261 8b/-> *(eax+8) 0/r32/eax # Stmt1-inouts - 8262 8b/-> *(eax+4) 0/r32/eax # Stmt-var-next - 8263 # var output-var/eax: (handle var) = second-inout->value - 8264 8b/-> *eax 0/r32/eax # Stmt-var-value - 8265 # return output-var->offset - 8266 8b/-> *(eax+0xc) 0/r32/eax # Var-offset - 8267 $emit-get-offset:end: - 8268 # . epilogue - 8269 89/<- %esp 5/r32/ebp - 8270 5d/pop-to-ebp - 8271 c3/return - 8272 - 8273 emit-subx-block: # out: (addr buffered-file), block: (handle block), vars: (addr stack (handle var)) - 8274 # . prologue - 8275 55/push-ebp - 8276 89/<- %ebp 4/r32/esp - 8277 # . save registers - 8278 50/push-eax - 8279 51/push-ecx - 8280 56/push-esi - 8281 # esi = block - 8282 8b/-> *(ebp+0xc) 6/r32/esi - 8283 # block->var->block-depth = *Curr-block-depth - 8284 8b/-> *(esi+8) 0/r32/eax # Block-var - 8285 8b/-> *Curr-block-depth 1/r32/ecx - 8286 89/<- *(eax+8) 1/r32/ecx # Var-block-depth - 8287 # var stmts/eax: (handle list stmt) = block->statements - 8288 8b/-> *(esi+4) 0/r32/eax # Block-stmts - 8289 # - 8290 { - 8291 $emit-subx-block:check-empty: - 8292 3d/compare-eax-and 0/imm32 - 8293 0f 84/jump-if-= break/disp32 - 8294 (emit-indent *(ebp+8) *Curr-block-depth) - 8295 (write-buffered *(ebp+8) "{\n") - 8296 # var v/ecx: (handle var) - 8297 8b/-> *(esi+8) 1/r32/ecx # Block-var - 8298 # - 8299 (write-buffered *(ebp+8) *ecx) # Var-name - 8300 (write-buffered *(ebp+8) ":loop:\n") - 8301 ff 0/subop/increment *Curr-block-depth - 8302 (push *(ebp+0x10) %ecx) - 8303 (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10)) - 8304 (pop *(ebp+0x10)) # => eax - 8305 ff 1/subop/decrement *Curr-block-depth - 8306 (emit-indent *(ebp+8) *Curr-block-depth) - 8307 (write-buffered *(ebp+8) "}\n") - 8308 (write-buffered *(ebp+8) *ecx) # Var-name - 8309 (write-buffered *(ebp+8) ":break:\n") - 8310 } - 8311 $emit-subx-block:end: - 8312 # . restore registers - 8313 5e/pop-to-esi - 8314 59/pop-to-ecx - 8315 58/pop-to-eax - 8316 # . epilogue - 8317 89/<- %esp 5/r32/ebp - 8318 5d/pop-to-ebp - 8319 c3/return - 8320 - 8321 # Primitives supported - 8322 # For each operation, put variants with hard-coded registers before flexible ones. - 8323 == data - 8324 Primitives: - 8325 # - increment/decrement - 8326 _Primitive-inc-eax: - 8327 # var/eax <- increment => 40/increment-eax - 8328 "increment"/imm32/name - 8329 0/imm32/no-inouts - 8330 Single-int-var-in-eax/imm32/outputs - 8331 "40/increment-eax"/imm32/subx-name - 8332 0/imm32/no-rm32 - 8333 0/imm32/no-r32 - 8334 0/imm32/no-imm32 - 8335 0/imm32/no-disp32 - 8336 0/imm32/output-is-write-only - 8337 _Primitive-inc-ecx/imm32/next - 8338 _Primitive-inc-ecx: - 8339 # var/ecx <- increment => 41/increment-ecx - 8340 "increment"/imm32/name - 8341 0/imm32/no-inouts - 8342 Single-int-var-in-ecx/imm32/outputs - 8343 "41/increment-ecx"/imm32/subx-name - 8344 0/imm32/no-rm32 - 8345 0/imm32/no-r32 - 8346 0/imm32/no-imm32 - 8347 0/imm32/no-disp32 - 8348 0/imm32/output-is-write-only - 8349 _Primitive-inc-edx/imm32/next - 8350 _Primitive-inc-edx: - 8351 # var/edx <- increment => 42/increment-edx - 8352 "increment"/imm32/name - 8353 0/imm32/no-inouts - 8354 Single-int-var-in-edx/imm32/outputs - 8355 "42/increment-edx"/imm32/subx-name - 8356 0/imm32/no-rm32 - 8357 0/imm32/no-r32 - 8358 0/imm32/no-imm32 - 8359 0/imm32/no-disp32 - 8360 0/imm32/output-is-write-only - 8361 _Primitive-inc-ebx/imm32/next - 8362 _Primitive-inc-ebx: - 8363 # var/ebx <- increment => 43/increment-ebx - 8364 "increment"/imm32/name - 8365 0/imm32/no-inouts - 8366 Single-int-var-in-ebx/imm32/outputs - 8367 "43/increment-ebx"/imm32/subx-name - 8368 0/imm32/no-rm32 - 8369 0/imm32/no-r32 - 8370 0/imm32/no-imm32 - 8371 0/imm32/no-disp32 - 8372 0/imm32/output-is-write-only - 8373 _Primitive-inc-esi/imm32/next - 8374 _Primitive-inc-esi: - 8375 # var/esi <- increment => 46/increment-esi - 8376 "increment"/imm32/name - 8377 0/imm32/no-inouts - 8378 Single-int-var-in-esi/imm32/outputs - 8379 "46/increment-esi"/imm32/subx-name - 8380 0/imm32/no-rm32 - 8381 0/imm32/no-r32 - 8382 0/imm32/no-imm32 - 8383 0/imm32/no-disp32 - 8384 0/imm32/output-is-write-only - 8385 _Primitive-inc-edi/imm32/next - 8386 _Primitive-inc-edi: - 8387 # var/edi <- increment => 47/increment-edi - 8388 "increment"/imm32/name - 8389 0/imm32/no-inouts - 8390 Single-int-var-in-edi/imm32/outputs - 8391 "47/increment-edi"/imm32/subx-name - 8392 0/imm32/no-rm32 - 8393 0/imm32/no-r32 - 8394 0/imm32/no-imm32 - 8395 0/imm32/no-disp32 - 8396 0/imm32/output-is-write-only - 8397 _Primitive-dec-eax/imm32/next - 8398 _Primitive-dec-eax: - 8399 # var/eax <- decrement => 48/decrement-eax - 8400 "decrement"/imm32/name - 8401 0/imm32/no-inouts - 8402 Single-int-var-in-eax/imm32/outputs - 8403 "48/decrement-eax"/imm32/subx-name - 8404 0/imm32/no-rm32 - 8405 0/imm32/no-r32 - 8406 0/imm32/no-imm32 - 8407 0/imm32/no-disp32 - 8408 0/imm32/output-is-write-only - 8409 _Primitive-dec-ecx/imm32/next - 8410 _Primitive-dec-ecx: - 8411 # var/ecx <- decrement => 49/decrement-ecx - 8412 "decrement"/imm32/name - 8413 0/imm32/no-inouts - 8414 Single-int-var-in-ecx/imm32/outputs - 8415 "49/decrement-ecx"/imm32/subx-name - 8416 0/imm32/no-rm32 - 8417 0/imm32/no-r32 - 8418 0/imm32/no-imm32 - 8419 0/imm32/no-disp32 - 8420 0/imm32/output-is-write-only - 8421 _Primitive-dec-edx/imm32/next - 8422 _Primitive-dec-edx: - 8423 # var/edx <- decrement => 4a/decrement-edx - 8424 "decrement"/imm32/name - 8425 0/imm32/no-inouts - 8426 Single-int-var-in-edx/imm32/outputs - 8427 "4a/decrement-edx"/imm32/subx-name - 8428 0/imm32/no-rm32 - 8429 0/imm32/no-r32 - 8430 0/imm32/no-imm32 - 8431 0/imm32/no-disp32 - 8432 0/imm32/output-is-write-only - 8433 _Primitive-dec-ebx/imm32/next - 8434 _Primitive-dec-ebx: - 8435 # var/ebx <- decrement => 4b/decrement-ebx - 8436 "decrement"/imm32/name - 8437 0/imm32/no-inouts - 8438 Single-int-var-in-ebx/imm32/outputs - 8439 "4b/decrement-ebx"/imm32/subx-name - 8440 0/imm32/no-rm32 - 8441 0/imm32/no-r32 - 8442 0/imm32/no-imm32 - 8443 0/imm32/no-disp32 - 8444 0/imm32/output-is-write-only - 8445 _Primitive-dec-esi/imm32/next - 8446 _Primitive-dec-esi: - 8447 # var/esi <- decrement => 4e/decrement-esi - 8448 "decrement"/imm32/name - 8449 0/imm32/no-inouts - 8450 Single-int-var-in-esi/imm32/outputs - 8451 "4e/decrement-esi"/imm32/subx-name - 8452 0/imm32/no-rm32 - 8453 0/imm32/no-r32 - 8454 0/imm32/no-imm32 - 8455 0/imm32/no-disp32 - 8456 0/imm32/output-is-write-only - 8457 _Primitive-dec-edi/imm32/next - 8458 _Primitive-dec-edi: - 8459 # var/edi <- decrement => 4f/decrement-edi - 8460 "decrement"/imm32/name - 8461 0/imm32/no-inouts - 8462 Single-int-var-in-edi/imm32/outputs - 8463 "4f/decrement-edi"/imm32/subx-name - 8464 0/imm32/no-rm32 - 8465 0/imm32/no-r32 - 8466 0/imm32/no-imm32 - 8467 0/imm32/no-disp32 - 8468 0/imm32/output-is-write-only - 8469 _Primitive-inc-mem/imm32/next - 8470 _Primitive-inc-mem: - 8471 # increment var => ff 0/subop/increment *(ebp+__) - 8472 "increment"/imm32/name - 8473 Single-int-var-in-mem/imm32/inouts - 8474 0/imm32/no-outputs - 8475 "ff 0/subop/increment"/imm32/subx-name - 8476 1/imm32/rm32-is-first-inout - 8477 0/imm32/no-r32 - 8478 0/imm32/no-imm32 - 8479 0/imm32/no-disp32 - 8480 0/imm32/output-is-write-only - 8481 _Primitive-inc-reg/imm32/next - 8482 _Primitive-inc-reg: - 8483 # var/reg <- increment => ff 0/subop/increment %__ - 8484 "increment"/imm32/name - 8485 0/imm32/no-inouts - 8486 Single-int-var-in-some-register/imm32/outputs - 8487 "ff 0/subop/increment"/imm32/subx-name - 8488 3/imm32/rm32-is-first-output - 8489 0/imm32/no-r32 - 8490 0/imm32/no-imm32 - 8491 0/imm32/no-disp32 - 8492 0/imm32/output-is-write-only - 8493 _Primitive-dec-mem/imm32/next - 8494 _Primitive-dec-mem: - 8495 # decrement var => ff 1/subop/decrement *(ebp+__) - 8496 "decrement"/imm32/name - 8497 Single-int-var-in-mem/imm32/inouts - 8498 0/imm32/no-outputs - 8499 "ff 1/subop/decrement"/imm32/subx-name - 8500 1/imm32/rm32-is-first-inout - 8501 0/imm32/no-r32 - 8502 0/imm32/no-imm32 - 8503 0/imm32/no-disp32 - 8504 0/imm32/output-is-write-only - 8505 _Primitive-dec-reg/imm32/next - 8506 _Primitive-dec-reg: - 8507 # var/reg <- decrement => ff 1/subop/decrement %__ - 8508 "decrement"/imm32/name - 8509 0/imm32/no-inouts - 8510 Single-int-var-in-some-register/imm32/outputs - 8511 "ff 1/subop/decrement"/imm32/subx-name - 8512 3/imm32/rm32-is-first-output - 8513 0/imm32/no-r32 - 8514 0/imm32/no-imm32 - 8515 0/imm32/no-disp32 - 8516 0/imm32/output-is-write-only - 8517 _Primitive-add-to-eax/imm32/next - 8518 # - add - 8519 _Primitive-add-to-eax: - 8520 # var/eax <- add lit => 05/add-to-eax lit/imm32 - 8521 "add"/imm32/name - 8522 Single-lit-var/imm32/inouts - 8523 Single-int-var-in-eax/imm32/outputs - 8524 "05/add-to-eax"/imm32/subx-name - 8525 0/imm32/no-rm32 - 8526 0/imm32/no-r32 - 8527 1/imm32/imm32-is-first-inout - 8528 0/imm32/no-disp32 - 8529 0/imm32/output-is-write-only - 8530 _Primitive-add-reg-to-reg/imm32/next - 8531 _Primitive-add-reg-to-reg: - 8532 # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32 - 8533 "add"/imm32/name - 8534 Single-int-var-in-some-register/imm32/inouts - 8535 Single-int-var-in-some-register/imm32/outputs - 8536 "01/add-to"/imm32/subx-name - 8537 3/imm32/rm32-is-first-output - 8538 1/imm32/r32-is-first-inout - 8539 0/imm32/no-imm32 - 8540 0/imm32/no-disp32 - 8541 0/imm32/output-is-write-only - 8542 _Primitive-add-reg-to-mem/imm32/next - 8543 _Primitive-add-reg-to-mem: - 8544 # add-to var1 var2/reg => 01/add-to var1 var2/r32 - 8545 "add-to"/imm32/name - 8546 Two-args-int-stack-int-reg/imm32/inouts - 8547 0/imm32/outputs - 8548 "01/add-to"/imm32/subx-name - 8549 1/imm32/rm32-is-first-inout - 8550 2/imm32/r32-is-second-inout - 8551 0/imm32/no-imm32 - 8552 0/imm32/no-disp32 - 8553 0/imm32/output-is-write-only - 8554 _Primitive-add-mem-to-reg/imm32/next - 8555 _Primitive-add-mem-to-reg: - 8556 # var1/reg <- add var2 => 03/add var2/rm32 var1/r32 - 8557 "add"/imm32/name - 8558 Single-int-var-in-mem/imm32/inouts - 8559 Single-int-var-in-some-register/imm32/outputs - 8560 "03/add"/imm32/subx-name - 8561 1/imm32/rm32-is-first-inout - 8562 3/imm32/r32-is-first-output - 8563 0/imm32/no-imm32 - 8564 0/imm32/no-disp32 - 8565 0/imm32/output-is-write-only - 8566 _Primitive-add-lit-to-reg/imm32/next - 8567 _Primitive-add-lit-to-reg: - 8568 # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32 - 8569 "add"/imm32/name - 8570 Single-lit-var/imm32/inouts - 8571 Single-int-var-in-some-register/imm32/outputs - 8572 "81 0/subop/add"/imm32/subx-name - 8573 3/imm32/rm32-is-first-output - 8574 0/imm32/no-r32 - 8575 1/imm32/imm32-is-first-inout - 8576 0/imm32/no-disp32 - 8577 0/imm32/output-is-write-only - 8578 _Primitive-add-lit-to-mem/imm32/next - 8579 _Primitive-add-lit-to-mem: - 8580 # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32 - 8581 "add-to"/imm32/name - 8582 Int-var-and-literal/imm32/inouts - 8583 0/imm32/outputs - 8584 "81 0/subop/add"/imm32/subx-name - 8585 1/imm32/rm32-is-first-inout - 8586 0/imm32/no-r32 - 8587 2/imm32/imm32-is-second-inout - 8588 0/imm32/no-disp32 - 8589 0/imm32/output-is-write-only - 8590 _Primitive-subtract-from-eax/imm32/next - 8591 # - subtract - 8592 _Primitive-subtract-from-eax: - 8593 # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32 - 8594 "subtract"/imm32/name - 8595 Single-lit-var/imm32/inouts - 8596 Single-int-var-in-eax/imm32/outputs - 8597 "2d/subtract-from-eax"/imm32/subx-name - 8598 0/imm32/no-rm32 - 8599 0/imm32/no-r32 - 8600 1/imm32/imm32-is-first-inout - 8601 0/imm32/no-disp32 - 8602 0/imm32/output-is-write-only - 8603 _Primitive-subtract-reg-from-reg/imm32/next - 8604 _Primitive-subtract-reg-from-reg: - 8605 # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32 - 8606 "subtract"/imm32/name - 8607 Single-int-var-in-some-register/imm32/inouts - 8608 Single-int-var-in-some-register/imm32/outputs - 8609 "29/subtract-from"/imm32/subx-name - 8610 3/imm32/rm32-is-first-output - 8611 1/imm32/r32-is-first-inout - 8612 0/imm32/no-imm32 - 8613 0/imm32/no-disp32 - 8614 0/imm32/output-is-write-only - 8615 _Primitive-subtract-reg-from-mem/imm32/next - 8616 _Primitive-subtract-reg-from-mem: - 8617 # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32 - 8618 "subtract-from"/imm32/name - 8619 Two-args-int-stack-int-reg/imm32/inouts - 8620 0/imm32/outputs - 8621 "29/subtract-from"/imm32/subx-name - 8622 1/imm32/rm32-is-first-inout - 8623 2/imm32/r32-is-second-inout - 8624 0/imm32/no-imm32 - 8625 0/imm32/no-disp32 - 8626 0/imm32/output-is-write-only - 8627 _Primitive-subtract-mem-from-reg/imm32/next - 8628 _Primitive-subtract-mem-from-reg: - 8629 # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32 - 8630 "subtract"/imm32/name - 8631 Single-int-var-in-mem/imm32/inouts - 8632 Single-int-var-in-some-register/imm32/outputs - 8633 "2b/subtract"/imm32/subx-name - 8634 1/imm32/rm32-is-first-inout - 8635 3/imm32/r32-is-first-output - 8636 0/imm32/no-imm32 - 8637 0/imm32/no-disp32 - 8638 0/imm32/output-is-write-only - 8639 _Primitive-subtract-lit-from-reg/imm32/next - 8640 _Primitive-subtract-lit-from-reg: - 8641 # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32 - 8642 "subtract"/imm32/name - 8643 Single-lit-var/imm32/inouts - 8644 Single-int-var-in-some-register/imm32/outputs - 8645 "81 5/subop/subtract"/imm32/subx-name - 8646 3/imm32/rm32-is-first-output - 8647 0/imm32/no-r32 - 8648 1/imm32/imm32-is-first-inout - 8649 0/imm32/no-disp32 - 8650 0/imm32/output-is-write-only - 8651 _Primitive-subtract-lit-from-mem/imm32/next - 8652 _Primitive-subtract-lit-from-mem: - 8653 # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32 - 8654 "subtract-from"/imm32/name - 8655 Int-var-and-literal/imm32/inouts - 8656 0/imm32/outputs - 8657 "81 5/subop/subtract"/imm32/subx-name - 8658 1/imm32/rm32-is-first-inout - 8659 0/imm32/no-r32 - 8660 2/imm32/imm32-is-first-inout - 8661 0/imm32/no-disp32 - 8662 0/imm32/output-is-write-only - 8663 _Primitive-and-with-eax/imm32/next - 8664 # - and - 8665 _Primitive-and-with-eax: - 8666 # var/eax <- and lit => 25/and-with-eax lit/imm32 - 8667 "and"/imm32/name - 8668 Single-lit-var/imm32/inouts - 8669 Single-int-var-in-eax/imm32/outputs - 8670 "25/and-with-eax"/imm32/subx-name - 8671 0/imm32/no-rm32 - 8672 0/imm32/no-r32 - 8673 1/imm32/imm32-is-first-inout - 8674 0/imm32/no-disp32 - 8675 0/imm32/output-is-write-only - 8676 _Primitive-and-reg-with-reg/imm32/next - 8677 _Primitive-and-reg-with-reg: - 8678 # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32 - 8679 "and"/imm32/name - 8680 Single-int-var-in-some-register/imm32/inouts - 8681 Single-int-var-in-some-register/imm32/outputs - 8682 "21/and-with"/imm32/subx-name - 8683 3/imm32/rm32-is-first-output - 8684 1/imm32/r32-is-first-inout - 8685 0/imm32/no-imm32 - 8686 0/imm32/no-disp32 - 8687 0/imm32/output-is-write-only - 8688 _Primitive-and-reg-with-mem/imm32/next - 8689 _Primitive-and-reg-with-mem: - 8690 # and-with var1 var2/reg => 21/and-with var1 var2/r32 - 8691 "and-with"/imm32/name - 8692 Two-args-int-stack-int-reg/imm32/inouts - 8693 0/imm32/outputs - 8694 "21/and-with"/imm32/subx-name - 8695 1/imm32/rm32-is-first-inout - 8696 2/imm32/r32-is-second-inout - 8697 0/imm32/no-imm32 - 8698 0/imm32/no-disp32 - 8699 0/imm32/output-is-write-only - 8700 _Primitive-and-mem-with-reg/imm32/next - 8701 _Primitive-and-mem-with-reg: - 8702 # var1/reg <- and var2 => 23/and var2/rm32 var1/r32 - 8703 "and"/imm32/name - 8704 Single-int-var-in-mem/imm32/inouts - 8705 Single-int-var-in-some-register/imm32/outputs - 8706 "23/and"/imm32/subx-name - 8707 1/imm32/rm32-is-first-inout - 8708 3/imm32/r32-is-first-output - 8709 0/imm32/no-imm32 - 8710 0/imm32/no-disp32 - 8711 0/imm32/output-is-write-only - 8712 _Primitive-and-lit-with-reg/imm32/next - 8713 _Primitive-and-lit-with-reg: - 8714 # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32 - 8715 "and"/imm32/name - 8716 Single-lit-var/imm32/inouts - 8717 Single-int-var-in-some-register/imm32/outputs - 8718 "81 4/subop/and"/imm32/subx-name - 8719 3/imm32/rm32-is-first-output - 8720 0/imm32/no-r32 - 8721 1/imm32/imm32-is-first-inout - 8722 0/imm32/no-disp32 - 8723 0/imm32/output-is-write-only - 8724 _Primitive-and-lit-with-mem/imm32/next - 8725 _Primitive-and-lit-with-mem: - 8726 # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32 - 8727 "and-with"/imm32/name - 8728 Int-var-and-literal/imm32/inouts - 8729 0/imm32/outputs - 8730 "81 4/subop/and"/imm32/subx-name - 8731 1/imm32/rm32-is-first-inout - 8732 0/imm32/no-r32 - 8733 2/imm32/imm32-is-first-inout - 8734 0/imm32/no-disp32 - 8735 0/imm32/output-is-write-only - 8736 _Primitive-or-with-eax/imm32/next - 8737 # - or - 8738 _Primitive-or-with-eax: - 8739 # var/eax <- or lit => 0d/or-with-eax lit/imm32 - 8740 "or"/imm32/name - 8741 Single-lit-var/imm32/inouts - 8742 Single-int-var-in-eax/imm32/outputs - 8743 "0d/or-with-eax"/imm32/subx-name - 8744 0/imm32/no-rm32 - 8745 0/imm32/no-r32 - 8746 1/imm32/imm32-is-first-inout - 8747 0/imm32/no-disp32 - 8748 0/imm32/output-is-write-only - 8749 _Primitive-or-reg-with-reg/imm32/next - 8750 _Primitive-or-reg-with-reg: - 8751 # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32 - 8752 "or"/imm32/name - 8753 Single-int-var-in-some-register/imm32/inouts - 8754 Single-int-var-in-some-register/imm32/outputs - 8755 "09/or-with"/imm32/subx-name - 8756 3/imm32/rm32-is-first-output - 8757 1/imm32/r32-is-first-inout - 8758 0/imm32/no-imm32 - 8759 0/imm32/no-disp32 - 8760 0/imm32/output-is-write-only - 8761 _Primitive-or-reg-with-mem/imm32/next - 8762 _Primitive-or-reg-with-mem: - 8763 # or-with var1 var2/reg => 09/or-with var1 var2/r32 - 8764 "or-with"/imm32/name - 8765 Two-args-int-stack-int-reg/imm32/inouts - 8766 0/imm32/outputs - 8767 "09/or-with"/imm32/subx-name - 8768 1/imm32/rm32-is-first-inout - 8769 2/imm32/r32-is-second-inout - 8770 0/imm32/no-imm32 - 8771 0/imm32/no-disp32 - 8772 0/imm32/output-is-write-only - 8773 _Primitive-or-mem-with-reg/imm32/next - 8774 _Primitive-or-mem-with-reg: - 8775 # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32 - 8776 "or"/imm32/name - 8777 Single-int-var-in-mem/imm32/inouts - 8778 Single-int-var-in-some-register/imm32/outputs - 8779 "0b/or"/imm32/subx-name - 8780 1/imm32/rm32-is-first-inout - 8781 3/imm32/r32-is-first-output - 8782 0/imm32/no-imm32 - 8783 0/imm32/no-disp32 - 8784 0/imm32/output-is-write-only - 8785 _Primitive-or-lit-with-reg/imm32/next - 8786 _Primitive-or-lit-with-reg: - 8787 # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32 - 8788 "or"/imm32/name - 8789 Single-lit-var/imm32/inouts - 8790 Single-int-var-in-some-register/imm32/outputs - 8791 "81 1/subop/or"/imm32/subx-name - 8792 3/imm32/rm32-is-first-output - 8793 0/imm32/no-r32 - 8794 1/imm32/imm32-is-first-inout - 8795 0/imm32/no-disp32 - 8796 0/imm32/output-is-write-only - 8797 _Primitive-or-lit-with-mem/imm32/next - 8798 _Primitive-or-lit-with-mem: - 8799 # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32 - 8800 "or-with"/imm32/name - 8801 Int-var-and-literal/imm32/inouts - 8802 0/imm32/outputs - 8803 "81 1/subop/or"/imm32/subx-name - 8804 1/imm32/rm32-is-first-inout - 8805 0/imm32/no-r32 - 8806 2/imm32/imm32-is-second-inout - 8807 0/imm32/no-disp32 - 8808 0/imm32/output-is-write-only - 8809 _Primitive-xor-with-eax/imm32/next - 8810 # - xor - 8811 _Primitive-xor-with-eax: - 8812 # var/eax <- xor lit => 35/xor-with-eax lit/imm32 - 8813 "xor"/imm32/name - 8814 Single-lit-var/imm32/inouts - 8815 Single-int-var-in-eax/imm32/outputs - 8816 "35/xor-with-eax"/imm32/subx-name - 8817 0/imm32/no-rm32 - 8818 0/imm32/no-r32 - 8819 1/imm32/imm32-is-first-inout - 8820 0/imm32/no-disp32 - 8821 0/imm32/output-is-write-only - 8822 _Primitive-xor-reg-with-reg/imm32/next - 8823 _Primitive-xor-reg-with-reg: - 8824 # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32 - 8825 "xor"/imm32/name - 8826 Single-int-var-in-some-register/imm32/inouts - 8827 Single-int-var-in-some-register/imm32/outputs - 8828 "31/xor-with"/imm32/subx-name - 8829 3/imm32/rm32-is-first-output - 8830 1/imm32/r32-is-first-inout - 8831 0/imm32/no-imm32 - 8832 0/imm32/no-disp32 - 8833 0/imm32/output-is-write-only - 8834 _Primitive-xor-reg-with-mem/imm32/next - 8835 _Primitive-xor-reg-with-mem: - 8836 # xor-with var1 var2/reg => 31/xor-with var1 var2/r32 - 8837 "xor-with"/imm32/name - 8838 Two-args-int-stack-int-reg/imm32/inouts - 8839 0/imm32/outputs - 8840 "31/xor-with"/imm32/subx-name - 8841 1/imm32/rm32-is-first-inout - 8842 2/imm32/r32-is-second-inout - 8843 0/imm32/no-imm32 - 8844 0/imm32/no-disp32 - 8845 0/imm32/output-is-write-only - 8846 _Primitive-xor-mem-with-reg/imm32/next - 8847 _Primitive-xor-mem-with-reg: - 8848 # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32 - 8849 "xor"/imm32/name - 8850 Single-int-var-in-mem/imm32/inouts - 8851 Single-int-var-in-some-register/imm32/outputs - 8852 "33/xor"/imm32/subx-name - 8853 1/imm32/rm32-is-first-inout - 8854 3/imm32/r32-is-first-output - 8855 0/imm32/no-imm32 - 8856 0/imm32/no-disp32 - 8857 0/imm32/output-is-write-only - 8858 _Primitive-xor-lit-with-reg/imm32/next - 8859 _Primitive-xor-lit-with-reg: - 8860 # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32 - 8861 "xor"/imm32/name - 8862 Single-lit-var/imm32/inouts - 8863 Single-int-var-in-some-register/imm32/outputs - 8864 "81 6/subop/xor"/imm32/subx-name - 8865 3/imm32/rm32-is-first-output - 8866 0/imm32/no-r32 - 8867 1/imm32/imm32-is-first-inout - 8868 0/imm32/no-disp32 - 8869 0/imm32/output-is-write-only - 8870 _Primitive-xor-lit-with-mem/imm32/next - 8871 _Primitive-xor-lit-with-mem: - 8872 # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32 - 8873 "xor-with"/imm32/name - 8874 Int-var-and-literal/imm32/inouts - 8875 0/imm32/outputs - 8876 "81 6/subop/xor"/imm32/subx-name - 8877 1/imm32/rm32-is-first-inout - 8878 0/imm32/no-r32 - 8879 2/imm32/imm32-is-first-inout - 8880 0/imm32/no-disp32 - 8881 0/imm32/output-is-write-only - 8882 _Primitive-copy-to-eax/imm32/next - 8883 # - copy - 8884 _Primitive-copy-to-eax: - 8885 # var/eax <- copy lit => b8/copy-to-eax lit/imm32 - 8886 "copy"/imm32/name - 8887 Single-lit-var/imm32/inouts - 8888 Single-int-var-in-eax/imm32/outputs - 8889 "b8/copy-to-eax"/imm32/subx-name - 8890 0/imm32/no-rm32 - 8891 0/imm32/no-r32 - 8892 1/imm32/imm32-is-first-inout - 8893 0/imm32/no-disp32 - 8894 1/imm32/output-is-write-only - 8895 _Primitive-copy-to-ecx/imm32/next - 8896 _Primitive-copy-to-ecx: - 8897 # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32 - 8898 "copy"/imm32/name - 8899 Single-lit-var/imm32/inouts - 8900 Single-int-var-in-ecx/imm32/outputs - 8901 "b9/copy-to-ecx"/imm32/subx-name - 8902 0/imm32/no-rm32 - 8903 0/imm32/no-r32 - 8904 1/imm32/imm32-is-first-inout - 8905 0/imm32/no-disp32 - 8906 1/imm32/output-is-write-only - 8907 _Primitive-copy-to-edx/imm32/next - 8908 _Primitive-copy-to-edx: - 8909 # var/edx <- copy lit => ba/copy-to-edx lit/imm32 - 8910 "copy"/imm32/name - 8911 Single-lit-var/imm32/inouts - 8912 Single-int-var-in-edx/imm32/outputs - 8913 "ba/copy-to-edx"/imm32/subx-name - 8914 0/imm32/no-rm32 - 8915 0/imm32/no-r32 - 8916 1/imm32/imm32-is-first-inout - 8917 0/imm32/no-disp32 - 8918 1/imm32/output-is-write-only - 8919 _Primitive-copy-to-ebx/imm32/next - 8920 _Primitive-copy-to-ebx: - 8921 # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32 - 8922 "copy"/imm32/name - 8923 Single-lit-var/imm32/inouts - 8924 Single-int-var-in-ebx/imm32/outputs - 8925 "bb/copy-to-ebx"/imm32/subx-name - 8926 0/imm32/no-rm32 - 8927 0/imm32/no-r32 - 8928 1/imm32/imm32-is-first-inout - 8929 0/imm32/no-disp32 - 8930 1/imm32/output-is-write-only - 8931 _Primitive-copy-to-esi/imm32/next - 8932 _Primitive-copy-to-esi: - 8933 # var/esi <- copy lit => be/copy-to-esi lit/imm32 - 8934 "copy"/imm32/name - 8935 Single-lit-var/imm32/inouts - 8936 Single-int-var-in-esi/imm32/outputs - 8937 "be/copy-to-esi"/imm32/subx-name - 8938 0/imm32/no-rm32 - 8939 0/imm32/no-r32 - 8940 1/imm32/imm32-is-first-inout - 8941 0/imm32/no-disp32 - 8942 1/imm32/output-is-write-only - 8943 _Primitive-copy-to-edi/imm32/next - 8944 _Primitive-copy-to-edi: - 8945 # var/edi <- copy lit => bf/copy-to-edi lit/imm32 - 8946 "copy"/imm32/name - 8947 Single-lit-var/imm32/inouts - 8948 Single-int-var-in-edi/imm32/outputs - 8949 "bf/copy-to-edi"/imm32/subx-name - 8950 0/imm32/no-rm32 - 8951 0/imm32/no-r32 - 8952 1/imm32/imm32-is-first-inout - 8953 0/imm32/no-disp32 - 8954 1/imm32/output-is-write-only - 8955 _Primitive-copy-reg-to-reg/imm32/next - 8956 _Primitive-copy-reg-to-reg: - 8957 # var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32 - 8958 "copy"/imm32/name - 8959 Single-int-var-in-some-register/imm32/inouts - 8960 Single-int-var-in-some-register/imm32/outputs - 8961 "89/<-"/imm32/subx-name - 8962 3/imm32/rm32-is-first-output - 8963 1/imm32/r32-is-first-inout - 8964 0/imm32/no-imm32 - 8965 0/imm32/no-disp32 - 8966 1/imm32/output-is-write-only - 8967 _Primitive-copy-reg-to-mem/imm32/next - 8968 _Primitive-copy-reg-to-mem: - 8969 # copy-to var1 var2/reg => 89/<- var1 var2/r32 - 8970 "copy-to"/imm32/name - 8971 Two-args-int-stack-int-reg/imm32/inouts - 8972 0/imm32/outputs - 8973 "89/<-"/imm32/subx-name - 8974 1/imm32/rm32-is-first-inout - 8975 2/imm32/r32-is-second-inout - 8976 0/imm32/no-imm32 - 8977 0/imm32/no-disp32 - 8978 1/imm32/output-is-write-only - 8979 _Primitive-copy-mem-to-reg/imm32/next - 8980 _Primitive-copy-mem-to-reg: - 8981 # var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32 - 8982 "copy"/imm32/name - 8983 Single-int-var-in-mem/imm32/inouts - 8984 Single-int-var-in-some-register/imm32/outputs - 8985 "8b/->"/imm32/subx-name - 8986 1/imm32/rm32-is-first-inout - 8987 3/imm32/r32-is-first-output - 8988 0/imm32/no-imm32 - 8989 0/imm32/no-disp32 - 8990 1/imm32/output-is-write-only - 8991 _Primitive-copy-lit-to-reg/imm32/next - 8992 _Primitive-copy-lit-to-reg: - 8993 # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32 - 8994 "copy"/imm32/name - 8995 Single-lit-var/imm32/inouts - 8996 Single-int-var-in-some-register/imm32/outputs - 8997 "c7 0/subop/copy"/imm32/subx-name - 8998 3/imm32/rm32-is-first-output - 8999 0/imm32/no-r32 - 9000 1/imm32/imm32-is-first-inout - 9001 0/imm32/no-disp32 - 9002 1/imm32/output-is-write-only - 9003 _Primitive-copy-lit-to-mem/imm32/next - 9004 _Primitive-copy-lit-to-mem: - 9005 # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32 - 9006 "copy-to"/imm32/name - 9007 Int-var-and-literal/imm32/inouts - 9008 0/imm32/outputs - 9009 "c7 0/subop/copy"/imm32/subx-name - 9010 1/imm32/rm32-is-first-inout - 9011 0/imm32/no-r32 - 9012 2/imm32/imm32-is-first-inout - 9013 0/imm32/no-disp32 - 9014 1/imm32/output-is-write-only - 9015 _Primitive-address/imm32/next - 9016 # - address - 9017 _Primitive-address: - 9018 # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32 - 9019 "address"/imm32/name - 9020 Single-int-var-in-mem/imm32/inouts - 9021 Single-addr-var-in-some-register/imm32/outputs - 9022 "8d/copy-address"/imm32/subx-name - 9023 1/imm32/rm32-is-first-inout - 9024 3/imm32/r32-is-first-output - 9025 0/imm32/no-imm32 - 9026 0/imm32/no-disp32 - 9027 1/imm32/output-is-write-only - 9028 _Primitive-compare-mem-with-reg/imm32/next - 9029 # - compare - 9030 _Primitive-compare-mem-with-reg: - 9031 # compare var1 var2/reg => 39/compare var1/rm32 var2/r32 - 9032 "compare"/imm32/name - 9033 Two-args-int-stack-int-reg/imm32/inouts - 9034 0/imm32/outputs - 9035 "39/compare->"/imm32/subx-name - 9036 1/imm32/rm32-is-first-inout - 9037 2/imm32/r32-is-second-inout - 9038 0/imm32/no-imm32 - 9039 0/imm32/no-disp32 - 9040 0/imm32/output-is-write-only - 9041 _Primitive-compare-reg-with-mem/imm32/next - 9042 _Primitive-compare-reg-with-mem: - 9043 # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32 - 9044 "compare"/imm32/name - 9045 Two-args-int-reg-int-stack/imm32/inouts - 9046 0/imm32/outputs - 9047 "3b/compare<-"/imm32/subx-name - 9048 2/imm32/rm32-is-second-inout - 9049 1/imm32/r32-is-first-inout - 9050 0/imm32/no-imm32 - 9051 0/imm32/no-disp32 - 9052 0/imm32/output-is-write-only - 9053 _Primitive-compare-eax-with-literal/imm32/next - 9054 _Primitive-compare-eax-with-literal: - 9055 # compare var1/eax n => 3d/compare-eax-with n/imm32 - 9056 "compare"/imm32/name - 9057 Two-args-int-eax-int-literal/imm32/inouts - 9058 0/imm32/outputs - 9059 "3d/compare-eax-with"/imm32/subx-name - 9060 0/imm32/no-rm32 - 9061 0/imm32/no-r32 - 9062 2/imm32/imm32-is-second-inout - 9063 0/imm32/no-disp32 - 9064 0/imm32/output-is-write-only - 9065 _Primitive-compare-reg-with-literal/imm32/next - 9066 _Primitive-compare-reg-with-literal: - 9067 # compare var1/reg n => 81 7/subop/compare %reg n/imm32 - 9068 "compare"/imm32/name - 9069 Int-var-in-register-and-literal/imm32/inouts - 9070 0/imm32/outputs - 9071 "81 7/subop/compare"/imm32/subx-name - 9072 1/imm32/rm32-is-first-inout - 9073 0/imm32/no-r32 - 9074 2/imm32/imm32-is-second-inout - 9075 0/imm32/no-disp32 - 9076 0/imm32/output-is-write-only - 9077 _Primitive-compare-mem-with-literal/imm32/next - 9078 _Primitive-compare-mem-with-literal: - 9079 # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32 - 9080 "compare"/imm32/name - 9081 Int-var-and-literal/imm32/inouts - 9082 0/imm32/outputs - 9083 "81 7/subop/compare"/imm32/subx-name - 9084 1/imm32/rm32-is-first-inout - 9085 0/imm32/no-r32 - 9086 2/imm32/imm32-is-second-inout - 9087 0/imm32/no-disp32 - 9088 0/imm32/output-is-write-only - 9089 _Primitive-multiply-reg-by-mem/imm32/next - 9090 # - multiply - 9091 _Primitive-multiply-reg-by-mem: - 9092 # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32 - 9093 "multiply"/imm32/name - 9094 Single-int-var-in-mem/imm32/inouts - 9095 Single-int-var-in-some-register/imm32/outputs - 9096 "0f af/multiply"/imm32/subx-name - 9097 1/imm32/rm32-is-first-inout - 9098 3/imm32/r32-is-first-output - 9099 0/imm32/no-imm32 - 9100 0/imm32/no-disp32 - 9101 0/imm32/output-is-write-only - 9102 _Primitive-break-if-addr</imm32/next - 9103 # - branches - 9104 _Primitive-break-if-addr<: - 9105 "break-if-addr<"/imm32/name - 9106 0/imm32/inouts - 9107 0/imm32/outputs - 9108 "0f 82/jump-if-addr< break/disp32"/imm32/subx-name - 9109 0/imm32/no-rm32 - 9110 0/imm32/no-r32 - 9111 0/imm32/no-imm32 - 9112 0/imm32/no-disp32 - 9113 0/imm32/no-output - 9114 _Primitive-break-if-addr>=/imm32/next - 9115 _Primitive-break-if-addr>=: - 9116 "break-if-addr>="/imm32/name - 9117 0/imm32/inouts - 9118 0/imm32/outputs - 9119 "0f 83/jump-if-addr>= break/disp32"/imm32/subx-name - 9120 0/imm32/no-rm32 - 9121 0/imm32/no-r32 - 9122 0/imm32/no-imm32 - 9123 0/imm32/no-disp32 - 9124 0/imm32/no-output - 9125 _Primitive-break-if-=/imm32/next - 9126 _Primitive-break-if-=: - 9127 "break-if-="/imm32/name - 9128 0/imm32/inouts - 9129 0/imm32/outputs - 9130 "0f 84/jump-if-= break/disp32"/imm32/subx-name - 9131 0/imm32/no-rm32 - 9132 0/imm32/no-r32 - 9133 0/imm32/no-imm32 - 9134 0/imm32/no-disp32 - 9135 0/imm32/no-output - 9136 _Primitive-break-if-!=/imm32/next - 9137 _Primitive-break-if-!=: - 9138 "break-if-!="/imm32/name - 9139 0/imm32/inouts - 9140 0/imm32/outputs - 9141 "0f 85/jump-if-!= break/disp32"/imm32/subx-name - 9142 0/imm32/no-rm32 - 9143 0/imm32/no-r32 - 9144 0/imm32/no-imm32 - 9145 0/imm32/no-disp32 - 9146 0/imm32/no-output - 9147 _Primitive-break-if-addr<=/imm32/next - 9148 _Primitive-break-if-addr<=: - 9149 "break-if-addr<="/imm32/name - 9150 0/imm32/inouts - 9151 0/imm32/outputs - 9152 "0f 86/jump-if-addr<= break/disp32"/imm32/subx-name - 9153 0/imm32/no-rm32 - 9154 0/imm32/no-r32 - 9155 0/imm32/no-imm32 - 9156 0/imm32/no-disp32 - 9157 0/imm32/no-output - 9158 _Primitive-break-if-addr>/imm32/next - 9159 _Primitive-break-if-addr>: - 9160 "break-if-addr>"/imm32/name - 9161 0/imm32/inouts - 9162 0/imm32/outputs - 9163 "0f 87/jump-if-addr> break/disp32"/imm32/subx-name - 9164 0/imm32/no-rm32 - 9165 0/imm32/no-r32 - 9166 0/imm32/no-imm32 - 9167 0/imm32/no-disp32 - 9168 0/imm32/no-output - 9169 _Primitive-break-if-</imm32/next - 9170 _Primitive-break-if-<: - 9171 "break-if-<"/imm32/name - 9172 0/imm32/inouts - 9173 0/imm32/outputs - 9174 "0f 8c/jump-if-< break/disp32"/imm32/subx-name - 9175 0/imm32/no-rm32 - 9176 0/imm32/no-r32 - 9177 0/imm32/no-imm32 - 9178 0/imm32/no-disp32 - 9179 0/imm32/no-output - 9180 _Primitive-break-if->=/imm32/next - 9181 _Primitive-break-if->=: - 9182 "break-if->="/imm32/name - 9183 0/imm32/inouts - 9184 0/imm32/outputs - 9185 "0f 8d/jump-if->= break/disp32"/imm32/subx-name - 9186 0/imm32/no-rm32 - 9187 0/imm32/no-r32 - 9188 0/imm32/no-imm32 - 9189 0/imm32/no-disp32 - 9190 0/imm32/no-output - 9191 _Primitive-break-if-<=/imm32/next - 9192 _Primitive-break-if-<=: - 9193 "break-if-<="/imm32/name - 9194 0/imm32/inouts - 9195 0/imm32/outputs - 9196 "0f 8e/jump-if-<= break/disp32"/imm32/subx-name - 9197 0/imm32/no-rm32 - 9198 0/imm32/no-r32 - 9199 0/imm32/no-imm32 - 9200 0/imm32/no-disp32 - 9201 0/imm32/no-output - 9202 _Primitive-break-if->/imm32/next - 9203 _Primitive-break-if->: - 9204 "break-if->"/imm32/name - 9205 0/imm32/inouts - 9206 0/imm32/outputs - 9207 "0f 8f/jump-if-> break/disp32"/imm32/subx-name - 9208 0/imm32/no-rm32 - 9209 0/imm32/no-r32 - 9210 0/imm32/no-imm32 - 9211 0/imm32/no-disp32 - 9212 0/imm32/no-output - 9213 _Primitive-break/imm32/next - 9214 _Primitive-break: - 9215 "break"/imm32/name - 9216 0/imm32/inouts - 9217 0/imm32/outputs - 9218 "e9/jump break/disp32"/imm32/subx-name - 9219 0/imm32/no-rm32 - 9220 0/imm32/no-r32 - 9221 0/imm32/no-imm32 - 9222 0/imm32/no-disp32 - 9223 0/imm32/no-output - 9224 _Primitive-loop-if-addr</imm32/next - 9225 _Primitive-loop-if-addr<: - 9226 "loop-if-addr<"/imm32/name - 9227 0/imm32/inouts - 9228 0/imm32/outputs - 9229 "0f 82/jump-if-addr< loop/disp32"/imm32/subx-name - 9230 0/imm32/no-rm32 - 9231 0/imm32/no-r32 - 9232 0/imm32/no-imm32 - 9233 0/imm32/no-disp32 - 9234 0/imm32/no-output - 9235 _Primitive-loop-if-addr>=/imm32/next - 9236 _Primitive-loop-if-addr>=: - 9237 "loop-if-addr>="/imm32/name - 9238 0/imm32/inouts - 9239 0/imm32/outputs - 9240 "0f 83/jump-if-addr>= loop/disp32"/imm32/subx-name - 9241 0/imm32/no-rm32 - 9242 0/imm32/no-r32 - 9243 0/imm32/no-imm32 - 9244 0/imm32/no-disp32 - 9245 0/imm32/no-output - 9246 _Primitive-loop-if-=/imm32/next - 9247 _Primitive-loop-if-=: - 9248 "loop-if-="/imm32/name - 9249 0/imm32/inouts - 9250 0/imm32/outputs - 9251 "0f 84/jump-if-= loop/disp32"/imm32/subx-name - 9252 0/imm32/no-rm32 - 9253 0/imm32/no-r32 - 9254 0/imm32/no-imm32 - 9255 0/imm32/no-disp32 - 9256 0/imm32/no-output - 9257 _Primitive-loop-if-!=/imm32/next - 9258 _Primitive-loop-if-!=: - 9259 "loop-if-!="/imm32/name - 9260 0/imm32/inouts - 9261 0/imm32/outputs - 9262 "0f 85/jump-if-!= loop/disp32"/imm32/subx-name - 9263 0/imm32/no-rm32 - 9264 0/imm32/no-r32 - 9265 0/imm32/no-imm32 - 9266 0/imm32/no-disp32 - 9267 0/imm32/no-output - 9268 _Primitive-loop-if-addr<=/imm32/next - 9269 _Primitive-loop-if-addr<=: - 9270 "loop-if-addr<="/imm32/name - 9271 0/imm32/inouts - 9272 0/imm32/outputs - 9273 "0f 86/jump-if-addr<= loop/disp32"/imm32/subx-name - 9274 0/imm32/no-rm32 - 9275 0/imm32/no-r32 - 9276 0/imm32/no-imm32 - 9277 0/imm32/no-disp32 - 9278 0/imm32/no-output - 9279 _Primitive-loop-if-addr>/imm32/next - 9280 _Primitive-loop-if-addr>: - 9281 "loop-if-addr>"/imm32/name - 9282 0/imm32/inouts - 9283 0/imm32/outputs - 9284 "0f 87/jump-if-addr> loop/disp32"/imm32/subx-name - 9285 0/imm32/no-rm32 - 9286 0/imm32/no-r32 - 9287 0/imm32/no-imm32 - 9288 0/imm32/no-disp32 - 9289 0/imm32/no-output - 9290 _Primitive-loop-if-</imm32/next - 9291 _Primitive-loop-if-<: - 9292 "loop-if-<"/imm32/name - 9293 0/imm32/inouts - 9294 0/imm32/outputs - 9295 "0f 8c/jump-if-< loop/disp32"/imm32/subx-name - 9296 0/imm32/no-rm32 - 9297 0/imm32/no-r32 - 9298 0/imm32/no-imm32 - 9299 0/imm32/no-disp32 - 9300 0/imm32/no-output - 9301 _Primitive-loop-if->=/imm32/next - 9302 _Primitive-loop-if->=: - 9303 "loop-if->="/imm32/name - 9304 0/imm32/inouts - 9305 0/imm32/outputs - 9306 "0f 8d/jump-if->= loop/disp32"/imm32/subx-name - 9307 0/imm32/no-rm32 - 9308 0/imm32/no-r32 - 9309 0/imm32/no-imm32 - 9310 0/imm32/no-disp32 - 9311 0/imm32/no-output - 9312 _Primitive-loop-if-<=/imm32/next - 9313 _Primitive-loop-if-<=: - 9314 "loop-if-<="/imm32/name - 9315 0/imm32/inouts - 9316 0/imm32/outputs - 9317 "0f 8e/jump-if-<= loop/disp32"/imm32/subx-name - 9318 0/imm32/no-rm32 - 9319 0/imm32/no-r32 - 9320 0/imm32/no-imm32 - 9321 0/imm32/no-disp32 - 9322 0/imm32/no-output - 9323 _Primitive-loop-if->/imm32/next - 9324 _Primitive-loop-if->: - 9325 "loop-if->"/imm32/name - 9326 0/imm32/inouts - 9327 0/imm32/outputs - 9328 "0f 8f/jump-if-> loop/disp32"/imm32/subx-name - 9329 0/imm32/no-rm32 - 9330 0/imm32/no-r32 - 9331 0/imm32/no-imm32 - 9332 0/imm32/no-disp32 - 9333 0/imm32/no-output - 9334 _Primitive-loop/imm32/next # we probably don't need an unconditional break - 9335 _Primitive-loop: - 9336 "loop"/imm32/name - 9337 0/imm32/inouts - 9338 0/imm32/outputs - 9339 "e9/jump loop/disp32"/imm32/subx-name - 9340 0/imm32/no-rm32 - 9341 0/imm32/no-r32 - 9342 0/imm32/no-imm32 - 9343 0/imm32/no-disp32 - 9344 0/imm32/no-output - 9345 _Primitive-break-if-addr<-named/imm32/next - 9346 # - branches to named blocks - 9347 _Primitive-break-if-addr<-named: - 9348 "break-if-addr<"/imm32/name - 9349 Single-lit-var/imm32/inouts - 9350 0/imm32/outputs - 9351 "0f 82/jump-if-addr<"/imm32/subx-name - 9352 0/imm32/no-rm32 - 9353 0/imm32/no-r32 - 9354 0/imm32/no-imm32 - 9355 1/imm32/disp32-is-first-inout - 9356 0/imm32/no-output - 9357 _Primitive-break-if-addr>=-named/imm32/next - 9358 _Primitive-break-if-addr>=-named: - 9359 "break-if-addr>="/imm32/name - 9360 Single-lit-var/imm32/inouts - 9361 0/imm32/outputs - 9362 "0f 83/jump-if-addr>="/imm32/subx-name - 9363 0/imm32/no-rm32 - 9364 0/imm32/no-r32 - 9365 0/imm32/no-imm32 - 9366 1/imm32/disp32-is-first-inout - 9367 0/imm32/no-output - 9368 _Primitive-break-if-=-named/imm32/next - 9369 _Primitive-break-if-=-named: - 9370 "break-if-="/imm32/name - 9371 Single-lit-var/imm32/inouts - 9372 0/imm32/outputs - 9373 "0f 84/jump-if-="/imm32/subx-name - 9374 0/imm32/no-rm32 - 9375 0/imm32/no-r32 - 9376 0/imm32/no-imm32 - 9377 1/imm32/disp32-is-first-inout - 9378 0/imm32/no-output - 9379 _Primitive-break-if-!=-named/imm32/next - 9380 _Primitive-break-if-!=-named: - 9381 "break-if-!="/imm32/name - 9382 Single-lit-var/imm32/inouts - 9383 0/imm32/outputs - 9384 "0f 85/jump-if-!="/imm32/subx-name - 9385 0/imm32/no-rm32 - 9386 0/imm32/no-r32 - 9387 0/imm32/no-imm32 - 9388 1/imm32/disp32-is-first-inout - 9389 0/imm32/no-output - 9390 _Primitive-break-if-addr<=-named/imm32/next - 9391 _Primitive-break-if-addr<=-named: - 9392 "break-if-addr<="/imm32/name - 9393 Single-lit-var/imm32/inouts - 9394 0/imm32/outputs - 9395 "0f 86/jump-if-addr<="/imm32/subx-name - 9396 0/imm32/no-rm32 - 9397 0/imm32/no-r32 - 9398 0/imm32/no-imm32 - 9399 1/imm32/disp32-is-first-inout - 9400 0/imm32/no-output - 9401 _Primitive-break-if-addr>-named/imm32/next - 9402 _Primitive-break-if-addr>-named: - 9403 "break-if-addr>"/imm32/name - 9404 Single-lit-var/imm32/inouts - 9405 0/imm32/outputs - 9406 "0f 87/jump-if-addr>"/imm32/subx-name - 9407 0/imm32/no-rm32 - 9408 0/imm32/no-r32 - 9409 0/imm32/no-imm32 - 9410 1/imm32/disp32-is-first-inout - 9411 0/imm32/no-output - 9412 _Primitive-break-if-<-named/imm32/next - 9413 _Primitive-break-if-<-named: - 9414 "break-if-<"/imm32/name - 9415 Single-lit-var/imm32/inouts - 9416 0/imm32/outputs - 9417 "0f 8c/jump-if-<"/imm32/subx-name - 9418 0/imm32/no-rm32 - 9419 0/imm32/no-r32 - 9420 0/imm32/no-imm32 - 9421 1/imm32/disp32-is-first-inout - 9422 0/imm32/no-output - 9423 _Primitive-break-if->=-named/imm32/next - 9424 _Primitive-break-if->=-named: - 9425 "break-if->="/imm32/name - 9426 Single-lit-var/imm32/inouts - 9427 0/imm32/outputs - 9428 "0f 8d/jump-if->="/imm32/subx-name + 7400 # + 7401 $check-mu-types:end: + 7402 # . epilogue + 7403 89/<- %esp 5/r32/ebp + 7404 5d/pop-to-ebp + 7405 c3/return + 7406 + 7407 size-of: # v: (addr var) -> result/eax: int + 7408 # . prologue + 7409 55/push-ebp + 7410 89/<- %ebp 4/r32/esp + 7411 # . save registers + 7412 51/push-ecx + 7413 # var t/ecx: (addr tree type-id) = lookup(v->type) + 7414 8b/-> *(ebp+8) 1/r32/ecx + 7415 #? (write-buffered Stderr "size-of ") + 7416 #? (print-int32-buffered Stderr %ecx) + 7417 #? (write-buffered Stderr Newline) + 7418 #? (write-buffered Stderr "type allocid: ") + 7419 #? (print-int32-buffered Stderr *(ecx+8)) + 7420 #? (write-buffered Stderr Newline) + 7421 #? (flush Stderr) + 7422 (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + 7423 89/<- %ecx 0/r32/eax + 7424 # if is-mu-array?(t) return size-of-array(t) + 7425 { + 7426 (is-mu-array? %ecx) # => eax + 7427 3d/compare-eax-and 0/imm32/false + 7428 74/jump-if-= break/disp8 + 7429 (size-of-array %ecx) # => eax + 7430 eb/jump $size-of:end/disp8 + 7431 } + 7432 # if (!t->is-atom?) t = lookup(t->left) + 7433 { + 7434 81 7/subop/compare *ecx 0/imm32/false # Tree-is-atom + 7435 75/jump-if-!= break/disp8 + 7436 (lookup *(ecx+4) *(ecx+8)) # Tree-left Tree-left => eax + 7437 89/<- %ecx 0/r32/eax + 7438 } + 7439 # TODO: assert t->is-atom? + 7440 (size-of-type-id *(ecx+4)) # Tree-value => eax + 7441 $size-of:end: + 7442 # . restore registers + 7443 59/pop-to-ecx + 7444 # . epilogue + 7445 89/<- %esp 5/r32/ebp + 7446 5d/pop-to-ebp + 7447 c3/return + 7448 + 7449 size-of-deref: # v: (addr var) -> result/eax: int + 7450 # . prologue + 7451 55/push-ebp + 7452 89/<- %ebp 4/r32/esp + 7453 # . save registers + 7454 51/push-ecx + 7455 # var t/ecx: (addr tree type-id) = lookup(v->type) + 7456 8b/-> *(ebp+8) 1/r32/ecx + 7457 (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + 7458 89/<- %ecx 0/r32/eax + 7459 # TODO: assert(t is an addr) + 7460 # t = lookup(t->right) + 7461 (lookup *(ecx+0xc) *(ecx+0x10)) # Tree-right Tree-right => eax + 7462 89/<- %ecx 0/r32/eax + 7463 # if is-mu-array?(t) return size-of-array(t) + 7464 { + 7465 (is-mu-array? %ecx) # => eax + 7466 3d/compare-eax-and 0/imm32/false + 7467 74/jump-if-= break/disp8 + 7468 (size-of-array %ecx) # => eax + 7469 eb/jump $size-of:end/disp8 + 7470 } + 7471 # if (!t->is-atom?) t = lookup(t->left) + 7472 { + 7473 81 7/subop/compare *ecx 0/imm32/false # Tree-is-atom + 7474 75/jump-if-!= break/disp8 + 7475 (lookup *(ecx+4) *(ecx+8)) # Tree-left Tree-left => eax + 7476 89/<- %ecx 0/r32/eax + 7477 } + 7478 # TODO: assert t->is-atom? + 7479 (size-of-type-id *(ecx+4)) # Tree-value => eax + 7480 $size-of-deref:end: + 7481 # . restore registers + 7482 59/pop-to-ecx + 7483 # . epilogue + 7484 89/<- %esp 5/r32/ebp + 7485 5d/pop-to-ebp + 7486 c3/return + 7487 + 7488 is-mu-array?: # t: (addr tree type-id) -> result/eax: boolean + 7489 # . prologue + 7490 55/push-ebp + 7491 89/<- %ebp 4/r32/esp + 7492 # . save registers + 7493 51/push-ecx + 7494 # ecx = t + 7495 8b/-> *(ebp+8) 1/r32/ecx + 7496 # if t->is-atom?, return false + 7497 81 7/subop/compare *ecx 0/imm32/false # Tree-is-atom + 7498 75/jump-if-!= $is-mu-array?:return-false/disp8 + 7499 # if !t->left->is-atom?, return false + 7500 (lookup *(ecx+4) *(ecx+8)) # Tree-left Tree-left => eax + 7501 81 7/subop/compare *eax 0/imm32/false # Tree-is-atom + 7502 74/jump-if-= $is-mu-array?:return-false/disp8 + 7503 # return t->left->value == array + 7504 81 7/subop/compare *(eax+4) 3/imm32/array-type-id # Tree-value + 7505 0f 94/set-if-= %al + 7506 81 4/subop/and %eax 0xff/imm32 + 7507 eb/jump $is-mu-array?:end/disp8 + 7508 $is-mu-array?:return-false: + 7509 b8/copy-to-eax 0/imm32/false + 7510 $is-mu-array?:end: + 7511 # . restore registers + 7512 59/pop-to-ecx + 7513 # . epilogue + 7514 89/<- %esp 5/r32/ebp + 7515 5d/pop-to-ebp + 7516 c3/return + 7517 + 7518 size-of-array: # a: (addr tree type-id) -> result/eax: int + 7519 # . prologue + 7520 55/push-ebp + 7521 89/<- %ebp 4/r32/esp + 7522 # . save registers + 7523 51/push-ecx + 7524 52/push-edx + 7525 # + 7526 8b/-> *(ebp+8) 1/r32/ecx + 7527 # TODO: assert that a->left is 'array' + 7528 (lookup *(ecx+0xc) *(ecx+0x10)) # Tree-right Tree-right => eax + 7529 89/<- %ecx 0/r32/eax + 7530 # var elem-type/edx: type-id = a->right->left->value + 7531 (lookup *(ecx+4) *(ecx+8)) # Tree-left Tree-left => eax + 7532 8b/-> *(eax+4) 2/r32/edx # Tree-value + 7533 # var array-size/ecx: int = a->right->right->left->value + 7534 (lookup *(ecx+0xc) *(ecx+0x10)) # Tree-right Tree-right => eax + 7535 (lookup *(eax+4) *(eax+8)) # Tree-left Tree-left => eax + 7536 8b/-> *(eax+4) 1/r32/ecx # Tree-value + 7537 # return array-size * size-of(elem-type) + 7538 (size-of-type-id %edx) # => eax + 7539 f7 4/subop/multiply-into-eax %ecx + 7540 05/add-to-eax 4/imm32 # for array size + 7541 $size-of-array:end: + 7542 # . restore registers + 7543 5a/pop-to-edx + 7544 59/pop-to-ecx + 7545 # . epilogue + 7546 89/<- %esp 5/r32/ebp + 7547 5d/pop-to-ebp + 7548 c3/return + 7549 + 7550 size-of-type-id: # t: type-id -> result/eax: int + 7551 # . prologue + 7552 55/push-ebp + 7553 89/<- %ebp 4/r32/esp + 7554 # . save registers + 7555 51/push-ecx + 7556 # var out/ecx: (handle typeinfo) + 7557 68/push 0/imm32 + 7558 68/push 0/imm32 + 7559 89/<- %ecx 4/r32/esp + 7560 # eax = t + 7561 8b/-> *(ebp+8) 0/r32/eax + 7562 # if v is a literal, return 0 + 7563 3d/compare-eax-and 0/imm32 + 7564 74/jump-if-= $size-of-type-id:end/disp8 # eax changes type from type-id to int + 7565 # if v has a user-defined type, return its size + 7566 # TODO: support non-atom type + 7567 (find-typeinfo %eax %ecx) + 7568 { + 7569 81 7/subop/compare *ecx 0/imm32 + 7570 74/jump-if-= break/disp8 + 7571 $size-of-type-id:user-defined: + 7572 (lookup *ecx *(ecx+4)) # => eax + 7573 8b/-> *(eax+0xc) 0/r32/eax # Typeinfo-total-size-in-bytes + 7574 eb/jump $size-of-type-id:end/disp8 + 7575 } + 7576 # otherwise return the word size + 7577 b8/copy-to-eax 4/imm32 + 7578 $size-of-type-id:end: + 7579 # . reclaim locals + 7580 81 0/subop/add %esp 8/imm32 + 7581 # . restore registers + 7582 59/pop-to-ecx + 7583 # . epilogue + 7584 89/<- %esp 5/r32/ebp + 7585 5d/pop-to-ebp + 7586 c3/return + 7587 + 7588 type-equal?: # a: (addr tree type-id), b: (addr tree type-id) -> result/eax: boolean + 7589 # . prologue + 7590 55/push-ebp + 7591 89/<- %ebp 4/r32/esp + 7592 # . save registers + 7593 51/push-ecx + 7594 52/push-edx + 7595 # ecx = a + 7596 8b/-> *(ebp+8) 1/r32/ecx + 7597 # edx = b + 7598 8b/-> *(ebp+0xc) 2/r32/edx + 7599 # if (a == b) return true + 7600 8b/-> %ecx 0/r32/eax # Var-type + 7601 39/compare %edx 0/r32/eax # Var-type + 7602 b8/copy-to-eax 1/imm32/true + 7603 74/jump-if-= $type-equal?:end/disp8 + 7604 # if (a < MAX_TYPE_ID) return false + 7605 81 7/subop/compare %ecx 0x10000/imm32 + 7606 b8/copy-to-eax 0/imm32/false + 7607 72/jump-if-addr< $type-equal?:end/disp8 + 7608 # if (b < MAX_TYPE_ID) return false + 7609 81 7/subop/compare %edx 0x10000/imm32 + 7610 b8/copy-to-eax 0/imm32/false + 7611 72/jump-if-addr< $type-equal?:end/disp8 + 7612 # if (!type-equal?(a->left, b->left)) return false + 7613 (type-equal? *(ecx+4) *(edx+4)) # Tree-left, Tree-left => eax + 7614 3d/compare-eax-and 0/imm32/false + 7615 74/jump-if-= $type-equal?:end/disp8 + 7616 # return type-equal?(a->right, b->right) + 7617 (type-equal? *(ecx+8) *(edx+8)) # Tree-right, Tree-right => eax + 7618 $type-equal?:end: + 7619 # . restore registers + 7620 5a/pop-to-edx + 7621 59/pop-to-ecx + 7622 # . epilogue + 7623 89/<- %esp 5/r32/ebp + 7624 5d/pop-to-ebp + 7625 c3/return + 7626 + 7627 ####################################################### + 7628 # Code-generation + 7629 ####################################################### + 7630 + 7631 == data + 7632 + 7633 Curr-block-depth: # (addr int) + 7634 0/imm32 + 7635 Curr-local-stack-offset: # (addr int) + 7636 0/imm32 + 7637 + 7638 == code + 7639 + 7640 emit-subx: # out: (addr buffered-file) + 7641 # . prologue + 7642 55/push-ebp + 7643 89/<- %ebp 4/r32/esp + 7644 # . save registers + 7645 50/push-eax + 7646 # var curr/eax: (addr function) = *Program->functions + 7647 (lookup *_Program-functions *_Program-functions->payload) # => eax + 7648 { + 7649 # if (curr == null) break + 7650 3d/compare-eax-and 0/imm32 + 7651 0f 84/jump-if-= break/disp32 + 7652 (emit-subx-function *(ebp+8) %eax) + 7653 # curr = lookup(curr->next) + 7654 (lookup *(eax+0x20) *(eax+0x24)) # Function-next Function-next => eax + 7655 e9/jump loop/disp32 + 7656 } + 7657 $emit-subx:end: + 7658 # . restore registers + 7659 58/pop-to-eax + 7660 # . epilogue + 7661 89/<- %esp 5/r32/ebp + 7662 5d/pop-to-ebp + 7663 c3/return + 7664 + 7665 emit-subx-function: # out: (addr buffered-file), f: (addr function) + 7666 # . prologue + 7667 55/push-ebp + 7668 89/<- %ebp 4/r32/esp + 7669 # some preprocessing + 7670 (populate-mu-type-offsets-in-inouts *(ebp+0xc)) + 7671 # . save registers + 7672 50/push-eax + 7673 51/push-ecx + 7674 52/push-edx + 7675 57/push-edi + 7676 # edi = out + 7677 8b/-> *(ebp+8) 7/r32/edi + 7678 # ecx = f + 7679 8b/-> *(ebp+0xc) 1/r32/ecx + 7680 # var vars/edx: (stack (addr var) 256) + 7681 81 5/subop/subtract %esp 0x800/imm32 + 7682 68/push 0x800/imm32/size + 7683 68/push 0/imm32/top + 7684 89/<- %edx 4/r32/esp + 7685 # + 7686 (lookup *ecx *(ecx+4)) # Function-name Function-name => eax + 7687 (write-buffered %edi %eax) + 7688 (write-buffered %edi ":\n") + 7689 # initialize some global state + 7690 c7 0/subop/copy *Curr-block-depth 1/imm32 + 7691 c7 0/subop/copy *Curr-local-stack-offset 0/imm32 + 7692 # + 7693 (emit-subx-prologue %edi) + 7694 (lookup *(ecx+0x18) *(ecx+0x1c)) # Function-body Function-body => eax + 7695 (emit-subx-block %edi %eax %edx) + 7696 (emit-subx-epilogue %edi) + 7697 # TODO: validate that *Curr-block-depth and *Curr-local-stack-offset have + 7698 # been cleaned up + 7699 $emit-subx-function:end: + 7700 # . reclaim locals + 7701 81 0/subop/add %esp 808/imm32 + 7702 # . restore registers + 7703 5f/pop-to-edi + 7704 5a/pop-to-edx + 7705 59/pop-to-ecx + 7706 58/pop-to-eax + 7707 # . epilogue + 7708 89/<- %esp 5/r32/ebp + 7709 5d/pop-to-ebp + 7710 c3/return + 7711 + 7712 populate-mu-type-offsets-in-inouts: # f: (addr function) + 7713 # . prologue + 7714 55/push-ebp + 7715 89/<- %ebp 4/r32/esp + 7716 # . save registers + 7717 50/push-eax + 7718 51/push-ecx + 7719 52/push-edx + 7720 53/push-ebx + 7721 57/push-edi + 7722 # var next-offset/edx: int = 8 + 7723 ba/copy-to-edx 8/imm32 + 7724 # var curr/ecx: (addr list var) = lookup(f->inouts) + 7725 8b/-> *(ebp+8) 1/r32/ecx + 7726 (lookup *(ecx+8) *(ecx+0xc)) # Function-inouts Function-inouts => eax + 7727 89/<- %ecx 0/r32/eax + 7728 { + 7729 $populate-mu-type-offsets-in-inouts:loop: + 7730 81 7/subop/compare %ecx 0/imm32 + 7731 74/jump-if-= break/disp8 + 7732 # var v/ebx: (addr var) = lookup(curr->value) + 7733 (lookup *ecx *(ecx+4)) # List-value List-value => eax + 7734 89/<- %ebx 0/r32/eax + 7735 # v->offset = next-offset + 7736 89/<- *(ebx+0x14) 2/r32/edx # Var-offset + 7737 # next-offset += size-of(v) + 7738 (size-of %ebx) # => eax + 7739 01/add-to %edx 0/r32/eax + 7740 # curr = lookup(curr->next) + 7741 (lookup *(ecx+8) *(ecx+0xc)) # List-next List-next => eax + 7742 89/<- %ecx 0/r32/eax + 7743 # + 7744 eb/jump loop/disp8 + 7745 } + 7746 $populate-mu-type-offsets-in-inouts:end: + 7747 # . restore registers + 7748 5f/pop-to-edi + 7749 5b/pop-to-ebx + 7750 5a/pop-to-edx + 7751 59/pop-to-ecx + 7752 58/pop-to-eax + 7753 # . epilogue + 7754 89/<- %esp 5/r32/ebp + 7755 5d/pop-to-ebp + 7756 c3/return + 7757 + 7758 emit-subx-stmt-list: # out: (addr buffered-file), stmts: (addr list stmt), vars: (addr stack (handle var)) + 7759 # . prologue + 7760 55/push-ebp + 7761 89/<- %ebp 4/r32/esp + 7762 # . save registers + 7763 50/push-eax + 7764 51/push-ecx + 7765 52/push-edx + 7766 53/push-ebx + 7767 56/push-esi + 7768 # esi = stmts + 7769 8b/-> *(ebp+0xc) 6/r32/esi + 7770 # var var-seen?/edx: boolean <- copy false + 7771 ba/copy-to-edx 0/imm32/false + 7772 # + 7773 { + 7774 $emit-subx-stmt-list:loop: + 7775 81 7/subop/compare %esi 0/imm32 + 7776 0f 84/jump-if-= break/disp32 + 7777 # var curr-stmt/ecx: (addr stmt) = lookup(stmts->value) + 7778 (lookup *esi *(esi+4)) # List-value List-value => eax + 7779 89/<- %ecx 0/r32/eax + 7780 { + 7781 $emit-subx-stmt-list:check-for-block: + 7782 81 7/subop/compare *ecx 0/imm32/block # Stmt-tag + 7783 75/jump-if-!= break/disp8 + 7784 $emit-subx-stmt-list:block: + 7785 (emit-subx-block *(ebp+8) %ecx *(ebp+0x10)) + 7786 } + 7787 { + 7788 $emit-subx-stmt-list:check-for-stmt: + 7789 81 7/subop/compare *ecx 1/imm32/stmt1 # Stmt-tag + 7790 0f 85/jump-if-!= break/disp32 + 7791 $emit-subx-stmt-list:stmt1: + 7792 { + 7793 (is-mu-branch? %ecx) # => eax + 7794 3d/compare-eax-and 0/imm32/false + 7795 0f 84/jump-if-= break/disp32 + 7796 $emit-subx-stmt-list:branch-stmt: + 7797 # if !var-seen? break + 7798 81 7/subop/compare %edx 0/imm32/false + 7799 0f 84/jump-if-= break/disp32 + 7800 $emit-subx-stmt-list:branch-stmt-and-var-seen: + 7801 +-- 27 lines: # unconditional loops ----------------------------------------------------------------------------------------------------------------------------------------------------- + 7828 +-- 16 lines: # unconditional breaks ---------------------------------------------------------------------------------------------------------------------------------------------------- + 7844 +-- 38 lines: # simple conditional branches without a target ---------------------------------------------------------------------------------------------------------------------------- + 7882 +-- 19 lines: # conditional branches with an explicit target ---------------------------------------------------------------------------------------------------------------------------- + 7901 } + 7902 $emit-subx-stmt-list:1-to-1: + 7903 (emit-subx-stmt *(ebp+8) %ecx Primitives) + 7904 e9/jump $emit-subx-stmt-list:continue/disp32 + 7905 } + 7906 { + 7907 $emit-subx-stmt-list:check-for-var-def: + 7908 81 7/subop/compare *ecx 2/imm32/var-def # Stmt-tag + 7909 75/jump-if-!= break/disp8 + 7910 $emit-subx-stmt-list:var-def: + 7911 (emit-subx-var-def *(ebp+8) %ecx) + 7912 (push *(ebp+0x10) *(ecx+4)) # Vardef-var + 7913 (push *(ebp+0x10) *(ecx+8)) # Vardef-var + 7914 # var-seen? = true + 7915 ba/copy-to-edx 1/imm32/true + 7916 eb/jump $emit-subx-stmt-list:continue/disp8 + 7917 } + 7918 { + 7919 $emit-subx-stmt-list:check-for-reg-var-def: + 7920 81 7/subop/compare *ecx 3/imm32/reg-var-def # Stmt-tag + 7921 0f 85/jump-if-!= break/disp32 + 7922 $emit-subx-stmt-list:reg-var-def: + 7923 # TODO: ensure that there's exactly one output + 7924 (push-output-and-maybe-emit-spill *(ebp+8) %ecx *(ebp+0x10)) + 7925 # emit the instruction as usual + 7926 (emit-subx-stmt *(ebp+8) %ecx Primitives) + 7927 # var-seen? = true + 7928 ba/copy-to-edx 1/imm32/true + 7929 eb/jump $emit-subx-stmt-list:continue/disp8 + 7930 } + 7931 $emit-subx-stmt-list:continue: + 7932 # TODO: raise an error on unrecognized Stmt-tag + 7933 (lookup *(esi+8) *(esi+0xc)) # List-next List-next => eax + 7934 89/<- %esi 0/r32/eax + 7935 e9/jump loop/disp32 + 7936 } + 7937 $emit-subx-stmt-list:emit-cleanup: + 7938 (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth) + 7939 $emit-subx-stmt-list:clean-up: + 7940 (clean-up-blocks *(ebp+0x10) *Curr-block-depth) + 7941 $emit-subx-stmt-list:end: + 7942 # . restore registers + 7943 5e/pop-to-esi + 7944 5b/pop-to-ebx + 7945 5a/pop-to-edx + 7946 59/pop-to-ecx + 7947 58/pop-to-eax + 7948 # . epilogue + 7949 89/<- %esp 5/r32/ebp + 7950 5d/pop-to-ebp + 7951 c3/return + 7952 + 7953 push-output-and-maybe-emit-spill: # out: (addr buffered-file), stmt: (addr reg-var-def), vars: (addr stack (handle var)) + 7954 # . prologue + 7955 55/push-ebp + 7956 89/<- %ebp 4/r32/esp + 7957 # . save registers + 7958 50/push-eax + 7959 51/push-ecx + 7960 # ecx = stmt + 7961 8b/-> *(ebp+0xc) 1/r32/ecx + 7962 # var sv/eax: (addr stmt-var) = lookup(curr-stmt->outputs) + 7963 (lookup *(ecx+0x14) *(ecx+0x18)) # Regvardef-outputs Regvardef-outputs => eax + 7964 # TODO: assert !sv->is-deref? + 7965 # var v/ecx: (addr var) = lookup(sv->value) + 7966 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 7967 89/<- %ecx 0/r32/eax + 7968 # v->block-depth = *Curr-block-depth + 7969 8b/-> *Curr-block-depth 0/r32/eax + 7970 89/<- *(ecx+0x10) 0/r32/eax # Var-block-depth + 7971 #? (write-buffered Stderr "var ") + 7972 #? (lookup *ecx *(ecx+4)) + 7973 #? (write-buffered Stderr %eax) + 7974 #? (write-buffered Stderr " at depth ") + 7975 #? (print-int32-buffered Stderr *(ecx+0x10)) + 7976 #? (write-buffered Stderr Newline) + 7977 #? (flush Stderr) + 7978 # ensure that v is in a register + 7979 81 7/subop/compare *(ecx+0x18) 0/imm32 # Var-register + 7980 0f 84/jump-if-= $push-output-and-maybe-emit-spill:abort/disp32 + 7981 # if !already-spilled-this-block?(reg, vars) emit code to spill reg + 7982 (already-spilled-this-block? %ecx *(ebp+0x10)) # => eax + 7983 3d/compare-eax-and 0/imm32/false + 7984 75/jump-if-!= $push-output-and-maybe-emit-spill:push/disp8 + 7985 # TODO: assert(size-of(output) == 4) + 7986 # *Curr-local-stack-offset -= 4 + 7987 81 5/subop/subtract *Curr-local-stack-offset 4/imm32 + 7988 # emit spill + 7989 (emit-indent *(ebp+8) *Curr-block-depth) + 7990 (write-buffered *(ebp+8) "ff 6/subop/push %") + 7991 (lookup *(ecx+0x18) *(ecx+0x1c)) # Var-register Var-register => eax + 7992 (write-buffered *(ebp+8) %eax) + 7993 (write-buffered *(ebp+8) Newline) + 7994 $push-output-and-maybe-emit-spill:push: + 7995 8b/-> *(ebp+0xc) 1/r32/ecx + 7996 (lookup *(ecx+0x14) *(ecx+0x18)) # Regvardef-outputs Regvardef-outputs => eax + 7997 # push(vars, sv->value) + 7998 (push *(ebp+0x10) *eax) # Stmt-var-value + 7999 (push *(ebp+0x10) *(eax+4)) # Stmt-var-value + 8000 $push-output-and-maybe-emit-spill:end: + 8001 # . restore registers + 8002 59/pop-to-ecx + 8003 58/pop-to-eax + 8004 # . epilogue + 8005 89/<- %esp 5/r32/ebp + 8006 5d/pop-to-ebp + 8007 c3/return + 8008 + 8009 $push-output-and-maybe-emit-spill:abort: + 8010 # error("var '" var->name "' initialized from an instruction must live in a register\n") + 8011 (write-buffered Stderr "var '") + 8012 (write-buffered Stderr *eax) # Var-name + 8013 (write-buffered Stderr "' initialized from an instruction must live in a register\n") + 8014 (flush Stderr) + 8015 # . syscall(exit, 1) + 8016 bb/copy-to-ebx 1/imm32 + 8017 b8/copy-to-eax 1/imm32/exit + 8018 cd/syscall 0x80/imm8 + 8019 # never gets here + 8020 + 8021 emit-subx-cleanup-and-unconditional-nonlocal-branch: # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack (handle var)) + 8022 # . prologue + 8023 55/push-ebp + 8024 89/<- %ebp 4/r32/esp + 8025 # . save registers + 8026 50/push-eax + 8027 51/push-ecx + 8028 # ecx = stmt + 8029 8b/-> *(ebp+0xc) 1/r32/ecx + 8030 # var target/eax: (addr array byte) = curr-stmt->inouts->value->name + 8031 (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 8032 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 8033 (lookup *eax *(eax+4)) # Var-name Var-name => eax + 8034 # clean up until target block + 8035 (emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %eax) + 8036 # emit jump to target block + 8037 (emit-indent *(ebp+8) *Curr-block-depth) + 8038 (write-buffered *(ebp+8) "e9/jump ") + 8039 (write-buffered *(ebp+8) %eax) + 8040 (lookup *(ecx+4) *(ecx+8)) # Stmt1-operation Stmt1-operation => eax + 8041 (string-starts-with? %eax "break") + 8042 3d/compare-eax-and 0/imm32/false + 8043 { + 8044 74/jump-if-= break/disp8 + 8045 (write-buffered *(ebp+8) ":break/disp32\n") + 8046 } + 8047 3d/compare-eax-and 0/imm32/false # just in case the function call modified flags + 8048 { + 8049 75/jump-if-!= break/disp8 + 8050 (write-buffered *(ebp+8) ":loop/disp32\n") + 8051 } + 8052 $emit-subx-cleanup-and-unconditional-nonlocal-branch:end: + 8053 # . restore registers + 8054 59/pop-to-ecx + 8055 58/pop-to-eax + 8056 # . epilogue + 8057 89/<- %esp 5/r32/ebp + 8058 5d/pop-to-ebp + 8059 c3/return + 8060 + 8061 is-mu-branch?: # stmt: (addr stmt1) -> result/eax: boolean + 8062 # . prologue + 8063 55/push-ebp + 8064 89/<- %ebp 4/r32/esp + 8065 # . save registers + 8066 51/push-ecx + 8067 # ecx = lookup(stmt->operation) + 8068 8b/-> *(ebp+8) 1/r32/ecx + 8069 (lookup *(ecx+4) *(ecx+8)) # Stmt1-operation Stmt1-operation => eax + 8070 89/<- %ecx 0/r32/eax + 8071 # if (stmt->operation starts with "loop") return true + 8072 (string-starts-with? %ecx "loop") # => eax + 8073 3d/compare-eax-and 0/imm32/false + 8074 75/jump-if-not-equal $is-mu-branch?:end/disp8 + 8075 # otherwise return (stmt->operation starts with "break") + 8076 (string-starts-with? %ecx "break") # => eax + 8077 $is-mu-branch?:end: + 8078 # . restore registers + 8079 59/pop-to-ecx + 8080 # . epilogue + 8081 89/<- %esp 5/r32/ebp + 8082 5d/pop-to-ebp + 8083 c3/return + 8084 + 8085 emit-reverse-break: # out: (addr buffered-file), stmt: (addr stmt1) + 8086 # . prologue + 8087 55/push-ebp + 8088 89/<- %ebp 4/r32/esp + 8089 # . save registers + 8090 50/push-eax + 8091 # eax = stmt + 8092 8b/-> *(ebp+0xc) 0/r32/eax + 8093 # + 8094 (lookup *(eax+4) *(eax+8)) # Stmt1-operation Stmt1-operation => eax + 8095 (get Reverse-branch %eax 0x10 "reverse-branch: ") # => eax: (addr handle array byte) + 8096 (emit-indent *(ebp+8) *Curr-block-depth) + 8097 (lookup *eax *(eax+4)) # => eax + 8098 (write-buffered *(ebp+8) %eax) + 8099 (write-buffered *(ebp+8) " break/disp32\n") + 8100 $emit-reverse-break:end: + 8101 # . restore registers + 8102 58/pop-to-eax + 8103 # . epilogue + 8104 89/<- %esp 5/r32/ebp + 8105 5d/pop-to-ebp + 8106 c3/return + 8107 + 8108 == data + 8109 + 8110 # Table from Mu branch instructions to the reverse SubX opcodes for them. + 8111 Reverse-branch: # (table (handle array byte) (handle array byte)) + 8112 # a table is a stream + 8113 0x140/imm32/write + 8114 0/imm32/read + 8115 0x140/imm32/size + 8116 # data + 8117 0x11/imm32/alloc-id _string-break-if-=/imm32 0x11/imm32/alloc-id _string_0f_85_jump_label/imm32 + 8118 0x11/imm32/alloc-id _string-loop-if-=/imm32 0x11/imm32/alloc-id _string_0f_85_jump_label/imm32 + 8119 0x11/imm32/alloc-id _string-break-if-!=/imm32 0x11/imm32/alloc-id _string_0f_84_jump_label/imm32 + 8120 0x11/imm32/alloc-id _string-loop-if-!=/imm32 0x11/imm32/alloc-id _string_0f_84_jump_label/imm32 + 8121 0x11/imm32/alloc-id _string-break-if-</imm32 0x11/imm32/alloc-id _string_0f_8d_jump_label/imm32 + 8122 0x11/imm32/alloc-id _string-loop-if-</imm32 0x11/imm32/alloc-id _string_0f_8d_jump_label/imm32 + 8123 0x11/imm32/alloc-id _string-break-if->/imm32 0x11/imm32/alloc-id _string_0f_8e_jump_label/imm32 + 8124 0x11/imm32/alloc-id _string-loop-if->/imm32 0x11/imm32/alloc-id _string_0f_8e_jump_label/imm32 + 8125 0x11/imm32/alloc-id _string-break-if-<=/imm32 0x11/imm32/alloc-id _string_0f_87_jump_label/imm32 + 8126 0x11/imm32/alloc-id _string-loop-if-<=/imm32 0x11/imm32/alloc-id _string_0f_87_jump_label/imm32 + 8127 0x11/imm32/alloc-id _string-break-if->=/imm32 0x11/imm32/alloc-id _string_0f_8c_jump_label/imm32 + 8128 0x11/imm32/alloc-id _string-loop-if->=/imm32 0x11/imm32/alloc-id _string_0f_8c_jump_label/imm32 + 8129 0x11/imm32/alloc-id _string-break-if-addr</imm32 0x11/imm32/alloc-id _string_0f_83_jump_label/imm32 + 8130 0x11/imm32/alloc-id _string-loop-if-addr</imm32 0x11/imm32/alloc-id _string_0f_83_jump_label/imm32 + 8131 0x11/imm32/alloc-id _string-break-if-addr>/imm32 0x11/imm32/alloc-id _string_0f_86_jump_label/imm32 + 8132 0x11/imm32/alloc-id _string-loop-if-addr>/imm32 0x11/imm32/alloc-id _string_0f_86_jump_label/imm32 + 8133 0x11/imm32/alloc-id _string-break-if-addr<=/imm32 0x11/imm32/alloc-id _string_0f_87_jump_label/imm32 + 8134 0x11/imm32/alloc-id _string-loop-if-addr<=/imm32 0x11/imm32/alloc-id _string_0f_87_jump_label/imm32 + 8135 0x11/imm32/alloc-id _string-break-if-addr>=/imm32 0x11/imm32/alloc-id _string_0f_82_jump_label/imm32 + 8136 0x11/imm32/alloc-id _string-loop-if-addr>=/imm32 0x11/imm32/alloc-id _string_0f_82_jump_label/imm32 + 8137 + 8138 == code + 8139 + 8140 emit-unconditional-jump-to-depth: # out: (addr buffered-file), vars: (addr stack (handle var)), depth: int, label-suffix: (addr array byte) + 8141 # . prologue + 8142 55/push-ebp + 8143 89/<- %ebp 4/r32/esp + 8144 # . save registers + 8145 50/push-eax + 8146 51/push-ecx + 8147 52/push-edx + 8148 53/push-ebx + 8149 56/push-esi + 8150 # ecx = vars + 8151 8b/-> *(ebp+0xc) 1/r32/ecx + 8152 # var eax: int = vars->top + 8153 8b/-> *ecx 0/r32/eax + 8154 # var curr/esi: (addr handle var) = &vars->data[vars->top - 8] + 8155 8d/copy-address *(ecx+eax) 6/r32/esi # vars + 8 + vars->top - 8 + 8156 # var min/ecx: (addr handle var) = vars->data + 8157 81 0/subop/add %ecx 8/imm32 + 8158 # edx = depth + 8159 8b/-> *(ebp+0x10) 2/r32/edx + 8160 { + 8161 $emit-unconditional-jump-to-depth:loop: + 8162 # if (curr < min) break + 8163 39/compare %esi 1/r32/ecx + 8164 0f 82/jump-if-addr< break/disp32 + 8165 # var v/ebx: (addr var) = lookup(*curr) + 8166 (lookup *esi *(esi+4)) # => eax + 8167 89/<- %ebx 0/r32/eax + 8168 # if (v->block-depth < until-block-depth) break + 8169 39/compare *(ebx+0x10) 2/r32/edx # Var-block-depth + 8170 0f 8c/jump-if-< break/disp32 + 8171 { + 8172 $emit-unconditional-jump-to-depth:check: + 8173 # if v->block-depth != until-block-depth, continue + 8174 39/compare *(ebx+0x10) 2/r32/edx # Var-block-depth + 8175 0f 85/jump-if-!= break/disp32 + 8176 $emit-unconditional-jump-to-depth:depth-found: + 8177 # if v is not a literal, continue + 8178 (size-of %ebx) # => eax + 8179 3d/compare-eax-and 0/imm32 + 8180 0f 85/jump-if-!= break/disp32 + 8181 $emit-unconditional-jump-to-depth:label-found: + 8182 # emit unconditional jump, then return + 8183 (emit-indent *(ebp+8) *Curr-block-depth) + 8184 (write-buffered *(ebp+8) "e9/jump ") + 8185 (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + 8186 (write-buffered *(ebp+8) %eax) + 8187 (write-buffered *(ebp+8) ":") + 8188 (write-buffered *(ebp+8) *(ebp+0x14)) + 8189 (write-buffered *(ebp+8) "/disp32\n") + 8190 eb/jump $emit-unconditional-jump-to-depth:end/disp8 + 8191 } + 8192 # curr -= 8 + 8193 81 5/subop/subtract %esi 8/imm32 + 8194 e9/jump loop/disp32 + 8195 } + 8196 # TODO: error if no label at 'depth' was found + 8197 $emit-unconditional-jump-to-depth:end: + 8198 # . restore registers + 8199 5e/pop-to-esi + 8200 5b/pop-to-ebx + 8201 5a/pop-to-edx + 8202 59/pop-to-ecx + 8203 58/pop-to-eax + 8204 # . epilogue + 8205 89/<- %esp 5/r32/ebp + 8206 5d/pop-to-ebp + 8207 c3/return + 8208 + 8209 # emit clean-up code for 'vars' until some block depth + 8210 # doesn't actually modify 'vars' so we need traverse manually inside the stack + 8211 emit-cleanup-code-until-depth: # out: (addr buffered-file), vars: (addr stack (handle var)), until-block-depth: int + 8212 # . prologue + 8213 55/push-ebp + 8214 89/<- %ebp 4/r32/esp + 8215 # . save registers + 8216 50/push-eax + 8217 51/push-ecx + 8218 52/push-edx + 8219 53/push-ebx + 8220 56/push-esi + 8221 #? (write-buffered Stderr "--- cleanup\n") + 8222 #? (flush Stderr) + 8223 # ecx = vars + 8224 8b/-> *(ebp+0xc) 1/r32/ecx + 8225 # var esi: int = vars->top + 8226 8b/-> *ecx 6/r32/esi + 8227 # var curr/esi: (addr handle var) = &vars->data[vars->top - 8] + 8228 8d/copy-address *(ecx+esi) 6/r32/esi # vars + 8 + vars->top - 8 + 8229 # var min/ecx: (addr handle var) = vars->data + 8230 81 0/subop/add %ecx 8/imm32 + 8231 # edx = until-block-depth + 8232 8b/-> *(ebp+0x10) 2/r32/edx + 8233 { + 8234 $emit-cleanup-code-until-depth:loop: + 8235 # if (curr < min) break + 8236 39/compare %esi 1/r32/ecx + 8237 0f 82/jump-if-addr< break/disp32 + 8238 # var v/ebx: (addr var) = lookup(*curr) + 8239 (lookup *esi *(esi+4)) # => eax + 8240 89/<- %ebx 0/r32/eax + 8241 #? (lookup *ebx *(ebx+4)) # Var-name + 8242 #? (write-buffered Stderr "var ") + 8243 #? (write-buffered Stderr %eax) + 8244 #? (write-buffered Stderr Newline) + 8245 #? (flush Stderr) + 8246 # if (v->block-depth < until-block-depth) break + 8247 39/compare *(ebx+0x10) 2/r32/edx # Var-block-depth + 8248 0f 8c/jump-if-< break/disp32 + 8249 # if v is in a register + 8250 81 7/subop/compare *(ebx+0x18) 0/imm32 # Var-register + 8251 { + 8252 0f 84/jump-if-= break/disp32 + 8253 { + 8254 $emit-cleanup-code-until-depth:check-for-previous-spill: + 8255 (same-register-spilled-before? %ebx *(ebp+0xc) %esi) # => eax + 8256 3d/compare-eax-and 0/imm32/false + 8257 0f 85/jump-if-!= break/disp32 + 8258 $emit-cleanup-code-until-depth:reclaim-var-in-register: + 8259 (emit-indent *(ebp+8) *Curr-block-depth) + 8260 (write-buffered *(ebp+8) "8f 0/subop/pop %") + 8261 (lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax + 8262 (write-buffered *(ebp+8) %eax) + 8263 (write-buffered *(ebp+8) Newline) + 8264 } + 8265 eb/jump $emit-cleanup-code-until-depth:continue/disp8 + 8266 } + 8267 # otherwise v is on the stack + 8268 { + 8269 75/jump-if-!= break/disp8 + 8270 $emit-cleanup-code-until-depth:var-on-stack: + 8271 (size-of %ebx) # => eax + 8272 # don't emit code for labels + 8273 3d/compare-eax-and 0/imm32 + 8274 74/jump-if-= break/disp8 + 8275 $emit-cleanup-code-until-depth:reclaim-var-on-stack: + 8276 (emit-indent *(ebp+8) *Curr-block-depth) + 8277 (write-buffered *(ebp+8) "81 0/subop/add %esp ") + 8278 (print-int32-buffered *(ebp+8) %eax) + 8279 (write-buffered *(ebp+8) "/imm32\n") + 8280 } + 8281 $emit-cleanup-code-until-depth:continue: + 8282 # curr -= 8 + 8283 81 5/subop/subtract %esi 8/imm32 + 8284 e9/jump loop/disp32 + 8285 } + 8286 $emit-cleanup-code-until-depth:end: + 8287 # . restore registers + 8288 5e/pop-to-esi + 8289 5b/pop-to-ebx + 8290 5a/pop-to-edx + 8291 59/pop-to-ecx + 8292 58/pop-to-eax + 8293 # . epilogue + 8294 89/<- %esp 5/r32/ebp + 8295 5d/pop-to-ebp + 8296 c3/return + 8297 + 8298 # emit clean-up code for 'vars' until a given label is encountered + 8299 # doesn't actually modify 'vars' so we need traverse manually inside the stack + 8300 emit-cleanup-code-until-target: # out: (addr buffered-file), vars: (addr stack (handle var)), until-block-label: (addr array byte) + 8301 # . prologue + 8302 55/push-ebp + 8303 89/<- %ebp 4/r32/esp + 8304 # . save registers + 8305 50/push-eax + 8306 51/push-ecx + 8307 52/push-edx + 8308 53/push-ebx + 8309 # ecx = vars + 8310 8b/-> *(ebp+0xc) 1/r32/ecx + 8311 # var eax: int = vars->top + 8312 8b/-> *ecx 0/r32/eax + 8313 # var curr/edx: (addr handle var) = &vars->data[vars->top - 8] + 8314 8d/copy-address *(ecx+eax) 2/r32/edx # vars + 8 + vars->top - 8 + 8315 # var min/ecx: (addr handle var) = vars->data + 8316 81 0/subop/add %ecx 8/imm32 + 8317 { + 8318 $emit-cleanup-code-until-target:loop: + 8319 # if (curr < min) break + 8320 39/compare %edx 1/r32/ecx + 8321 0f 82/jump-if-addr< break/disp32 + 8322 # var v/ebx: (handle var) = lookup(*curr) + 8323 (lookup *edx *(edx+4)) # => eax + 8324 89/<- %ebx 0/r32/eax + 8325 # if (v->name == until-block-label) break + 8326 (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + 8327 (string-equal? %eax *(ebp+0x10)) # => eax + 8328 3d/compare-eax-and 0/imm32/false + 8329 0f 85/jump-if-!= break/disp32 + 8330 # if v is in a register + 8331 81 7/subop/compare *(ebx+0x18) 0/imm32 # Var-register + 8332 { + 8333 0f 84/jump-if-= break/disp32 + 8334 { + 8335 $emit-cleanup-code-until-target:check-for-previous-spill: + 8336 (same-register-spilled-before? %ebx *(ebp+0xc) %edx) # => eax + 8337 3d/compare-eax-and 0/imm32/false + 8338 75/jump-if-!= break/disp8 + 8339 $emit-cleanup-code-until-target:reclaim-var-in-register: + 8340 (emit-indent *(ebp+8) *Curr-block-depth) + 8341 (write-buffered *(ebp+8) "8f 0/subop/pop %") + 8342 (lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax + 8343 (write-buffered *(ebp+8) %eax) + 8344 (write-buffered *(ebp+8) Newline) + 8345 } + 8346 eb/jump $emit-cleanup-code-until-target:continue/disp8 + 8347 } + 8348 # otherwise v is on the stack + 8349 { + 8350 75/jump-if-!= break/disp8 + 8351 $emit-cleanup-code-until-target:reclaim-var-on-stack: + 8352 (size-of %ebx) # => eax + 8353 # don't emit code for labels + 8354 3d/compare-eax-and 0/imm32 + 8355 74/jump-if-= break/disp8 + 8356 # + 8357 (emit-indent *(ebp+8) *Curr-block-depth) + 8358 (write-buffered *(ebp+8) "81 0/subop/add %esp ") + 8359 (print-int32-buffered *(ebp+8) %eax) + 8360 (write-buffered *(ebp+8) "/imm32\n") + 8361 } + 8362 $emit-cleanup-code-until-target:continue: + 8363 # curr -= 8 + 8364 81 5/subop/subtract %edx 8/imm32 + 8365 e9/jump loop/disp32 + 8366 } + 8367 $emit-cleanup-code-until-target:end: + 8368 # . restore registers + 8369 5b/pop-to-ebx + 8370 5a/pop-to-edx + 8371 59/pop-to-ecx + 8372 58/pop-to-eax + 8373 # . epilogue + 8374 89/<- %esp 5/r32/ebp + 8375 5d/pop-to-ebp + 8376 c3/return + 8377 + 8378 # is there already a var with the same block-depth and register as 'v' on the 'vars' stack? + 8379 # v is guaranteed not to be within vars + 8380 already-spilled-this-block?: # v: (addr var), vars: (addr stack (handle var)) -> result/eax: boolean + 8381 # . prologue + 8382 55/push-ebp + 8383 89/<- %ebp 4/r32/esp + 8384 # . save registers + 8385 51/push-ecx + 8386 52/push-edx + 8387 53/push-ebx + 8388 56/push-esi + 8389 57/push-edi + 8390 # ecx = vars + 8391 8b/-> *(ebp+0xc) 1/r32/ecx + 8392 # var eax: int = vars->top + 8393 8b/-> *ecx 0/r32/eax + 8394 # var min/ecx: (addr handle var) = vars->data + 8395 81 0/subop/add %ecx 8/imm32 + 8396 # var curr/edx: (addr handle var) = &vars->data[vars->top - 8] + 8397 81 5/subop/subtract %eax 8/imm32 + 8398 8d/copy-address *(ecx+eax) 2/r32/edx + 8399 # var depth/ebx: int = v->block-depth + 8400 8b/-> *(ebp+8) 3/r32/ebx + 8401 8b/-> *(ebx+0x10) 3/r32/ebx # Var-block-depth + 8402 # var needle/esi: (addr array byte) = v->register + 8403 8b/-> *(ebp+8) 6/r32/esi + 8404 (lookup *(esi+0x18) *(esi+0x1c)) # Var-register Var-register => eax + 8405 89/<- %esi 0/r32/eax + 8406 { + 8407 $already-spilled-this-block?:loop: + 8408 # if (curr < min) break + 8409 39/compare %edx 1/r32/ecx + 8410 0f 82/jump-if-addr< break/disp32 + 8411 # var cand/edi: (addr var) = lookup(*curr) + 8412 (lookup *edx *(edx+4)) # => eax + 8413 89/<- %edi 0/r32/eax + 8414 # if (cand->block-depth < depth) break + 8415 39/compare *(edi+0x10) 3/r32/ebx # Var-block-depth + 8416 0f 8c/jump-if-< break/disp32 + 8417 # var cand-reg/edi: (array array byte) = cand->reg + 8418 (lookup *(edi+0x18) *(edi+0x1c)) # Var-register Var-register => eax + 8419 89/<- %edi 0/r32/eax + 8420 # if (cand-reg == null) continue + 8421 { + 8422 $already-spilled-this-block?:check-reg: + 8423 81 7/subop/compare %edi 0/imm32 + 8424 0f 84/jump-if-= break/disp32 + 8425 # if (cand-reg == needle) return true + 8426 (string-equal? %esi %edi) # => eax + 8427 3d/compare-eax-and 0/imm32/false + 8428 74/jump-if-= break/disp8 + 8429 $already-spilled-this-block?:return-true: + 8430 b8/copy-to-eax 1/imm32/true + 8431 eb/jump $already-spilled-this-block?:end/disp8 + 8432 } + 8433 $already-spilled-this-block?:continue: + 8434 # curr -= 8 + 8435 81 5/subop/subtract %edx 8/imm32 + 8436 e9/jump loop/disp32 + 8437 } + 8438 # return false + 8439 b8/copy-to-eax 0/imm32/false + 8440 $already-spilled-this-block?:end: + 8441 # . restore registers + 8442 5f/pop-to-edi + 8443 5e/pop-to-esi + 8444 5b/pop-to-ebx + 8445 5a/pop-to-edx + 8446 59/pop-to-ecx + 8447 # . epilogue + 8448 89/<- %esp 5/r32/ebp + 8449 5d/pop-to-ebp + 8450 c3/return + 8451 + 8452 # is there a var before 'v' with the same block-depth and register on the 'vars' stack? + 8453 # v is guaranteed to be within vars + 8454 # 'start' is provided as an optimization, a pointer within vars + 8455 # *start == v + 8456 same-register-spilled-before?: # v: (addr var), vars: (addr stack (handle var)), start: (addr var) -> result/eax: boolean + 8457 # . prologue + 8458 55/push-ebp + 8459 89/<- %ebp 4/r32/esp + 8460 # . save registers + 8461 51/push-ecx + 8462 52/push-edx + 8463 53/push-ebx + 8464 56/push-esi + 8465 57/push-edi + 8466 # ecx = v + 8467 8b/-> *(ebp+8) 1/r32/ecx + 8468 # var reg/edx: (addr array byte) = lookup(v->register) + 8469 (lookup *(ecx+0x18) *(ecx+0x1c)) # Var-register Var-register => eax + 8470 89/<- %edx 0/r32/eax + 8471 # var depth/ebx: int = v->block-depth + 8472 8b/-> *(ecx+0x10) 3/r32/ebx # Var-block-depth + 8473 # var min/ecx: (addr handle var) = vars->data + 8474 8b/-> *(ebp+0xc) 1/r32/ecx + 8475 81 0/subop/add %ecx 8/imm32 + 8476 # TODO: check that start >= min and start < &vars->data[top] + 8477 # TODO: check that *start == v + 8478 # var curr/esi: (addr handle var) = start + 8479 8b/-> *(ebp+0x10) 6/r32/esi + 8480 # curr -= 8 + 8481 81 5/subop/subtract %esi 8/imm32 + 8482 { + 8483 $same-register-spilled-before?:loop: + 8484 # if (curr < min) break + 8485 39/compare %esi 1/r32/ecx + 8486 0f 82/jump-if-addr< break/disp32 + 8487 # var x/eax: (addr var) = lookup(*curr) + 8488 (lookup *esi *(esi+4)) # => eax + 8489 # if (x->block-depth < depth) break + 8490 39/compare *(eax+0x10) 3/r32/ebx # Var-block-depth + 8491 0f 8c/jump-if-< break/disp32 + 8492 # if (x->register == 0) continue + 8493 81 7/subop/compare *(eax+0x18) 0/imm32 # Var-register + 8494 74/jump-if-= $same-register-spilled-before?:continue/disp8 + 8495 # if (x->register == reg) return true + 8496 (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + 8497 (string-equal? %eax %edx) # => eax + 8498 3d/compare-eax-and 0/imm32/false + 8499 b8/copy-to-eax 1/imm32/true + 8500 75/jump-if-!= $same-register-spilled-before?:end/disp8 + 8501 $same-register-spilled-before?:continue: + 8502 # curr -= 8 + 8503 81 5/subop/subtract %esi 8/imm32 + 8504 e9/jump loop/disp32 + 8505 } + 8506 $same-register-spilled-before?:false: + 8507 b8/copy-to-eax 0/imm32/false + 8508 $same-register-spilled-before?:end: + 8509 # . restore registers + 8510 5f/pop-to-edi + 8511 5e/pop-to-esi + 8512 5b/pop-to-ebx + 8513 5a/pop-to-edx + 8514 59/pop-to-ecx + 8515 # . epilogue + 8516 89/<- %esp 5/r32/ebp + 8517 5d/pop-to-ebp + 8518 c3/return + 8519 + 8520 # clean up global state for 'vars' until some block depth + 8521 clean-up-blocks: # vars: (addr stack (handle var)), until-block-depth: int + 8522 # . prologue + 8523 55/push-ebp + 8524 89/<- %ebp 4/r32/esp + 8525 # . save registers + 8526 50/push-eax + 8527 51/push-ecx + 8528 56/push-esi + 8529 # esi = vars + 8530 8b/-> *(ebp+8) 6/r32/esi + 8531 # ecx = until-block-depth + 8532 8b/-> *(ebp+0xc) 1/r32/ecx + 8533 { + 8534 $clean-up-blocks:reclaim-loop: + 8535 # if (vars->top <= 0) break + 8536 8b/-> *esi 0/r32/eax # Stack-top + 8537 3d/compare-eax-and 0/imm32 + 8538 7e/jump-if-<= break/disp8 + 8539 # var v/eax: (addr var) = lookup(vars[vars->top-8]) + 8540 (lookup *(esi+eax) *(esi+eax+4)) # vars + 8 + vars->top - 8 => eax + 8541 # if (v->block-depth < until-block-depth) break + 8542 39/compare *(eax+0x10) 1/r32/ecx # Var-block-depth + 8543 7c/jump-if-< break/disp8 + 8544 # if v is on the stack, update Curr-local-stack-offset + 8545 81 7/subop/compare *(eax+0x18) 0/imm32 # Var-register + 8546 { + 8547 75/jump-if-!= break/disp8 + 8548 $clean-up-blocks:reclaim-var-on-stack: + 8549 (size-of %eax) # => eax + 8550 01/add-to *Curr-local-stack-offset 0/r32/eax + 8551 } + 8552 (pop %esi) # => eax + 8553 (pop %esi) # => eax + 8554 e9/jump loop/disp32 + 8555 } + 8556 $clean-up-blocks:end: + 8557 # . restore registers + 8558 5e/pop-to-esi + 8559 59/pop-to-ecx + 8560 58/pop-to-eax + 8561 # . epilogue + 8562 89/<- %esp 5/r32/ebp + 8563 5d/pop-to-ebp + 8564 c3/return + 8565 + 8566 emit-subx-var-def: # out: (addr buffered-file), stmt: (addr stmt) + 8567 # . prologue + 8568 55/push-ebp + 8569 89/<- %ebp 4/r32/esp + 8570 # . save registers + 8571 50/push-eax + 8572 51/push-ecx + 8573 52/push-edx + 8574 # eax = stmt + 8575 8b/-> *(ebp+0xc) 0/r32/eax + 8576 # var v/ecx: (addr var) + 8577 (lookup *(eax+4) *(eax+8)) # Vardef-var Vardef-var => eax + 8578 89/<- %ecx 0/r32/eax + 8579 # v->block-depth = *Curr-block-depth + 8580 8b/-> *Curr-block-depth 0/r32/eax + 8581 89/<- *(ecx+0x10) 0/r32/eax # Var-block-depth + 8582 # var n/edx: int = size-of(stmt->var) + 8583 (size-of %ecx) # => eax + 8584 89/<- %edx 0/r32/eax + 8585 # *Curr-local-stack-offset -= n + 8586 29/subtract-from *Curr-local-stack-offset 2/r32/edx + 8587 # v->offset = *Curr-local-stack-offset + 8588 8b/-> *Curr-local-stack-offset 0/r32/eax + 8589 89/<- *(ecx+0x14) 0/r32/eax # Var-offset + 8590 # if v is an array, do something special + 8591 { + 8592 (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + 8593 (is-mu-array? %eax) # => eax + 8594 3d/compare-eax-and 0/imm32/false + 8595 0f 84/jump-if-= break/disp32 + 8596 # var array-size-without-size/edx: int = n-4 + 8597 81 5/subop/subtract %edx 4/imm32 + 8598 (emit-indent *(ebp+8) *Curr-block-depth) + 8599 (write-buffered *(ebp+8) "(push-n-zero-bytes ") + 8600 (print-int32-buffered *(ebp+8) %edx) + 8601 (write-buffered *(ebp+8) ")\n") + 8602 (emit-indent *(ebp+8) *Curr-block-depth) + 8603 (write-buffered *(ebp+8) "68/push ") + 8604 (print-int32-buffered *(ebp+8) %edx) + 8605 (write-buffered *(ebp+8) "/imm32\n") + 8606 eb/jump $emit-subx-var-def:end/disp8 + 8607 } + 8608 # while n > 0 + 8609 { + 8610 81 7/subop/compare %edx 0/imm32 + 8611 7e/jump-if-<= break/disp8 + 8612 (emit-indent *(ebp+8) *Curr-block-depth) + 8613 (write-buffered *(ebp+8) "68/push 0/imm32\n") + 8614 # n -= 4 + 8615 81 5/subop/subtract %edx 4/imm32 + 8616 # + 8617 eb/jump loop/disp8 + 8618 } + 8619 $emit-subx-var-def:end: + 8620 # . restore registers + 8621 5a/pop-to-edx + 8622 59/pop-to-ecx + 8623 58/pop-to-eax + 8624 # . epilogue + 8625 89/<- %esp 5/r32/ebp + 8626 5d/pop-to-ebp + 8627 c3/return + 8628 + 8629 emit-subx-stmt: # out: (addr buffered-file), stmt: (addr stmt), primitives: (addr primitive) + 8630 # . prologue + 8631 55/push-ebp + 8632 89/<- %ebp 4/r32/esp + 8633 # . save registers + 8634 50/push-eax + 8635 51/push-ecx + 8636 # - some special-case primitives that don't actually use the 'primitives' data structure + 8637 # var op/ecx: (addr array byte) = lookup(stmt->operation) + 8638 8b/-> *(ebp+0xc) 1/r32/ecx + 8639 (lookup *(ecx+4) *(ecx+8)) # Stmt1-operation Stmt1-operation => eax + 8640 89/<- %ecx 0/r32/eax + 8641 # array size + 8642 { + 8643 # if (!string-equal?(stmt->operation, "length")) break + 8644 (string-equal? %ecx "length") # => eax + 8645 3d/compare-eax-and 0/imm32 + 8646 0f 84/jump-if-= break/disp32 + 8647 (translate-mu-length-stmt *(ebp+8) *(ebp+0xc)) + 8648 e9/jump $emit-subx-stmt:end/disp32 + 8649 } + 8650 # index into array + 8651 { + 8652 # if (!string-equal?(stmt->operation, "index")) break + 8653 (string-equal? %ecx "index") # => eax + 8654 3d/compare-eax-and 0/imm32 + 8655 0f 84/jump-if-= break/disp32 + 8656 (translate-mu-index-stmt *(ebp+8) *(ebp+0xc)) + 8657 e9/jump $emit-subx-stmt:end/disp32 + 8658 } + 8659 # compute-offset for index into array + 8660 { + 8661 # if (!string-equal?(stmt->operation, "compute-offset")) break + 8662 (string-equal? %ecx "compute-offset") # => eax + 8663 3d/compare-eax-and 0/imm32 + 8664 0f 84/jump-if-= break/disp32 + 8665 (translate-mu-compute-index-stmt *(ebp+8) *(ebp+0xc)) + 8666 e9/jump $emit-subx-stmt:end/disp32 + 8667 } + 8668 # get field from record + 8669 { + 8670 # if (!string-equal?(stmt->operation, "get")) break + 8671 (string-equal? %ecx "get") # => eax + 8672 3d/compare-eax-and 0/imm32 + 8673 0f 84/jump-if-= break/disp32 + 8674 (translate-mu-get-stmt *(ebp+8) *(ebp+0xc)) + 8675 e9/jump $emit-subx-stmt:end/disp32 + 8676 } + 8677 # - if stmt matches a primitive, emit it + 8678 { + 8679 $emit-subx-stmt:check-for-primitive: + 8680 # var curr/eax: (addr primitive) + 8681 (find-matching-primitive *(ebp+0x10) *(ebp+0xc)) # primitives, stmt => eax + 8682 3d/compare-eax-and 0/imm32 + 8683 74/jump-if-= break/disp8 + 8684 $emit-subx-stmt:primitive: + 8685 (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr + 8686 e9/jump $emit-subx-stmt:end/disp32 + 8687 } + 8688 # - otherwise emit a call + 8689 # TODO: type-checking + 8690 $emit-subx-stmt:call: + 8691 (emit-call *(ebp+8) *(ebp+0xc)) + 8692 $emit-subx-stmt:end: + 8693 # . restore registers + 8694 59/pop-to-ecx + 8695 58/pop-to-eax + 8696 # . epilogue + 8697 89/<- %esp 5/r32/ebp + 8698 5d/pop-to-ebp + 8699 c3/return + 8700 + 8701 # TODO: actually return the length in array elements, rather than the size in bytes + 8702 translate-mu-length-stmt: # out: (addr buffered-file), stmt: (addr stmt) + 8703 # . prologue + 8704 55/push-ebp + 8705 89/<- %ebp 4/r32/esp + 8706 # . save registers + 8707 50/push-eax + 8708 51/push-ecx + 8709 # ecx = stmt + 8710 8b/-> *(ebp+0xc) 1/r32/ecx + 8711 # + 8712 (emit-indent *(ebp+8) *Curr-block-depth) + 8713 (write-buffered *(ebp+8) "8b/-> *") + 8714 # var base/eax: (handle var) = inouts[0] + 8715 (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 8716 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 8717 # if base is an (addr array ...) in a register + 8718 { + 8719 81 7/subop/compare *(eax+0x18)) 0/imm32 # Var-register + 8720 74/jump-if-= break/disp8 + 8721 (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + 8722 (write-buffered *(ebp+8) %eax) + 8723 eb/jump $translate-mu-length-stmt:emit-output/disp8 + 8724 } + 8725 # otherwise if base is an (array ...) on the stack + 8726 { + 8727 81 7/subop/compare *(eax+0x14)) 0/imm32 # Var-offset + 8728 74/jump-if-= break/disp8 + 8729 (write-buffered *(ebp+8) "(ebp+") + 8730 (print-int32-buffered *(ebp+8) *(eax+0x14)) # Var-offset + 8731 (write-buffered *(ebp+8) ")") + 8732 } + 8733 $translate-mu-length-stmt:emit-output: + 8734 (write-buffered *(ebp+8) " ") + 8735 # outputs[0] "/r32" + 8736 (lookup *(ecx+0x14) *(ecx+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 8737 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 8738 (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + 8739 (get Registers %eax 0xc "Registers") # => eax + 8740 (print-int32-buffered *(ebp+8) *eax) + 8741 (write-buffered *(ebp+8) "/r32\n") + 8742 $translate-mu-length-stmt:end: + 8743 # . restore registers + 8744 59/pop-to-ecx + 8745 58/pop-to-eax + 8746 # . epilogue + 8747 89/<- %esp 5/r32/ebp + 8748 5d/pop-to-ebp + 8749 c3/return + 8750 + 8751 translate-mu-index-stmt: # out: (addr buffered-file), stmt: (addr stmt) + 8752 # . prologue + 8753 55/push-ebp + 8754 89/<- %ebp 4/r32/esp + 8755 # . save registers + 8756 51/push-ecx + 8757 # ecx = stmt + 8758 8b/-> *(ebp+0xc) 1/r32/ecx + 8759 # var base/ecx: (addr var) = stmt->inouts[0] + 8760 (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 8761 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 8762 89/<- %ecx 0/r32/eax + 8763 # if (var->register) do one thing + 8764 { + 8765 81 7/subop/compare *(ecx+0x18) 0/imm32 # Var-register + 8766 74/jump-if-= break/disp8 + 8767 # TODO: ensure there's no dereference + 8768 (translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc)) + 8769 eb/jump $translate-mu-index-stmt:end/disp8 + 8770 } + 8771 # if (var->offset) do a different thing + 8772 { + 8773 81 7/subop/compare *(ecx+0x14) 0/imm32 # Var-offset + 8774 74/jump-if-= break/disp8 + 8775 # TODO: ensure there's no dereference + 8776 (translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc)) + 8777 eb/jump $translate-mu-index-stmt:end/disp8 + 8778 } + 8779 $translate-mu-index-stmt:end: + 8780 # . restore registers + 8781 59/pop-to-ecx + 8782 # . epilogue + 8783 89/<- %esp 5/r32/ebp + 8784 5d/pop-to-ebp + 8785 c3/return + 8786 + 8787 $translate-mu-index-stmt-with-array:error1: + 8788 (write-buffered Stderr "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n") + 8789 (flush Stderr) + 8790 # . syscall(exit, 1) + 8791 bb/copy-to-ebx 1/imm32 + 8792 b8/copy-to-eax 1/imm32/exit + 8793 cd/syscall 0x80/imm8 + 8794 # never gets here + 8795 + 8796 $translate-mu-index-stmt-with-array:error2: + 8797 (write-buffered Stderr "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n") + 8798 (flush Stderr) + 8799 # . syscall(exit, 1) + 8800 bb/copy-to-ebx 1/imm32 + 8801 b8/copy-to-eax 1/imm32/exit + 8802 cd/syscall 0x80/imm8 + 8803 # never gets here + 8804 + 8805 translate-mu-index-stmt-with-array-in-register: # out: (addr buffered-file), stmt: (addr stmt) + 8806 # . prologue + 8807 55/push-ebp + 8808 89/<- %ebp 4/r32/esp + 8809 # . save registers + 8810 50/push-eax + 8811 51/push-ecx + 8812 52/push-edx + 8813 53/push-ebx + 8814 # + 8815 (emit-indent *(ebp+8) *Curr-block-depth) + 8816 (write-buffered *(ebp+8) "8d/copy-address *(") + 8817 # TODO: ensure inouts[0] is in a register and not dereferenced + 8818 $translate-mu-index-stmt-with-array-in-register:emit-base: + 8819 # ecx = stmt + 8820 8b/-> *(ebp+0xc) 1/r32/ecx + 8821 # var base/ebx: (addr var) = inouts[0] + 8822 (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 8823 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 8824 89/<- %ebx 0/r32/eax + 8825 # print base->register " + " + 8826 (lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax + 8827 (write-buffered *(ebp+8) %eax) + 8828 (write-buffered *(ebp+8) " + ") + 8829 # var index/edx: (addr var) = inouts[1] + 8830 (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 8831 (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + 8832 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 8833 89/<- %edx 0/r32/eax + 8834 # if index->register + 8835 81 7/subop/compare *(edx+0x18) 0/imm32 # Var-register + 8836 { + 8837 0f 84/jump-if-= break/disp32 + 8838 $translate-mu-index-stmt-with-array-in-register:emit-register-index: + 8839 # if index is an int + 8840 (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + 8841 (is-simple-mu-type? %eax 1) # int => eax + 8842 3d/compare-eax-and 0/imm32/false + 8843 { + 8844 0f 84/jump-if-= break/disp32 + 8845 $translate-mu-index-stmt-with-array-in-register:emit-int-register-index: + 8846 # print index->register "<<" log2(size-of(element(base->type))) " + 4) " + 8847 # . index->register "<<" + 8848 (lookup *(edx+0x18) *(edx+0x1c)) # Var-register Var-register => eax + 8849 (write-buffered *(ebp+8) %eax) + 8850 (write-buffered *(ebp+8) "<<") + 8851 # . log2(size-of(element(base->type))) + 8852 # TODO: ensure size is a power of 2 + 8853 (array-element-type-id %ebx) # => eax + 8854 (size-of-type-id %eax) # => eax + 8855 (num-shift-rights %eax) # => eax + 8856 (print-int32-buffered *(ebp+8) %eax) + 8857 e9/jump $translate-mu-index-stmt-with-array-in-register:emit-register-index-done/disp32 + 8858 } + 8859 # if index->type is any other atom, abort + 8860 (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + 8861 81 7/subop/compare *eax 0/imm32/false # Tree-is-atom + 8862 0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32 + 8863 # if index has type (offset ...) + 8864 (lookup *(eax+4) *(eax+8)) # Tree-left Tree-left => eax + 8865 (is-simple-mu-type? %eax 7) # => eax + 8866 3d/compare-eax-and 0/imm32/false + 8867 { + 8868 0f 84/jump-if-= break/disp32 + 8869 # print index->register + 8870 $translate-mu-index-stmt-with-array-in-register:emit-offset-register-index: + 8871 (lookup *(edx+0x18) *(edx+0x1c)) # Var-register Var-register => eax + 8872 (write-buffered *(ebp+8) %eax) + 8873 } + 8874 $translate-mu-index-stmt-with-array-in-register:emit-register-index-done: + 8875 (write-buffered *(ebp+8) " + 4) ") + 8876 e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32 + 8877 } + 8878 # otherwise if index is a literal + 8879 (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + 8880 (is-simple-mu-type? %eax 0) # => eax + 8881 3d/compare-eax-and 0/imm32/false + 8882 { + 8883 0f 84/jump-if-= break/disp32 + 8884 $translate-mu-index-stmt-with-array-in-register:emit-literal-index: + 8885 # var index-value/edx: int = parse-hex-int(index->name) + 8886 (lookup *edx *(edx+4)) # Var-name Var-name => eax + 8887 (parse-hex-int %eax) # => eax + 8888 89/<- %edx 0/r32/eax + 8889 # offset = idx-value * size-of(element(base->type)) + 8890 (array-element-type-id %ebx) # => eax + 8891 (size-of-type-id %eax) # => eax + 8892 f7 4/subop/multiply-into-eax %edx # clobbers edx + 8893 # offset += 4 for array size + 8894 05/add-to-eax 4/imm32 + 8895 # TODO: check edx for overflow + 8896 # print offset + 8897 (print-int32-buffered *(ebp+8) %eax) + 8898 (write-buffered *(ebp+8) ") ") + 8899 e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32 + 8900 } + 8901 # otherwise abort + 8902 e9/jump $translate-mu-index-stmt-with-array:error1/disp32 + 8903 $translate-mu-index-stmt-with-array-in-register:emit-output: + 8904 # outputs[0] "/r32" + 8905 8b/-> *(ebp+0xc) 1/r32/ecx + 8906 (lookup *(ecx+0x14) *(ecx+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 8907 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 8908 (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + 8909 (get Registers %eax 0xc "Registers") # => eax: (addr int) + 8910 (print-int32-buffered *(ebp+8) *eax) + 8911 (write-buffered *(ebp+8) "/r32\n") + 8912 $translate-mu-index-stmt-with-array-in-register:end: + 8913 # . restore registers + 8914 5b/pop-to-ebx + 8915 5a/pop-to-edx + 8916 59/pop-to-ecx + 8917 58/pop-to-eax + 8918 # . epilogue + 8919 89/<- %esp 5/r32/ebp + 8920 5d/pop-to-ebp + 8921 c3/return + 8922 + 8923 translate-mu-index-stmt-with-array-on-stack: # out: (addr buffered-file), stmt: (addr stmt) + 8924 # . prologue + 8925 55/push-ebp + 8926 89/<- %ebp 4/r32/esp + 8927 # . save registers + 8928 50/push-eax + 8929 51/push-ecx + 8930 52/push-edx + 8931 53/push-ebx + 8932 # + 8933 (emit-indent *(ebp+8) *Curr-block-depth) + 8934 (write-buffered *(ebp+8) "8d/copy-address *(ebp + ") + 8935 # var curr/edx: (addr stmt-var) = lookup(stmt->inouts) + 8936 8b/-> *(ebp+0xc) 0/r32/eax + 8937 (lookup *(eax+0xc) *(eax+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 8938 89/<- %edx 0/r32/eax + 8939 # var base/ecx: (addr var) = lookup(curr->value) + 8940 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 8941 89/<- %ecx 0/r32/eax + 8942 # var curr2/eax: (addr stmt-var) = lookup(curr->next) + 8943 (lookup *(edx+8) *(edx+0xc)) # Stmt-var-next Stmt-var-next => eax + 8944 # var index/edx: (handle var) = curr2->value + 8945 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 8946 89/<- %edx 0/r32/eax + 8947 # if index->register + 8948 81 7/subop/compare *(edx+0x18) 0/imm32 # Var-register + 8949 { + 8950 0f 84/jump-if-= break/disp32 + 8951 $translate-mu-index-stmt-with-array-on-stack:emit-register-index: + 8952 # if index is an int + 8953 (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + 8954 (is-simple-mu-type? %eax 1) # int => eax + 8955 3d/compare-eax-and 0/imm32/false + 8956 { + 8957 0f 84/jump-if-= break/disp32 + 8958 $translate-mu-index-stmt-with-array-on-stack:emit-int-register-index: + 8959 # print index->register "<<" log2(size-of(element-type(base))) " + " base->offset+4 + 8960 # . inouts[1]->register "<<" + 8961 (lookup *(edx+0x18) *(edx+0x1c)) # Var-register Var-register => eax + 8962 (write-buffered *(ebp+8) %eax) + 8963 (write-buffered *(ebp+8) "<<") + 8964 # . log2(size-of(element(base))) + 8965 # TODO: ensure size is a power of 2 + 8966 (array-element-type-id %ecx) # => eax + 8967 (size-of-type-id %eax) # => eax + 8968 (num-shift-rights %eax) # => eax + 8969 (print-int32-buffered *(ebp+8) %eax) + 8970 # + 8971 (write-buffered *(ebp+8) " + ") + 8972 # + 8973 8b/-> *(ecx+0x14) 0/r32/eax # Var-offset + 8974 05/add-to-eax 4/imm32 # for array length + 8975 (print-int32-buffered *(ebp+8) %eax) + 8976 e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done/disp32 + 8977 } + 8978 # if index->type is any other atom, abort + 8979 (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + 8980 81 7/subop/compare *eax 0/imm32/false # Tree-is-atom + 8981 0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32 + 8982 # if index has type (offset ...) + 8983 (lookup *(eax+4) *(eax+8)) # Tree-left Tree-left => eax + 8984 (is-simple-mu-type? %eax 7) # => eax + 8985 3d/compare-eax-and 0/imm32/false + 8986 { + 8987 0f 84/jump-if-= break/disp32 + 8988 # print index->register + 8989 $translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index: + 8990 (lookup *(edx+0x18) *(edx+0x1c)) # Var-register Var-register => eax + 8991 (write-buffered *(ebp+8) %eax) + 8992 } + 8993 $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done: + 8994 (write-buffered *(ebp+8) ") ") + 8995 e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32 + 8996 } + 8997 # otherwise if index is a literal + 8998 (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + 8999 (is-simple-mu-type? %eax 0) # => eax + 9000 3d/compare-eax-and 0/imm32/false + 9001 { + 9002 0f 84/jump-if-= break/disp32 + 9003 $translate-mu-index-stmt-with-array-on-stack:emit-literal-index: + 9004 # var idx-value/edx: int = parse-hex-int(index->name) + 9005 (lookup *edx *(edx+4)) # Var-name Var-name => eax + 9006 (parse-hex-int %eax) # Var-name => eax + 9007 89/<- %edx 0/r32/eax + 9008 # offset = idx-value * size-of(element-type(base->type)) + 9009 (array-element-type-id %ecx) # => eax + 9010 (size-of-type-id %eax) # => eax + 9011 f7 4/subop/multiply-into-eax %edx # clobbers edx + 9012 # offset += base->offset + 9013 03/add *(ecx+0x14) 0/r32/eax # Var-offset + 9014 # offset += 4 for array size + 9015 05/add-to-eax 4/imm32 + 9016 # TODO: check edx for overflow + 9017 # print offset + 9018 (print-int32-buffered *(ebp+8) %eax) + 9019 (write-buffered *(ebp+8) ") ") + 9020 e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32 + 9021 } + 9022 # otherwise abort + 9023 e9/jump $translate-mu-index-stmt-with-array:error1/disp32 + 9024 $translate-mu-index-stmt-with-array-on-stack:emit-output: + 9025 # outputs[0] "/r32" + 9026 8b/-> *(ebp+0xc) 0/r32/eax + 9027 (lookup *(eax+0x14) *(eax+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 9028 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 9029 (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + 9030 (get Registers %eax 0xc "Registers") # => eax: (addr int) + 9031 (print-int32-buffered *(ebp+8) *eax) + 9032 (write-buffered *(ebp+8) "/r32\n") + 9033 $translate-mu-index-stmt-with-array-on-stack:end: + 9034 # . restore registers + 9035 5b/pop-to-ebx + 9036 5a/pop-to-edx + 9037 59/pop-to-ecx + 9038 58/pop-to-eax + 9039 # . epilogue + 9040 89/<- %esp 5/r32/ebp + 9041 5d/pop-to-ebp + 9042 c3/return + 9043 + 9044 translate-mu-compute-index-stmt: # out: (addr buffered-file), stmt: (addr stmt) + 9045 # . prologue + 9046 55/push-ebp + 9047 89/<- %ebp 4/r32/esp + 9048 # . save registers + 9049 50/push-eax + 9050 51/push-ecx + 9051 52/push-edx + 9052 53/push-ebx + 9053 # + 9054 (emit-indent *(ebp+8) *Curr-block-depth) + 9055 (write-buffered *(ebp+8) "69/multiply") + 9056 # ecx = stmt + 9057 8b/-> *(ebp+0xc) 1/r32/ecx + 9058 # var first-inout/ebx: (addr stmt-var) = stmt->inouts[0] + 9059 (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 9060 89/<- %ebx 0/r32/eax + 9061 $translate-mu-compute-index-stmt:emit-index: + 9062 (lookup *(ebx+8) *(ebx+0xc)) # Stmt-var-next Stmt-var-next => eax + 9063 (emit-subx-var-as-rm32 *(ebp+8) %eax) + 9064 (write-buffered *(ebp+8) Space) + 9065 $translate-mu-compute-index-stmt:emit-elem-size: + 9066 # var base/ebx: (addr var) + 9067 (lookup *ebx *(ebx+4)) # Stmt-var-value Stmt-var-value => eax + 9068 89/<- %ebx 0/r32/eax + 9069 # print size-of(element(base->type)) + 9070 (array-element-type-id %ebx) # => eax + 9071 (size-of-type-id %eax) # => eax + 9072 (print-int32-buffered *(ebp+8) %eax) + 9073 (write-buffered *(ebp+8) "/imm32 ") + 9074 $translate-mu-compute-index-stmt:emit-output: + 9075 # outputs[0] "/r32" + 9076 (lookup *(ecx+0x14) *(ecx+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 9077 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 9078 (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + 9079 (get Registers %eax 0xc "Registers") # => eax: (addr int) + 9080 (print-int32-buffered *(ebp+8) *eax) + 9081 (write-buffered *(ebp+8) "/r32\n") + 9082 $translate-mu-compute-index-stmt:end: + 9083 # . restore registers + 9084 5b/pop-to-ebx + 9085 5a/pop-to-edx + 9086 59/pop-to-ecx + 9087 58/pop-to-eax + 9088 # . epilogue + 9089 89/<- %esp 5/r32/ebp + 9090 5d/pop-to-ebp + 9091 c3/return + 9092 + 9093 translate-mu-get-stmt: # out: (addr buffered-file), stmt: (addr stmt) + 9094 # . prologue + 9095 55/push-ebp + 9096 89/<- %ebp 4/r32/esp + 9097 # . save registers + 9098 50/push-eax + 9099 51/push-ecx + 9100 52/push-edx + 9101 # + 9102 (emit-indent *(ebp+8) *Curr-block-depth) + 9103 (write-buffered *(ebp+8) "8d/copy-address ") + 9104 # ecx = stmt + 9105 8b/-> *(ebp+0xc) 1/r32/ecx + 9106 # var offset/edx: int = get offset of stmt + 9107 (mu-get-offset %ecx) # => eax + 9108 89/<- %edx 0/r32/eax + 9109 # var base/eax: (addr var) = stmt->inouts->value + 9110 (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 9111 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 9112 # if base is in a register + 9113 81 7/subop/compare *(eax+0x18) 0/imm32 # Var-register + 9114 { + 9115 0f 84/jump-if-= break/disp32 + 9116 $translate-mu-get-stmt:emit-register-input: + 9117 # emit "*(" base->register " + " offset ") " + 9118 (write-buffered *(ebp+8) "*(") + 9119 (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + 9120 (write-buffered *(ebp+8) %eax) + 9121 (write-buffered *(ebp+8) " + ") + 9122 (print-int32-buffered *(ebp+8) %edx) + 9123 (write-buffered *(ebp+8) ") ") + 9124 e9/jump $translate-mu-get-stmt:emit-output/disp32 + 9125 } + 9126 # otherwise base is on the stack + 9127 { + 9128 $translate-mu-get-stmt:emit-stack-input: + 9129 # emit "*(ebp + " inouts[0]->stack-offset + offset ") " + 9130 (write-buffered *(ebp+8) "*(ebp+") + 9131 03/add *(eax+0x14) 2/r32/edx # Var-offset + 9132 (print-int32-buffered *(ebp+8) %edx) + 9133 (write-buffered *(ebp+8) ") ") + 9134 eb/jump $translate-mu-get-stmt:emit-output/disp8 + 9135 } + 9136 $translate-mu-get-stmt:emit-output: + 9137 # var output/eax: (addr var) = stmt->outputs->value + 9138 (lookup *(ecx+0x14) *(ecx+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 9139 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 9140 # emit offset->register "/r32" + 9141 (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + 9142 (get Registers %eax 0xc "Registers") # => eax: (addr int) + 9143 (print-int32-buffered *(ebp+8) *eax) + 9144 (write-buffered *(ebp+8) "/r32\n") + 9145 $translate-mu-get-stmt:end: + 9146 # . restore registers + 9147 5a/pop-to-edx + 9148 59/pop-to-ecx + 9149 58/pop-to-eax + 9150 # . epilogue + 9151 89/<- %esp 5/r32/ebp + 9152 5d/pop-to-ebp + 9153 c3/return + 9154 + 9155 array-element-type-id: # v: (addr var) -> result/eax: type-id + 9156 # precondition: n is positive + 9157 # . prologue + 9158 55/push-ebp + 9159 89/<- %ebp 4/r32/esp + 9160 # + 9161 8b/-> *(ebp+8) 0/r32/eax + 9162 (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 9163 # TODO: ensure type->left is 'addr' + 9164 (lookup *(eax+0xc) *(eax+0x10)) # Tree-right Tree-right => eax + 9165 # TODO: ensure that type->right is non-null + 9166 # TODO: ensure that type->right->left is 'array' + 9167 (lookup *(eax+0xc) *(eax+0x10)) # Tree-right Tree-right => eax + 9168 # TODO: ensure that type->right->right is non-null + 9169 (lookup *(eax+4) *(eax+8)) # Tree-left Tree-left => eax + 9170 8b/-> *(eax+4) 0/r32/eax # Tree-value + 9171 $array-element-type-id:end: + 9172 # . epilogue + 9173 89/<- %esp 5/r32/ebp + 9174 5d/pop-to-ebp + 9175 c3/return + 9176 + 9177 num-shift-rights: # n: int -> result/eax: int + 9178 # precondition: n is a positive power of 2 + 9179 # . prologue + 9180 55/push-ebp + 9181 89/<- %ebp 4/r32/esp + 9182 # . save registers + 9183 51/push-ecx + 9184 # var curr/ecx: int = n + 9185 8b/-> *(ebp+8) 1/r32/ecx + 9186 # result = 0 + 9187 b8/copy-to-eax 0/imm32 + 9188 { + 9189 # if (curr <= 1) break + 9190 81 7/subop/compare %ecx 1/imm32 + 9191 7e/jump-if-<= break/disp8 + 9192 40/increment-eax + 9193 c1/shift 5/subop/arithmetic-right %ecx 1/imm8 + 9194 eb/jump loop/disp8 + 9195 } + 9196 $num-shift-rights:end: + 9197 # . restore registers + 9198 59/pop-to-ecx + 9199 # . epilogue + 9200 89/<- %esp 5/r32/ebp + 9201 5d/pop-to-ebp + 9202 c3/return + 9203 + 9204 mu-get-offset: # stmt: (addr stmt) -> result/eax: int + 9205 # . prologue + 9206 55/push-ebp + 9207 89/<- %ebp 4/r32/esp + 9208 # var second-inout/eax: (addr stmt-var) = stmt->inouts->next + 9209 8b/-> *(ebp+8) 0/r32/eax + 9210 (lookup *(eax+0xc) *(eax+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 9211 (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + 9212 # var output-var/eax: (addr var) = second-inout->value + 9213 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 9214 # return output-var->stack-offset + 9215 8b/-> *(eax+0x14) 0/r32/eax # Var-offset + 9216 $emit-get-offset:end: + 9217 # . epilogue + 9218 89/<- %esp 5/r32/ebp + 9219 5d/pop-to-ebp + 9220 c3/return + 9221 + 9222 emit-subx-block: # out: (addr buffered-file), block: (addr block), vars: (addr stack (handle var)) + 9223 # . prologue + 9224 55/push-ebp + 9225 89/<- %ebp 4/r32/esp + 9226 # . save registers + 9227 50/push-eax + 9228 51/push-ecx + 9229 56/push-esi + 9230 # esi = block + 9231 8b/-> *(ebp+0xc) 6/r32/esi + 9232 # block->var->block-depth = *Curr-block-depth + 9233 (lookup *(esi+0xc) *(esi+0x10)) # Block-var Block-var => eax + 9234 8b/-> *Curr-block-depth 1/r32/ecx + 9235 89/<- *(eax+0x10) 1/r32/ecx # Var-block-depth + 9236 # var stmts/eax: (addr list stmt) = lookup(block->statements) + 9237 (lookup *(esi+4) *(esi+8)) # Block-stmts Block-stmts => eax + 9238 # + 9239 { + 9240 $emit-subx-block:check-empty: + 9241 3d/compare-eax-and 0/imm32 + 9242 0f 84/jump-if-= break/disp32 + 9243 (emit-indent *(ebp+8) *Curr-block-depth) + 9244 (write-buffered *(ebp+8) "{\n") + 9245 # var v/ecx: (addr var) = lookup(block->var) + 9246 (lookup *(esi+0xc) *(esi+0x10)) # Block-var Block-var => eax + 9247 89/<- %ecx 0/r32/eax + 9248 # + 9249 (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + 9250 (write-buffered *(ebp+8) %eax) + 9251 (write-buffered *(ebp+8) ":loop:\n") + 9252 ff 0/subop/increment *Curr-block-depth + 9253 (push *(ebp+0x10) *(esi+0xc)) # Block-var + 9254 (push *(ebp+0x10) *(esi+0x10)) # Block-var + 9255 # emit block->statements + 9256 (lookup *(esi+4) *(esi+8)) # Block-stmts Block-stmts => eax + 9257 (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10)) + 9258 (pop *(ebp+0x10)) # => eax + 9259 (pop *(ebp+0x10)) # => eax + 9260 ff 1/subop/decrement *Curr-block-depth + 9261 (emit-indent *(ebp+8) *Curr-block-depth) + 9262 (write-buffered *(ebp+8) "}\n") + 9263 (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + 9264 (write-buffered *(ebp+8) %eax) + 9265 (write-buffered *(ebp+8) ":break:\n") + 9266 } + 9267 $emit-subx-block:end: + 9268 # . restore registers + 9269 5e/pop-to-esi + 9270 59/pop-to-ecx + 9271 58/pop-to-eax + 9272 # . epilogue + 9273 89/<- %esp 5/r32/ebp + 9274 5d/pop-to-ebp + 9275 c3/return + 9276 + 9277 # Primitives supported + 9278 # See mu_instructions for a summary of this linked-list data structure. + 9279 # + 9280 # For each operation, put variants with hard-coded registers before flexible ones. + 9281 # + 9282 # Unfortunately, our restrictions on addresses require that various fields in + 9283 # primitives be handles, which complicates these definitions. + 9284 # - we need to insert dummy fields all over the place for fake alloc-ids + 9285 # - we can't use our syntax sugar of quoted literals for string fields + 9286 # + 9287 # Fake alloc-ids are needed because our type definitions up top require + 9288 # handles but it's clearer to statically allocate these long-lived objects. + 9289 # Fake alloc-ids are perfectly safe, but they can't be reclaimed. + 9290 # + 9291 # Every 'object' below starts with a fake alloc-id. It may also contain other + 9292 # fake alloc-ids for various handle fields. + 9293 # + 9294 # I think of objects starting with a fake alloc-id as having type 'payload'. + 9295 # It's not really intended to be created dynamically; for that use `allocate` + 9296 # as usual. + 9297 # + 9298 # Idea for a notation to simplify such definitions: + 9299 # _Primitive-increment-eax: # (payload primitive) + 9300 # 0x11/alloc-id:fake:payload + 9301 # 0x11 @(0x11 "increment") # name + 9302 # 0 0 # inouts + 9303 # 0x11 @(0x11/payload + 9304 # 0x11 @(0x11/payload # List-value + 9305 # 0 0 # Var-name + 9306 # 0x11 @(0x11 # Var-type + 9307 # 1/is-atom + 9308 # 1/value 0/unused # Tree-left + 9309 # 0 0 # Tree-right + 9310 # ) + 9311 # 1 # block-depth + 9312 # 0 # stack-offset + 9313 # 0x11 @(0x11 "eax") # Var-register + 9314 # ) + 9315 # 0 0) # List-next + 9316 # ... + 9317 # _Primitive-increment-ecx/imm32/next + 9318 # ... + 9319 # Awfully complex and non-obvious. But also clearly signals there's something + 9320 # to learn here, so may be worth trying. + 9321 # + 9322 # '@' is just an initial thought. Punctuation used so far in Mu: () * % # / " + 9323 # + 9324 # For now we'll continue to just use comments and manually ensure they stay up + 9325 # to date. + 9326 == data + 9327 Primitives: # (addr primitive) + 9328 # - increment/decrement + 9329 _Primitive-increment-eax: # (addr primitive) + 9330 # var/eax <- increment => 40/increment-eax + 9331 0x11/imm32/alloc-id:fake + 9332 _string-increment/imm32/name + 9333 0/imm32/no-inouts + 9334 0/imm32/no-inouts + 9335 0x11/imm32/alloc-id:fake + 9336 Single-int-var-in-eax/imm32/outputs + 9337 0x11/imm32/alloc-id:fake + 9338 _string_40_increment_eax/imm32/subx-name + 9339 0/imm32/no-rm32 + 9340 0/imm32/no-r32 + 9341 0/imm32/no-imm32 + 9342 0/imm32/no-disp32 + 9343 0/imm32/output-is-write-only + 9344 0x11/imm32/alloc-id:fake + 9345 _Primitive-increment-ecx/imm32/next + 9346 _Primitive-increment-ecx: # (payload primitive) + 9347 0x11/imm32/alloc-id:fake:payload + 9348 # var/ecx <- increment => 41/increment-ecx + 9349 0x11/imm32/alloc-id:fake + 9350 _string-increment/imm32/name + 9351 0/imm32/no-inouts + 9352 0/imm32/no-inouts + 9353 0x11/imm32/alloc-id:fake + 9354 Single-int-var-in-ecx/imm32/outputs + 9355 0x11/imm32/alloc-id:fake + 9356 _string_41_increment_ecx/imm32/subx-name + 9357 0/imm32/no-rm32 + 9358 0/imm32/no-r32 + 9359 0/imm32/no-imm32 + 9360 0/imm32/no-disp32 + 9361 0/imm32/output-is-write-only + 9362 0x11/imm32/alloc-id:fake + 9363 _Primitive-increment-edx/imm32/next + 9364 _Primitive-increment-edx: # (payload primitive) + 9365 0x11/imm32/alloc-id:fake:payload + 9366 # var/edx <- increment => 42/increment-edx + 9367 0x11/imm32/alloc-id:fake + 9368 _string-increment/imm32/name + 9369 0/imm32/no-inouts + 9370 0/imm32/no-inouts + 9371 0x11/imm32/alloc-id:fake + 9372 Single-int-var-in-edx/imm32/outputs + 9373 0x11/imm32/alloc-id:fake + 9374 _string_42_increment_edx/imm32/subx-name + 9375 0/imm32/no-rm32 + 9376 0/imm32/no-r32 + 9377 0/imm32/no-imm32 + 9378 0/imm32/no-disp32 + 9379 0/imm32/output-is-write-only + 9380 0x11/imm32/alloc-id:fake + 9381 _Primitive-increment-ebx/imm32/next + 9382 _Primitive-increment-ebx: # (payload primitive) + 9383 0x11/imm32/alloc-id:fake:payload + 9384 # var/ebx <- increment => 43/increment-ebx + 9385 0x11/imm32/alloc-id:fake + 9386 _string-increment/imm32/name + 9387 0/imm32/no-inouts + 9388 0/imm32/no-inouts + 9389 0x11/imm32/alloc-id:fake + 9390 Single-int-var-in-ebx/imm32/outputs + 9391 0x11/imm32/alloc-id:fake + 9392 _string_43_increment_ebx/imm32/subx-name + 9393 0/imm32/no-rm32 + 9394 0/imm32/no-r32 + 9395 0/imm32/no-imm32 + 9396 0/imm32/no-disp32 + 9397 0/imm32/output-is-write-only + 9398 0x11/imm32/alloc-id:fake + 9399 _Primitive-increment-esi/imm32/next + 9400 _Primitive-increment-esi: # (payload primitive) + 9401 0x11/imm32/alloc-id:fake:payload + 9402 # var/esi <- increment => 46/increment-esi + 9403 0x11/imm32/alloc-id:fake + 9404 _string-increment/imm32/name + 9405 0/imm32/no-inouts + 9406 0/imm32/no-inouts + 9407 0x11/imm32/alloc-id:fake + 9408 Single-int-var-in-esi/imm32/outputs + 9409 0x11/imm32/alloc-id:fake + 9410 _string_46_increment_esi/imm32/subx-name + 9411 0/imm32/no-rm32 + 9412 0/imm32/no-r32 + 9413 0/imm32/no-imm32 + 9414 0/imm32/no-disp32 + 9415 0/imm32/output-is-write-only + 9416 0x11/imm32/alloc-id:fake + 9417 _Primitive-increment-edi/imm32/next + 9418 _Primitive-increment-edi: # (payload primitive) + 9419 0x11/imm32/alloc-id:fake:payload + 9420 # var/edi <- increment => 47/increment-edi + 9421 0x11/imm32/alloc-id:fake + 9422 _string-increment/imm32/name + 9423 0/imm32/no-inouts + 9424 0/imm32/no-inouts + 9425 0x11/imm32/alloc-id:fake + 9426 Single-int-var-in-edi/imm32/outputs + 9427 0x11/imm32/alloc-id:fake + 9428 _string_47_increment_edi/imm32/subx-name 9429 0/imm32/no-rm32 9430 0/imm32/no-r32 9431 0/imm32/no-imm32 - 9432 1/imm32/disp32-is-first-inout - 9433 0/imm32/no-output - 9434 _Primitive-break-if-<=-named/imm32/next - 9435 _Primitive-break-if-<=-named: - 9436 "break-if-<="/imm32/name - 9437 Single-lit-var/imm32/inouts - 9438 0/imm32/outputs - 9439 "0f 8e/jump-if-<="/imm32/subx-name - 9440 0/imm32/no-rm32 - 9441 0/imm32/no-r32 - 9442 0/imm32/no-imm32 - 9443 1/imm32/disp32-is-first-inout - 9444 0/imm32/no-output - 9445 _Primitive-break-if->-named/imm32/next - 9446 _Primitive-break-if->-named: - 9447 "break-if->"/imm32/name - 9448 Single-lit-var/imm32/inouts - 9449 0/imm32/outputs - 9450 "0f 8f/jump-if->"/imm32/subx-name - 9451 0/imm32/no-rm32 - 9452 0/imm32/no-r32 - 9453 0/imm32/no-imm32 - 9454 1/imm32/disp32-is-first-inout - 9455 0/imm32/no-output - 9456 _Primitive-break-named/imm32/next - 9457 _Primitive-break-named: - 9458 "break"/imm32/name - 9459 Single-lit-var/imm32/inouts - 9460 0/imm32/outputs - 9461 "e9/jump"/imm32/subx-name - 9462 0/imm32/no-rm32 - 9463 0/imm32/no-r32 - 9464 0/imm32/no-imm32 - 9465 1/imm32/disp32-is-first-inout - 9466 0/imm32/no-output - 9467 _Primitive-loop-if-addr<-named/imm32/next - 9468 _Primitive-loop-if-addr<-named: - 9469 "loop-if-addr<"/imm32/name - 9470 Single-lit-var/imm32/inouts - 9471 0/imm32/outputs - 9472 "0f 82/jump-if-addr<"/imm32/subx-name - 9473 0/imm32/no-rm32 - 9474 0/imm32/no-r32 - 9475 0/imm32/no-imm32 - 9476 1/imm32/disp32-is-first-inout - 9477 0/imm32/no-output - 9478 _Primitive-loop-if-addr>=-named/imm32/next - 9479 _Primitive-loop-if-addr>=-named: - 9480 "loop-if-addr>="/imm32/name - 9481 Single-lit-var/imm32/inouts - 9482 0/imm32/outputs - 9483 "0f 83/jump-if-addr>="/imm32/subx-name - 9484 0/imm32/no-rm32 - 9485 0/imm32/no-r32 - 9486 0/imm32/no-imm32 - 9487 1/imm32/disp32-is-first-inout - 9488 0/imm32/no-output - 9489 _Primitive-loop-if-=-named/imm32/next - 9490 _Primitive-loop-if-=-named: - 9491 "loop-if-="/imm32/name - 9492 Single-lit-var/imm32/inouts - 9493 0/imm32/outputs - 9494 "0f 84/jump-if-="/imm32/subx-name - 9495 0/imm32/no-rm32 - 9496 0/imm32/no-r32 - 9497 0/imm32/no-imm32 - 9498 1/imm32/disp32-is-first-inout - 9499 0/imm32/no-output - 9500 _Primitive-loop-if-!=-named/imm32/next - 9501 _Primitive-loop-if-!=-named: - 9502 "loop-if-!="/imm32/name - 9503 Single-lit-var/imm32/inouts - 9504 0/imm32/outputs - 9505 "0f 85/jump-if-!="/imm32/subx-name - 9506 0/imm32/no-rm32 - 9507 0/imm32/no-r32 - 9508 0/imm32/no-imm32 - 9509 1/imm32/disp32-is-first-inout - 9510 0/imm32/no-output - 9511 _Primitive-loop-if-addr<=-named/imm32/next - 9512 _Primitive-loop-if-addr<=-named: - 9513 "loop-if-addr<="/imm32/name - 9514 Single-lit-var/imm32/inouts - 9515 0/imm32/outputs - 9516 "0f 86/jump-if-addr<="/imm32/subx-name - 9517 0/imm32/no-rm32 - 9518 0/imm32/no-r32 - 9519 0/imm32/no-imm32 - 9520 1/imm32/disp32-is-first-inout - 9521 0/imm32/no-output - 9522 _Primitive-loop-if-addr>-named/imm32/next - 9523 _Primitive-loop-if-addr>-named: - 9524 "loop-if-addr>"/imm32/name - 9525 Single-lit-var/imm32/inouts - 9526 0/imm32/outputs - 9527 "0f 87/jump-if-addr>"/imm32/subx-name - 9528 0/imm32/no-rm32 - 9529 0/imm32/no-r32 - 9530 0/imm32/no-imm32 - 9531 1/imm32/disp32-is-first-inout - 9532 0/imm32/no-output - 9533 _Primitive-loop-if-<-named/imm32/next - 9534 _Primitive-loop-if-<-named: - 9535 "loop-if-<"/imm32/name - 9536 Single-lit-var/imm32/inouts - 9537 0/imm32/outputs - 9538 "0f 8c/jump-if-<"/imm32/subx-name - 9539 0/imm32/no-rm32 - 9540 0/imm32/no-r32 - 9541 0/imm32/no-imm32 - 9542 1/imm32/disp32-is-first-inout - 9543 0/imm32/no-output - 9544 _Primitive-loop-if->=-named/imm32/next - 9545 _Primitive-loop-if->=-named: - 9546 "loop-if->="/imm32/name - 9547 Single-lit-var/imm32/inouts - 9548 0/imm32/outputs - 9549 "0f 8d/jump-if->="/imm32/subx-name - 9550 0/imm32/no-rm32 - 9551 0/imm32/no-r32 - 9552 0/imm32/no-imm32 - 9553 1/imm32/disp32-is-first-inout - 9554 0/imm32/no-output - 9555 _Primitive-loop-if-<=-named/imm32/next - 9556 _Primitive-loop-if-<=-named: - 9557 "loop-if-<="/imm32/name - 9558 Single-lit-var/imm32/inouts - 9559 0/imm32/outputs - 9560 "0f 8e/jump-if-<="/imm32/subx-name - 9561 0/imm32/no-rm32 - 9562 0/imm32/no-r32 - 9563 0/imm32/no-imm32 - 9564 1/imm32/disp32-is-first-inout - 9565 0/imm32/no-output - 9566 _Primitive-loop-if->-named/imm32/next - 9567 _Primitive-loop-if->-named: - 9568 "loop-if->"/imm32/name - 9569 Single-lit-var/imm32/inouts - 9570 0/imm32/outputs - 9571 "0f 8f/jump-if->"/imm32/subx-name - 9572 0/imm32/no-rm32 - 9573 0/imm32/no-r32 - 9574 0/imm32/no-imm32 - 9575 1/imm32/disp32-is-first-inout - 9576 0/imm32/no-output - 9577 _Primitive-loop-named/imm32/next # we probably don't need an unconditional break - 9578 _Primitive-loop-named: - 9579 "loop"/imm32/name - 9580 Single-lit-var/imm32/inouts - 9581 0/imm32/outputs - 9582 "e9/jump"/imm32/subx-name - 9583 0/imm32/no-rm32 - 9584 0/imm32/no-r32 - 9585 0/imm32/no-imm32 - 9586 1/imm32/disp32-is-first-inout - 9587 0/imm32/no-output - 9588 0/imm32/next - 9589 - 9590 Single-int-var-in-mem: - 9591 Int-var-in-mem/imm32 - 9592 0/imm32/next - 9593 - 9594 Int-var-in-mem: - 9595 "arg1"/imm32/name - 9596 Type-int/imm32 - 9597 1/imm32/some-block-depth - 9598 1/imm32/some-stack-offset - 9599 0/imm32/no-register - 9600 - 9601 Two-args-int-stack-int-reg: - 9602 Int-var-in-mem/imm32 - 9603 Single-int-var-in-some-register/imm32/next - 9604 - 9605 Two-args-int-reg-int-stack: - 9606 Int-var-in-some-register/imm32 - 9607 Single-int-var-in-mem/imm32/next - 9608 - 9609 Two-args-int-eax-int-literal: - 9610 Int-var-in-eax/imm32 - 9611 Single-lit-var/imm32/next - 9612 - 9613 Int-var-and-literal: - 9614 Int-var-in-mem/imm32 - 9615 Single-lit-var/imm32/next - 9616 - 9617 Int-var-in-register-and-literal: - 9618 Int-var-in-some-register/imm32 - 9619 Single-lit-var/imm32/next - 9620 - 9621 Single-int-var-in-some-register: - 9622 Int-var-in-some-register/imm32 - 9623 0/imm32/next - 9624 - 9625 Single-addr-var-in-some-register: - 9626 Addr-var-in-some-register/imm32 - 9627 0/imm32/next - 9628 - 9629 Int-var-in-some-register: - 9630 "arg1"/imm32/name - 9631 Type-int/imm32 - 9632 1/imm32/some-block-depth - 9633 0/imm32/no-stack-offset - 9634 Any-register/imm32 - 9635 - 9636 Addr-var-in-some-register: - 9637 "arg1"/imm32/name - 9638 Type-addr/imm32 - 9639 1/imm32/some-block-depth - 9640 0/imm32/no-stack-offset - 9641 Any-register/imm32 - 9642 - 9643 Single-int-var-in-eax: - 9644 Int-var-in-eax/imm32 - 9645 0/imm32/next - 9646 - 9647 Int-var-in-eax: - 9648 "arg1"/imm32/name - 9649 Type-int/imm32 - 9650 1/imm32/some-block-depth - 9651 0/imm32/no-stack-offset - 9652 "eax"/imm32/register - 9653 - 9654 Single-int-var-in-ecx: - 9655 Int-var-in-ecx/imm32 - 9656 0/imm32/next - 9657 - 9658 Int-var-in-ecx: - 9659 "arg1"/imm32/name - 9660 Type-int/imm32 - 9661 1/imm32/some-block-depth - 9662 0/imm32/no-stack-offset - 9663 "ecx"/imm32/register - 9664 - 9665 Single-int-var-in-edx: - 9666 Int-var-in-edx/imm32 - 9667 0/imm32/next - 9668 - 9669 Int-var-in-edx: - 9670 "arg1"/imm32/name - 9671 Type-int/imm32 - 9672 1/imm32/some-block-depth - 9673 0/imm32/no-stack-offset - 9674 "edx"/imm32/register - 9675 - 9676 Single-int-var-in-ebx: - 9677 Int-var-in-ebx/imm32 - 9678 0/imm32/next - 9679 - 9680 Int-var-in-ebx: - 9681 "arg1"/imm32/name - 9682 Type-int/imm32 - 9683 1/imm32/some-block-depth - 9684 0/imm32/no-stack-offset - 9685 "ebx"/imm32/register - 9686 - 9687 Single-int-var-in-esi: - 9688 Int-var-in-esi/imm32 - 9689 0/imm32/next - 9690 - 9691 Int-var-in-esi: - 9692 "arg1"/imm32/name - 9693 Type-int/imm32 - 9694 1/imm32/some-block-depth - 9695 0/imm32/no-stack-offset - 9696 "esi"/imm32/register - 9697 - 9698 Single-int-var-in-edi: - 9699 Int-var-in-edi/imm32 - 9700 0/imm32/next - 9701 - 9702 Int-var-in-edi: - 9703 "arg1"/imm32/name - 9704 Type-int/imm32 - 9705 1/imm32/some-block-depth - 9706 0/imm32/no-stack-offset - 9707 "edi"/imm32/register - 9708 - 9709 Single-lit-var: - 9710 Lit-var/imm32 - 9711 0/imm32/next - 9712 - 9713 Lit-var: - 9714 "literal"/imm32/name - 9715 Type-literal/imm32 - 9716 1/imm32/some-block-depth - 9717 0/imm32/no-stack-offset - 9718 0/imm32/no-register - 9719 - 9720 Type-int: - 9721 1/imm32/left-is-atom - 9722 1/imm32/left/int - 9723 0/imm32/right/null - 9724 - 9725 Type-literal: - 9726 1/imm32/left-is-atom - 9727 0/imm32/left/literal - 9728 0/imm32/right/null - 9729 - 9730 Type-addr: - 9731 1/imm32/left-is-atom - 9732 2/imm32/left/addr - 9733 0/imm32/right/null - 9734 - 9735 == code - 9736 emit-subx-primitive: # out: (addr buffered-file), stmt: (handle stmt), primitive: (handle function) - 9737 # . prologue - 9738 55/push-ebp - 9739 89/<- %ebp 4/r32/esp - 9740 # . save registers - 9741 50/push-eax - 9742 51/push-ecx - 9743 # ecx = primitive - 9744 8b/-> *(ebp+0x10) 1/r32/ecx - 9745 # emit primitive name - 9746 (emit-indent *(ebp+8) *Curr-block-depth) - 9747 (write-buffered *(ebp+8) *(ecx+0xc)) # Primitive-subx-name - 9748 # emit rm32 if necessary - 9749 (emit-subx-rm32 *(ebp+8) *(ecx+0x10) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt - 9750 # emit r32 if necessary - 9751 (emit-subx-r32 *(ebp+8) *(ecx+0x14) *(ebp+0xc)) # out, Primitive-subx-r32, stmt - 9752 # emit imm32 if necessary - 9753 (emit-subx-imm32 *(ebp+8) *(ecx+0x18) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt - 9754 # emit disp32 if necessary - 9755 (emit-subx-disp32 *(ebp+8) *(ecx+0x1c) *(ebp+0xc)) # out, Primitive-subx-disp32, stmt - 9756 (write-buffered *(ebp+8) Newline) - 9757 $emit-subx-primitive:end: - 9758 # . restore registers - 9759 59/pop-to-ecx - 9760 58/pop-to-eax - 9761 # . epilogue - 9762 89/<- %esp 5/r32/ebp - 9763 5d/pop-to-ebp - 9764 c3/return - 9765 - 9766 emit-subx-rm32: # out: (addr buffered-file), l: arg-location, stmt: (handle stmt) - 9767 # . prologue - 9768 55/push-ebp - 9769 89/<- %ebp 4/r32/esp - 9770 # . save registers - 9771 50/push-eax - 9772 # if (l == 0) return - 9773 81 7/subop/compare *(ebp+0xc) 0/imm32 - 9774 74/jump-if-= $emit-subx-rm32:end/disp8 - 9775 # var v/eax: (handle var) - 9776 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # => eax - 9777 (emit-subx-var-as-rm32 *(ebp+8) %eax) - 9778 $emit-subx-rm32:end: - 9779 # . restore registers - 9780 58/pop-to-eax - 9781 # . epilogue - 9782 89/<- %esp 5/r32/ebp - 9783 5d/pop-to-ebp - 9784 c3/return - 9785 - 9786 get-stmt-operand-from-arg-location: # stmt: (handle stmt), l: arg-location -> var/eax: (handle stmt-var) - 9787 # . prologue - 9788 55/push-ebp - 9789 89/<- %ebp 4/r32/esp - 9790 # . save registers - 9791 51/push-ecx - 9792 # eax = l - 9793 8b/-> *(ebp+0xc) 0/r32/eax - 9794 # ecx = stmt - 9795 8b/-> *(ebp+8) 1/r32/ecx - 9796 # if (l == 1) return stmt->inouts - 9797 { - 9798 3d/compare-eax-and 1/imm32 - 9799 75/jump-if-!= break/disp8 - 9800 $get-stmt-operand-from-arg-location:1: - 9801 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts or Regvardef-inouts - 9802 eb/jump $get-stmt-operand-from-arg-location:end/disp8 - 9803 } - 9804 # if (l == 2) return stmt->inouts->next - 9805 { - 9806 3d/compare-eax-and 2/imm32 - 9807 75/jump-if-!= break/disp8 - 9808 $get-stmt-operand-from-arg-location:2: - 9809 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts or Regvardef-inouts - 9810 8b/-> *(eax+4) 0/r32/eax # Stmt-var-next - 9811 eb/jump $get-stmt-operand-from-arg-location:end/disp8 - 9812 } - 9813 # if (l == 3) return stmt->outputs - 9814 { - 9815 3d/compare-eax-and 3/imm32 - 9816 75/jump-if-!= break/disp8 - 9817 $get-stmt-operand-from-arg-location:3: - 9818 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs - 9819 eb/jump $get-stmt-operand-from-arg-location:end/disp8 - 9820 } - 9821 # abort - 9822 e9/jump $get-stmt-operand-from-arg-location:abort/disp32 - 9823 $get-stmt-operand-from-arg-location:end: - 9824 # . restore registers - 9825 59/pop-to-ecx - 9826 # . epilogue - 9827 89/<- %esp 5/r32/ebp - 9828 5d/pop-to-ebp - 9829 c3/return - 9830 - 9831 $get-stmt-operand-from-arg-location:abort: - 9832 # error("invalid arg-location " eax) - 9833 (write-buffered Stderr "invalid arg-location ") - 9834 (print-int32-buffered Stderr %eax) - 9835 (write-buffered Stderr Newline) - 9836 (flush Stderr) - 9837 # . syscall(exit, 1) - 9838 bb/copy-to-ebx 1/imm32 - 9839 b8/copy-to-eax 1/imm32/exit - 9840 cd/syscall 0x80/imm8 - 9841 # never gets here - 9842 - 9843 emit-subx-r32: # out: (addr buffered-file), l: arg-location, stmt: (handle stmt) - 9844 # . prologue - 9845 55/push-ebp - 9846 89/<- %ebp 4/r32/esp - 9847 # . save registers - 9848 50/push-eax - 9849 51/push-ecx - 9850 # if (location == 0) return - 9851 81 7/subop/compare *(ebp+0xc) 0/imm32 - 9852 0f 84/jump-if-= $emit-subx-r32:end/disp32 - 9853 # var v/eax: (handle var) - 9854 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # => eax - 9855 8b/-> *eax 0/r32/eax # Stmt-var-value - 9856 (maybe-get Registers *(eax+0x10) 8) # Var-register => eax: (addr register-index) - 9857 (write-buffered *(ebp+8) Space) - 9858 (print-int32-buffered *(ebp+8) *eax) - 9859 (write-buffered *(ebp+8) "/r32") - 9860 $emit-subx-r32:end: - 9861 # . restore registers - 9862 59/pop-to-ecx - 9863 58/pop-to-eax - 9864 # . epilogue - 9865 89/<- %esp 5/r32/ebp - 9866 5d/pop-to-ebp - 9867 c3/return - 9868 - 9869 emit-subx-imm32: # out: (addr buffered-file), l: arg-location, stmt: (handle stmt) - 9870 # . prologue - 9871 55/push-ebp - 9872 89/<- %ebp 4/r32/esp - 9873 # . save registers - 9874 50/push-eax - 9875 51/push-ecx - 9876 # if (location == 0) return - 9877 81 7/subop/compare *(ebp+0xc) 0/imm32 - 9878 74/jump-if-= $emit-subx-imm32:end/disp8 - 9879 # var v/eax: (handle var) - 9880 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # => eax - 9881 8b/-> *eax 0/r32/eax # Stmt-var-value - 9882 (write-buffered *(ebp+8) Space) - 9883 (write-buffered *(ebp+8) *eax) # Var-name - 9884 (write-buffered *(ebp+8) "/imm32") - 9885 $emit-subx-imm32:end: - 9886 # . restore registers - 9887 59/pop-to-ecx - 9888 58/pop-to-eax - 9889 # . epilogue - 9890 89/<- %esp 5/r32/ebp - 9891 5d/pop-to-ebp - 9892 c3/return - 9893 - 9894 emit-subx-disp32: # out: (addr buffered-file), l: arg-location, stmt: (handle stmt) - 9895 # . prologue - 9896 55/push-ebp - 9897 89/<- %ebp 4/r32/esp - 9898 # . save registers - 9899 50/push-eax - 9900 51/push-ecx - 9901 # if (location == 0) return - 9902 81 7/subop/compare *(ebp+0xc) 0/imm32 - 9903 0f 84/jump-if-= $emit-subx-disp32:end/disp32 - 9904 # var v/eax: (handle var) - 9905 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # => eax - 9906 8b/-> *eax 0/r32/eax # Stmt-var-value - 9907 (write-buffered *(ebp+8) Space) - 9908 (write-buffered *(ebp+8) *eax) # Var-name - 9909 # hack: if instruction operation starts with "break", emit ":break" - 9910 # var name/ecx: (addr array byte) = stmt->operation - 9911 8b/-> *(ebp+0x10) 0/r32/eax - 9912 8b/-> *(eax+4) 1/r32/ecx - 9913 { - 9914 (string-starts-with? %ecx "break") # => eax - 9915 3d/compare-eax-and 0/imm32/false - 9916 74/jump-if-= break/disp8 - 9917 (write-buffered *(ebp+8) ":break") - 9918 } - 9919 # hack: if instruction operation starts with "loop", emit ":loop" - 9920 { - 9921 (string-starts-with? %ecx "loop") # => eax - 9922 3d/compare-eax-and 0/imm32/false - 9923 74/jump-if-= break/disp8 - 9924 (write-buffered *(ebp+8) ":loop") - 9925 } - 9926 (write-buffered *(ebp+8) "/disp32") - 9927 $emit-subx-disp32:end: - 9928 # . restore registers - 9929 59/pop-to-ecx - 9930 58/pop-to-eax - 9931 # . epilogue - 9932 89/<- %esp 5/r32/ebp - 9933 5d/pop-to-ebp - 9934 c3/return - 9935 - 9936 emit-call: # out: (addr buffered-file), stmt: (handle stmt) - 9937 # . prologue - 9938 55/push-ebp - 9939 89/<- %ebp 4/r32/esp - 9940 # . save registers - 9941 51/push-ecx - 9942 # - 9943 (emit-indent *(ebp+8) *Curr-block-depth) - 9944 (write-buffered *(ebp+8) "(") - 9945 # ecx = stmt - 9946 8b/-> *(ebp+0xc) 1/r32/ecx - 9947 # - emit function name - 9948 (write-buffered *(ebp+8) *(ecx+4)) # Stmt1-operation - 9949 # - emit arguments - 9950 # var curr/ecx: (handle stmt-var) = stmt->inouts - 9951 8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts - 9952 { - 9953 # if (curr == null) break - 9954 81 7/subop/compare %ecx 0/imm32 - 9955 74/jump-if-= break/disp8 - 9956 # - 9957 (emit-subx-call-operand *(ebp+8) %ecx) - 9958 # curr = curr->next - 9959 8b/-> *(ecx+4) 1/r32/ecx # Stmt-var-next - 9960 eb/jump loop/disp8 - 9961 } - 9962 # - 9963 (write-buffered *(ebp+8) ")\n") - 9964 $emit-call:end: - 9965 # . restore registers - 9966 59/pop-to-ecx - 9967 # . epilogue - 9968 89/<- %esp 5/r32/ebp - 9969 5d/pop-to-ebp - 9970 c3/return - 9971 - 9972 emit-subx-call-operand: # out: (addr buffered-file), s: (handle stmt-var) - 9973 # shares code with emit-subx-var-as-rm32 - 9974 # . prologue - 9975 55/push-ebp - 9976 89/<- %ebp 4/r32/esp - 9977 # . save registers - 9978 50/push-eax - 9979 51/push-ecx - 9980 56/push-esi - 9981 # ecx = s - 9982 8b/-> *(ebp+0xc) 1/r32/ecx - 9983 # var operand/esi: (handle var) = s->value - 9984 8b/-> *ecx 6/r32/esi # Stmt-var-value - 9985 # if (operand->register && !s->is-deref?) emit "%__" - 9986 { - 9987 $emit-subx-call-operand:check-for-register-direct: - 9988 81 7/subop/compare *(esi+0x10) 0/imm32 # Var-register - 9989 74/jump-if-= break/disp8 - 9990 81 7/subop/compare *(ecx+8) 0/imm32/false # Stmt-var-is-deref - 9991 75/jump-if-!= break/disp8 - 9992 $emit-subx-call-operand:register-direct: - 9993 (write-buffered *(ebp+8) " %") - 9994 (write-buffered *(ebp+8) *(esi+0x10)) # Var-register - 9995 e9/jump $emit-subx-call-operand:end/disp32 - 9996 } - 9997 # else if (operand->register && s->is-deref?) emit "*__" - 9998 { - 9999 $emit-subx-call-operand:check-for-register-indirect: -10000 81 7/subop/compare *(esi+0x10) 0/imm32 # Var-register -10001 74/jump-if-= break/disp8 -10002 81 7/subop/compare *(ecx+8) 0/imm32/false # Stmt-var-is-deref -10003 74/jump-if-= break/disp8 -10004 $emit-subx-call-operand:register-indirect: -10005 (emit-subx-call-operand-register-indirect *(ebp+8) %esi) -10006 e9/jump $emit-subx-call-operand:end/disp32 -10007 } -10008 # else if (operand->stack-offset) emit "*(ebp+__)" -10009 { -10010 81 7/subop/compare *(esi+0xc) 0/imm32 # Var-offset -10011 74/jump-if-= break/disp8 -10012 $emit-subx-call-operand:stack: -10013 (emit-subx-call-operand-stack *(ebp+8) %esi) -10014 e9/jump $emit-subx-call-operand:end/disp32 -10015 } -10016 # else if (operand->type == literal) emit "__" -10017 { -10018 8b/-> *(esi+4) 0/r32/eax # Var-type -10019 81 7/subop/compare *(eax+4) 0/imm32 # Tree-left -10020 75/jump-if-!= break/disp8 -10021 $emit-subx-call-operand:literal: -10022 (write-buffered *(ebp+8) Space) -10023 (write-buffered *(ebp+8) *esi) -10024 } -10025 $emit-subx-call-operand:end: -10026 # . restore registers -10027 5e/pop-to-esi -10028 59/pop-to-ecx -10029 58/pop-to-eax -10030 # . epilogue -10031 89/<- %esp 5/r32/ebp -10032 5d/pop-to-ebp -10033 c3/return -10034 -10035 emit-subx-call-operand-register-indirect: # out: (addr buffered-file), v: (handle var) -10036 # . prologue -10037 55/push-ebp -10038 89/<- %ebp 4/r32/esp -10039 # . save registers -10040 50/push-eax -10041 51/push-ecx -10042 56/push-esi -10043 # esi = v -10044 8b/-> *(ebp+0xc) 6/r32/esi -10045 # var size/ecx: int = size-of-deref(v) -10046 (size-of-deref %esi) # => eax -10047 89/<- %ecx 0/r32/eax -10048 # TODO: assert size is a multiple of 4 -10049 # var i/eax: int = 0 -10050 b8/copy-to-eax 0/imm32 -10051 { -10052 $emit-subx-call-operand-register-indirect:loop: -10053 # if (i >= size) break -10054 39/compare %eax 1/r32/ecx -10055 7d/jump-if->= break/disp8 -10056 # emit " *(" v->register "+" i ")" -10057 (write-buffered *(ebp+8) " *(") -10058 (write-buffered *(ebp+8) *(esi+0x10)) # Var-register -10059 (write-buffered *(ebp+8) "+") -10060 (print-int32-buffered *(ebp+8) %eax) -10061 (write-buffered *(ebp+8) ")") -10062 # i += 4 -10063 05/add-to-eax 4/imm32 -10064 # -10065 eb/jump loop/disp8 -10066 } -10067 $emit-subx-call-operand-register-indirect:end: -10068 # . restore registers -10069 5e/pop-to-esi -10070 59/pop-to-ecx -10071 58/pop-to-eax -10072 # . epilogue -10073 89/<- %esp 5/r32/ebp -10074 5d/pop-to-ebp -10075 c3/return -10076 -10077 emit-subx-call-operand-stack: # out: (addr buffered-file), v: (handle var) -10078 # . prologue -10079 55/push-ebp -10080 89/<- %ebp 4/r32/esp -10081 # . save registers -10082 50/push-eax -10083 51/push-ecx -10084 56/push-esi -10085 # esi = v -10086 8b/-> *(ebp+0xc) 6/r32/esi -10087 # var curr/ecx: int = v->offset -10088 8b/-> *(esi+0xc) 1/r32/ecx # Var-offset -10089 # var max/eax: int = v->offset + size-of(v) -10090 (size-of %esi) # => eax -10091 # TODO: assert size is a multiple of 4 -10092 01/add-to %eax 1/r32/ecx -10093 { -10094 $emit-subx-call-operand-stack:loop: -10095 # if (curr >= max) break -10096 39/compare %ecx 0/r32/eax -10097 7d/jump-if->= break/disp8 -10098 # emit " *(ebp+" curr ")" -10099 (write-buffered *(ebp+8) " *(ebp+") -10100 (print-int32-buffered *(ebp+8) %ecx) -10101 (write-buffered *(ebp+8) ")") -10102 # i += 4 -10103 81 0/subop/add %ecx 4/imm32 -10104 # -10105 eb/jump loop/disp8 -10106 } -10107 $emit-subx-call-operand-stack:end: -10108 # . restore registers -10109 5e/pop-to-esi -10110 59/pop-to-ecx -10111 58/pop-to-eax -10112 # . epilogue -10113 89/<- %esp 5/r32/ebp -10114 5d/pop-to-ebp -10115 c3/return -10116 -10117 emit-subx-var-as-rm32: # out: (addr buffered-file), s: (handle stmt-var) -10118 # . prologue -10119 55/push-ebp -10120 89/<- %ebp 4/r32/esp -10121 # . save registers -10122 50/push-eax -10123 51/push-ecx -10124 56/push-esi -10125 # ecx = s -10126 8b/-> *(ebp+0xc) 1/r32/ecx -10127 # var operand/esi: (handle var) = s->value -10128 8b/-> *ecx 6/r32/esi # Stmt-var-value -10129 # if (operand->register && s->is-deref?) emit "*__" -10130 { -10131 $emit-subx-var-as-rm32:check-for-register-indirect: -10132 81 7/subop/compare *(esi+0x10) 0/imm32 # Var-register -10133 74/jump-if-= break/disp8 -10134 81 7/subop/compare *(ecx+8) 0/imm32/false # Stmt-var-is-deref -10135 74/jump-if-= break/disp8 -10136 $emit-subx-var-as-rm32:register-indirect: -10137 (write-buffered *(ebp+8) " *") -10138 (write-buffered *(ebp+8) *(esi+0x10)) # Var-register -10139 } -10140 # if (operand->register && !s->is-deref?) emit "%__" -10141 { -10142 $emit-subx-var-as-rm32:check-for-register-direct: -10143 81 7/subop/compare *(esi+0x10) 0/imm32 # Var-register -10144 74/jump-if-= break/disp8 -10145 81 7/subop/compare *(ecx+8) 0/imm32/false # Stmt-var-is-deref -10146 75/jump-if-!= break/disp8 -10147 $emit-subx-var-as-rm32:register-direct: -10148 (write-buffered *(ebp+8) " %") -10149 (write-buffered *(ebp+8) *(esi+0x10)) # Var-register -10150 } -10151 # else if (operand->stack-offset) emit "*(ebp+__)" -10152 { -10153 81 7/subop/compare *(esi+0xc) 0/imm32 # Var-offset -10154 74/jump-if-= break/disp8 -10155 $emit-subx-var-as-rm32:stack: -10156 (write-buffered *(ebp+8) Space) -10157 (write-buffered *(ebp+8) "*(ebp+") -10158 (print-int32-buffered *(ebp+8) *(esi+0xc)) # Var-offset -10159 (write-buffered *(ebp+8) ")") -10160 } -10161 $emit-subx-var-as-rm32:end: -10162 # . restore registers -10163 5e/pop-to-esi -10164 59/pop-to-ecx -10165 58/pop-to-eax -10166 # . epilogue -10167 89/<- %esp 5/r32/ebp -10168 5d/pop-to-ebp -10169 c3/return -10170 -10171 find-matching-primitive: # primitives: (handle primitive), stmt: (handle stmt) -> result/eax: (handle primitive) -10172 # . prologue -10173 55/push-ebp -10174 89/<- %ebp 4/r32/esp -10175 # . save registers -10176 51/push-ecx -10177 # var curr/ecx: (handle primitive) = primitives -10178 8b/-> *(ebp+8) 1/r32/ecx -10179 { -10180 $find-matching-primitive:loop: -10181 # if (curr == null) break -10182 81 7/subop/compare %ecx 0/imm32 -10183 0f 84/jump-if-= break/disp32 -10184 # if match(curr, stmt) return curr -10185 { -10186 (mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax -10187 3d/compare-eax-and 0/imm32/false -10188 74/jump-if-= break/disp8 -10189 89/<- %eax 1/r32/ecx -10190 eb/jump $find-matching-primitive:end/disp8 -10191 } -10192 $find-matching-primitive:next-primitive: -10193 # curr = curr->next -10194 8b/-> *(ecx+0x24) 1/r32/ecx # Primitive-next -10195 e9/jump loop/disp32 -10196 } -10197 # return null -10198 b8/copy-to-eax 0/imm32 -10199 $find-matching-primitive:end: -10200 # . restore registers -10201 59/pop-to-ecx -10202 # . epilogue -10203 89/<- %esp 5/r32/ebp -10204 5d/pop-to-ebp -10205 c3/return -10206 -10207 mu-stmt-matches-primitive?: # stmt: (handle stmt), primitive: (handle primitive) -> result/eax: boolean -10208 # A mu stmt matches a primitive if the name matches, all the inout vars -10209 # match, and all the output vars match. -10210 # Vars match if types match and registers match. -10211 # In addition, a stmt output matches a primitive's output if types match -10212 # and the primitive has a wildcard register. -10213 # . prologue -10214 55/push-ebp -10215 89/<- %ebp 4/r32/esp -10216 # . save registers -10217 51/push-ecx -10218 52/push-edx -10219 53/push-ebx -10220 56/push-esi -10221 57/push-edi -10222 # ecx = stmt -10223 8b/-> *(ebp+8) 1/r32/ecx -10224 # edx = primitive -10225 8b/-> *(ebp+0xc) 2/r32/edx -10226 { -10227 $mu-stmt-matches-primitive?:check-name: -10228 # if (primitive->name != stmt->operation) return false -10229 (string-equal? *(ecx+4) *edx) # Stmt1-operation, Primitive-name => eax -10230 3d/compare-eax-and 0/imm32/false -10231 75/jump-if-!= break/disp8 -10232 b8/copy-to-eax 0/imm32 -10233 e9/jump $mu-stmt-matches-primitive?:end/disp32 -10234 } -10235 $mu-stmt-matches-primitive?:check-inouts: -10236 # for (curr/esi in stmt->inouts, curr2/edi in primitive->inouts) -10237 8b/-> *(ecx+8) 6/r32/esi # Stmt1-inouts or Regvardef-inouts -10238 8b/-> *(edx+4) 7/r32/edi # Primitive-inouts -10239 { -10240 # if (curr == 0 && curr2 == 0) move on to check outputs -10241 { -10242 81 7/subop/compare %esi 0/imm32 -10243 75/jump-if-!= break/disp8 -10244 $mu-stmt-matches-primitive?:stmt-inout-is-null: -10245 { -10246 81 7/subop/compare %edi 0/imm32 -10247 75/jump-if-!= break/disp8 -10248 # -10249 e9/jump $mu-stmt-matches-primitive?:check-outputs/disp32 -10250 } -10251 # return false -10252 b8/copy-to-eax 0/imm32/false -10253 e9/jump $mu-stmt-matches-primitive?:end/disp32 -10254 } -10255 # if (curr2 == 0) return false -10256 { -10257 81 7/subop/compare %edi 0/imm32 -10258 75/jump-if-!= break/disp8 -10259 $mu-stmt-matches-primitive?:prim-inout-is-null: -10260 b8/copy-to-eax 0/imm32/false -10261 e9/jump $mu-stmt-matches-primitive?:end/disp32 -10262 } -10263 # if (curr != curr2) return false -10264 { -10265 (operand-matches-primitive? %esi *edi) # List-value => eax -10266 3d/compare-eax-and 0/imm32/false -10267 75/jump-if-!= break/disp8 -10268 b8/copy-to-eax 0/imm32/false -10269 e9/jump $mu-stmt-matches-primitive?:end/disp32 -10270 } -10271 # curr=curr->next -10272 8b/-> *(esi+4) 6/r32/esi # Stmt-var-next -10273 # curr2=curr2->next -10274 8b/-> *(edi+4) 7/r32/edi # Stmt-var-next -10275 eb/jump loop/disp8 -10276 } -10277 $mu-stmt-matches-primitive?:check-outputs: -10278 # for (curr/esi in stmt->outputs, curr2/edi in primitive->outputs) -10279 8b/-> *(ecx+0xc) 6/r32/esi # Stmt1-outputs -10280 8b/-> *(edx+8) 7/r32/edi # Primitive-outputs -10281 { -10282 # if (curr == 0) return (curr2 == 0) -10283 { -10284 $mu-stmt-matches-primitive?:check-output: -10285 81 7/subop/compare %esi 0/imm32 -10286 75/jump-if-!= break/disp8 -10287 { -10288 81 7/subop/compare %edi 0/imm32 -10289 75/jump-if-!= break/disp8 -10290 # return true -10291 b8/copy-to-eax 1/imm32 -10292 e9/jump $mu-stmt-matches-primitive?:end/disp32 -10293 } -10294 # return false -10295 b8/copy-to-eax 0/imm32 -10296 e9/jump $mu-stmt-matches-primitive?:end/disp32 -10297 } -10298 # if (curr2 == 0) return false -10299 { -10300 81 7/subop/compare %edi 0/imm32 -10301 75/jump-if-!= break/disp8 -10302 b8/copy-to-eax 0/imm32 -10303 e9/jump $mu-stmt-matches-primitive?:end/disp32 -10304 } -10305 # if (curr != curr2) return false -10306 { -10307 (operand-matches-primitive? %esi *edi) # List-value => eax -10308 3d/compare-eax-and 0/imm32/false -10309 75/jump-if-!= break/disp8 -10310 b8/copy-to-eax 0/imm32 -10311 e9/jump $mu-stmt-matches-primitive?:end/disp32 -10312 } -10313 # curr=curr->next -10314 8b/-> *(esi+4) 6/r32/esi # Stmt-var-next -10315 # curr2=curr2->next -10316 8b/-> *(edi+4) 7/r32/edi # Stmt-var-next -10317 eb/jump loop/disp8 -10318 } -10319 $mu-stmt-matches-primitive?:return-true: -10320 b8/copy-to-eax 1/imm32 -10321 $mu-stmt-matches-primitive?:end: -10322 # . restore registers -10323 5f/pop-to-edi -10324 5e/pop-to-esi -10325 5b/pop-to-ebx -10326 5a/pop-to-edx -10327 59/pop-to-ecx -10328 # . epilogue -10329 89/<- %esp 5/r32/ebp -10330 5d/pop-to-ebp -10331 c3/return -10332 -10333 operand-matches-primitive?: # s: (handle stmt-var), prim-var: (handle var) -> result/eax: boolean -10334 # . prologue -10335 55/push-ebp -10336 89/<- %ebp 4/r32/esp -10337 # . save registers -10338 51/push-ecx -10339 56/push-esi -10340 57/push-edi -10341 # ecx = s -10342 8b/-> *(ebp+8) 1/r32/ecx -10343 # var var/esi : (handle var) = s->value -10344 8b/-> *ecx 6/r32/esi # Stmt-var-value -10345 # edi = prim-var -10346 8b/-> *(ebp+0xc) 7/r32/edi -10347 $operand-matches-primitive?:check-type: -10348 # if (var->type != prim-var->type) return false -10349 (subx-type-equal? *(esi+4) *(edi+4)) # Var-type, Var-type => eax -10350 3d/compare-eax-and 0/imm32/false -10351 b8/copy-to-eax 0/imm32/false -10352 0f 84/jump-if-= $operand-matches-primitive?:end/disp32 -10353 { -10354 $operand-matches-primitive?:check-register: -10355 # if prim-var is in memory and var is in register but dereference, match -10356 { -10357 81 7/subop/compare *(edi+0x10) 0/imm32 # Var-register -10358 0f 85/jump-if-!= break/disp32 -10359 81 7/subop/compare *(esi+0x10) 0/imm32 # Var-register -10360 74/jump-if-= break/disp8 -10361 81 7/subop/compare *(ecx+8) 0/imm32/false # Stmt-var-is-deref -10362 74/jump-if-= break/disp8 -10363 e9/jump $operand-matches-primitive?:return-true/disp32 -10364 } -10365 # if prim-var is in register and var is in register but dereference, no match -10366 { -10367 81 7/subop/compare *(edi+0x10) 0/imm32 # Var-register -10368 0f 84/jump-if-= break/disp32 -10369 81 7/subop/compare *(esi+0x10) 0/imm32 # Var-register -10370 0f 84/jump-if-= break/disp32 -10371 81 7/subop/compare *(ecx+8) 0/imm32/false # Stmt-var-is-deref -10372 74/jump-if-= break/disp8 -10373 e9/jump $operand-matches-primitive?:return-false/disp32 -10374 } -10375 # return false if var->register doesn't match prim-var->register -10376 { -10377 # if register addresses are equal, it's a match -10378 8b/-> *(esi+0x10) 0/r32/eax # Var-register -10379 39/compare *(edi+0x10) 0/r32/eax # Var-register -10380 74/jump-if-= break/disp8 -10381 # if either address is 0, return false -10382 3d/compare-eax-and 0/imm32 -10383 74/jump-if-= $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result -10384 81 7/subop/compare *(edi+0x10) 0/imm32 # Var-register -10385 74/jump-if-= $operand-matches-primitive?:return-false/disp8 -10386 # if prim-var->register is wildcard, it's a match -10387 (string-equal? *(edi+0x10) Any-register) # Var-register => eax -10388 3d/compare-eax-and 0/imm32/false -10389 75/jump-if-!= break/disp8 -10390 # if string contents aren't equal, return false -10391 (string-equal? *(esi+0x10) *(edi+0x10)) # Var-register Var-register => eax -10392 3d/compare-eax-and 0/imm32/false -10393 74/jump-if-= $operand-matches-primitive?:return-false/disp8 -10394 } -10395 } -10396 $operand-matches-primitive?:return-true: -10397 b8/copy-to-eax 1/imm32/true -10398 eb/jump $operand-matches-primitive?:end/disp8 -10399 $operand-matches-primitive?:return-false: -10400 b8/copy-to-eax 0/imm32/false -10401 $operand-matches-primitive?:end: -10402 # . restore registers -10403 5f/pop-to-edi -10404 5e/pop-to-esi -10405 59/pop-to-ecx -10406 # . epilogue -10407 89/<- %esp 5/r32/ebp -10408 5d/pop-to-ebp -10409 c3/return -10410 -10411 subx-type-equal?: # a: (handle tree type-id), b: (handle tree type-id) -> result/eax: boolean -10412 # . prologue -10413 55/push-ebp -10414 89/<- %ebp 4/r32/esp -10415 # . save registers -10416 51/push-ecx -10417 # var alit/ecx: boolean = is-literal-type?(a) -10418 (is-simple-mu-type? *(ebp+8) 0) # => eax -10419 89/<- %ecx 0/r32/eax -10420 # var blit/eax: boolean = is-literal-type?(b) -10421 (is-simple-mu-type? *(ebp+0xc) 0) # => eax -10422 # return alit == blit -10423 39/compare %eax 1/r32/ecx -10424 0f 94/set-byte-if-= %al -10425 81 4/subop/and %eax 0xff/imm32 -10426 $subx-type-equal?:end: -10427 # . restore registers -10428 59/pop-to-ecx -10429 # . epilogue -10430 89/<- %esp 5/r32/ebp -10431 5d/pop-to-ebp -10432 c3/return -10433 -10434 is-simple-mu-type?: # a: (handle tree type-id), n: type-id -> result/eax: boolean -10435 # . prologue -10436 55/push-ebp -10437 89/<- %ebp 4/r32/esp -10438 # . save registers -10439 51/push-ecx -10440 # ecx = n -10441 8b/-> *(ebp+0xc) 1/r32/ecx -10442 # return (a->value == n) -10443 8b/-> *(ebp+8) 0/r32/eax -10444 39/compare *(eax+4) 1/r32/ecx # Tree-value -10445 0f 94/set-byte-if-= %al -10446 81 4/subop/and %eax 0xff/imm32 -10447 $is-simple-mu-type?:end: -10448 # . restore registers -10449 59/pop-to-ecx -10450 # . epilogue -10451 89/<- %esp 5/r32/ebp -10452 5d/pop-to-ebp -10453 c3/return -10454 -10455 test-emit-subx-stmt-primitive: -10456 # Primitive operation on a variable on the stack. -10457 # increment foo -10458 # => -10459 # ff 0/subop/increment *(ebp-8) -10460 # -10461 # There's a variable on the var stack as follows: -10462 # name: 'foo' -10463 # type: int -10464 # stack-offset: -8 -10465 # -10466 # There's a primitive with this info: -10467 # name: 'increment' -10468 # inouts: int/mem -10469 # value: 'ff 0/subop/increment' -10470 # -10471 # There's nothing in functions. -10472 # -10473 # . prologue -10474 55/push-ebp -10475 89/<- %ebp 4/r32/esp -10476 # setup -10477 (clear-stream _test-output-stream) -10478 (clear-stream $_test-output-buffered-file->buffer) -10479 # var type/ecx: (handle tree type-id) = int -10480 68/push 0/imm32/right/null -10481 68/push 1/imm32/left/int -10482 89/<- %ecx 4/r32/esp -10483 # var var-foo/ecx: var -10484 68/push 0/imm32/no-register -10485 68/push -8/imm32/stack-offset -10486 68/push 1/imm32/block-depth -10487 51/push-ecx -10488 68/push "foo"/imm32 -10489 89/<- %ecx 4/r32/esp -10490 # var operand/ebx: (handle stmt-var) -10491 68/push 0/imm32/is-deref:false -10492 68/push 0/imm32/next -10493 51/push-ecx/var-foo -10494 89/<- %ebx 4/r32/esp -10495 # var stmt/esi: statement -10496 68/push 0/imm32/next -10497 68/push 0/imm32/outputs -10498 53/push-ebx/operands -10499 68/push "increment"/imm32/operation -10500 68/push 1/imm32 -10501 89/<- %esi 4/r32/esp -10502 # var primitives/ebx: primitive -10503 68/push 0/imm32/next -10504 68/push 0/imm32/output-is-write-only -10505 68/push 0/imm32/no-disp32 -10506 68/push 0/imm32/no-imm32 -10507 68/push 0/imm32/no-r32 -10508 68/push 1/imm32/rm32-is-first-inout -10509 68/push "ff 0/subop/increment"/imm32/subx-name -10510 68/push 0/imm32/outputs -10511 53/push-ebx/inouts # hack; in practice we won't have the same var in function definition and call -10512 68/push "increment"/imm32/name -10513 89/<- %ebx 4/r32/esp -10514 # convert -10515 c7 0/subop/copy *Curr-block-depth 0/imm32 -10516 (emit-subx-stmt _test-output-buffered-file %esi %ebx) -10517 (flush _test-output-buffered-file) -10518 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- -10524 # check output -10525 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-stmt-primitive") -10526 # . epilogue -10527 89/<- %esp 5/r32/ebp -10528 5d/pop-to-ebp -10529 c3/return -10530 -10531 test-emit-subx-stmt-primitive-register: -10532 # Primitive operation on a variable in a register. -10533 # foo <- increment -10534 # => -10535 # ff 0/subop/increment %eax # sub-optimal, but should suffice -10536 # -10537 # There's a variable on the var stack as follows: -10538 # name: 'foo' -10539 # type: int -10540 # register: 'eax' -10541 # -10542 # There's a primitive with this info: -10543 # name: 'increment' -10544 # out: int/reg -10545 # value: 'ff 0/subop/increment' -10546 # -10547 # There's nothing in functions. -10548 # -10549 # . prologue -10550 55/push-ebp -10551 89/<- %ebp 4/r32/esp -10552 # setup -10553 (clear-stream _test-output-stream) -10554 (clear-stream $_test-output-buffered-file->buffer) -10555 # var type/ecx: (handle tree type-id) = int -10556 68/push 0/imm32/right/null -10557 68/push 1/imm32/left/int -10558 89/<- %ecx 4/r32/esp -10559 # var var-foo/ecx: var in eax -10560 68/push "eax"/imm32/register -10561 68/push 0/imm32/no-stack-offset -10562 68/push 1/imm32/block-depth -10563 51/push-ecx -10564 68/push "foo"/imm32 -10565 89/<- %ecx 4/r32/esp -10566 # var operand/ebx: (handle stmt-var) -10567 68/push 0/imm32/is-deref:false -10568 68/push 0/imm32/next -10569 51/push-ecx/var-foo -10570 89/<- %ebx 4/r32/esp -10571 # var stmt/esi: statement -10572 68/push 0/imm32/next -10573 53/push-ebx/outputs -10574 68/push 0/imm32/inouts -10575 68/push "increment"/imm32/operation -10576 68/push 1/imm32 -10577 89/<- %esi 4/r32/esp -10578 # var formal-var/ebx: var in any register -10579 68/push Any-register/imm32 -10580 68/push 0/imm32/no-stack-offset -10581 68/push 1/imm32/block-depth -10582 ff 6/subop/push *(ecx+4) # Var-type -10583 68/push "dummy"/imm32 -10584 89/<- %ebx 4/r32/esp -10585 # var operand/ebx: (handle stmt-var) -10586 68/push 0/imm32/is-deref:false -10587 68/push 0/imm32/next -10588 53/push-ebx/formal-var -10589 89/<- %ebx 4/r32/esp -10590 # var primitives/ebx: primitive -10591 68/push 0/imm32/next -10592 68/push 0/imm32/output-is-write-only -10593 68/push 0/imm32/no-disp32 -10594 68/push 0/imm32/no-imm32 -10595 68/push 0/imm32/no-r32 -10596 68/push 3/imm32/rm32-in-first-output -10597 68/push "ff 0/subop/increment"/imm32/subx-name -10598 53/push-ebx/outputs -10599 68/push 0/imm32/inouts -10600 68/push "increment"/imm32/name -10601 89/<- %ebx 4/r32/esp -10602 # convert -10603 c7 0/subop/copy *Curr-block-depth 0/imm32 -10604 (emit-subx-stmt _test-output-buffered-file %esi %ebx) -10605 (flush _test-output-buffered-file) -10606 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- -10612 # check output -10613 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-primitive-register") -10614 # . epilogue -10615 89/<- %esp 5/r32/ebp -10616 5d/pop-to-ebp -10617 c3/return -10618 -10619 test-emit-subx-stmt-select-primitive: -10620 # Select the right primitive between overloads. -10621 # foo <- increment -10622 # => -10623 # ff 0/subop/increment %eax # sub-optimal, but should suffice -10624 # -10625 # There's a variable on the var stack as follows: -10626 # name: 'foo' -10627 # type: int -10628 # register: 'eax' -10629 # -10630 # There's two primitives, as follows: -10631 # - name: 'increment' -10632 # out: int/reg -10633 # value: 'ff 0/subop/increment' -10634 # - name: 'increment' -10635 # inout: int/mem -10636 # value: 'ff 0/subop/increment' -10637 # -10638 # There's nothing in functions. -10639 # -10640 # . prologue -10641 55/push-ebp -10642 89/<- %ebp 4/r32/esp -10643 # setup -10644 (clear-stream _test-output-stream) -10645 (clear-stream $_test-output-buffered-file->buffer) -10646 # var type/ecx: (handle tree type-id) = int -10647 68/push 0/imm32/right/null -10648 68/push 1/imm32/left/int -10649 89/<- %ecx 4/r32/esp -10650 # var var-foo/ecx: var in eax -10651 68/push "eax"/imm32/register -10652 68/push 0/imm32/no-stack-offset -10653 68/push 1/imm32/block-depth -10654 51/push-ecx -10655 68/push "foo"/imm32 -10656 89/<- %ecx 4/r32/esp -10657 # var real-outputs/edi: (handle stmt-var) -10658 68/push 0/imm32/is-deref:false -10659 68/push 0/imm32/next -10660 51/push-ecx/var-foo -10661 89/<- %edi 4/r32/esp -10662 # var stmt/esi: statement -10663 68/push 0/imm32/next -10664 57/push-edi/outputs -10665 68/push 0/imm32/inouts -10666 68/push "increment"/imm32/operation -10667 68/push 1/imm32 -10668 89/<- %esi 4/r32/esp -10669 # var formal-var/ebx: var in any register -10670 68/push Any-register/imm32 -10671 68/push 0/imm32/no-stack-offset -10672 68/push 1/imm32/block-depth -10673 ff 6/subop/push *(ecx+4) # Var-type -10674 68/push "dummy"/imm32 -10675 89/<- %ebx 4/r32/esp -10676 # var formal-outputs/ebx: (handle stmt-var) -10677 68/push 0/imm32/is-deref:false -10678 68/push 0/imm32/next -10679 53/push-ebx/formal-var -10680 89/<- %ebx 4/r32/esp -10681 # var primitive1/ebx: primitive -10682 68/push 0/imm32/next -10683 68/push 0/imm32/output-is-write-only -10684 68/push 0/imm32/no-disp32 -10685 68/push 0/imm32/no-imm32 -10686 68/push 0/imm32/no-r32 -10687 68/push 3/imm32/rm32-in-first-output -10688 68/push "ff 0/subop/increment"/imm32/subx-name -10689 53/push-ebx/outputs/formal-outputs -10690 68/push 0/imm32/inouts -10691 68/push "increment"/imm32/name -10692 89/<- %ebx 4/r32/esp -10693 # var primitives/ebx: primitive -10694 53/push-ebx/next -10695 68/push 0/imm32/output-is-write-only -10696 68/push 0/imm32/no-disp32 -10697 68/push 0/imm32/no-imm32 -10698 68/push 0/imm32/no-r32 -10699 68/push 1/imm32/rm32-is-first-inout -10700 68/push "ff 0/subop/increment"/imm32/subx-name -10701 68/push 0/imm32/outputs -10702 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call -10703 68/push "increment"/imm32/name -10704 89/<- %ebx 4/r32/esp -10705 # convert -10706 c7 0/subop/copy *Curr-block-depth 0/imm32 -10707 (emit-subx-stmt _test-output-buffered-file %esi %ebx) -10708 (flush _test-output-buffered-file) -10709 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- -10715 # check output -10716 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive") -10717 # . epilogue -10718 89/<- %esp 5/r32/ebp -10719 5d/pop-to-ebp -10720 c3/return -10721 -10722 test-emit-subx-stmt-select-primitive-2: -10723 # Select the right primitive between overloads. -10724 # foo <- increment -10725 # => -10726 # ff 0/subop/increment %eax # sub-optimal, but should suffice -10727 # -10728 # There's a variable on the var stack as follows: -10729 # name: 'foo' -10730 # type: int -10731 # register: 'eax' -10732 # -10733 # There's two primitives, as follows: -10734 # - name: 'increment' -10735 # out: int/reg -10736 # value: 'ff 0/subop/increment' -10737 # - name: 'increment' -10738 # inout: int/mem -10739 # value: 'ff 0/subop/increment' -10740 # -10741 # There's nothing in functions. -10742 # -10743 # . prologue -10744 55/push-ebp -10745 89/<- %ebp 4/r32/esp -10746 # setup -10747 (clear-stream _test-output-stream) -10748 (clear-stream $_test-output-buffered-file->buffer) -10749 # var type/ecx: (handle tree type-id) = int -10750 68/push 0/imm32/right/null -10751 68/push 1/imm32/left/int -10752 89/<- %ecx 4/r32/esp -10753 # var var-foo/ecx: var in eax -10754 68/push "eax"/imm32/register -10755 68/push 0/imm32/no-stack-offset -10756 68/push 1/imm32/block-depth -10757 51/push-ecx -10758 68/push "foo"/imm32 -10759 89/<- %ecx 4/r32/esp -10760 # var inouts/edi: (handle stmt-var) -10761 68/push 0/imm32/is-deref:false -10762 68/push 0/imm32/next -10763 51/push-ecx/var-foo -10764 89/<- %edi 4/r32/esp -10765 # var stmt/esi: statement -10766 68/push 0/imm32/next -10767 68/push 0/imm32/outputs -10768 57/push-edi/inouts -10769 68/push "increment"/imm32/operation -10770 68/push 1/imm32 -10771 89/<- %esi 4/r32/esp -10772 # var formal-var/ebx: var in any register -10773 68/push Any-register/imm32 -10774 68/push 0/imm32/no-stack-offset -10775 68/push 1/imm32/block-depth -10776 ff 6/subop/push *(ecx+4) # Var-type -10777 68/push "dummy"/imm32 -10778 89/<- %ebx 4/r32/esp -10779 # var operand/ebx: (handle stmt-var) -10780 68/push 0/imm32/is-deref:false -10781 68/push 0/imm32/next -10782 53/push-ebx/formal-var -10783 89/<- %ebx 4/r32/esp -10784 # var primitive1/ebx: primitive -10785 68/push 0/imm32/next -10786 68/push 0/imm32/output-is-write-only -10787 68/push 0/imm32/no-disp32 -10788 68/push 0/imm32/no-imm32 -10789 68/push 0/imm32/no-r32 -10790 68/push 3/imm32/rm32-in-first-output -10791 68/push "ff 0/subop/increment"/imm32/subx-name -10792 53/push-ebx/outputs/formal-outputs -10793 68/push 0/imm32/inouts -10794 68/push "increment"/imm32/name -10795 89/<- %ebx 4/r32/esp -10796 # var primitives/ebx: primitive -10797 53/push-ebx/next -10798 68/push 0/imm32/output-is-write-only -10799 68/push 0/imm32/no-disp32 -10800 68/push 0/imm32/no-imm32 -10801 68/push 0/imm32/no-r32 -10802 68/push 1/imm32/rm32-is-first-inout -10803 68/push "ff 0/subop/increment"/imm32/subx-name -10804 68/push 0/imm32/outputs -10805 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call -10806 68/push "increment"/imm32/name -10807 89/<- %ebx 4/r32/esp -10808 # convert -10809 c7 0/subop/copy *Curr-block-depth 0/imm32 -10810 (emit-subx-stmt _test-output-buffered-file %esi %ebx) -10811 (flush _test-output-buffered-file) -10812 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- -10818 # check output -10819 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive-2") -10820 # . epilogue -10821 89/<- %esp 5/r32/ebp -10822 5d/pop-to-ebp -10823 c3/return -10824 -10825 test-increment-register: -10826 # Select the right register between overloads. -10827 # foo <- increment -10828 # => -10829 # 50/increment-eax -10830 # -10831 # There's a variable on the var stack as follows: -10832 # name: 'foo' -10833 # type: int -10834 # register: 'eax' -10835 # -10836 # Primitives are the global definitions. -10837 # -10838 # There are no functions defined. -10839 # -10840 # . prologue -10841 55/push-ebp -10842 89/<- %ebp 4/r32/esp -10843 # setup -10844 (clear-stream _test-output-stream) -10845 (clear-stream $_test-output-buffered-file->buffer) -10846 # var type/ecx: (handle tree type-id) = int -10847 68/push 0/imm32/right/null -10848 68/push 1/imm32/left/int -10849 68/push 1/imm32/is-atom -10850 89/<- %ecx 4/r32/esp -10851 # var var-foo/ecx: var in eax -10852 68/push "eax"/imm32/register -10853 68/push 0/imm32/no-stack-offset -10854 68/push 1/imm32/block-depth -10855 51/push-ecx -10856 68/push "foo"/imm32 -10857 89/<- %ecx 4/r32/esp -10858 # var real-outputs/edi: (handle stmt-var) -10859 68/push 0/imm32/is-deref:false -10860 68/push 0/imm32/next -10861 51/push-ecx/var-foo -10862 89/<- %edi 4/r32/esp -10863 # var stmt/esi: statement -10864 68/push 0/imm32/next -10865 57/push-edi/outputs -10866 68/push 0/imm32/inouts -10867 68/push "increment"/imm32/operation -10868 68/push 1/imm32/regular-stmt -10869 89/<- %esi 4/r32/esp -10870 # convert -10871 c7 0/subop/copy *Curr-block-depth 0/imm32 -10872 (emit-subx-stmt _test-output-buffered-file %esi Primitives) -10873 (flush _test-output-buffered-file) -10874 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- -10880 # check output -10881 (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register") -10882 # . epilogue -10883 89/<- %esp 5/r32/ebp -10884 5d/pop-to-ebp -10885 c3/return -10886 -10887 test-increment-var: -10888 # Select the right primitive between overloads. -10889 # foo <- increment -10890 # => -10891 # ff 0/subop/increment %eax # sub-optimal, but should suffice -10892 # -10893 # There's a variable on the var stack as follows: -10894 # name: 'foo' -10895 # type: int -10896 # register: 'eax' -10897 # -10898 # Primitives are the global definitions. -10899 # -10900 # There are no functions defined. -10901 # -10902 # . prologue -10903 55/push-ebp -10904 89/<- %ebp 4/r32/esp -10905 # setup -10906 (clear-stream _test-output-stream) -10907 (clear-stream $_test-output-buffered-file->buffer) -10908 # var type/ecx: (handle tree type-id) = int -10909 68/push 0/imm32/right/null -10910 68/push 1/imm32/left/int -10911 68/push 1/imm32/is-atom -10912 89/<- %ecx 4/r32/esp -10913 # var var-foo/ecx: var in eax -10914 68/push "eax"/imm32/register -10915 68/push 0/imm32/no-stack-offset -10916 68/push 1/imm32/block-depth -10917 51/push-ecx -10918 68/push "foo"/imm32 -10919 89/<- %ecx 4/r32/esp -10920 # var inouts/edi: (handle stmt-var) -10921 68/push 0/imm32/is-deref:false -10922 68/push 0/imm32/next -10923 51/push-ecx/var-foo -10924 89/<- %edi 4/r32/esp -10925 # var stmt/esi: statement -10926 68/push 0/imm32/next -10927 57/push-edi/outputs -10928 68/push 0/imm32/inouts -10929 68/push "increment"/imm32/operation -10930 68/push 1/imm32 -10931 89/<- %esi 4/r32/esp -10932 # convert -10933 c7 0/subop/copy *Curr-block-depth 0/imm32 -10934 (emit-subx-stmt _test-output-buffered-file %esi Primitives) -10935 (flush _test-output-buffered-file) -10936 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- -10942 # check output -10943 (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-var") -10944 # . epilogue -10945 89/<- %esp 5/r32/ebp -10946 5d/pop-to-ebp -10947 c3/return -10948 -10949 test-add-reg-to-reg: -10950 # var1/reg <- add var2/reg -10951 # => -10952 # 01/add-to %var1 var2 -10953 # -10954 # . prologue -10955 55/push-ebp -10956 89/<- %ebp 4/r32/esp -10957 # setup -10958 (clear-stream _test-output-stream) -10959 (clear-stream $_test-output-buffered-file->buffer) -10960 # var type/ecx: (handle tree type-id) = int -10961 68/push 0/imm32/right/null -10962 68/push 1/imm32/left/int -10963 68/push 1/imm32/is-atom -10964 89/<- %ecx 4/r32/esp -10965 # var var-var1/ecx: var in eax -10966 68/push "eax"/imm32/register -10967 68/push 0/imm32/no-stack-offset -10968 68/push 1/imm32/block-depth -10969 51/push-ecx -10970 68/push "var1"/imm32 -10971 89/<- %ecx 4/r32/esp -10972 # var var-var2/edx: var in ecx -10973 68/push "ecx"/imm32/register -10974 68/push 0/imm32/no-stack-offset -10975 68/push 1/imm32/block-depth -10976 ff 6/subop/push *(ecx+4) # Var-type -10977 68/push "var2"/imm32 -10978 89/<- %edx 4/r32/esp -10979 # var inouts/esi: (handle stmt-var) = [var2] -10980 68/push 0/imm32/is-deref:false -10981 68/push 0/imm32/next -10982 52/push-edx/var-var2 -10983 89/<- %esi 4/r32/esp -10984 # var outputs/edi: (handle stmt-var) = [var1, var2] -10985 68/push 0/imm32/is-deref:false -10986 68/push 0/imm32/next -10987 51/push-ecx/var-var1 -10988 89/<- %edi 4/r32/esp -10989 # var stmt/esi: statement -10990 68/push 0/imm32/next -10991 57/push-edi/outputs -10992 56/push-esi/inouts -10993 68/push "add"/imm32/operation -10994 68/push 1/imm32 -10995 89/<- %esi 4/r32/esp -10996 # convert -10997 c7 0/subop/copy *Curr-block-depth 0/imm32 -10998 (emit-subx-stmt _test-output-buffered-file %esi Primitives) -10999 (flush _test-output-buffered-file) -11000 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- -11006 # check output -11007 (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg") -11008 # . epilogue -11009 89/<- %esp 5/r32/ebp -11010 5d/pop-to-ebp -11011 c3/return -11012 -11013 test-add-reg-to-mem: -11014 # add-to var1 var2/reg -11015 # => -11016 # 01/add-to *(ebp+__) var2 -11017 # -11018 # . prologue -11019 55/push-ebp -11020 89/<- %ebp 4/r32/esp -11021 # setup -11022 (clear-stream _test-output-stream) -11023 (clear-stream $_test-output-buffered-file->buffer) -11024 # var type/ecx: (handle tree type-id) = int -11025 68/push 0/imm32/right/null -11026 68/push 1/imm32/left/int -11027 68/push 1/imm32/is-atom -11028 89/<- %ecx 4/r32/esp -11029 # var var-var1/ecx: var -11030 68/push 0/imm32/no-register -11031 68/push 8/imm32/stack-offset -11032 68/push 1/imm32/block-depth -11033 51/push-ecx -11034 68/push "var1"/imm32 -11035 89/<- %ecx 4/r32/esp -11036 # var var-var2/edx: var in ecx -11037 68/push "ecx"/imm32/register -11038 68/push 0/imm32/no-stack-offset -11039 68/push 1/imm32/block-depth -11040 ff 6/subop/push *(ecx+4) # Var-type -11041 68/push "var2"/imm32 -11042 89/<- %edx 4/r32/esp -11043 # var inouts/esi: (handle stmt-var) = [var2] -11044 68/push 0/imm32/is-deref:false -11045 68/push 0/imm32/next -11046 52/push-edx/var-var2 -11047 89/<- %esi 4/r32/esp -11048 # var inouts = (handle stmt-var) = [var1, var2] -11049 56/push-esi/next -11050 51/push-ecx/var-var1 -11051 89/<- %esi 4/r32/esp -11052 # var stmt/esi: statement -11053 68/push 0/imm32/next -11054 68/push 0/imm32/outputs -11055 56/push-esi/inouts -11056 68/push "add-to"/imm32/operation -11057 68/push 1/imm32 -11058 89/<- %esi 4/r32/esp -11059 # convert -11060 c7 0/subop/copy *Curr-block-depth 0/imm32 -11061 (emit-subx-stmt _test-output-buffered-file %esi Primitives) -11062 (flush _test-output-buffered-file) -11063 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- -11069 # check output -11070 (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem") -11071 # . epilogue -11072 89/<- %esp 5/r32/ebp -11073 5d/pop-to-ebp -11074 c3/return -11075 -11076 test-add-mem-to-reg: -11077 # var1/reg <- add var2 -11078 # => -11079 # 03/add *(ebp+__) var1 -11080 # -11081 # . prologue -11082 55/push-ebp -11083 89/<- %ebp 4/r32/esp -11084 # setup -11085 (clear-stream _test-output-stream) -11086 (clear-stream $_test-output-buffered-file->buffer) -11087 # var type/ecx: (handle tree type-id) = int -11088 68/push 0/imm32/right/null -11089 68/push 1/imm32/left/int -11090 68/push 1/imm32/is-atom -11091 89/<- %ecx 4/r32/esp -11092 # var var-var1/ecx: var in eax -11093 68/push "eax"/imm32/register -11094 68/push 0/imm32/no-stack-offset -11095 68/push 1/imm32/block-depth -11096 51/push-ecx -11097 68/push "var1"/imm32 -11098 89/<- %ecx 4/r32/esp -11099 # var var-var2/edx: var -11100 68/push 0/imm32/no-register -11101 68/push 8/imm32/stack-offset -11102 68/push 1/imm32/block-depth -11103 ff 6/subop/push *(ecx+4) # Var-type -11104 68/push "var2"/imm32 -11105 89/<- %edx 4/r32/esp -11106 # var inouts/esi: (handle stmt-var) = [var2] -11107 68/push 0/imm32/is-deref:false -11108 68/push 0/imm32/next -11109 52/push-edx/var-var2 -11110 89/<- %esi 4/r32/esp -11111 # var outputs/edi = (handle stmt-var) = [var1] -11112 68/push 0/imm32/is-deref:false -11113 68/push 0/imm32/next -11114 51/push-ecx/var-var1 -11115 89/<- %edi 4/r32/esp -11116 # var stmt/esi: statement -11117 68/push 0/imm32/next -11118 57/push-edi/outputs -11119 56/push-esi/inouts -11120 68/push "add"/imm32/operation -11121 68/push 1/imm32 -11122 89/<- %esi 4/r32/esp -11123 # convert -11124 c7 0/subop/copy *Curr-block-depth 0/imm32 -11125 (emit-subx-stmt _test-output-buffered-file %esi Primitives) -11126 (flush _test-output-buffered-file) -11127 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- -11133 # check output -11134 (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg") -11135 # . epilogue -11136 89/<- %esp 5/r32/ebp -11137 5d/pop-to-ebp -11138 c3/return -11139 -11140 test-add-literal-to-eax: -11141 # var1/eax <- add 0x34 -11142 # => -11143 # 05/add-to-eax 0x34/imm32 -11144 # -11145 # . prologue -11146 55/push-ebp -11147 89/<- %ebp 4/r32/esp -11148 # setup -11149 (clear-stream _test-output-stream) -11150 (clear-stream $_test-output-buffered-file->buffer) -11151 # var type/ecx: (handle tree type-id) = int -11152 68/push 0/imm32/right/null -11153 68/push 1/imm32/left/int -11154 68/push 1/imm32/is-atom -11155 89/<- %ecx 4/r32/esp -11156 # var var-var1/ecx: var in eax -11157 68/push "eax"/imm32/register -11158 68/push 0/imm32/no-stack-offset -11159 68/push 1/imm32/block-depth -11160 51/push-ecx -11161 68/push "var1"/imm32 -11162 89/<- %ecx 4/r32/esp -11163 # var type/edx: (handle tree type-id) = literal -11164 68/push 0/imm32/right/null -11165 68/push 0/imm32/left/literal -11166 89/<- %edx 4/r32/esp -11167 # var var-var2/edx: var literal -11168 68/push 0/imm32/no-register -11169 68/push 0/imm32/no-stack-offset -11170 68/push 1/imm32/block-depth -11171 52/push-edx -11172 68/push "0x34"/imm32 -11173 89/<- %edx 4/r32/esp -11174 # var inouts/esi: (handle stmt-var) = [var2] -11175 68/push 0/imm32/is-deref:false -11176 68/push 0/imm32/next -11177 52/push-edx/var-var2 -11178 89/<- %esi 4/r32/esp -11179 # var outputs/edi: (handle stmt-var) = [var1] -11180 68/push 0/imm32/is-deref:false -11181 68/push 0/imm32/next -11182 51/push-ecx/var-var1 -11183 89/<- %edi 4/r32/esp -11184 # var stmt/esi: statement -11185 68/push 0/imm32/next -11186 57/push-edi/outputs -11187 56/push-esi/inouts -11188 68/push "add"/imm32/operation -11189 68/push 1/imm32 -11190 89/<- %esi 4/r32/esp -11191 # convert -11192 c7 0/subop/copy *Curr-block-depth 0/imm32 -11193 (emit-subx-stmt _test-output-buffered-file %esi Primitives) -11194 (flush _test-output-buffered-file) -11195 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- -11201 # check output -11202 (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax") -11203 # . epilogue -11204 89/<- %esp 5/r32/ebp -11205 5d/pop-to-ebp -11206 c3/return -11207 -11208 test-add-literal-to-reg: -11209 # var1/ecx <- add 0x34 -11210 # => -11211 # 81 0/subop/add %ecx 0x34/imm32 -11212 # -11213 # . prologue -11214 55/push-ebp -11215 89/<- %ebp 4/r32/esp -11216 # setup -11217 (clear-stream _test-output-stream) -11218 (clear-stream $_test-output-buffered-file->buffer) -11219 # var type/ecx: (handle tree type-id) = int -11220 68/push 0/imm32/right/null -11221 68/push 1/imm32/left/int -11222 68/push 1/imm32/is-atom -11223 89/<- %ecx 4/r32/esp -11224 # var var-var1/ecx: var in ecx -11225 68/push "ecx"/imm32/register -11226 68/push 0/imm32/no-stack-offset -11227 68/push 1/imm32/block-depth -11228 51/push-ecx -11229 68/push "var1"/imm32 -11230 89/<- %ecx 4/r32/esp -11231 # var type/edx: (handle tree type-id) = literal -11232 68/push 0/imm32/right/null -11233 68/push 0/imm32/left/literal -11234 89/<- %edx 4/r32/esp -11235 # var var-var2/edx: var literal -11236 68/push 0/imm32/no-register -11237 68/push 0/imm32/no-stack-offset -11238 68/push 1/imm32/block-depth -11239 52/push-edx -11240 68/push "0x34"/imm32 -11241 89/<- %edx 4/r32/esp -11242 # var inouts/esi: (handle stmt-var) = [var2] -11243 68/push 0/imm32/is-deref:false -11244 68/push 0/imm32/next -11245 52/push-edx/var-var2 -11246 89/<- %esi 4/r32/esp -11247 # var outputs/edi: (handle stmt-var) = [var1] -11248 68/push 0/imm32/is-deref:false -11249 68/push 0/imm32/next -11250 51/push-ecx/var-var1 -11251 89/<- %edi 4/r32/esp -11252 # var stmt/esi: statement -11253 68/push 0/imm32/next -11254 57/push-edi/outputs -11255 56/push-esi/inouts -11256 68/push "add"/imm32/operation -11257 68/push 1/imm32 -11258 89/<- %esi 4/r32/esp -11259 # convert -11260 c7 0/subop/copy *Curr-block-depth 0/imm32 -11261 (emit-subx-stmt _test-output-buffered-file %esi Primitives) -11262 (flush _test-output-buffered-file) -11263 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- -11269 # check output -11270 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg") -11271 # . epilogue -11272 89/<- %esp 5/r32/ebp -11273 5d/pop-to-ebp -11274 c3/return -11275 -11276 test-add-literal-to-mem: -11277 # add-to var1, 0x34 -11278 # => -11279 # 81 0/subop/add %eax 0x34/imm32 -11280 # -11281 # . prologue -11282 55/push-ebp -11283 89/<- %ebp 4/r32/esp -11284 # setup -11285 (clear-stream _test-output-stream) -11286 (clear-stream $_test-output-buffered-file->buffer) -11287 # var type/ecx: (handle tree type-id) = int -11288 68/push 0/imm32/right/null -11289 68/push 1/imm32/left/int -11290 68/push 1/imm32/is-atom -11291 89/<- %ecx 4/r32/esp -11292 # var var-var1/ecx: var -11293 68/push 0/imm32/no-register -11294 68/push 8/imm32/stack-offset -11295 68/push 1/imm32/block-depth -11296 51/push-ecx -11297 68/push "var1"/imm32 -11298 89/<- %ecx 4/r32/esp -11299 # var type/edx: (handle tree type-id) = literal -11300 68/push 0/imm32/right/null -11301 68/push 0/imm32/left/literal -11302 89/<- %edx 4/r32/esp -11303 # var var-var2/edx: var literal -11304 68/push 0/imm32/no-register -11305 68/push 0/imm32/no-stack-offset -11306 68/push 1/imm32/block-depth -11307 52/push-edx -11308 68/push "0x34"/imm32 -11309 89/<- %edx 4/r32/esp -11310 # var inouts/esi: (handle stmt-var) = [var2] -11311 68/push 0/imm32/is-deref:false -11312 68/push 0/imm32/next -11313 52/push-edx/var-var2 -11314 89/<- %esi 4/r32/esp -11315 # var inouts = (handle stmt-var) = [var1, var2] -11316 68/push 0/imm32/is-deref:false -11317 56/push-esi/next -11318 51/push-ecx/var-var1 -11319 89/<- %esi 4/r32/esp -11320 # var stmt/esi: statement -11321 68/push 0/imm32/next -11322 68/push 0/imm32/outputs -11323 56/push-esi/inouts -11324 68/push "add-to"/imm32/operation -11325 68/push 1/imm32 -11326 89/<- %esi 4/r32/esp -11327 # convert -11328 c7 0/subop/copy *Curr-block-depth 0/imm32 -11329 (emit-subx-stmt _test-output-buffered-file %esi Primitives) -11330 (flush _test-output-buffered-file) -11331 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- -11337 # check output -11338 (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem") -11339 # . epilogue -11340 89/<- %esp 5/r32/ebp -11341 5d/pop-to-ebp -11342 c3/return -11343 -11344 test-compare-mem-with-reg: -11345 # compare var1, var2/eax -11346 # => -11347 # 39/compare *(ebp+___) 0/r32/eax -11348 # -11349 # . prologue -11350 55/push-ebp -11351 89/<- %ebp 4/r32/esp -11352 # setup -11353 (clear-stream _test-output-stream) -11354 (clear-stream $_test-output-buffered-file->buffer) -11355 # var type/ecx: (handle tree type-id) = int -11356 68/push 0/imm32/right/null -11357 68/push 1/imm32/left/int -11358 68/push 1/imm32/is-atom -11359 89/<- %ecx 4/r32/esp -11360 # var var-var2/ecx: var in eax -11361 68/push "eax"/imm32/register -11362 68/push 0/imm32/no-stack-offset -11363 68/push 1/imm32/block-depth -11364 51/push-ecx -11365 68/push "var2"/imm32 -11366 89/<- %ecx 4/r32/esp -11367 # var var-var1/edx: var -11368 68/push 0/imm32/no-register -11369 68/push 8/imm32/stack-offset -11370 68/push 1/imm32/block-depth -11371 ff 6/subop/push *(ecx+4) # Var-type -11372 68/push "var1"/imm32 -11373 89/<- %edx 4/r32/esp -11374 # var inouts/esi: (handle stmt-var) = [var2] -11375 68/push 0/imm32/is-deref:false -11376 68/push 0/imm32/next -11377 51/push-ecx/var-var2 -11378 89/<- %esi 4/r32/esp -11379 # inouts = [var1, var2] -11380 68/push 0/imm32/is-deref:false -11381 56/push-esi -11382 52/push-edx/var-var1 -11383 89/<- %esi 4/r32/esp -11384 # var stmt/esi: statement -11385 68/push 0/imm32/next -11386 68/push 0/imm32/outputs -11387 56/push-esi/inouts -11388 68/push "compare"/imm32/operation -11389 68/push 1/imm32 -11390 89/<- %esi 4/r32/esp -11391 # convert -11392 c7 0/subop/copy *Curr-block-depth 0/imm32 -11393 (emit-subx-stmt _test-output-buffered-file %esi Primitives) -11394 (flush _test-output-buffered-file) -11395 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- -11401 # check output -11402 (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg") -11403 # . epilogue -11404 89/<- %esp 5/r32/ebp -11405 5d/pop-to-ebp -11406 c3/return -11407 -11408 test-compare-reg-with-mem: -11409 # compare var1/eax, var2 -11410 # => -11411 # 3b/compare<- *(ebp+___) 0/r32/eax -11412 # -11413 # . prologue -11414 55/push-ebp -11415 89/<- %ebp 4/r32/esp -11416 # setup -11417 (clear-stream _test-output-stream) -11418 (clear-stream $_test-output-buffered-file->buffer) -11419 # var type/ecx: (handle tree type-id) = int -11420 68/push 0/imm32/right/null -11421 68/push 1/imm32/left/int -11422 68/push 1/imm32/is-atom -11423 89/<- %ecx 4/r32/esp -11424 # var var-var1/ecx: var in eax -11425 68/push "eax"/imm32/register -11426 68/push 0/imm32/no-stack-offset -11427 68/push 1/imm32/block-depth -11428 51/push-ecx -11429 68/push "var1"/imm32 -11430 89/<- %ecx 4/r32/esp -11431 # var var-var2/edx: var -11432 68/push 0/imm32/no-register -11433 68/push 8/imm32/stack-offset -11434 68/push 1/imm32/block-depth -11435 ff 6/subop/push *(ecx+4) # Var-type -11436 68/push "var2"/imm32 -11437 89/<- %edx 4/r32/esp -11438 # var inouts/esi: (handle stmt-var) = [var2] -11439 68/push 0/imm32/is-deref:false -11440 68/push 0/imm32/next -11441 52/push-edx/var-var2 -11442 89/<- %esi 4/r32/esp -11443 # inouts = [var1, var2] -11444 68/push 0/imm32/is-deref:false -11445 56/push-esi -11446 51/push-ecx/var-var1 -11447 89/<- %esi 4/r32/esp -11448 # var stmt/esi: statement -11449 68/push 0/imm32/next -11450 68/push 0/imm32/outputs -11451 56/push-esi/inouts -11452 68/push "compare"/imm32/operation -11453 68/push 1/imm32 -11454 89/<- %esi 4/r32/esp -11455 # convert -11456 c7 0/subop/copy *Curr-block-depth 0/imm32 -11457 (emit-subx-stmt _test-output-buffered-file %esi Primitives) -11458 (flush _test-output-buffered-file) -11459 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- -11465 # check output -11466 (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem") -11467 # . epilogue -11468 89/<- %esp 5/r32/ebp -11469 5d/pop-to-ebp -11470 c3/return -11471 -11472 test-compare-mem-with-literal: -11473 # compare var1, 0x34 -11474 # => -11475 # 81 7/subop/compare *(ebp+___) 0x34/imm32 -11476 # -11477 # . prologue -11478 55/push-ebp -11479 89/<- %ebp 4/r32/esp -11480 # setup -11481 (clear-stream _test-output-stream) -11482 (clear-stream $_test-output-buffered-file->buffer) -11483 # var type/ecx: (handle tree type-id) = int -11484 68/push 0/imm32/right/null -11485 68/push 1/imm32/left/int -11486 68/push 1/imm32/is-atom -11487 89/<- %ecx 4/r32/esp -11488 # var var-var1/ecx: var -11489 68/push 0/imm32/no-register -11490 68/push 8/imm32/stack-offset -11491 68/push 1/imm32/block-depth -11492 51/push-ecx -11493 68/push "var1"/imm32 -11494 89/<- %ecx 4/r32/esp -11495 # var type/edx: (handle tree type-id) = literal -11496 68/push 0/imm32/right/null -11497 68/push 0/imm32/left/literal -11498 89/<- %edx 4/r32/esp -11499 # var var-var2/edx: var literal -11500 68/push 0/imm32/no-register -11501 68/push 0/imm32/no-stack-offset -11502 68/push 1/imm32/block-depth -11503 52/push-edx -11504 68/push "0x34"/imm32 -11505 89/<- %edx 4/r32/esp -11506 # var inouts/esi: (handle stmt-var) = [var2] -11507 68/push 0/imm32/is-deref:false -11508 68/push 0/imm32/next -11509 52/push-edx/var-var2 -11510 89/<- %esi 4/r32/esp -11511 # inouts = [var1, var2] -11512 68/push 0/imm32/is-deref:false -11513 56/push-esi/next -11514 51/push-ecx/var-var1 -11515 89/<- %esi 4/r32/esp -11516 # var stmt/esi: statement -11517 68/push 0/imm32/next -11518 68/push 0/imm32/outputs -11519 56/push-esi/inouts -11520 68/push "compare"/imm32/operation -11521 68/push 1/imm32 -11522 89/<- %esi 4/r32/esp -11523 # convert -11524 c7 0/subop/copy *Curr-block-depth 0/imm32 -11525 (emit-subx-stmt _test-output-buffered-file %esi Primitives) -11526 (flush _test-output-buffered-file) -11527 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- -11533 # check output -11534 (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal") -11535 # . epilogue -11536 89/<- %esp 5/r32/ebp -11537 5d/pop-to-ebp -11538 c3/return -11539 -11540 test-compare-eax-with-literal: -11541 # compare var1/eax 0x34 -11542 # => -11543 # 3d/compare-eax-with 0x34/imm32 -11544 # -11545 # . prologue -11546 55/push-ebp -11547 89/<- %ebp 4/r32/esp -11548 # setup -11549 (clear-stream _test-output-stream) -11550 (clear-stream $_test-output-buffered-file->buffer) -11551 # var type/ecx: (handle tree type-id) = int -11552 68/push 0/imm32/right/null -11553 68/push 1/imm32/left/int -11554 68/push 1/imm32/is-atom -11555 89/<- %ecx 4/r32/esp -11556 # var var-var1/ecx: var in eax -11557 68/push "eax"/imm32/register -11558 68/push 0/imm32/no-stack-offset -11559 68/push 1/imm32/block-depth -11560 51/push-ecx -11561 68/push "var1"/imm32 -11562 89/<- %ecx 4/r32/esp -11563 # var type/edx: (handle tree type-id) = literal -11564 68/push 0/imm32/right/null -11565 68/push 0/imm32/left/literal -11566 89/<- %edx 4/r32/esp -11567 # var var-var2/edx: var literal -11568 68/push 0/imm32/no-register -11569 68/push 0/imm32/no-stack-offset -11570 68/push 1/imm32/block-depth -11571 52/push-edx -11572 68/push "0x34"/imm32 -11573 89/<- %edx 4/r32/esp -11574 # var inouts/esi: (handle stmt-var) = [var2] -11575 68/push 0/imm32/is-deref:false -11576 68/push 0/imm32/next -11577 52/push-edx/var-var2 -11578 89/<- %esi 4/r32/esp -11579 # inouts = [var1, var2] -11580 68/push 0/imm32/is-deref:false -11581 56/push-esi/next -11582 51/push-ecx/var-var1 -11583 89/<- %esi 4/r32/esp -11584 # var stmt/esi: statement -11585 68/push 0/imm32/next -11586 68/push 0/imm32/outputs -11587 56/push-esi/inouts -11588 68/push "compare"/imm32/operation -11589 68/push 1/imm32/regular-stmt -11590 89/<- %esi 4/r32/esp -11591 # convert -11592 c7 0/subop/copy *Curr-block-depth 0/imm32 -11593 (emit-subx-stmt _test-output-buffered-file %esi Primitives) -11594 (flush _test-output-buffered-file) -11595 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- -11601 # check output -11602 (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal") -11603 # . epilogue -11604 89/<- %esp 5/r32/ebp -11605 5d/pop-to-ebp -11606 c3/return -11607 -11608 test-compare-reg-with-literal: -11609 # compare var1/ecx 0x34 -11610 # => -11611 # 81 7/subop/compare %ecx 0x34/imm32 -11612 # -11613 # . prologue -11614 55/push-ebp -11615 89/<- %ebp 4/r32/esp -11616 # setup -11617 (clear-stream _test-output-stream) -11618 (clear-stream $_test-output-buffered-file->buffer) -11619 # var type/ecx: (handle tree type-id) = int -11620 68/push 0/imm32/right/null -11621 68/push 1/imm32/left/int -11622 68/push 1/imm32/is-atom -11623 89/<- %ecx 4/r32/esp -11624 # var var-var1/ecx: var in ecx -11625 68/push "ecx"/imm32/register -11626 68/push 0/imm32/no-stack-offset -11627 68/push 1/imm32/block-depth -11628 51/push-ecx -11629 68/push "var1"/imm32 -11630 89/<- %ecx 4/r32/esp -11631 # var type/edx: (handle tree type-id) = literal -11632 68/push 0/imm32/right/null -11633 68/push 0/imm32/left/literal -11634 89/<- %edx 4/r32/esp -11635 # var var-var2/edx: var literal -11636 68/push 0/imm32/no-register -11637 68/push 0/imm32/no-stack-offset -11638 68/push 1/imm32/block-depth -11639 52/push-edx -11640 68/push "0x34"/imm32 -11641 89/<- %edx 4/r32/esp -11642 # var inouts/esi: (handle stmt-var) = [var2] -11643 68/push 0/imm32/is-deref:false -11644 68/push 0/imm32/next -11645 52/push-edx/var-var2 -11646 89/<- %esi 4/r32/esp -11647 # inouts = [var1, var2] -11648 68/push 0/imm32/is-deref:false -11649 56/push-esi/next -11650 51/push-ecx/var-var1 -11651 89/<- %esi 4/r32/esp -11652 # var stmt/esi: statement -11653 68/push 0/imm32/next -11654 68/push 0/imm32/outputs -11655 56/push-esi/inouts -11656 68/push "compare"/imm32/operation -11657 68/push 1/imm32/regular-stmt -11658 89/<- %esi 4/r32/esp -11659 # convert -11660 c7 0/subop/copy *Curr-block-depth 0/imm32 -11661 (emit-subx-stmt _test-output-buffered-file %esi Primitives) -11662 (flush _test-output-buffered-file) -11663 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- -11669 # check output -11670 (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal") -11671 # . epilogue -11672 89/<- %esp 5/r32/ebp -11673 5d/pop-to-ebp -11674 c3/return -11675 -11676 test-emit-subx-stmt-function-call: -11677 # Call a function on a variable on the stack. -11678 # f foo -11679 # => -11680 # (f *(ebp-8)) -11681 # (Changing the function name supports overloading in general, but here it -11682 # just serves to help disambiguate things.) -11683 # -11684 # There's a variable on the var stack as follows: -11685 # name: 'foo' -11686 # type: int -11687 # stack-offset: -8 -11688 # -11689 # There's nothing in primitives. -11690 # -11691 # We don't perform any checking here on the type of 'f'. -11692 # -11693 # . prologue -11694 55/push-ebp -11695 89/<- %ebp 4/r32/esp -11696 # setup -11697 (clear-stream _test-output-stream) -11698 (clear-stream $_test-output-buffered-file->buffer) -11699 # var type/ecx: (handle tree type-id) = int -11700 68/push 0/imm32/right/null -11701 68/push 1/imm32/left/int -11702 68/push 1/imm32/is-atom -11703 89/<- %ecx 4/r32/esp -11704 # var var-foo/ecx: var -11705 68/push 0/imm32/no-register -11706 68/push -8/imm32/stack-offset -11707 68/push 0/imm32/block-depth -11708 51/push-ecx -11709 68/push "foo"/imm32 -11710 89/<- %ecx 4/r32/esp -11711 # var inouts/esi: (handle stmt-var) -11712 68/push 0/imm32/is-deref:false -11713 68/push 0/imm32/next -11714 51/push-ecx/var-foo -11715 89/<- %esi 4/r32/esp -11716 # var stmt/esi: statement -11717 68/push 0/imm32/next -11718 68/push 0/imm32/outputs -11719 56/push-esi/inouts -11720 68/push "f"/imm32/operation -11721 68/push 1/imm32 -11722 89/<- %esi 4/r32/esp -11723 # convert -11724 c7 0/subop/copy *Curr-block-depth 0/imm32 -11725 (emit-subx-stmt _test-output-buffered-file %esi 0) -11726 (flush _test-output-buffered-file) -11727 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- -11733 # check output -11734 (check-next-stream-line-equal _test-output-stream "(f *(ebp+0xfffffff8))" "F - test-emit-subx-stmt-function-call") -11735 # . epilogue -11736 89/<- %esp 5/r32/ebp -11737 5d/pop-to-ebp -11738 c3/return -11739 -11740 test-emit-subx-stmt-function-call-with-literal-arg: -11741 # Call a function on a literal. -11742 # f 34 -11743 # => -11744 # (f2 34) -11745 # -11746 # . prologue -11747 55/push-ebp -11748 89/<- %ebp 4/r32/esp -11749 # setup -11750 (clear-stream _test-output-stream) -11751 (clear-stream $_test-output-buffered-file->buffer) -11752 # var type/ecx: (handle tree type-id) = literal -11753 68/push 0/imm32/right/null -11754 68/push 0/imm32/left/literal -11755 89/<- %ecx 4/r32/esp -11756 # var var-foo/ecx: var literal -11757 68/push 0/imm32/no-register -11758 68/push 0/imm32/no-stack-offset -11759 68/push 0/imm32/block-depth -11760 51/push-ecx -11761 68/push "34"/imm32 -11762 89/<- %ecx 4/r32/esp -11763 # var inouts/esi: (handle stmt-var) -11764 68/push 0/imm32/is-deref:false -11765 68/push 0/imm32/next -11766 51/push-ecx/var-foo -11767 89/<- %esi 4/r32/esp -11768 # var stmt/esi: statement -11769 68/push 0/imm32/next -11770 68/push 0/imm32/outputs -11771 56/push-esi/inouts -11772 68/push "f"/imm32/operation -11773 68/push 1/imm32 -11774 89/<- %esi 4/r32/esp -11775 # convert -11776 c7 0/subop/copy *Curr-block-depth 0/imm32 -11777 (emit-subx-stmt _test-output-buffered-file %esi 0 %ebx) -11778 (flush _test-output-buffered-file) -11779 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------------------------------------------------------------- -11785 # check output -11786 (check-next-stream-line-equal _test-output-stream "(f 34)" "F - test-emit-subx-stmt-function-call-with-literal-arg") -11787 # . epilogue -11788 89/<- %esp 5/r32/ebp -11789 5d/pop-to-ebp -11790 c3/return -11791 -11792 emit-indent: # out: (addr buffered-file), n: int -11793 # . prologue -11794 55/push-ebp -11795 89/<- %ebp 4/r32/esp -11796 # . save registers -11797 50/push-eax -11798 # var i/eax: int = n -11799 8b/-> *(ebp+0xc) 0/r32/eax -11800 { -11801 # if (i <= 0) break -11802 3d/compare-eax-with 0/imm32 -11803 7e/jump-if-<= break/disp8 -11804 (write-buffered *(ebp+8) " ") -11805 48/decrement-eax -11806 eb/jump loop/disp8 -11807 } -11808 $emit-indent:end: -11809 # . restore registers -11810 58/pop-to-eax -11811 # . epilogue -11812 89/<- %esp 5/r32/ebp -11813 5d/pop-to-ebp -11814 c3/return -11815 -11816 emit-subx-prologue: # out: (addr buffered-file) -11817 # . prologue -11818 55/push-ebp -11819 89/<- %ebp 4/r32/esp -11820 # -11821 (write-buffered *(ebp+8) " # . prologue\n") -11822 (write-buffered *(ebp+8) " 55/push-ebp\n") -11823 (write-buffered *(ebp+8) " 89/<- %ebp 4/r32/esp\n") -11824 $emit-subx-prologue:end: -11825 # . epilogue -11826 89/<- %esp 5/r32/ebp -11827 5d/pop-to-ebp -11828 c3/return -11829 -11830 emit-subx-epilogue: # out: (addr buffered-file) -11831 # . prologue -11832 55/push-ebp -11833 89/<- %ebp 4/r32/esp -11834 # -11835 (write-buffered *(ebp+8) " # . epilogue\n") -11836 (write-buffered *(ebp+8) " 89/<- %esp 5/r32/ebp\n") -11837 (write-buffered *(ebp+8) " 5d/pop-to-ebp\n") -11838 (write-buffered *(ebp+8) " c3/return\n") -11839 $emit-subx-epilogue:end: -11840 # . epilogue -11841 89/<- %esp 5/r32/ebp -11842 5d/pop-to-ebp -11843 c3/return + 9432 0/imm32/no-disp32 + 9433 0/imm32/output-is-write-only + 9434 0x11/imm32/alloc-id:fake + 9435 _Primitive-decrement-eax/imm32/next + 9436 _Primitive-decrement-eax: # (payload primitive) + 9437 0x11/imm32/alloc-id:fake:payload + 9438 # var/eax <- decrement => 48/decrement-eax + 9439 0x11/imm32/alloc-id:fake + 9440 _string-decrement/imm32/name + 9441 0/imm32/no-inouts + 9442 0/imm32/no-inouts + 9443 0x11/imm32/alloc-id:fake + 9444 Single-int-var-in-eax/imm32/outputs + 9445 0x11/imm32/alloc-id:fake + 9446 _string_48_decrement_eax/imm32/subx-name + 9447 0/imm32/no-rm32 + 9448 0/imm32/no-r32 + 9449 0/imm32/no-imm32 + 9450 0/imm32/no-disp32 + 9451 0/imm32/output-is-write-only + 9452 0x11/imm32/alloc-id:fake + 9453 _Primitive-decrement-ecx/imm32/next + 9454 _Primitive-decrement-ecx: # (payload primitive) + 9455 0x11/imm32/alloc-id:fake:payload + 9456 # var/ecx <- decrement => 49/decrement-ecx + 9457 0x11/imm32/alloc-id:fake + 9458 _string-decrement/imm32/name + 9459 0/imm32/no-inouts + 9460 0/imm32/no-inouts + 9461 0x11/imm32/alloc-id:fake + 9462 Single-int-var-in-ecx/imm32/outputs + 9463 0x11/imm32/alloc-id:fake + 9464 _string_49_decrement_ecx/imm32/subx-name + 9465 0/imm32/no-rm32 + 9466 0/imm32/no-r32 + 9467 0/imm32/no-imm32 + 9468 0/imm32/no-disp32 + 9469 0/imm32/output-is-write-only + 9470 0x11/imm32/alloc-id:fake + 9471 _Primitive-decrement-edx/imm32/next + 9472 _Primitive-decrement-edx: # (payload primitive) + 9473 0x11/imm32/alloc-id:fake:payload + 9474 # var/edx <- decrement => 4a/decrement-edx + 9475 0x11/imm32/alloc-id:fake + 9476 _string-decrement/imm32/name + 9477 0/imm32/no-inouts + 9478 0/imm32/no-inouts + 9479 0x11/imm32/alloc-id:fake + 9480 Single-int-var-in-edx/imm32/outputs + 9481 0x11/imm32/alloc-id:fake + 9482 _string_4a_decrement_edx/imm32/subx-name + 9483 0/imm32/no-rm32 + 9484 0/imm32/no-r32 + 9485 0/imm32/no-imm32 + 9486 0/imm32/no-disp32 + 9487 0/imm32/output-is-write-only + 9488 0x11/imm32/alloc-id:fake + 9489 _Primitive-decrement-ebx/imm32/next + 9490 _Primitive-decrement-ebx: # (payload primitive) + 9491 0x11/imm32/alloc-id:fake:payload + 9492 # var/ebx <- decrement => 4b/decrement-ebx + 9493 0x11/imm32/alloc-id:fake + 9494 _string-decrement/imm32/name + 9495 0/imm32/no-inouts + 9496 0/imm32/no-inouts + 9497 0x11/imm32/alloc-id:fake + 9498 Single-int-var-in-ebx/imm32/outputs + 9499 0x11/imm32/alloc-id:fake + 9500 _string_4b_decrement_ebx/imm32/subx-name + 9501 0/imm32/no-rm32 + 9502 0/imm32/no-r32 + 9503 0/imm32/no-imm32 + 9504 0/imm32/no-disp32 + 9505 0/imm32/output-is-write-only + 9506 0x11/imm32/alloc-id:fake + 9507 _Primitive-decrement-esi/imm32/next + 9508 _Primitive-decrement-esi: # (payload primitive) + 9509 0x11/imm32/alloc-id:fake:payload + 9510 # var/esi <- decrement => 4e/decrement-esi + 9511 0x11/imm32/alloc-id:fake + 9512 _string-decrement/imm32/name + 9513 0/imm32/no-inouts + 9514 0/imm32/no-inouts + 9515 0x11/imm32/alloc-id:fake + 9516 Single-int-var-in-esi/imm32/outputs + 9517 0x11/imm32/alloc-id:fake + 9518 _string_4e_decrement_esi/imm32/subx-name + 9519 0/imm32/no-rm32 + 9520 0/imm32/no-r32 + 9521 0/imm32/no-imm32 + 9522 0/imm32/no-disp32 + 9523 0/imm32/output-is-write-only + 9524 0x11/imm32/alloc-id:fake + 9525 _Primitive-decrement-edi/imm32/next + 9526 _Primitive-decrement-edi: # (payload primitive) + 9527 0x11/imm32/alloc-id:fake:payload + 9528 # var/edi <- decrement => 4f/decrement-edi + 9529 0x11/imm32/alloc-id:fake + 9530 _string-decrement/imm32/name + 9531 0/imm32/no-inouts + 9532 0/imm32/no-inouts + 9533 0x11/imm32/alloc-id:fake + 9534 Single-int-var-in-edi/imm32/outputs + 9535 0x11/imm32/alloc-id:fake + 9536 _string_4f_decrement_edi/imm32/subx-name + 9537 0/imm32/no-rm32 + 9538 0/imm32/no-r32 + 9539 0/imm32/no-imm32 + 9540 0/imm32/no-disp32 + 9541 0/imm32/output-is-write-only + 9542 0x11/imm32/alloc-id:fake + 9543 _Primitive-increment-mem/imm32/next + 9544 _Primitive-increment-mem: # (payload primitive) + 9545 0x11/imm32/alloc-id:fake:payload + 9546 # increment var => ff 0/subop/increment *(ebp+__) + 9547 0x11/imm32/alloc-id:fake + 9548 _string-increment/imm32/name + 9549 0x11/imm32/alloc-id:fake + 9550 Single-int-var-in-mem/imm32/inouts + 9551 0/imm32/no-outputs + 9552 0/imm32/no-outputs + 9553 0x11/imm32/alloc-id:fake + 9554 _string_ff_subop_increment/imm32/subx-name + 9555 1/imm32/rm32-is-first-inout + 9556 0/imm32/no-r32 + 9557 0/imm32/no-imm32 + 9558 0/imm32/no-disp32 + 9559 0/imm32/output-is-write-only + 9560 0x11/imm32/alloc-id:fake + 9561 _Primitive-increment-reg/imm32/next + 9562 _Primitive-increment-reg: # (payload primitive) + 9563 0x11/imm32/alloc-id:fake:payload + 9564 # var/reg <- increment => ff 0/subop/increment %__ + 9565 0x11/imm32/alloc-id:fake + 9566 _string-increment/imm32/name + 9567 0/imm32/no-inouts + 9568 0/imm32/no-inouts + 9569 0x11/imm32/alloc-id:fake + 9570 Single-int-var-in-some-register/imm32/outputs + 9571 0x11/imm32/alloc-id:fake + 9572 _string_ff_subop_increment/imm32/subx-name + 9573 3/imm32/rm32-is-first-output + 9574 0/imm32/no-r32 + 9575 0/imm32/no-imm32 + 9576 0/imm32/no-disp32 + 9577 0/imm32/output-is-write-only + 9578 0x11/imm32/alloc-id:fake + 9579 _Primitive-decrement-mem/imm32/next + 9580 _Primitive-decrement-mem: # (payload primitive) + 9581 0x11/imm32/alloc-id:fake:payload + 9582 # decrement var => ff 1/subop/decrement *(ebp+__) + 9583 0x11/imm32/alloc-id:fake + 9584 _string-decrement/imm32/name + 9585 0x11/imm32/alloc-id:fake + 9586 Single-int-var-in-mem/imm32/inouts + 9587 0/imm32/no-outputs + 9588 0/imm32/no-outputs + 9589 0x11/imm32/alloc-id:fake + 9590 _string_ff_subop_decrement/imm32/subx-name + 9591 1/imm32/rm32-is-first-inout + 9592 0/imm32/no-r32 + 9593 0/imm32/no-imm32 + 9594 0/imm32/no-disp32 + 9595 0/imm32/output-is-write-only + 9596 0x11/imm32/alloc-id:fake + 9597 _Primitive-decrement-reg/imm32/next + 9598 _Primitive-decrement-reg: # (payload primitive) + 9599 0x11/imm32/alloc-id:fake:payload + 9600 # var/reg <- decrement => ff 1/subop/decrement %__ + 9601 0x11/imm32/alloc-id:fake + 9602 _string-decrement/imm32/name + 9603 0/imm32/no-inouts + 9604 0/imm32/no-inouts + 9605 0x11/imm32/alloc-id:fake + 9606 Single-int-var-in-some-register/imm32/outputs + 9607 0x11/imm32/alloc-id:fake + 9608 _string_ff_subop_decrement/imm32/subx-name + 9609 3/imm32/rm32-is-first-output + 9610 0/imm32/no-r32 + 9611 0/imm32/no-imm32 + 9612 0/imm32/no-disp32 + 9613 0/imm32/output-is-write-only + 9614 0x11/imm32/alloc-id:fake + 9615 _Primitive-add-to-eax/imm32/next + 9616 # - add + 9617 _Primitive-add-to-eax: # (payload primitive) + 9618 0x11/imm32/alloc-id:fake:payload + 9619 # var/eax <- add lit => 05/add-to-eax lit/imm32 + 9620 0x11/imm32/alloc-id:fake + 9621 _string-add/imm32/name + 9622 0x11/imm32/alloc-id:fake + 9623 Single-lit-var/imm32/inouts + 9624 0x11/imm32/alloc-id:fake + 9625 Single-int-var-in-eax/imm32/outputs + 9626 0x11/imm32/alloc-id:fake + 9627 _string_05_add_to_eax/imm32/subx-name + 9628 0/imm32/no-rm32 + 9629 0/imm32/no-r32 + 9630 1/imm32/imm32-is-first-inout + 9631 0/imm32/no-disp32 + 9632 0/imm32/output-is-write-only + 9633 0x11/imm32/alloc-id:fake + 9634 _Primitive-add-reg-to-reg/imm32/next + 9635 _Primitive-add-reg-to-reg: # (payload primitive) + 9636 0x11/imm32/alloc-id:fake:payload + 9637 # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32 + 9638 0x11/imm32/alloc-id:fake + 9639 _string-add/imm32/name + 9640 0x11/imm32/alloc-id:fake + 9641 Single-int-var-in-some-register/imm32/inouts + 9642 0x11/imm32/alloc-id:fake + 9643 Single-int-var-in-some-register/imm32/outputs + 9644 0x11/imm32/alloc-id:fake + 9645 _string_01_add_to/imm32/subx-name + 9646 3/imm32/rm32-is-first-output + 9647 1/imm32/r32-is-first-inout + 9648 0/imm32/no-imm32 + 9649 0/imm32/no-disp32 + 9650 0/imm32/output-is-write-only + 9651 0x11/imm32/alloc-id:fake + 9652 _Primitive-add-reg-to-mem/imm32/next + 9653 _Primitive-add-reg-to-mem: # (payload primitive) + 9654 0x11/imm32/alloc-id:fake:payload + 9655 # add-to var1 var2/reg => 01/add-to var1 var2/r32 + 9656 0x11/imm32/alloc-id:fake + 9657 _string-add-to/imm32/name + 9658 0x11/imm32/alloc-id:fake + 9659 Two-args-int-stack-int-reg/imm32/inouts + 9660 0/imm32/no-outputs + 9661 0/imm32/no-outputs + 9662 0x11/imm32/alloc-id:fake + 9663 _string_01_add_to/imm32/subx-name + 9664 1/imm32/rm32-is-first-inout + 9665 2/imm32/r32-is-second-inout + 9666 0/imm32/no-imm32 + 9667 0/imm32/no-disp32 + 9668 0/imm32/output-is-write-only + 9669 0x11/imm32/alloc-id:fake + 9670 _Primitive-add-mem-to-reg/imm32/next + 9671 _Primitive-add-mem-to-reg: # (payload primitive) + 9672 0x11/imm32/alloc-id:fake:payload + 9673 # var1/reg <- add var2 => 03/add var2/rm32 var1/r32 + 9674 0x11/imm32/alloc-id:fake + 9675 _string-add/imm32/name + 9676 0x11/imm32/alloc-id:fake + 9677 Single-int-var-in-mem/imm32/inouts + 9678 0x11/imm32/alloc-id:fake + 9679 Single-int-var-in-some-register/imm32/outputs + 9680 0x11/imm32/alloc-id:fake + 9681 _string_03_add/imm32/subx-name + 9682 1/imm32/rm32-is-first-inout + 9683 3/imm32/r32-is-first-output + 9684 0/imm32/no-imm32 + 9685 0/imm32/no-disp32 + 9686 0/imm32/output-is-write-only + 9687 0x11/imm32/alloc-id:fake + 9688 _Primitive-add-lit-to-reg/imm32/next + 9689 _Primitive-add-lit-to-reg: # (payload primitive) + 9690 0x11/imm32/alloc-id:fake:payload + 9691 # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32 + 9692 0x11/imm32/alloc-id:fake + 9693 _string-add/imm32/name + 9694 0x11/imm32/alloc-id:fake + 9695 Single-lit-var/imm32/inouts + 9696 0x11/imm32/alloc-id:fake + 9697 Single-int-var-in-some-register/imm32/outputs + 9698 0x11/imm32/alloc-id:fake + 9699 _string_81_subop_add/imm32/subx-name + 9700 3/imm32/rm32-is-first-output + 9701 0/imm32/no-r32 + 9702 1/imm32/imm32-is-first-inout + 9703 0/imm32/no-disp32 + 9704 0/imm32/output-is-write-only + 9705 0x11/imm32/alloc-id:fake + 9706 _Primitive-add-lit-to-mem/imm32/next + 9707 _Primitive-add-lit-to-mem: # (payload primitive) + 9708 0x11/imm32/alloc-id:fake:payload + 9709 # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32 + 9710 0x11/imm32/alloc-id:fake + 9711 _string-add-to/imm32/name + 9712 0x11/imm32/alloc-id:fake + 9713 Int-var-and-literal/imm32/inouts + 9714 0/imm32/no-outputs + 9715 0/imm32/no-outputs + 9716 0x11/imm32/alloc-id:fake + 9717 _string_81_subop_add/imm32/subx-name + 9718 1/imm32/rm32-is-first-inout + 9719 0/imm32/no-r32 + 9720 2/imm32/imm32-is-second-inout + 9721 0/imm32/no-disp32 + 9722 0/imm32/output-is-write-only + 9723 0x11/imm32/alloc-id:fake + 9724 _Primitive-subtract-from-eax/imm32/next + 9725 # - subtract + 9726 _Primitive-subtract-from-eax: # (payload primitive) + 9727 0x11/imm32/alloc-id:fake:payload + 9728 # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32 + 9729 0x11/imm32/alloc-id:fake + 9730 _string-subtract/imm32/name + 9731 0x11/imm32/alloc-id:fake + 9732 Single-lit-var/imm32/inouts + 9733 0x11/imm32/alloc-id:fake + 9734 Single-int-var-in-eax/imm32/outputs + 9735 0x11/imm32/alloc-id:fake + 9736 _string_2d_subtract_from_eax/imm32/subx-name + 9737 0/imm32/no-rm32 + 9738 0/imm32/no-r32 + 9739 1/imm32/imm32-is-first-inout + 9740 0/imm32/no-disp32 + 9741 0/imm32/output-is-write-only + 9742 0x11/imm32/alloc-id:fake + 9743 _Primitive-subtract-reg-from-reg/imm32/next + 9744 _Primitive-subtract-reg-from-reg: # (payload primitive) + 9745 0x11/imm32/alloc-id:fake:payload + 9746 # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32 + 9747 0x11/imm32/alloc-id:fake + 9748 _string-subtract/imm32/name + 9749 0x11/imm32/alloc-id:fake + 9750 Single-int-var-in-some-register/imm32/inouts + 9751 0x11/imm32/alloc-id:fake + 9752 Single-int-var-in-some-register/imm32/outputs + 9753 0x11/imm32/alloc-id:fake + 9754 _string_29_subtract_from/imm32/subx-name + 9755 3/imm32/rm32-is-first-output + 9756 1/imm32/r32-is-first-inout + 9757 0/imm32/no-imm32 + 9758 0/imm32/no-disp32 + 9759 0/imm32/output-is-write-only + 9760 0x11/imm32/alloc-id:fake + 9761 _Primitive-subtract-reg-from-mem/imm32/next + 9762 _Primitive-subtract-reg-from-mem: # (payload primitive) + 9763 0x11/imm32/alloc-id:fake:payload + 9764 # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32 + 9765 0x11/imm32/alloc-id:fake + 9766 _string-subtract-from/imm32/name + 9767 0x11/imm32/alloc-id:fake + 9768 Two-args-int-stack-int-reg/imm32/inouts + 9769 0/imm32/no-outputs + 9770 0/imm32/no-outputs + 9771 0x11/imm32/alloc-id:fake + 9772 _string_29_subtract_from/imm32/subx-name + 9773 1/imm32/rm32-is-first-inout + 9774 2/imm32/r32-is-second-inout + 9775 0/imm32/no-imm32 + 9776 0/imm32/no-disp32 + 9777 0/imm32/output-is-write-only + 9778 0x11/imm32/alloc-id:fake + 9779 _Primitive-subtract-mem-from-reg/imm32/next + 9780 _Primitive-subtract-mem-from-reg: # (payload primitive) + 9781 0x11/imm32/alloc-id:fake:payload + 9782 # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32 + 9783 0x11/imm32/alloc-id:fake + 9784 _string-subtract/imm32/name + 9785 0x11/imm32/alloc-id:fake + 9786 Single-int-var-in-mem/imm32/inouts + 9787 0x11/imm32/alloc-id:fake + 9788 Single-int-var-in-some-register/imm32/outputs + 9789 0x11/imm32/alloc-id:fake + 9790 _string_2b_subtract/imm32/subx-name + 9791 1/imm32/rm32-is-first-inout + 9792 3/imm32/r32-is-first-output + 9793 0/imm32/no-imm32 + 9794 0/imm32/no-disp32 + 9795 0/imm32/output-is-write-only + 9796 0x11/imm32/alloc-id:fake + 9797 _Primitive-subtract-lit-from-reg/imm32/next + 9798 _Primitive-subtract-lit-from-reg: # (payload primitive) + 9799 0x11/imm32/alloc-id:fake:payload + 9800 # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32 + 9801 0x11/imm32/alloc-id:fake + 9802 _string-subtract/imm32/name + 9803 0x11/imm32/alloc-id:fake + 9804 Single-lit-var/imm32/inouts + 9805 0x11/imm32/alloc-id:fake + 9806 Single-int-var-in-some-register/imm32/outputs + 9807 0x11/imm32/alloc-id:fake + 9808 _string_81_subop_subtract/imm32/subx-name + 9809 3/imm32/rm32-is-first-output + 9810 0/imm32/no-r32 + 9811 1/imm32/imm32-is-first-inout + 9812 0/imm32/no-disp32 + 9813 0/imm32/output-is-write-only + 9814 0x11/imm32/alloc-id:fake + 9815 _Primitive-subtract-lit-from-mem/imm32/next + 9816 _Primitive-subtract-lit-from-mem: # (payload primitive) + 9817 0x11/imm32/alloc-id:fake:payload + 9818 # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32 + 9819 0x11/imm32/alloc-id:fake + 9820 _string-subtract-from/imm32/name + 9821 0x11/imm32/alloc-id:fake + 9822 Int-var-and-literal/imm32/inouts + 9823 0/imm32/no-outputs + 9824 0/imm32/no-outputs + 9825 0x11/imm32/alloc-id:fake + 9826 _string_81_subop_subtract/imm32/subx-name + 9827 1/imm32/rm32-is-first-inout + 9828 0/imm32/no-r32 + 9829 2/imm32/imm32-is-first-inout + 9830 0/imm32/no-disp32 + 9831 0/imm32/output-is-write-only + 9832 0x11/imm32/alloc-id:fake + 9833 _Primitive-and-with-eax/imm32/next + 9834 # - and + 9835 _Primitive-and-with-eax: # (payload primitive) + 9836 0x11/imm32/alloc-id:fake:payload + 9837 # var/eax <- and lit => 25/and-with-eax lit/imm32 + 9838 0x11/imm32/alloc-id:fake + 9839 _string-and/imm32/name + 9840 0x11/imm32/alloc-id:fake + 9841 Single-lit-var/imm32/inouts + 9842 0x11/imm32/alloc-id:fake + 9843 Single-int-var-in-eax/imm32/outputs + 9844 0x11/imm32/alloc-id:fake + 9845 _string_25_and_with_eax/imm32/subx-name + 9846 0/imm32/no-rm32 + 9847 0/imm32/no-r32 + 9848 1/imm32/imm32-is-first-inout + 9849 0/imm32/no-disp32 + 9850 0/imm32/output-is-write-only + 9851 0x11/imm32/alloc-id:fake + 9852 _Primitive-and-reg-with-reg/imm32/next + 9853 _Primitive-and-reg-with-reg: # (payload primitive) + 9854 0x11/imm32/alloc-id:fake:payload + 9855 # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32 + 9856 0x11/imm32/alloc-id:fake + 9857 _string-and/imm32/name + 9858 0x11/imm32/alloc-id:fake + 9859 Single-int-var-in-some-register/imm32/inouts + 9860 0x11/imm32/alloc-id:fake + 9861 Single-int-var-in-some-register/imm32/outputs + 9862 0x11/imm32/alloc-id:fake + 9863 _string_21_and_with/imm32/subx-name + 9864 3/imm32/rm32-is-first-output + 9865 1/imm32/r32-is-first-inout + 9866 0/imm32/no-imm32 + 9867 0/imm32/no-disp32 + 9868 0/imm32/output-is-write-only + 9869 0x11/imm32/alloc-id:fake + 9870 _Primitive-and-reg-with-mem/imm32/next + 9871 _Primitive-and-reg-with-mem: # (payload primitive) + 9872 0x11/imm32/alloc-id:fake:payload + 9873 # and-with var1 var2/reg => 21/and-with var1 var2/r32 + 9874 0x11/imm32/alloc-id:fake + 9875 _string-and-with/imm32/name + 9876 0x11/imm32/alloc-id:fake + 9877 Two-args-int-stack-int-reg/imm32/inouts + 9878 0/imm32/no-outputs + 9879 0/imm32/no-outputs + 9880 0x11/imm32/alloc-id:fake + 9881 _string_21_and_with/imm32/subx-name + 9882 1/imm32/rm32-is-first-inout + 9883 2/imm32/r32-is-second-inout + 9884 0/imm32/no-imm32 + 9885 0/imm32/no-disp32 + 9886 0/imm32/output-is-write-only + 9887 0x11/imm32/alloc-id:fake + 9888 _Primitive-and-mem-with-reg/imm32/next + 9889 _Primitive-and-mem-with-reg: # (payload primitive) + 9890 0x11/imm32/alloc-id:fake:payload + 9891 # var1/reg <- and var2 => 23/and var2/rm32 var1/r32 + 9892 0x11/imm32/alloc-id:fake + 9893 _string-and/imm32/name + 9894 0x11/imm32/alloc-id:fake + 9895 Single-int-var-in-mem/imm32/inouts + 9896 0x11/imm32/alloc-id:fake + 9897 Single-int-var-in-some-register/imm32/outputs + 9898 0x11/imm32/alloc-id:fake + 9899 _string_23_and/imm32/subx-name + 9900 1/imm32/rm32-is-first-inout + 9901 3/imm32/r32-is-first-output + 9902 0/imm32/no-imm32 + 9903 0/imm32/no-disp32 + 9904 0/imm32/output-is-write-only + 9905 0x11/imm32/alloc-id:fake + 9906 _Primitive-and-lit-with-reg/imm32/next + 9907 _Primitive-and-lit-with-reg: # (payload primitive) + 9908 0x11/imm32/alloc-id:fake:payload + 9909 # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32 + 9910 0x11/imm32/alloc-id:fake + 9911 _string-and/imm32/name + 9912 0x11/imm32/alloc-id:fake + 9913 Single-lit-var/imm32/inouts + 9914 0x11/imm32/alloc-id:fake + 9915 Single-int-var-in-some-register/imm32/outputs + 9916 0x11/imm32/alloc-id:fake + 9917 _string_81_subop_and/imm32/subx-name + 9918 3/imm32/rm32-is-first-output + 9919 0/imm32/no-r32 + 9920 1/imm32/imm32-is-first-inout + 9921 0/imm32/no-disp32 + 9922 0/imm32/output-is-write-only + 9923 0x11/imm32/alloc-id:fake + 9924 _Primitive-and-lit-with-mem/imm32/next + 9925 _Primitive-and-lit-with-mem: # (payload primitive) + 9926 0x11/imm32/alloc-id:fake:payload + 9927 # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32 + 9928 0x11/imm32/alloc-id:fake + 9929 _string-and-with/imm32/name + 9930 0x11/imm32/alloc-id:fake + 9931 Int-var-and-literal/imm32/inouts + 9932 0/imm32/no-outputs + 9933 0/imm32/no-outputs + 9934 0x11/imm32/alloc-id:fake + 9935 _string_81_subop_and/imm32/subx-name + 9936 1/imm32/rm32-is-first-inout + 9937 0/imm32/no-r32 + 9938 2/imm32/imm32-is-first-inout + 9939 0/imm32/no-disp32 + 9940 0/imm32/output-is-write-only + 9941 0x11/imm32/alloc-id:fake + 9942 _Primitive-or-with-eax/imm32/next + 9943 # - or + 9944 _Primitive-or-with-eax: # (payload primitive) + 9945 0x11/imm32/alloc-id:fake:payload + 9946 # var/eax <- or lit => 0d/or-with-eax lit/imm32 + 9947 0x11/imm32/alloc-id:fake + 9948 _string-or/imm32/name + 9949 0x11/imm32/alloc-id:fake + 9950 Single-lit-var/imm32/inouts + 9951 0x11/imm32/alloc-id:fake + 9952 Single-int-var-in-eax/imm32/outputs + 9953 0x11/imm32/alloc-id:fake + 9954 _string_0d_or_with_eax/imm32/subx-name + 9955 0/imm32/no-rm32 + 9956 0/imm32/no-r32 + 9957 1/imm32/imm32-is-first-inout + 9958 0/imm32/no-disp32 + 9959 0/imm32/output-is-write-only + 9960 0x11/imm32/alloc-id:fake + 9961 _Primitive-or-reg-with-reg/imm32/next + 9962 _Primitive-or-reg-with-reg: # (payload primitive) + 9963 0x11/imm32/alloc-id:fake:payload + 9964 # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32 + 9965 0x11/imm32/alloc-id:fake + 9966 _string-or/imm32/name + 9967 0x11/imm32/alloc-id:fake + 9968 Single-int-var-in-some-register/imm32/inouts + 9969 0x11/imm32/alloc-id:fake + 9970 Single-int-var-in-some-register/imm32/outputs + 9971 0x11/imm32/alloc-id:fake + 9972 _string_09_or_with/imm32/subx-name + 9973 3/imm32/rm32-is-first-output + 9974 1/imm32/r32-is-first-inout + 9975 0/imm32/no-imm32 + 9976 0/imm32/no-disp32 + 9977 0/imm32/output-is-write-only + 9978 0x11/imm32/alloc-id:fake + 9979 _Primitive-or-reg-with-mem/imm32/next + 9980 _Primitive-or-reg-with-mem: # (payload primitive) + 9981 0x11/imm32/alloc-id:fake:payload + 9982 # or-with var1 var2/reg => 09/or-with var1 var2/r32 + 9983 0x11/imm32/alloc-id:fake + 9984 _string-or-with/imm32/name + 9985 0x11/imm32/alloc-id:fake + 9986 Two-args-int-stack-int-reg/imm32/inouts + 9987 0/imm32/no-outputs + 9988 0/imm32/no-outputs + 9989 0x11/imm32/alloc-id:fake + 9990 _string_09_or_with/imm32/subx-name + 9991 1/imm32/rm32-is-first-inout + 9992 2/imm32/r32-is-second-inout + 9993 0/imm32/no-imm32 + 9994 0/imm32/no-disp32 + 9995 0/imm32/output-is-write-only + 9996 0x11/imm32/alloc-id:fake + 9997 _Primitive-or-mem-with-reg/imm32/next + 9998 _Primitive-or-mem-with-reg: # (payload primitive) + 9999 0x11/imm32/alloc-id:fake:payload +10000 # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32 +10001 0x11/imm32/alloc-id:fake +10002 _string-or/imm32/name +10003 0x11/imm32/alloc-id:fake +10004 Single-int-var-in-mem/imm32/inouts +10005 0x11/imm32/alloc-id:fake +10006 Single-int-var-in-some-register/imm32/outputs +10007 0x11/imm32/alloc-id:fake +10008 _string_0b_or/imm32/subx-name +10009 1/imm32/rm32-is-first-inout +10010 3/imm32/r32-is-first-output +10011 0/imm32/no-imm32 +10012 0/imm32/no-disp32 +10013 0/imm32/output-is-write-only +10014 0x11/imm32/alloc-id:fake +10015 _Primitive-or-lit-with-reg/imm32/next +10016 _Primitive-or-lit-with-reg: # (payload primitive) +10017 0x11/imm32/alloc-id:fake:payload +10018 # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32 +10019 0x11/imm32/alloc-id:fake +10020 _string-or/imm32/name +10021 0x11/imm32/alloc-id:fake +10022 Single-lit-var/imm32/inouts +10023 0x11/imm32/alloc-id:fake +10024 Single-int-var-in-some-register/imm32/outputs +10025 0x11/imm32/alloc-id:fake +10026 _string_81_subop_or/imm32/subx-name +10027 3/imm32/rm32-is-first-output +10028 0/imm32/no-r32 +10029 1/imm32/imm32-is-first-inout +10030 0/imm32/no-disp32 +10031 0/imm32/output-is-write-only +10032 0x11/imm32/alloc-id:fake +10033 _Primitive-or-lit-with-mem/imm32/next +10034 _Primitive-or-lit-with-mem: # (payload primitive) +10035 0x11/imm32/alloc-id:fake:payload +10036 # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32 +10037 0x11/imm32/alloc-id:fake +10038 _string-or-with/imm32/name +10039 0x11/imm32/alloc-id:fake +10040 Int-var-and-literal/imm32/inouts +10041 0/imm32/no-outputs +10042 0/imm32/no-outputs +10043 0x11/imm32/alloc-id:fake +10044 _string_81_subop_or/imm32/subx-name +10045 1/imm32/rm32-is-first-inout +10046 0/imm32/no-r32 +10047 2/imm32/imm32-is-second-inout +10048 0/imm32/no-disp32 +10049 0/imm32/output-is-write-only +10050 0x11/imm32/alloc-id:fake +10051 _Primitive-xor-with-eax/imm32/next +10052 # - xor +10053 _Primitive-xor-with-eax: # (payload primitive) +10054 0x11/imm32/alloc-id:fake:payload +10055 # var/eax <- xor lit => 35/xor-with-eax lit/imm32 +10056 0x11/imm32/alloc-id:fake +10057 _string-xor/imm32/name +10058 0x11/imm32/alloc-id:fake +10059 Single-lit-var/imm32/inouts +10060 0x11/imm32/alloc-id:fake +10061 Single-int-var-in-eax/imm32/outputs +10062 0x11/imm32/alloc-id:fake +10063 _string_35_xor_with_eax/imm32/subx-name +10064 0/imm32/no-rm32 +10065 0/imm32/no-r32 +10066 1/imm32/imm32-is-first-inout +10067 0/imm32/no-disp32 +10068 0/imm32/output-is-write-only +10069 0x11/imm32/alloc-id:fake +10070 _Primitive-xor-reg-with-reg/imm32/next +10071 _Primitive-xor-reg-with-reg: # (payload primitive) +10072 0x11/imm32/alloc-id:fake:payload +10073 # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32 +10074 0x11/imm32/alloc-id:fake +10075 _string-xor/imm32/name +10076 0x11/imm32/alloc-id:fake +10077 Single-int-var-in-some-register/imm32/inouts +10078 0x11/imm32/alloc-id:fake +10079 Single-int-var-in-some-register/imm32/outputs +10080 0x11/imm32/alloc-id:fake +10081 _string_31_xor_with/imm32/subx-name +10082 3/imm32/rm32-is-first-output +10083 1/imm32/r32-is-first-inout +10084 0/imm32/no-imm32 +10085 0/imm32/no-disp32 +10086 0/imm32/output-is-write-only +10087 0x11/imm32/alloc-id:fake +10088 _Primitive-xor-reg-with-mem/imm32/next +10089 _Primitive-xor-reg-with-mem: # (payload primitive) +10090 0x11/imm32/alloc-id:fake:payload +10091 # xor-with var1 var2/reg => 31/xor-with var1 var2/r32 +10092 0x11/imm32/alloc-id:fake +10093 _string-xor-with/imm32/name +10094 0x11/imm32/alloc-id:fake +10095 Two-args-int-stack-int-reg/imm32/inouts +10096 0/imm32/no-outputs +10097 0/imm32/no-outputs +10098 0x11/imm32/alloc-id:fake +10099 _string_31_xor_with/imm32/subx-name +10100 1/imm32/rm32-is-first-inout +10101 2/imm32/r32-is-second-inout +10102 0/imm32/no-imm32 +10103 0/imm32/no-disp32 +10104 0/imm32/output-is-write-only +10105 0x11/imm32/alloc-id:fake +10106 _Primitive-xor-mem-with-reg/imm32/next +10107 _Primitive-xor-mem-with-reg: # (payload primitive) +10108 0x11/imm32/alloc-id:fake:payload +10109 # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32 +10110 0x11/imm32/alloc-id:fake +10111 _string-xor/imm32/name +10112 0x11/imm32/alloc-id:fake +10113 Single-int-var-in-mem/imm32/inouts +10114 0x11/imm32/alloc-id:fake +10115 Single-int-var-in-some-register/imm32/outputs +10116 0x11/imm32/alloc-id:fake +10117 _string_33_xor/imm32/subx-name +10118 1/imm32/rm32-is-first-inout +10119 3/imm32/r32-is-first-output +10120 0/imm32/no-imm32 +10121 0/imm32/no-disp32 +10122 0/imm32/output-is-write-only +10123 0x11/imm32/alloc-id:fake +10124 _Primitive-xor-lit-with-reg/imm32/next +10125 _Primitive-xor-lit-with-reg: # (payload primitive) +10126 0x11/imm32/alloc-id:fake:payload +10127 # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32 +10128 0x11/imm32/alloc-id:fake +10129 _string-xor/imm32/name +10130 0x11/imm32/alloc-id:fake +10131 Single-lit-var/imm32/inouts +10132 0x11/imm32/alloc-id:fake +10133 Single-int-var-in-some-register/imm32/outputs +10134 0x11/imm32/alloc-id:fake +10135 _string_81_subop_xor/imm32/subx-name +10136 3/imm32/rm32-is-first-output +10137 0/imm32/no-r32 +10138 1/imm32/imm32-is-first-inout +10139 0/imm32/no-disp32 +10140 0/imm32/output-is-write-only +10141 0x11/imm32/alloc-id:fake +10142 _Primitive-xor-lit-with-mem/imm32/next +10143 _Primitive-xor-lit-with-mem: # (payload primitive) +10144 0x11/imm32/alloc-id:fake:payload +10145 # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32 +10146 0x11/imm32/alloc-id:fake +10147 _string-xor-with/imm32/name +10148 0x11/imm32/alloc-id:fake +10149 Int-var-and-literal/imm32/inouts +10150 0/imm32/no-outputs +10151 0/imm32/no-outputs +10152 0x11/imm32/alloc-id:fake +10153 _string_81_subop_xor/imm32/subx-name +10154 1/imm32/rm32-is-first-inout +10155 0/imm32/no-r32 +10156 2/imm32/imm32-is-first-inout +10157 0/imm32/no-disp32 +10158 0/imm32/output-is-write-only +10159 0x11/imm32/alloc-id:fake +10160 _Primitive-copy-to-eax/imm32/next +10161 # - copy +10162 _Primitive-copy-to-eax: # (payload primitive) +10163 0x11/imm32/alloc-id:fake:payload +10164 # var/eax <- copy lit => b8/copy-to-eax lit/imm32 +10165 0x11/imm32/alloc-id:fake +10166 _string-copy/imm32/name +10167 0x11/imm32/alloc-id:fake +10168 Single-lit-var/imm32/inouts +10169 0x11/imm32/alloc-id:fake +10170 Single-int-var-in-eax/imm32/outputs +10171 0x11/imm32/alloc-id:fake +10172 _string_b8_copy_to_eax/imm32/subx-name +10173 0/imm32/no-rm32 +10174 0/imm32/no-r32 +10175 1/imm32/imm32-is-first-inout +10176 0/imm32/no-disp32 +10177 1/imm32/output-is-write-only +10178 0x11/imm32/alloc-id:fake +10179 _Primitive-copy-to-ecx/imm32/next +10180 _Primitive-copy-to-ecx: # (payload primitive) +10181 0x11/imm32/alloc-id:fake:payload +10182 # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32 +10183 0x11/imm32/alloc-id:fake +10184 _string-copy/imm32/name +10185 0x11/imm32/alloc-id:fake +10186 Single-lit-var/imm32/inouts +10187 0x11/imm32/alloc-id:fake +10188 Single-int-var-in-ecx/imm32/outputs +10189 0x11/imm32/alloc-id:fake +10190 _string_b9_copy_to_ecx/imm32/subx-name +10191 0/imm32/no-rm32 +10192 0/imm32/no-r32 +10193 1/imm32/imm32-is-first-inout +10194 0/imm32/no-disp32 +10195 1/imm32/output-is-write-only +10196 0x11/imm32/alloc-id:fake +10197 _Primitive-copy-to-edx/imm32/next +10198 _Primitive-copy-to-edx: # (payload primitive) +10199 0x11/imm32/alloc-id:fake:payload +10200 # var/edx <- copy lit => ba/copy-to-edx lit/imm32 +10201 0x11/imm32/alloc-id:fake +10202 _string-copy/imm32/name +10203 0x11/imm32/alloc-id:fake +10204 Single-lit-var/imm32/inouts +10205 0x11/imm32/alloc-id:fake +10206 Single-int-var-in-edx/imm32/outputs +10207 0x11/imm32/alloc-id:fake +10208 _string_ba_copy_to_edx/imm32/subx-name +10209 0/imm32/no-rm32 +10210 0/imm32/no-r32 +10211 1/imm32/imm32-is-first-inout +10212 0/imm32/no-disp32 +10213 1/imm32/output-is-write-only +10214 0x11/imm32/alloc-id:fake +10215 _Primitive-copy-to-ebx/imm32/next +10216 _Primitive-copy-to-ebx: # (payload primitive) +10217 0x11/imm32/alloc-id:fake:payload +10218 # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32 +10219 0x11/imm32/alloc-id:fake +10220 _string-copy/imm32/name +10221 0x11/imm32/alloc-id:fake +10222 Single-lit-var/imm32/inouts +10223 0x11/imm32/alloc-id:fake +10224 Single-int-var-in-ebx/imm32/outputs +10225 0x11/imm32/alloc-id:fake +10226 _string_bb_copy_to_ebx/imm32/subx-name +10227 0/imm32/no-rm32 +10228 0/imm32/no-r32 +10229 1/imm32/imm32-is-first-inout +10230 0/imm32/no-disp32 +10231 1/imm32/output-is-write-only +10232 0x11/imm32/alloc-id:fake +10233 _Primitive-copy-to-esi/imm32/next +10234 _Primitive-copy-to-esi: # (payload primitive) +10235 0x11/imm32/alloc-id:fake:payload +10236 # var/esi <- copy lit => be/copy-to-esi lit/imm32 +10237 0x11/imm32/alloc-id:fake +10238 _string-copy/imm32/name +10239 0x11/imm32/alloc-id:fake +10240 Single-lit-var/imm32/inouts +10241 0x11/imm32/alloc-id:fake +10242 Single-int-var-in-esi/imm32/outputs +10243 0x11/imm32/alloc-id:fake +10244 _string_be_copy_to_esi/imm32/subx-name +10245 0/imm32/no-rm32 +10246 0/imm32/no-r32 +10247 1/imm32/imm32-is-first-inout +10248 0/imm32/no-disp32 +10249 1/imm32/output-is-write-only +10250 0x11/imm32/alloc-id:fake +10251 _Primitive-copy-to-edi/imm32/next +10252 _Primitive-copy-to-edi: # (payload primitive) +10253 0x11/imm32/alloc-id:fake:payload +10254 # var/edi <- copy lit => bf/copy-to-edi lit/imm32 +10255 0x11/imm32/alloc-id:fake +10256 _string-copy/imm32/name +10257 0x11/imm32/alloc-id:fake +10258 Single-lit-var/imm32/inouts +10259 0x11/imm32/alloc-id:fake +10260 Single-int-var-in-edi/imm32/outputs +10261 0x11/imm32/alloc-id:fake +10262 _string_bf_copy_to_edi/imm32/subx-name +10263 0/imm32/no-rm32 +10264 0/imm32/no-r32 +10265 1/imm32/imm32-is-first-inout +10266 0/imm32/no-disp32 +10267 1/imm32/output-is-write-only +10268 0x11/imm32/alloc-id:fake +10269 _Primitive-copy-reg-to-reg/imm32/next +10270 _Primitive-copy-reg-to-reg: # (payload primitive) +10271 0x11/imm32/alloc-id:fake:payload +10272 # var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32 +10273 0x11/imm32/alloc-id:fake +10274 _string-copy/imm32/name +10275 0x11/imm32/alloc-id:fake +10276 Single-int-var-in-some-register/imm32/inouts +10277 0x11/imm32/alloc-id:fake +10278 Single-int-var-in-some-register/imm32/outputs +10279 0x11/imm32/alloc-id:fake +10280 _string_89_<-/imm32/subx-name +10281 3/imm32/rm32-is-first-output +10282 1/imm32/r32-is-first-inout +10283 0/imm32/no-imm32 +10284 0/imm32/no-disp32 +10285 1/imm32/output-is-write-only +10286 0x11/imm32/alloc-id:fake +10287 _Primitive-copy-reg-to-mem/imm32/next +10288 _Primitive-copy-reg-to-mem: # (payload primitive) +10289 0x11/imm32/alloc-id:fake:payload +10290 # copy-to var1 var2/reg => 89/<- var1 var2/r32 +10291 0x11/imm32/alloc-id:fake +10292 _string-copy-to/imm32/name +10293 0x11/imm32/alloc-id:fake +10294 Two-args-int-stack-int-reg/imm32/inouts +10295 0/imm32/no-outputs +10296 0/imm32/no-outputs +10297 0x11/imm32/alloc-id:fake +10298 _string_89_<-/imm32/subx-name +10299 1/imm32/rm32-is-first-inout +10300 2/imm32/r32-is-second-inout +10301 0/imm32/no-imm32 +10302 0/imm32/no-disp32 +10303 1/imm32/output-is-write-only +10304 0x11/imm32/alloc-id:fake +10305 _Primitive-copy-mem-to-reg/imm32/next +10306 _Primitive-copy-mem-to-reg: # (payload primitive) +10307 0x11/imm32/alloc-id:fake:payload +10308 # var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32 +10309 0x11/imm32/alloc-id:fake +10310 _string-copy/imm32/name +10311 0x11/imm32/alloc-id:fake +10312 Single-int-var-in-mem/imm32/inouts +10313 0x11/imm32/alloc-id:fake +10314 Single-int-var-in-some-register/imm32/outputs +10315 0x11/imm32/alloc-id:fake +10316 _string_8b_->/imm32/subx-name +10317 1/imm32/rm32-is-first-inout +10318 3/imm32/r32-is-first-output +10319 0/imm32/no-imm32 +10320 0/imm32/no-disp32 +10321 1/imm32/output-is-write-only +10322 0x11/imm32/alloc-id:fake +10323 _Primitive-copy-lit-to-reg/imm32/next +10324 _Primitive-copy-lit-to-reg: # (payload primitive) +10325 0x11/imm32/alloc-id:fake:payload +10326 # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32 +10327 0x11/imm32/alloc-id:fake +10328 _string-copy/imm32/name +10329 0x11/imm32/alloc-id:fake +10330 Single-lit-var/imm32/inouts +10331 0x11/imm32/alloc-id:fake +10332 Single-int-var-in-some-register/imm32/outputs +10333 0x11/imm32/alloc-id:fake +10334 _string_c7_subop_copy/imm32/subx-name +10335 3/imm32/rm32-is-first-output +10336 0/imm32/no-r32 +10337 1/imm32/imm32-is-first-inout +10338 0/imm32/no-disp32 +10339 1/imm32/output-is-write-only +10340 0x11/imm32/alloc-id:fake +10341 _Primitive-copy-lit-to-mem/imm32/next +10342 _Primitive-copy-lit-to-mem: # (payload primitive) +10343 0x11/imm32/alloc-id:fake:payload +10344 # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32 +10345 0x11/imm32/alloc-id:fake +10346 _string-copy-to/imm32/name +10347 0x11/imm32/alloc-id:fake +10348 Int-var-and-literal/imm32/inouts +10349 0/imm32/no-outputs +10350 0/imm32/no-outputs +10351 0x11/imm32/alloc-id:fake +10352 _string_c7_subop_copy/imm32/subx-name +10353 1/imm32/rm32-is-first-inout +10354 0/imm32/no-r32 +10355 2/imm32/imm32-is-first-inout +10356 0/imm32/no-disp32 +10357 1/imm32/output-is-write-only +10358 0x11/imm32/alloc-id:fake +10359 _Primitive-address/imm32/next +10360 # - address +10361 _Primitive-address: # (payload primitive) +10362 0x11/imm32/alloc-id:fake:payload +10363 # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32 +10364 0x11/imm32/alloc-id:fake +10365 _string-address/imm32/name +10366 0x11/imm32/alloc-id:fake +10367 Single-int-var-in-mem/imm32/inouts +10368 0x11/imm32/alloc-id:fake +10369 Single-addr-var-in-some-register/imm32/outputs +10370 0x11/imm32/alloc-id:fake +10371 _string_8d_copy_address/imm32/subx-name +10372 1/imm32/rm32-is-first-inout +10373 3/imm32/r32-is-first-output +10374 0/imm32/no-imm32 +10375 0/imm32/no-disp32 +10376 1/imm32/output-is-write-only +10377 0x11/imm32/alloc-id:fake +10378 _Primitive-compare-mem-with-reg/imm32/next +10379 # - compare +10380 _Primitive-compare-mem-with-reg: # (payload primitive) +10381 0x11/imm32/alloc-id:fake:payload +10382 # compare var1 var2/reg => 39/compare var1/rm32 var2/r32 +10383 0x11/imm32/alloc-id:fake +10384 _string-compare/imm32/name +10385 0x11/imm32/alloc-id:fake +10386 Two-args-int-stack-int-reg/imm32/inouts +10387 0/imm32/no-outputs +10388 0/imm32/no-outputs +10389 0x11/imm32/alloc-id:fake +10390 _string_39_compare->/imm32/subx-name +10391 1/imm32/rm32-is-first-inout +10392 2/imm32/r32-is-second-inout +10393 0/imm32/no-imm32 +10394 0/imm32/no-disp32 +10395 0/imm32/output-is-write-only +10396 0x11/imm32/alloc-id:fake +10397 _Primitive-compare-reg-with-mem/imm32/next +10398 _Primitive-compare-reg-with-mem: # (payload primitive) +10399 0x11/imm32/alloc-id:fake:payload +10400 # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32 +10401 0x11/imm32/alloc-id:fake +10402 _string-compare/imm32/name +10403 0x11/imm32/alloc-id:fake +10404 Two-args-int-reg-int-stack/imm32/inouts +10405 0/imm32/no-outputs +10406 0/imm32/no-outputs +10407 0x11/imm32/alloc-id:fake +10408 _string_3b_compare<-/imm32/subx-name +10409 2/imm32/rm32-is-second-inout +10410 1/imm32/r32-is-first-inout +10411 0/imm32/no-imm32 +10412 0/imm32/no-disp32 +10413 0/imm32/output-is-write-only +10414 0x11/imm32/alloc-id:fake +10415 _Primitive-compare-eax-with-literal/imm32/next +10416 _Primitive-compare-eax-with-literal: # (payload primitive) +10417 0x11/imm32/alloc-id:fake:payload +10418 # compare var1/eax n => 3d/compare-eax-with n/imm32 +10419 0x11/imm32/alloc-id:fake +10420 _string-compare/imm32/name +10421 0x11/imm32/alloc-id:fake +10422 Two-args-int-eax-int-literal/imm32/inouts +10423 0/imm32/no-outputs +10424 0/imm32/no-outputs +10425 0x11/imm32/alloc-id:fake +10426 _string_3d_compare_eax_with/imm32/subx-name +10427 0/imm32/no-rm32 +10428 0/imm32/no-r32 +10429 2/imm32/imm32-is-second-inout +10430 0/imm32/no-disp32 +10431 0/imm32/output-is-write-only +10432 0x11/imm32/alloc-id:fake +10433 _Primitive-compare-reg-with-literal/imm32/next +10434 _Primitive-compare-reg-with-literal: # (payload primitive) +10435 0x11/imm32/alloc-id:fake:payload +10436 # compare var1/reg n => 81 7/subop/compare %reg n/imm32 +10437 0x11/imm32/alloc-id:fake +10438 _string-compare/imm32/name +10439 0x11/imm32/alloc-id:fake +10440 Int-var-in-register-and-literal/imm32/inouts +10441 0/imm32/no-outputs +10442 0/imm32/no-outputs +10443 0x11/imm32/alloc-id:fake +10444 _string_81_subop_compare/imm32/subx-name +10445 1/imm32/rm32-is-first-inout +10446 0/imm32/no-r32 +10447 2/imm32/imm32-is-second-inout +10448 0/imm32/no-disp32 +10449 0/imm32/output-is-write-only +10450 0x11/imm32/alloc-id:fake +10451 _Primitive-compare-mem-with-literal/imm32/next +10452 _Primitive-compare-mem-with-literal: # (payload primitive) +10453 0x11/imm32/alloc-id:fake:payload +10454 # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32 +10455 0x11/imm32/alloc-id:fake +10456 _string-compare/imm32/name +10457 0x11/imm32/alloc-id:fake +10458 Int-var-and-literal/imm32/inouts +10459 0/imm32/no-outputs +10460 0/imm32/no-outputs +10461 0x11/imm32/alloc-id:fake +10462 _string_81_subop_compare/imm32/subx-name +10463 1/imm32/rm32-is-first-inout +10464 0/imm32/no-r32 +10465 2/imm32/imm32-is-second-inout +10466 0/imm32/no-disp32 +10467 0/imm32/output-is-write-only +10468 0x11/imm32/alloc-id:fake +10469 _Primitive-multiply-reg-by-mem/imm32/next +10470 # - multiply +10471 _Primitive-multiply-reg-by-mem: # (payload primitive) +10472 0x11/imm32/alloc-id:fake:payload +10473 # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32 +10474 0x11/imm32/alloc-id:fake +10475 _string-multiply/imm32/name +10476 0x11/imm32/alloc-id:fake +10477 Single-int-var-in-mem/imm32/inouts +10478 0x11/imm32/alloc-id:fake +10479 Single-int-var-in-some-register/imm32/outputs +10480 0x11/imm32/alloc-id:fake +10481 _string_0f_af_multiply/imm32/subx-name +10482 1/imm32/rm32-is-first-inout +10483 3/imm32/r32-is-first-output +10484 0/imm32/no-imm32 +10485 0/imm32/no-disp32 +10486 0/imm32/output-is-write-only +10487 0x11/imm32/alloc-id:fake +10488 _Primitive-break-if-addr</imm32/next +10489 # - branches +10490 _Primitive-break-if-addr<: # (payload primitive) +10491 0x11/imm32/alloc-id:fake:payload +10492 0x11/imm32/alloc-id:fake +10493 _string-break-if-addr</imm32/name +10494 0/imm32/no-inouts +10495 0/imm32/no-inouts +10496 0/imm32/no-outputs +10497 0/imm32/no-outputs +10498 0x11/imm32/alloc-id:fake +10499 _string_0f_82_jump_break/imm32/subx-name +10500 0/imm32/no-rm32 +10501 0/imm32/no-r32 +10502 0/imm32/no-imm32 +10503 0/imm32/no-disp32 +10504 0/imm32/no-output +10505 0x11/imm32/alloc-id:fake +10506 _Primitive-break-if-addr>=/imm32/next +10507 _Primitive-break-if-addr>=: # (payload primitive) +10508 0x11/imm32/alloc-id:fake:payload +10509 0x11/imm32/alloc-id:fake +10510 _string-break-if-addr>=/imm32/name +10511 0/imm32/no-inouts +10512 0/imm32/no-inouts +10513 0/imm32/no-outputs +10514 0/imm32/no-outputs +10515 0x11/imm32/alloc-id:fake +10516 _string_0f_83_jump_break/imm32/subx-name +10517 0/imm32/no-rm32 +10518 0/imm32/no-r32 +10519 0/imm32/no-imm32 +10520 0/imm32/no-disp32 +10521 0/imm32/no-output +10522 0x11/imm32/alloc-id:fake +10523 _Primitive-break-if-=/imm32/next +10524 _Primitive-break-if-=: # (payload primitive) +10525 0x11/imm32/alloc-id:fake:payload +10526 0x11/imm32/alloc-id:fake +10527 _string-break-if-=/imm32/name +10528 0/imm32/no-inouts +10529 0/imm32/no-inouts +10530 0/imm32/no-outputs +10531 0/imm32/no-outputs +10532 0x11/imm32/alloc-id:fake +10533 _string_0f_84_jump_break/imm32/subx-name +10534 0/imm32/no-rm32 +10535 0/imm32/no-r32 +10536 0/imm32/no-imm32 +10537 0/imm32/no-disp32 +10538 0/imm32/no-output +10539 0x11/imm32/alloc-id:fake +10540 _Primitive-break-if-!=/imm32/next +10541 _Primitive-break-if-!=: # (payload primitive) +10542 0x11/imm32/alloc-id:fake:payload +10543 0x11/imm32/alloc-id:fake +10544 _string-break-if-!=/imm32/name +10545 0/imm32/no-inouts +10546 0/imm32/no-inouts +10547 0/imm32/no-outputs +10548 0/imm32/no-outputs +10549 0x11/imm32/alloc-id:fake +10550 _string_0f_85_jump_break/imm32/subx-name +10551 0/imm32/no-rm32 +10552 0/imm32/no-r32 +10553 0/imm32/no-imm32 +10554 0/imm32/no-disp32 +10555 0/imm32/no-output +10556 0x11/imm32/alloc-id:fake +10557 _Primitive-break-if-addr<=/imm32/next +10558 _Primitive-break-if-addr<=: # (payload primitive) +10559 0x11/imm32/alloc-id:fake:payload +10560 0x11/imm32/alloc-id:fake +10561 _string-break-if-addr<=/imm32/name +10562 0/imm32/no-inouts +10563 0/imm32/no-inouts +10564 0/imm32/no-outputs +10565 0/imm32/no-outputs +10566 0x11/imm32/alloc-id:fake +10567 _string_0f_86_jump_break/imm32/subx-name +10568 0/imm32/no-rm32 +10569 0/imm32/no-r32 +10570 0/imm32/no-imm32 +10571 0/imm32/no-disp32 +10572 0/imm32/no-output +10573 0x11/imm32/alloc-id:fake +10574 _Primitive-break-if-addr>/imm32/next +10575 _Primitive-break-if-addr>: # (payload primitive) +10576 0x11/imm32/alloc-id:fake:payload +10577 0x11/imm32/alloc-id:fake +10578 _string-break-if-addr>/imm32/name +10579 0/imm32/no-inouts +10580 0/imm32/no-inouts +10581 0/imm32/no-outputs +10582 0/imm32/no-outputs +10583 0x11/imm32/alloc-id:fake +10584 _string_0f_87_jump_break/imm32/subx-name +10585 0/imm32/no-rm32 +10586 0/imm32/no-r32 +10587 0/imm32/no-imm32 +10588 0/imm32/no-disp32 +10589 0/imm32/no-output +10590 0x11/imm32/alloc-id:fake +10591 _Primitive-break-if-</imm32/next +10592 _Primitive-break-if-<: # (payload primitive) +10593 0x11/imm32/alloc-id:fake:payload +10594 0x11/imm32/alloc-id:fake +10595 _string-break-if-</imm32/name +10596 0/imm32/no-inouts +10597 0/imm32/no-inouts +10598 0/imm32/no-outputs +10599 0/imm32/no-outputs +10600 0x11/imm32/alloc-id:fake +10601 _string_0f_8c_jump_break/imm32/subx-name +10602 0/imm32/no-rm32 +10603 0/imm32/no-r32 +10604 0/imm32/no-imm32 +10605 0/imm32/no-disp32 +10606 0/imm32/no-output +10607 0x11/imm32/alloc-id:fake +10608 _Primitive-break-if->=/imm32/next +10609 _Primitive-break-if->=: # (payload primitive) +10610 0x11/imm32/alloc-id:fake:payload +10611 0x11/imm32/alloc-id:fake +10612 _string-break-if->=/imm32/name +10613 0/imm32/no-inouts +10614 0/imm32/no-inouts +10615 0/imm32/no-outputs +10616 0/imm32/no-outputs +10617 0x11/imm32/alloc-id:fake +10618 _string_0f_8d_jump_break/imm32/subx-name +10619 0/imm32/no-rm32 +10620 0/imm32/no-r32 +10621 0/imm32/no-imm32 +10622 0/imm32/no-disp32 +10623 0/imm32/no-output +10624 0x11/imm32/alloc-id:fake +10625 _Primitive-break-if-<=/imm32/next +10626 _Primitive-break-if-<=: # (payload primitive) +10627 0x11/imm32/alloc-id:fake:payload +10628 0x11/imm32/alloc-id:fake +10629 _string-break-if-<=/imm32/name +10630 0/imm32/no-inouts +10631 0/imm32/no-inouts +10632 0/imm32/no-outputs +10633 0/imm32/no-outputs +10634 0x11/imm32/alloc-id:fake +10635 _string_0f_8e_jump_break/imm32/subx-name +10636 0/imm32/no-rm32 +10637 0/imm32/no-r32 +10638 0/imm32/no-imm32 +10639 0/imm32/no-disp32 +10640 0/imm32/no-output +10641 0x11/imm32/alloc-id:fake +10642 _Primitive-break-if->/imm32/next +10643 _Primitive-break-if->: # (payload primitive) +10644 0x11/imm32/alloc-id:fake:payload +10645 0x11/imm32/alloc-id:fake +10646 _string-break-if->/imm32/name +10647 0/imm32/no-inouts +10648 0/imm32/no-inouts +10649 0/imm32/no-outputs +10650 0/imm32/no-outputs +10651 0x11/imm32/alloc-id:fake +10652 _string_0f_8f_jump_break/imm32/subx-name +10653 0/imm32/no-rm32 +10654 0/imm32/no-r32 +10655 0/imm32/no-imm32 +10656 0/imm32/no-disp32 +10657 0/imm32/no-output +10658 0x11/imm32/alloc-id:fake +10659 _Primitive-break/imm32/next +10660 _Primitive-break: # (payload primitive) +10661 0x11/imm32/alloc-id:fake:payload +10662 0x11/imm32/alloc-id:fake +10663 _string-break/imm32/name +10664 0/imm32/no-inouts +10665 0/imm32/no-inouts +10666 0/imm32/no-outputs +10667 0/imm32/no-outputs +10668 0x11/imm32/alloc-id:fake +10669 _string_e9_jump_break/imm32/subx-name +10670 0/imm32/no-rm32 +10671 0/imm32/no-r32 +10672 0/imm32/no-imm32 +10673 0/imm32/no-disp32 +10674 0/imm32/no-output +10675 0x11/imm32/alloc-id:fake +10676 _Primitive-loop-if-addr</imm32/next +10677 _Primitive-loop-if-addr<: # (payload primitive) +10678 0x11/imm32/alloc-id:fake:payload +10679 0x11/imm32/alloc-id:fake +10680 _string-loop-if-addr</imm32/name +10681 0/imm32/no-inouts +10682 0/imm32/no-inouts +10683 0/imm32/no-outputs +10684 0/imm32/no-outputs +10685 0x11/imm32/alloc-id:fake +10686 _string_0f_82_jump_loop/imm32/subx-name +10687 0/imm32/no-rm32 +10688 0/imm32/no-r32 +10689 0/imm32/no-imm32 +10690 0/imm32/no-disp32 +10691 0/imm32/no-output +10692 0x11/imm32/alloc-id:fake +10693 _Primitive-loop-if-addr>=/imm32/next +10694 _Primitive-loop-if-addr>=: # (payload primitive) +10695 0x11/imm32/alloc-id:fake:payload +10696 0x11/imm32/alloc-id:fake +10697 _string-loop-if-addr>=/imm32/name +10698 0/imm32/no-inouts +10699 0/imm32/no-inouts +10700 0/imm32/no-outputs +10701 0/imm32/no-outputs +10702 0x11/imm32/alloc-id:fake +10703 _string_0f_83_jump_loop/imm32/subx-name +10704 0/imm32/no-rm32 +10705 0/imm32/no-r32 +10706 0/imm32/no-imm32 +10707 0/imm32/no-disp32 +10708 0/imm32/no-output +10709 0x11/imm32/alloc-id:fake +10710 _Primitive-loop-if-=/imm32/next +10711 _Primitive-loop-if-=: # (payload primitive) +10712 0x11/imm32/alloc-id:fake:payload +10713 0x11/imm32/alloc-id:fake +10714 _string-loop-if-=/imm32/name +10715 0/imm32/no-inouts +10716 0/imm32/no-inouts +10717 0/imm32/no-outputs +10718 0/imm32/no-outputs +10719 0x11/imm32/alloc-id:fake +10720 _string_0f_84_jump_loop/imm32/subx-name +10721 0/imm32/no-rm32 +10722 0/imm32/no-r32 +10723 0/imm32/no-imm32 +10724 0/imm32/no-disp32 +10725 0/imm32/no-output +10726 0x11/imm32/alloc-id:fake +10727 _Primitive-loop-if-!=/imm32/next +10728 _Primitive-loop-if-!=: # (payload primitive) +10729 0x11/imm32/alloc-id:fake:payload +10730 0x11/imm32/alloc-id:fake +10731 _string-loop-if-!=/imm32/name +10732 0/imm32/no-inouts +10733 0/imm32/no-inouts +10734 0/imm32/no-outputs +10735 0/imm32/no-outputs +10736 0x11/imm32/alloc-id:fake +10737 _string_0f_85_jump_loop/imm32/subx-name +10738 0/imm32/no-rm32 +10739 0/imm32/no-r32 +10740 0/imm32/no-imm32 +10741 0/imm32/no-disp32 +10742 0/imm32/no-output +10743 0x11/imm32/alloc-id:fake +10744 _Primitive-loop-if-addr<=/imm32/next +10745 _Primitive-loop-if-addr<=: # (payload primitive) +10746 0x11/imm32/alloc-id:fake:payload +10747 0x11/imm32/alloc-id:fake +10748 _string-loop-if-addr<=/imm32/name +10749 0/imm32/no-inouts +10750 0/imm32/no-inouts +10751 0/imm32/no-outputs +10752 0/imm32/no-outputs +10753 0x11/imm32/alloc-id:fake +10754 _string_0f_86_jump_loop/imm32/subx-name +10755 0/imm32/no-rm32 +10756 0/imm32/no-r32 +10757 0/imm32/no-imm32 +10758 0/imm32/no-disp32 +10759 0/imm32/no-output +10760 0x11/imm32/alloc-id:fake +10761 _Primitive-loop-if-addr>/imm32/next +10762 _Primitive-loop-if-addr>: # (payload primitive) +10763 0x11/imm32/alloc-id:fake:payload +10764 0x11/imm32/alloc-id:fake +10765 _string-loop-if-addr>/imm32/name +10766 0/imm32/no-inouts +10767 0/imm32/no-inouts +10768 0/imm32/no-outputs +10769 0/imm32/no-outputs +10770 0x11/imm32/alloc-id:fake +10771 _string_0f_87_jump_loop/imm32/subx-name +10772 0/imm32/no-rm32 +10773 0/imm32/no-r32 +10774 0/imm32/no-imm32 +10775 0/imm32/no-disp32 +10776 0/imm32/no-output +10777 0x11/imm32/alloc-id:fake +10778 _Primitive-loop-if-</imm32/next +10779 _Primitive-loop-if-<: # (payload primitive) +10780 0x11/imm32/alloc-id:fake:payload +10781 0x11/imm32/alloc-id:fake +10782 _string-loop-if-</imm32/name +10783 0/imm32/no-inouts +10784 0/imm32/no-inouts +10785 0/imm32/no-outputs +10786 0/imm32/no-outputs +10787 0x11/imm32/alloc-id:fake +10788 _string_0f_8c_jump_loop/imm32/subx-name +10789 0/imm32/no-rm32 +10790 0/imm32/no-r32 +10791 0/imm32/no-imm32 +10792 0/imm32/no-disp32 +10793 0/imm32/no-output +10794 0x11/imm32/alloc-id:fake +10795 _Primitive-loop-if->=/imm32/next +10796 _Primitive-loop-if->=: # (payload primitive) +10797 0x11/imm32/alloc-id:fake:payload +10798 0x11/imm32/alloc-id:fake +10799 _string-loop-if->=/imm32/name +10800 0/imm32/no-inouts +10801 0/imm32/no-inouts +10802 0/imm32/no-outputs +10803 0/imm32/no-outputs +10804 0x11/imm32/alloc-id:fake +10805 _string_0f_8d_jump_loop/imm32/subx-name +10806 0/imm32/no-rm32 +10807 0/imm32/no-r32 +10808 0/imm32/no-imm32 +10809 0/imm32/no-disp32 +10810 0/imm32/no-output +10811 0x11/imm32/alloc-id:fake +10812 _Primitive-loop-if-<=/imm32/next +10813 _Primitive-loop-if-<=: # (payload primitive) +10814 0x11/imm32/alloc-id:fake:payload +10815 0x11/imm32/alloc-id:fake +10816 _string-loop-if-<=/imm32/name +10817 0/imm32/no-inouts +10818 0/imm32/no-inouts +10819 0/imm32/no-outputs +10820 0/imm32/no-outputs +10821 0x11/imm32/alloc-id:fake +10822 _string_0f_8e_jump_loop/imm32/subx-name +10823 0/imm32/no-rm32 +10824 0/imm32/no-r32 +10825 0/imm32/no-imm32 +10826 0/imm32/no-disp32 +10827 0/imm32/no-output +10828 0x11/imm32/alloc-id:fake +10829 _Primitive-loop-if->/imm32/next +10830 _Primitive-loop-if->: # (payload primitive) +10831 0x11/imm32/alloc-id:fake:payload +10832 0x11/imm32/alloc-id:fake +10833 _string-loop-if->/imm32/name +10834 0/imm32/no-inouts +10835 0/imm32/no-inouts +10836 0/imm32/no-outputs +10837 0/imm32/no-outputs +10838 0x11/imm32/alloc-id:fake +10839 _string_0f_8f_jump_loop/imm32/subx-name +10840 0/imm32/no-rm32 +10841 0/imm32/no-r32 +10842 0/imm32/no-imm32 +10843 0/imm32/no-disp32 +10844 0/imm32/no-output +10845 0x11/imm32/alloc-id:fake +10846 _Primitive-loop/imm32/next # we probably don't need an unconditional break +10847 _Primitive-loop: # (payload primitive) +10848 0x11/imm32/alloc-id:fake:payload +10849 0x11/imm32/alloc-id:fake +10850 _string-loop/imm32/name +10851 0/imm32/no-inouts +10852 0/imm32/no-inouts +10853 0/imm32/no-outputs +10854 0/imm32/no-outputs +10855 0x11/imm32/alloc-id:fake +10856 _string_e9_jump_loop/imm32/subx-name +10857 0/imm32/no-rm32 +10858 0/imm32/no-r32 +10859 0/imm32/no-imm32 +10860 0/imm32/no-disp32 +10861 0/imm32/no-output +10862 0x11/imm32/alloc-id:fake +10863 _Primitive-break-if-addr<-named/imm32/next +10864 # - branches to named blocks +10865 _Primitive-break-if-addr<-named: # (payload primitive) +10866 0x11/imm32/alloc-id:fake:payload +10867 0x11/imm32/alloc-id:fake +10868 _string-break-if-addr</imm32/name +10869 0x11/imm32/alloc-id:fake +10870 Single-lit-var/imm32/inouts +10871 0/imm32/no-outputs +10872 0/imm32/no-outputs +10873 0x11/imm32/alloc-id:fake +10874 _string_0f_82_jump_label/imm32/subx-name +10875 0/imm32/no-rm32 +10876 0/imm32/no-r32 +10877 0/imm32/no-imm32 +10878 1/imm32/disp32-is-first-inout +10879 0/imm32/no-output +10880 0x11/imm32/alloc-id:fake +10881 _Primitive-break-if-addr>=-named/imm32/next +10882 _Primitive-break-if-addr>=-named: # (payload primitive) +10883 0x11/imm32/alloc-id:fake:payload +10884 0x11/imm32/alloc-id:fake +10885 _string-break-if-addr>=/imm32/name +10886 0x11/imm32/alloc-id:fake +10887 Single-lit-var/imm32/inouts +10888 0/imm32/no-outputs +10889 0/imm32/no-outputs +10890 0x11/imm32/alloc-id:fake +10891 _string_0f_83_jump_label/imm32/subx-name +10892 0/imm32/no-rm32 +10893 0/imm32/no-r32 +10894 0/imm32/no-imm32 +10895 1/imm32/disp32-is-first-inout +10896 0/imm32/no-output +10897 0x11/imm32/alloc-id:fake +10898 _Primitive-break-if-=-named/imm32/next +10899 _Primitive-break-if-=-named: # (payload primitive) +10900 0x11/imm32/alloc-id:fake:payload +10901 0x11/imm32/alloc-id:fake +10902 _string-break-if-=/imm32/name +10903 0x11/imm32/alloc-id:fake +10904 Single-lit-var/imm32/inouts +10905 0/imm32/no-outputs +10906 0/imm32/no-outputs +10907 0x11/imm32/alloc-id:fake +10908 _string_0f_84_jump_label/imm32/subx-name +10909 0/imm32/no-rm32 +10910 0/imm32/no-r32 +10911 0/imm32/no-imm32 +10912 1/imm32/disp32-is-first-inout +10913 0/imm32/no-output +10914 0x11/imm32/alloc-id:fake +10915 _Primitive-break-if-!=-named/imm32/next +10916 _Primitive-break-if-!=-named: # (payload primitive) +10917 0x11/imm32/alloc-id:fake:payload +10918 0x11/imm32/alloc-id:fake +10919 _string-break-if-!=/imm32/name +10920 0x11/imm32/alloc-id:fake +10921 Single-lit-var/imm32/inouts +10922 0/imm32/no-outputs +10923 0/imm32/no-outputs +10924 0x11/imm32/alloc-id:fake +10925 _string_0f_85_jump_label/imm32/subx-name +10926 0/imm32/no-rm32 +10927 0/imm32/no-r32 +10928 0/imm32/no-imm32 +10929 1/imm32/disp32-is-first-inout +10930 0/imm32/no-output +10931 0x11/imm32/alloc-id:fake +10932 _Primitive-break-if-addr<=-named/imm32/next +10933 _Primitive-break-if-addr<=-named: # (payload primitive) +10934 0x11/imm32/alloc-id:fake:payload +10935 0x11/imm32/alloc-id:fake +10936 _string-break-if-addr<=/imm32/name +10937 0x11/imm32/alloc-id:fake +10938 Single-lit-var/imm32/inouts +10939 0/imm32/no-outputs +10940 0/imm32/no-outputs +10941 0x11/imm32/alloc-id:fake +10942 _string_0f_86_jump_label/imm32/subx-name +10943 0/imm32/no-rm32 +10944 0/imm32/no-r32 +10945 0/imm32/no-imm32 +10946 1/imm32/disp32-is-first-inout +10947 0/imm32/no-output +10948 0x11/imm32/alloc-id:fake +10949 _Primitive-break-if-addr>-named/imm32/next +10950 _Primitive-break-if-addr>-named: # (payload primitive) +10951 0x11/imm32/alloc-id:fake:payload +10952 0x11/imm32/alloc-id:fake +10953 _string-break-if-addr>/imm32/name +10954 0x11/imm32/alloc-id:fake +10955 Single-lit-var/imm32/inouts +10956 0/imm32/no-outputs +10957 0/imm32/no-outputs +10958 0x11/imm32/alloc-id:fake +10959 _string_0f_87_jump_label/imm32/subx-name +10960 0/imm32/no-rm32 +10961 0/imm32/no-r32 +10962 0/imm32/no-imm32 +10963 1/imm32/disp32-is-first-inout +10964 0/imm32/no-output +10965 0x11/imm32/alloc-id:fake +10966 _Primitive-break-if-<-named/imm32/next +10967 _Primitive-break-if-<-named: # (payload primitive) +10968 0x11/imm32/alloc-id:fake:payload +10969 0x11/imm32/alloc-id:fake +10970 _string-break-if-</imm32/name +10971 0x11/imm32/alloc-id:fake +10972 Single-lit-var/imm32/inouts +10973 0/imm32/no-outputs +10974 0/imm32/no-outputs +10975 0x11/imm32/alloc-id:fake +10976 _string_0f_8c_jump_label/imm32/subx-name +10977 0/imm32/no-rm32 +10978 0/imm32/no-r32 +10979 0/imm32/no-imm32 +10980 1/imm32/disp32-is-first-inout +10981 0/imm32/no-output +10982 0x11/imm32/alloc-id:fake +10983 _Primitive-break-if->=-named/imm32/next +10984 _Primitive-break-if->=-named: # (payload primitive) +10985 0x11/imm32/alloc-id:fake:payload +10986 0x11/imm32/alloc-id:fake +10987 _string-break-if->=/imm32/name +10988 0x11/imm32/alloc-id:fake +10989 Single-lit-var/imm32/inouts +10990 0/imm32/no-outputs +10991 0/imm32/no-outputs +10992 0x11/imm32/alloc-id:fake +10993 _string_0f_8d_jump_label/imm32/subx-name +10994 0/imm32/no-rm32 +10995 0/imm32/no-r32 +10996 0/imm32/no-imm32 +10997 1/imm32/disp32-is-first-inout +10998 0/imm32/no-output +10999 0x11/imm32/alloc-id:fake +11000 _Primitive-break-if-<=-named/imm32/next +11001 _Primitive-break-if-<=-named: # (payload primitive) +11002 0x11/imm32/alloc-id:fake:payload +11003 0x11/imm32/alloc-id:fake +11004 _string-break-if-<=/imm32/name +11005 0x11/imm32/alloc-id:fake +11006 Single-lit-var/imm32/inouts +11007 0/imm32/no-outputs +11008 0/imm32/no-outputs +11009 0x11/imm32/alloc-id:fake +11010 _string_0f_8e_jump_label/imm32/subx-name +11011 0/imm32/no-rm32 +11012 0/imm32/no-r32 +11013 0/imm32/no-imm32 +11014 1/imm32/disp32-is-first-inout +11015 0/imm32/no-output +11016 0x11/imm32/alloc-id:fake +11017 _Primitive-break-if->-named/imm32/next +11018 _Primitive-break-if->-named: # (payload primitive) +11019 0x11/imm32/alloc-id:fake:payload +11020 0x11/imm32/alloc-id:fake +11021 _string-break-if->/imm32/name +11022 0x11/imm32/alloc-id:fake +11023 Single-lit-var/imm32/inouts +11024 0/imm32/no-outputs +11025 0/imm32/no-outputs +11026 0x11/imm32/alloc-id:fake +11027 _string_0f_8f_jump_label/imm32/subx-name +11028 0/imm32/no-rm32 +11029 0/imm32/no-r32 +11030 0/imm32/no-imm32 +11031 1/imm32/disp32-is-first-inout +11032 0/imm32/no-output +11033 0x11/imm32/alloc-id:fake +11034 _Primitive-break-named/imm32/next +11035 _Primitive-break-named: # (payload primitive) +11036 0x11/imm32/alloc-id:fake:payload +11037 0x11/imm32/alloc-id:fake +11038 _string-break/imm32/name +11039 0x11/imm32/alloc-id:fake +11040 Single-lit-var/imm32/inouts +11041 0/imm32/no-outputs +11042 0/imm32/no-outputs +11043 0x11/imm32/alloc-id:fake +11044 _string_e9_jump_label/imm32/subx-name +11045 0/imm32/no-rm32 +11046 0/imm32/no-r32 +11047 0/imm32/no-imm32 +11048 1/imm32/disp32-is-first-inout +11049 0/imm32/no-output +11050 0x11/imm32/alloc-id:fake +11051 _Primitive-loop-if-addr<-named/imm32/next +11052 _Primitive-loop-if-addr<-named: # (payload primitive) +11053 0x11/imm32/alloc-id:fake:payload +11054 0x11/imm32/alloc-id:fake +11055 _string-loop-if-addr</imm32/name +11056 0x11/imm32/alloc-id:fake +11057 Single-lit-var/imm32/inouts +11058 0/imm32/no-outputs +11059 0/imm32/no-outputs +11060 0x11/imm32/alloc-id:fake +11061 _string_0f_82_jump_label/imm32/subx-name +11062 0/imm32/no-rm32 +11063 0/imm32/no-r32 +11064 0/imm32/no-imm32 +11065 1/imm32/disp32-is-first-inout +11066 0/imm32/no-output +11067 0x11/imm32/alloc-id:fake +11068 _Primitive-loop-if-addr>=-named/imm32/next +11069 _Primitive-loop-if-addr>=-named: # (payload primitive) +11070 0x11/imm32/alloc-id:fake:payload +11071 0x11/imm32/alloc-id:fake +11072 _string-loop-if-addr>=/imm32/name +11073 0x11/imm32/alloc-id:fake +11074 Single-lit-var/imm32/inouts +11075 0/imm32/no-outputs +11076 0/imm32/no-outputs +11077 0x11/imm32/alloc-id:fake +11078 _string_0f_83_jump_label/imm32/subx-name +11079 0/imm32/no-rm32 +11080 0/imm32/no-r32 +11081 0/imm32/no-imm32 +11082 1/imm32/disp32-is-first-inout +11083 0/imm32/no-output +11084 0x11/imm32/alloc-id:fake +11085 _Primitive-loop-if-=-named/imm32/next +11086 _Primitive-loop-if-=-named: # (payload primitive) +11087 0x11/imm32/alloc-id:fake:payload +11088 0x11/imm32/alloc-id:fake +11089 _string-loop-if-=/imm32/name +11090 0x11/imm32/alloc-id:fake +11091 Single-lit-var/imm32/inouts +11092 0/imm32/no-outputs +11093 0/imm32/no-outputs +11094 0x11/imm32/alloc-id:fake +11095 _string_0f_84_jump_label/imm32/subx-name +11096 0/imm32/no-rm32 +11097 0/imm32/no-r32 +11098 0/imm32/no-imm32 +11099 1/imm32/disp32-is-first-inout +11100 0/imm32/no-output +11101 0x11/imm32/alloc-id:fake +11102 _Primitive-loop-if-!=-named/imm32/next +11103 _Primitive-loop-if-!=-named: # (payload primitive) +11104 0x11/imm32/alloc-id:fake:payload +11105 0x11/imm32/alloc-id:fake +11106 _string-loop-if-!=/imm32/name +11107 0x11/imm32/alloc-id:fake +11108 Single-lit-var/imm32/inouts +11109 0/imm32/no-outputs +11110 0/imm32/no-outputs +11111 0x11/imm32/alloc-id:fake +11112 _string_0f_85_jump_label/imm32/subx-name +11113 0/imm32/no-rm32 +11114 0/imm32/no-r32 +11115 0/imm32/no-imm32 +11116 1/imm32/disp32-is-first-inout +11117 0/imm32/no-output +11118 0x11/imm32/alloc-id:fake +11119 _Primitive-loop-if-addr<=-named/imm32/next +11120 _Primitive-loop-if-addr<=-named: # (payload primitive) +11121 0x11/imm32/alloc-id:fake:payload +11122 0x11/imm32/alloc-id:fake +11123 _string-loop-if-addr<=/imm32/name +11124 0x11/imm32/alloc-id:fake +11125 Single-lit-var/imm32/inouts +11126 0/imm32/no-outputs +11127 0/imm32/no-outputs +11128 0x11/imm32/alloc-id:fake +11129 _string_0f_86_jump_label/imm32/subx-name +11130 0/imm32/no-rm32 +11131 0/imm32/no-r32 +11132 0/imm32/no-imm32 +11133 1/imm32/disp32-is-first-inout +11134 0/imm32/no-output +11135 0x11/imm32/alloc-id:fake +11136 _Primitive-loop-if-addr>-named/imm32/next +11137 _Primitive-loop-if-addr>-named: # (payload primitive) +11138 0x11/imm32/alloc-id:fake:payload +11139 0x11/imm32/alloc-id:fake +11140 _string-loop-if-addr>/imm32/name +11141 0x11/imm32/alloc-id:fake +11142 Single-lit-var/imm32/inouts +11143 0/imm32/no-outputs +11144 0/imm32/no-outputs +11145 0x11/imm32/alloc-id:fake +11146 _string_0f_87_jump_label/imm32/subx-name +11147 0/imm32/no-rm32 +11148 0/imm32/no-r32 +11149 0/imm32/no-imm32 +11150 1/imm32/disp32-is-first-inout +11151 0/imm32/no-output +11152 0x11/imm32/alloc-id:fake +11153 _Primitive-loop-if-<-named/imm32/next +11154 _Primitive-loop-if-<-named: # (payload primitive) +11155 0x11/imm32/alloc-id:fake:payload +11156 0x11/imm32/alloc-id:fake +11157 _string-loop-if-</imm32/name +11158 0x11/imm32/alloc-id:fake +11159 Single-lit-var/imm32/inouts +11160 0/imm32/no-outputs +11161 0/imm32/no-outputs +11162 0x11/imm32/alloc-id:fake +11163 _string_0f_8c_jump_label/imm32/subx-name +11164 0/imm32/no-rm32 +11165 0/imm32/no-r32 +11166 0/imm32/no-imm32 +11167 1/imm32/disp32-is-first-inout +11168 0/imm32/no-output +11169 0x11/imm32/alloc-id:fake +11170 _Primitive-loop-if->=-named/imm32/next +11171 _Primitive-loop-if->=-named: # (payload primitive) +11172 0x11/imm32/alloc-id:fake:payload +11173 0x11/imm32/alloc-id:fake +11174 _string-loop-if->=/imm32/name +11175 0x11/imm32/alloc-id:fake +11176 Single-lit-var/imm32/inouts +11177 0/imm32/no-outputs +11178 0/imm32/no-outputs +11179 0x11/imm32/alloc-id:fake +11180 _string_0f_8d_jump_label/imm32/subx-name +11181 0/imm32/no-rm32 +11182 0/imm32/no-r32 +11183 0/imm32/no-imm32 +11184 1/imm32/disp32-is-first-inout +11185 0/imm32/no-output +11186 0x11/imm32/alloc-id:fake +11187 _Primitive-loop-if-<=-named/imm32/next +11188 _Primitive-loop-if-<=-named: # (payload primitive) +11189 0x11/imm32/alloc-id:fake:payload +11190 0x11/imm32/alloc-id:fake +11191 _string-loop-if-<=/imm32/name +11192 0x11/imm32/alloc-id:fake +11193 Single-lit-var/imm32/inouts +11194 0/imm32/no-outputs +11195 0/imm32/no-outputs +11196 0x11/imm32/alloc-id:fake +11197 _string_0f_8e_jump_label/imm32/subx-name +11198 0/imm32/no-rm32 +11199 0/imm32/no-r32 +11200 0/imm32/no-imm32 +11201 1/imm32/disp32-is-first-inout +11202 0/imm32/no-output +11203 0x11/imm32/alloc-id:fake +11204 _Primitive-loop-if->-named/imm32/next +11205 _Primitive-loop-if->-named: # (payload primitive) +11206 0x11/imm32/alloc-id:fake:payload +11207 0x11/imm32/alloc-id:fake +11208 _string-loop-if->/imm32/name +11209 0x11/imm32/alloc-id:fake +11210 Single-lit-var/imm32/inouts +11211 0/imm32/no-outputs +11212 0/imm32/no-outputs +11213 0x11/imm32/alloc-id:fake +11214 _string_0f_8f_jump_label/imm32/subx-name +11215 0/imm32/no-rm32 +11216 0/imm32/no-r32 +11217 0/imm32/no-imm32 +11218 1/imm32/disp32-is-first-inout +11219 0/imm32/no-output +11220 0x11/imm32/alloc-id:fake +11221 _Primitive-loop-named/imm32/next # we probably don't need an unconditional break +11222 _Primitive-loop-named: # (payload primitive) +11223 0x11/imm32/alloc-id:fake:payload +11224 0x11/imm32/alloc-id:fake +11225 _string-loop/imm32/name +11226 0x11/imm32/alloc-id:fake +11227 Single-lit-var/imm32/inouts +11228 0/imm32/no-outputs +11229 0/imm32/no-outputs +11230 0x11/imm32/alloc-id:fake +11231 _string_e9_jump_label/imm32/subx-name +11232 0/imm32/no-rm32 +11233 0/imm32/no-r32 +11234 0/imm32/no-imm32 +11235 1/imm32/disp32-is-first-inout +11236 0/imm32/no-output +11237 0/imm32/next +11238 0/imm32/next +11239 +11240 # string literals for Mu instructions +11241 _string-add: # (payload array byte) +11242 0x11/imm32/alloc-id:fake:payload +11243 # "add" +11244 0x3/imm32/size +11245 0x61/a 0x64/d 0x64/d +11246 _string-address: # (payload array byte) +11247 0x11/imm32/alloc-id:fake:payload +11248 # "address" +11249 0x7/imm32/size +11250 0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s +11251 _string-add-to: # (payload array byte) +11252 0x11/imm32/alloc-id:fake:payload +11253 # "add-to" +11254 0x6/imm32/size +11255 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o +11256 _string-and: # (payload array byte) +11257 0x11/imm32/alloc-id:fake:payload +11258 # "and" +11259 0x3/imm32/size +11260 0x61/a 0x6e/n 0x64/d +11261 _string-and-with: # (payload array byte) +11262 0x11/imm32/alloc-id:fake:payload +11263 # "and-with" +11264 0x8/imm32/size +11265 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h +11266 _string-break: # (payload array byte) +11267 0x11/imm32/alloc-id:fake:payload +11268 # "break" +11269 0x5/imm32/size +11270 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k +11271 _string-break-if-<: # (payload array byte) +11272 0x11/imm32/alloc-id:fake:payload +11273 # "break-if-<" +11274 0xa/imm32/size +11275 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< +11276 _string-break-if-<=: # (payload array byte) +11277 0x11/imm32/alloc-id:fake:payload +11278 # "break-if-<=" +11279 0xb/imm32/size +11280 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/= +11281 _string-break-if-=: # (payload array byte) +11282 0x11/imm32/alloc-id:fake:payload +11283 # "break-if-=" +11284 0xa/imm32/size +11285 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/= +11286 _string-break-if->: # (payload array byte) +11287 0x11/imm32/alloc-id:fake:payload +11288 # "break-if->" +11289 0xa/imm32/size +11290 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> +11291 _string-break-if->=: # (payload array byte) +11292 0x11/imm32/alloc-id:fake:payload +11293 # "break-if->=" +11294 0xb/imm32/size +11295 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/= +11296 _string-break-if-!=: # (payload array byte) +11297 0x11/imm32/alloc-id:fake:payload +11298 # "break-if-!=" +11299 0xb/imm32/size +11300 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/= +11301 _string-break-if-addr<: # (payload array byte) +11302 0x11/imm32/alloc-id:fake:payload +11303 # "break-if-addr<" +11304 0xe/imm32/size +11305 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< +11306 _string-break-if-addr<=: # (payload array byte) +11307 0x11/imm32/alloc-id:fake:payload +11308 # "break-if-addr<=" +11309 0xf/imm32/size +11310 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x3d/= +11311 _string-break-if-addr>: # (payload array byte) +11312 0x11/imm32/alloc-id:fake:payload +11313 # "break-if-addr>" +11314 0xe/imm32/size +11315 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> +11316 _string-break-if-addr>=: # (payload array byte) +11317 0x11/imm32/alloc-id:fake:payload +11318 # "break-if-addr>=" +11319 0xf/imm32/size +11320 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x3d/= +11321 _string-compare: # (payload array byte) +11322 0x11/imm32/alloc-id:fake:payload +11323 # "compare" +11324 0x7/imm32/size +11325 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e +11326 _string-copy: # (payload array byte) +11327 0x11/imm32/alloc-id:fake:payload +11328 # "copy" +11329 0x4/imm32/size +11330 0x63/c 0x6f/o 0x70/p 0x79/y +11331 _string-copy-to: # (payload array byte) +11332 0x11/imm32/alloc-id:fake:payload +11333 # "copy-to" +11334 0x7/imm32/size +11335 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o +11336 _string-decrement: # (payload array byte) +11337 0x11/imm32/alloc-id:fake:payload +11338 # "decrement" +11339 0x9/imm32/size +11340 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t +11341 _string-increment: # (payload array byte) +11342 0x11/imm32/alloc-id:fake:payload +11343 # "increment" +11344 0x9/imm32/size +11345 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t +11346 _string-loop: # (payload array byte) +11347 0x11/imm32/alloc-id:fake:payload +11348 # "loop" +11349 0x4/imm32/size +11350 0x6c/l 0x6f/o 0x6f/o 0x70/p +11351 _string-loop-if-<: # (payload array byte) +11352 0x11/imm32/alloc-id:fake:payload +11353 # "loop-if-<" +11354 0x9/imm32/size +11355 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< +11356 _string-loop-if-<=: # (payload array byte) +11357 0x11/imm32/alloc-id:fake:payload +11358 # "loop-if-<=" +11359 0xa/imm32/size +11360 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/= +11361 _string-loop-if-=: # (payload array byte) +11362 0x11/imm32/alloc-id:fake:payload +11363 # "loop-if-=" +11364 0x9/imm32/size +11365 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/= +11366 _string-loop-if->: # (payload array byte) +11367 0x11/imm32/alloc-id:fake:payload +11368 # "loop-if->" +11369 0x9/imm32/size +11370 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> +11371 _string-loop-if->=: # (payload array byte) +11372 0x11/imm32/alloc-id:fake:payload +11373 # "loop-if->=" +11374 0xa/imm32/size +11375 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/= +11376 _string-loop-if-!=: # (payload array byte) +11377 0x11/imm32/alloc-id:fake:payload +11378 # "loop-if-!=" +11379 0xa/imm32/size +11380 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/= +11381 _string-loop-if-addr<: # (payload array byte) +11382 0x11/imm32/alloc-id:fake:payload +11383 # "loop-if-addr<" +11384 0xd/imm32/size +11385 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< +11386 _string-loop-if-addr<=: # (payload array byte) +11387 0x11/imm32/alloc-id:fake:payload +11388 # "loop-if-addr<=" +11389 0xe/imm32/size +11390 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x3d/= +11391 _string-loop-if-addr>: # (payload array byte) +11392 0x11/imm32/alloc-id:fake:payload +11393 # "loop-if-addr>" +11394 0xd/imm32/size +11395 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> +11396 _string-loop-if-addr>=: # (payload array byte) +11397 0x11/imm32/alloc-id:fake:payload +11398 # "loop-if-addr>=" +11399 0xe/imm32/size +11400 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x3d/= +11401 _string-multiply: # (payload array byte) +11402 0x11/imm32/alloc-id:fake:payload +11403 # "multiply" +11404 0x8/imm32/size +11405 0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y +11406 _string-or: # (payload array byte) +11407 0x11/imm32/alloc-id:fake:payload +11408 # "or" +11409 0x2/imm32/size +11410 0x6f/o 0x72/r +11411 _string-or-with: # (payload array byte) +11412 0x11/imm32/alloc-id:fake:payload +11413 # "or-with" +11414 0x7/imm32/size +11415 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h +11416 _string-subtract: # (payload array byte) +11417 0x11/imm32/alloc-id:fake:payload +11418 # "subtract" +11419 0x8/imm32/size +11420 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t +11421 _string-subtract-from: # (payload array byte) +11422 0x11/imm32/alloc-id:fake:payload +11423 # "subtract-from" +11424 0xd/imm32/size +11425 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t 0x2d/dash 0x66/f 0x72/r 0x6f/o 0x6d/m +11426 _string-xor: # (payload array byte) +11427 0x11/imm32/alloc-id:fake:payload +11428 # "xor" +11429 0x3/imm32/size +11430 0x78/x 0x6f/o 0x72/r +11431 _string-xor-with: # (payload array byte) +11432 0x11/imm32/alloc-id:fake:payload +11433 # "xor-with" +11434 0x8/imm32/size +11435 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h +11436 +11437 # string literals for SubX instructions +11438 _string_01_add_to: # (payload array byte) +11439 0x11/imm32/alloc-id:fake:payload +11440 # "01/add-to" +11441 0x9/imm32/size +11442 0x30/0 0x31/1 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o +11443 _string_03_add: # (payload array byte) +11444 0x11/imm32/alloc-id:fake:payload +11445 # "03/add" +11446 0x6/imm32/size +11447 0x30/0 0x33/3 0x2f/slash 0x61/a 0x64/d 0x64/d +11448 _string_05_add_to_eax: # (payload array byte) +11449 0x11/imm32/alloc-id:fake:payload +11450 # "05/add-to-eax" +11451 0xd/imm32/size +11452 0x30/0 0x35/5 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x61/a 0x78/x +11453 _string_09_or_with: # (payload array byte) +11454 0x11/imm32/alloc-id:fake:payload +11455 # "09/or-with" +11456 0xa/imm32/size +11457 0x30/0 0x39/9 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h +11458 _string_0b_or: # (payload array byte) +11459 0x11/imm32/alloc-id:fake:payload +11460 # "0b/or" +11461 0x5/imm32/size +11462 0x30/0 0x62/b 0x2f/slash 0x6f/o 0x72/r +11463 _string_0d_or_with_eax: # (payload array byte) +11464 0x11/imm32/alloc-id:fake:payload +11465 # "0d/or-with-eax" +11466 0xe/imm32/size +11467 0x30/0 0x64/d 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h 0x2d/dash 0x65/e 0x61/a 0x78/x +11468 _string_0f_82_jump_label: # (payload array byte) +11469 0x11/imm32/alloc-id:fake:payload +11470 # "0f 82/jump-if-addr<" +11471 0x13/imm32/size +11472 0x30/0 0x66/f 0x20/space 0x38/8 0x32/2 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< +11473 _string_0f_82_jump_break: # (payload array byte) +11474 0x11/imm32/alloc-id:fake:payload +11475 # "0f 82/jump-if-addr< break/disp32" +11476 0x20/imm32/size +11477 0x30/0 0x66/f 0x20/space 0x38/8 0x32/2 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11478 _string_0f_82_jump_loop: # (payload array byte) +11479 0x11/imm32/alloc-id:fake:payload +11480 # "0f 82/jump-if-addr< loop/disp32" +11481 0x1f/imm32/size +11482 0x30/0 0x66/f 0x20/space 0x38/8 0x32/2 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11483 _string_0f_83_jump_label: # (payload array byte) +11484 0x11/imm32/alloc-id:fake:payload +11485 # "0f 83/jump-if-addr>=" +11486 0x14/imm32/size +11487 0x30/0 0x66/f 0x20/space 0x38/8 0x33/3 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x3d/= +11488 _string_0f_83_jump_break: # (payload array byte) +11489 0x11/imm32/alloc-id:fake:payload +11490 # "0f 83/jump-if-addr>= break/disp32" +11491 0x21/imm32/size +11492 0x30/0 0x66/f 0x20/space 0x38/8 0x33/3 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11493 _string_0f_83_jump_loop: # (payload array byte) +11494 0x11/imm32/alloc-id:fake:payload +11495 # "0f 83/jump-if-addr>= loop/disp32" +11496 0x20/imm32/size +11497 0x30/0 0x66/f 0x20/space 0x38/8 0x33/3 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x3d/= 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11498 _string_0f_84_jump_label: # (payload array byte) +11499 0x11/imm32/alloc-id:fake:payload +11500 # "0f 84/jump-if-=" +11501 0xf/imm32/size +11502 0x30/0 0x66/f 0x20/space 0x38/8 0x34/4 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/= +11503 _string_0f_84_jump_break: # (payload array byte) +11504 0x11/imm32/alloc-id:fake:payload +11505 # "0f 84/jump-if-= break/disp32" +11506 0x1c/imm32/size +11507 0x30/0 0x66/f 0x20/space 0x38/8 0x34/4 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11508 _string_0f_84_jump_loop: # (payload array byte) +11509 0x11/imm32/alloc-id:fake:payload +11510 # "0f 84/jump-if-= loop/disp32" +11511 0x1b/imm32/size +11512 0x30/0 0x66/f 0x20/space 0x38/8 0x34/4 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/= 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11513 _string_0f_85_jump_label: # (payload array byte) +11514 0x11/imm32/alloc-id:fake:payload +11515 # "0f 85/jump-if-!=" +11516 0x10/imm32/size +11517 0x30/0 0x66/f 0x20/space 0x38/8 0x35/5 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/= +11518 _string_0f_85_jump_break: # (payload array byte) +11519 0x11/imm32/alloc-id:fake:payload +11520 # "0f 85/jump-if-!= break/disp32" +11521 0x1d/imm32/size +11522 0x30/0 0x66/f 0x20/space 0x38/8 0x35/5 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11523 _string_0f_85_jump_loop: # (payload array byte) +11524 0x11/imm32/alloc-id:fake:payload +11525 # "0f 85/jump-if-!= loop/disp32" +11526 0x1c/imm32/size +11527 0x30/0 0x66/f 0x20/space 0x38/8 0x35/5 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/= 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11528 _string_0f_86_jump_label: # (payload array byte) +11529 0x11/imm32/alloc-id:fake:payload +11530 # "0f 86/jump-if-addr<=" +11531 0x14/imm32/size +11532 0x30/0 0x66/f 0x20/space 0x38/8 0x36/6 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x3d/= +11533 _string_0f_86_jump_break: # (payload array byte) +11534 0x11/imm32/alloc-id:fake:payload +11535 # "0f 86/jump-if-addr<= break/disp32" +11536 0x21/imm32/size +11537 0x30/0 0x66/f 0x20/space 0x38/8 0x36/6 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11538 _string_0f_86_jump_loop: # (payload array byte) +11539 0x11/imm32/alloc-id:fake:payload +11540 # "0f 86/jump-if-addr<= loop/disp32" +11541 0x20/imm32/size +11542 0x30/0 0x66/f 0x20/space 0x38/8 0x36/6 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x3d/= 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11543 _string_0f_87_jump_label: # (payload array byte) +11544 0x11/imm32/alloc-id:fake:payload +11545 # "0f 87/jump-if-addr>" +11546 0x13/imm32/size +11547 0x30/0 0x66/f 0x20/space 0x38/8 0x37/7 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> +11548 _string_0f_87_jump_break: # (payload array byte) +11549 0x11/imm32/alloc-id:fake:payload +11550 # "0f 87/jump-if-addr> break/disp32" +11551 0x20/imm32/size +11552 0x30/0 0x66/f 0x20/space 0x38/8 0x37/7 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11553 _string_0f_87_jump_loop: # (payload array byte) +11554 0x11/imm32/alloc-id:fake:payload +11555 # "0f 87/jump-if-addr> loop/disp32" +11556 0x1f/imm32/size +11557 0x30/0 0x66/f 0x20/space 0x38/8 0x37/7 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11558 _string_0f_8c_jump_label: # (payload array byte) +11559 0x11/imm32/alloc-id:fake:payload +11560 # "0f 8c/jump-if-<" +11561 0xf/imm32/size +11562 0x30/0 0x66/f 0x20/space 0x38/8 0x63/c 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< +11563 _string_0f_8c_jump_break: # (payload array byte) +11564 0x11/imm32/alloc-id:fake:payload +11565 # "0f 8c/jump-if-< break/disp32" +11566 0x1c/imm32/size +11567 0x30/0 0x66/f 0x20/space 0x38/8 0x63/c 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11568 _string_0f_8c_jump_loop: # (payload array byte) +11569 0x11/imm32/alloc-id:fake:payload +11570 # "0f 8c/jump-if-< loop/disp32" +11571 0x1b/imm32/size +11572 0x30/0 0x66/f 0x20/space 0x38/8 0x63/c 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11573 _string_0f_8d_jump_label: # (payload array byte) +11574 0x11/imm32/alloc-id:fake:payload +11575 # "0f 8d/jump-if->=" +11576 0x10/imm32/size +11577 0x30/0 0x66/f 0x20/space 0x38/8 0x64/d 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/= +11578 _string_0f_8d_jump_break: # (payload array byte) +11579 0x11/imm32/alloc-id:fake:payload +11580 # "0f 8d/jump-if->= break/disp32" +11581 0x1d/imm32/size +11582 0x30/0 0x66/f 0x20/space 0x38/8 0x64/d 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11583 _string_0f_8d_jump_loop: # (payload array byte) +11584 0x11/imm32/alloc-id:fake:payload +11585 # "0f 8d/jump-if->= loop/disp32" +11586 0x1c/imm32/size +11587 0x30/0 0x66/f 0x20/space 0x38/8 0x64/d 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/= 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11588 _string_0f_8e_jump_label: # (payload array byte) +11589 0x11/imm32/alloc-id:fake:payload +11590 # "0f 8e/jump-if-<=" +11591 0x10/imm32/size +11592 0x30/0 0x66/f 0x20/space 0x38/8 0x65/e 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/= +11593 _string_0f_8e_jump_break: # (payload array byte) +11594 0x11/imm32/alloc-id:fake:payload +11595 # "0f 8e/jump-if-<= break/disp32" +11596 0x1d/imm32/size +11597 0x30/0 0x66/f 0x20/space 0x38/8 0x65/e 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11598 _string_0f_8e_jump_loop: # (payload array byte) +11599 0x11/imm32/alloc-id:fake:payload +11600 # "0f 8e/jump-if-<= loop/disp32" +11601 0x1c/imm32/size +11602 0x30/0 0x66/f 0x20/space 0x38/8 0x65/e 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/= 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11603 _string_0f_8f_jump_label: # (payload array byte) +11604 0x11/imm32/alloc-id:fake:payload +11605 # "0f 8f/jump-if->" +11606 0xf/imm32/size +11607 0x30/0 0x66/f 0x20/space 0x38/8 0x66/f 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> +11608 _string_0f_8f_jump_break: # (payload array byte) +11609 0x11/imm32/alloc-id:fake:payload +11610 # "0f 8f/jump-if-> break/disp32" +11611 0x1c/imm32/size +11612 0x30/0 0x66/f 0x20/space 0x38/8 0x66/f 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11613 _string_0f_8f_jump_loop: # (payload array byte) +11614 0x11/imm32/alloc-id:fake:payload +11615 # "0f 8f/jump-if-> loop/disp32" +11616 0x1b/imm32/size +11617 0x30/0 0x66/f 0x20/space 0x38/8 0x66/f 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11618 _string_0f_af_multiply: # (payload array byte) +11619 0x11/imm32/alloc-id:fake:payload +11620 # "0f af/multiply" +11621 0xe/imm32/size +11622 0x30/0 0x66/f 0x20/space 0x61/a 0x66/f 0x2f/slash 0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y +11623 _string_21_and_with: # (payload array byte) +11624 0x11/imm32/alloc-id:fake:payload +11625 # "21/and-with" +11626 0xb/imm32/size +11627 0x32/2 0x31/1 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h +11628 _string_23_and: # (payload array byte) +11629 0x11/imm32/alloc-id:fake:payload +11630 # "23/and" +11631 0x6/imm32/size +11632 0x32/2 0x33/3 0x2f/slash 0x61/a 0x6e/n 0x64/d +11633 _string_25_and_with_eax: # (payload array byte) +11634 0x11/imm32/alloc-id:fake:payload +11635 # "25/and-with-eax" +11636 0xf/imm32/size +11637 0x32/2 0x35/5 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h 0x2d/dash 0x65/e 0x61/a 0x78/x +11638 _string_29_subtract_from: # (payload array byte) +11639 0x11/imm32/alloc-id:fake:payload +11640 # "29/subtract-from" +11641 0x10/imm32/size +11642 0x32/2 0x39/9 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t 0x2d/dash 0x66/f 0x72/r 0x6f/o 0x6d/m +11643 _string_2b_subtract: # (payload array byte) +11644 0x11/imm32/alloc-id:fake:payload +11645 # "2b/subtract" +11646 0xb/imm32/size +11647 0x32/2 0x62/b 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t +11648 _string_2d_subtract_from_eax: # (payload array byte) +11649 0x11/imm32/alloc-id:fake:payload +11650 # "2d/subtract-from-eax" +11651 0x14/imm32/size +11652 0x32/2 0x64/d 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t 0x2d/dash 0x66/f 0x72/r 0x6f/o 0x6d/m 0x2d/dash 0x65/e 0x61/a 0x78/x +11653 _string_31_xor_with: # (payload array byte) +11654 0x11/imm32/alloc-id:fake:payload +11655 # "31/xor-with" +11656 0xb/imm32/size +11657 0x33/3 0x31/1 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h +11658 _string_33_xor: # (payload array byte) +11659 0x11/imm32/alloc-id:fake:payload +11660 # "33/xor" +11661 0x6/imm32/size +11662 0x33/3 0x33/3 0x2f/slash 0x78/x 0x6f/o 0x72/r +11663 _string_35_xor_with_eax: # (payload array byte) +11664 0x11/imm32/alloc-id:fake:payload +11665 # "35/xor-with-eax" +11666 0xf/imm32/size +11667 0x33/3 0x35/5 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h 0x2d/dash 0x65/e 0x61/a 0x78/x +11668 _string_39_compare->: # (payload array byte) +11669 0x11/imm32/alloc-id:fake:payload +11670 # "39/compare->" +11671 0xc/imm32/size +11672 0x33/3 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x3e/> +11673 _string_3b_compare<-: # (payload array byte) +11674 0x11/imm32/alloc-id:fake:payload +11675 # "3b/compare<-" +11676 0xc/imm32/size +11677 0x33/3 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x3c/< 0x2d/dash +11678 _string_3d_compare_eax_with: # (payload array byte) +11679 0x11/imm32/alloc-id:fake:payload +11680 # "3d/compare-eax-with" +11681 0x13/imm32/size +11682 0x33/3 0x64/d 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x65/e 0x61/a 0x78/x 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h +11683 _string_40_increment_eax: # (payload array byte) +11684 0x11/imm32/alloc-id:fake:payload +11685 # "40/increment-eax" +11686 0x10/imm32/size +11687 0x34/4 0x30/0 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x61/a 0x78/x +11688 _string_41_increment_ecx: # (payload array byte) +11689 0x11/imm32/alloc-id:fake:payload +11690 # "41/increment-ecx" +11691 0x10/imm32/size +11692 0x34/4 0x31/1 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x63/c 0x78/x +11693 _string_42_increment_edx: # (payload array byte) +11694 0x11/imm32/alloc-id:fake:payload +11695 # "42/increment-edx" +11696 0x10/imm32/size +11697 0x34/4 0x32/2 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x64/d 0x78/x +11698 _string_43_increment_ebx: # (payload array byte) +11699 0x11/imm32/alloc-id:fake:payload +11700 # "43/increment-ebx" +11701 0x10/imm32/size +11702 0x34/4 0x33/3 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x62/b 0x78/x +11703 _string_46_increment_esi: # (payload array byte) +11704 0x11/imm32/alloc-id:fake:payload +11705 # "46/increment-esi" +11706 0x10/imm32/size +11707 0x34/4 0x36/6 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x73/s 0x69/i +11708 _string_47_increment_edi: # (payload array byte) +11709 0x11/imm32/alloc-id:fake:payload +11710 # "47/increment-edi" +11711 0x10/imm32/size +11712 0x34/4 0x37/7 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x64/d 0x69/i +11713 _string_48_decrement_eax: # (payload array byte) +11714 0x11/imm32/alloc-id:fake:payload +11715 # "48/decrement-eax" +11716 0x10/imm32/size +11717 0x34/4 0x38/8 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x61/a 0x78/x +11718 _string_49_decrement_ecx: # (payload array byte) +11719 0x11/imm32/alloc-id:fake:payload +11720 # "49/decrement-ecx" +11721 0x10/imm32/size +11722 0x34/4 0x39/9 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x63/c 0x78/x +11723 _string_4a_decrement_edx: # (payload array byte) +11724 0x11/imm32/alloc-id:fake:payload +11725 # "4a/decrement-edx" +11726 0x10/imm32/size +11727 0x34/4 0x61/a 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x64/d 0x78/x +11728 _string_4b_decrement_ebx: # (payload array byte) +11729 0x11/imm32/alloc-id:fake:payload +11730 # "4b/decrement-ebx" +11731 0x10/imm32/size +11732 0x34/4 0x62/b 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x62/b 0x78/x +11733 _string_4e_decrement_esi: # (payload array byte) +11734 0x11/imm32/alloc-id:fake:payload +11735 # "4e/decrement-esi" +11736 0x10/imm32/size +11737 0x34/4 0x65/e 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x73/s 0x69/i +11738 _string_4f_decrement_edi: # (payload array byte) +11739 0x11/imm32/alloc-id:fake:payload +11740 # "4f/decrement-edi" +11741 0x10/imm32/size +11742 0x34/4 0x66/f 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x64/d 0x69/i +11743 _string_81_subop_add: # (payload array byte) +11744 0x11/imm32/alloc-id:fake:payload +11745 # "81 0/subop/add" +11746 0xe/imm32/size +11747 0x38/8 0x31/1 0x20/space 0x30/0 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x61/a 0x64/d 0x64/d +11748 _string_81_subop_or: # (payload array byte) +11749 0x11/imm32/alloc-id:fake:payload +11750 # "81 1/subop/or" +11751 0xd/imm32/size +11752 0x38/8 0x31/1 0x20/space 0x31/1 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x6f/o 0x72/r +11753 _string_81_subop_and: # (payload array byte) +11754 0x11/imm32/alloc-id:fake:payload +11755 # "81 4/subop/and" +11756 0xe/imm32/size +11757 0x38/8 0x31/1 0x20/space 0x34/4 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x61/a 0x6e/n 0x64/d +11758 _string_81_subop_subtract: # (payload array byte) +11759 0x11/imm32/alloc-id:fake:payload +11760 # "81 5/subop/subtract" +11761 0x13/imm32/size +11762 0x38/8 0x31/1 0x20/space 0x35/5 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t +11763 _string_81_subop_xor: # (payload array byte) +11764 0x11/imm32/alloc-id:fake:payload +11765 # "81 6/subop/xor" +11766 0xe/imm32/size +11767 0x38/8 0x31/1 0x20/space 0x36/6 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x78/x 0x6f/o 0x72/r +11768 _string_81_subop_compare: # (payload array byte) +11769 0x11/imm32/alloc-id:fake:payload +11770 # "81 7/subop/compare" +11771 0x12/imm32/size +11772 0x38/8 0x31/1 0x20/space 0x37/7 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e +11773 _string_89_<-: # (payload array byte) +11774 0x11/imm32/alloc-id:fake:payload +11775 # "89/<-" +11776 0x5/imm32/size +11777 0x38/8 0x39/9 0x2f/slash 0x3c/< 0x2d/dash +11778 _string_8b_->: # (payload array byte) +11779 0x11/imm32/alloc-id:fake:payload +11780 # "8b/->" +11781 0x5/imm32/size +11782 0x38/8 0x62/b 0x2f/slash 0x2d/dash 0x3e/> +11783 _string_8d_copy_address: # (payload array byte) +11784 0x11/imm32/alloc-id:fake:payload +11785 # "8d/copy-address" +11786 0xf/imm32/size +11787 0x38/8 0x64/d 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s +11788 _string_b8_copy_to_eax: # (payload array byte) +11789 0x11/imm32/alloc-id:fake:payload +11790 # "b8/copy-to-eax" +11791 0xe/imm32/size +11792 0x62/b 0x38/8 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x61/a 0x78/x +11793 _string_b9_copy_to_ecx: # (payload array byte) +11794 0x11/imm32/alloc-id:fake:payload +11795 # "b9/copy-to-ecx" +11796 0xe/imm32/size +11797 0x62/b 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x63/c 0x78/x +11798 _string_ba_copy_to_edx: # (payload array byte) +11799 0x11/imm32/alloc-id:fake:payload +11800 # "ba/copy-to-edx" +11801 0xe/imm32/size +11802 0x62/b 0x61/a 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x64/d 0x78/x +11803 _string_bb_copy_to_ebx: # (payload array byte) +11804 0x11/imm32/alloc-id:fake:payload +11805 # "bb/copy-to-ebx" +11806 0xe/imm32/size +11807 0x62/b 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x62/b 0x78/x +11808 _string_be_copy_to_esi: # (payload array byte) +11809 0x11/imm32/alloc-id:fake:payload +11810 # "be/copy-to-esi" +11811 0xe/imm32/size +11812 0x62/b 0x65/e 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x73/s 0x69/i +11813 _string_bf_copy_to_edi: # (payload array byte) +11814 0x11/imm32/alloc-id:fake:payload +11815 # "bf/copy-to-edi" +11816 0xe/imm32/size +11817 0x62/b 0x66/f 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x64/d 0x69/i +11818 _string_c7_subop_copy: # (payload array byte) +11819 0x11/imm32/alloc-id:fake:payload +11820 # "c7 0/subop/copy" +11821 0xf/imm32/size +11822 0x63/c 0x37/7 0x20/space 0x30/0 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y +11823 _string_e9_jump_label: # (payload array byte) +11824 0x11/imm32/alloc-id:fake:payload +11825 # "e9/jump" +11826 0x7/imm32/size +11827 0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p +11828 _string_e9_jump_break: # (payload array byte) +11829 0x11/imm32/alloc-id:fake:payload +11830 # "e9/jump break/disp32" +11831 0x14/imm32/size +11832 0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11833 _string_e9_jump_loop: # (payload array byte) +11834 0x11/imm32/alloc-id:fake:payload +11835 # "e9/jump loop/disp32" +11836 0x13/imm32/size +11837 0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2 +11838 _string_ff_subop_increment: # (payload array byte) +11839 0x11/imm32/alloc-id:fake:payload +11840 # "ff 0/subop/increment" +11841 0x14/imm32/size +11842 0x66/f 0x66/f 0x20/space 0x30/0 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t +11843 _string_ff_subop_decrement: # (payload array byte) +11844 0x11/imm32/alloc-id:fake:payload +11845 # "ff 1/subop/decrement" +11846 0x14/imm32/size +11847 0x66/f 0x66/f 0x31/1 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t +11848 +11849 Single-int-var-in-mem: # (payload list var) +11850 0x11/imm32/alloc-id:fake:payload +11851 0x11/imm32/alloc-id:fake +11852 Int-var-in-mem/imm32 +11853 0/imm32/next +11854 0/imm32/next +11855 +11856 Int-var-in-mem: # (payload var) +11857 0x11/imm32/alloc-id:fake:payload +11858 0/imm32/name +11859 0/imm32/name +11860 0x11/imm32/alloc-id:fake +11861 Type-int/imm32 +11862 1/imm32/some-block-depth +11863 1/imm32/some-stack-offset +11864 0/imm32/no-register +11865 0/imm32/no-register +11866 +11867 Two-args-int-stack-int-reg: # (payload list var) +11868 0x11/imm32/alloc-id:fake:payload +11869 0x11/imm32/alloc-id:fake +11870 Int-var-in-mem/imm32 +11871 0x11/imm32/alloc-id:fake +11872 Single-int-var-in-some-register/imm32/next +11873 +11874 Two-args-int-reg-int-stack: # (payload list var) +11875 0x11/imm32/alloc-id:fake:payload +11876 0x11/imm32/alloc-id:fake +11877 Int-var-in-some-register/imm32 +11878 0x11/imm32/alloc-id:fake +11879 Single-int-var-in-mem/imm32/next +11880 +11881 Two-args-int-eax-int-literal: # (payload list var) +11882 0x11/imm32/alloc-id:fake:payload +11883 0x11/imm32/alloc-id:fake +11884 Int-var-in-eax/imm32 +11885 0x11/imm32/alloc-id:fake +11886 Single-lit-var/imm32/next +11887 +11888 Int-var-and-literal: # (payload list var) +11889 0x11/imm32/alloc-id:fake:payload +11890 0x11/imm32/alloc-id:fake +11891 Int-var-in-mem/imm32 +11892 0x11/imm32/alloc-id:fake +11893 Single-lit-var/imm32/next +11894 +11895 Int-var-in-register-and-literal: # (payload list var) +11896 0x11/imm32/alloc-id:fake:payload +11897 0x11/imm32/alloc-id:fake +11898 Int-var-in-some-register/imm32 +11899 0x11/imm32/alloc-id:fake +11900 Single-lit-var/imm32/next +11901 +11902 Single-int-var-in-some-register: # (payload list var) +11903 0x11/imm32/alloc-id:fake:payload +11904 0x11/imm32/alloc-id:fake +11905 Int-var-in-some-register/imm32 +11906 0/imm32/next +11907 0/imm32/next +11908 +11909 Single-addr-var-in-some-register: # (payload list var) +11910 0x11/imm32/alloc-id:fake:payload +11911 0x11/imm32/alloc-id:fake +11912 Addr-var-in-some-register/imm32 +11913 0/imm32/next +11914 0/imm32/next +11915 +11916 Int-var-in-some-register: # (payload var) +11917 0x11/imm32/alloc-id:fake:payload +11918 0/imm32/name +11919 0/imm32/name +11920 0x11/imm32/alloc-id:fake +11921 Type-int/imm32 +11922 1/imm32/some-block-depth +11923 0/imm32/no-stack-offset +11924 0x11/imm32/alloc-id:fake +11925 Any-register/imm32 +11926 +11927 Any-register: # (payload array byte) +11928 0x11/imm32/alloc-id:fake:payload +11929 1/imm32/size +11930 # data +11931 2a/asterisk +11932 +11933 Addr-var-in-some-register: # (payload var) +11934 0x11/imm32/alloc-id:fake:payload +11935 0/imm32/name +11936 0/imm32/name +11937 0x11/imm32/alloc-id:fake +11938 Type-addr/imm32 +11939 1/imm32/some-block-depth +11940 0/imm32/no-stack-offset +11941 0x11/imm32/alloc-id:fake +11942 Any-register/imm32 +11943 +11944 Single-int-var-in-eax: # (payload list var) +11945 0x11/imm32/alloc-id:fake:payload +11946 0x11/imm32/alloc-id:fake +11947 Int-var-in-eax/imm32 +11948 0/imm32/next +11949 0/imm32/next +11950 +11951 Int-var-in-eax: +11952 0x11/imm32/alloc-id:fake:payload +11953 0/imm32/name +11954 0/imm32/name +11955 0x11/imm32/alloc-id:fake +11956 Type-int/imm32 +11957 1/imm32/some-block-depth +11958 0/imm32/no-stack-offset +11959 0x11/imm32/alloc-id:fake +11960 $Register-eax/imm32 +11961 +11962 Single-int-var-in-ecx: # (payload list var) +11963 0x11/imm32/alloc-id:fake:payload +11964 0x11/imm32/alloc-id:fake +11965 Int-var-in-ecx/imm32 +11966 0/imm32/next +11967 0/imm32/next +11968 +11969 Int-var-in-ecx: +11970 0x11/imm32/alloc-id:fake:payload +11971 0/imm32/name +11972 0/imm32/name +11973 0x11/imm32/alloc-id:fake +11974 Type-int/imm32 +11975 1/imm32/some-block-depth +11976 0/imm32/no-stack-offset +11977 0x11/imm32/alloc-id:fake +11978 $Register-ecx/imm32/register +11979 +11980 Single-int-var-in-edx: # (payload list var) +11981 0x11/imm32/alloc-id:fake:payload +11982 0x11/imm32/alloc-id:fake +11983 Int-var-in-edx/imm32 +11984 0/imm32/next +11985 0/imm32/next +11986 +11987 Int-var-in-edx: # (payload list var) +11988 0x11/imm32/alloc-id:fake:payload +11989 0/imm32/name +11990 0/imm32/name +11991 0x11/imm32/alloc-id:fake +11992 Type-int/imm32 +11993 1/imm32/some-block-depth +11994 0/imm32/no-stack-offset +11995 0x11/imm32/alloc-id:fake +11996 $Register-edx/imm32/register +11997 +11998 Single-int-var-in-ebx: # (payload list var) +11999 0x11/imm32/alloc-id:fake:payload +12000 0x11/imm32/alloc-id:fake +12001 Int-var-in-ebx/imm32 +12002 0/imm32/next +12003 0/imm32/next +12004 +12005 Int-var-in-ebx: # (payload list var) +12006 0x11/imm32/alloc-id:fake:payload +12007 0/imm32/name +12008 0/imm32/name +12009 0x11/imm32/alloc-id:fake +12010 Type-int/imm32 +12011 1/imm32/some-block-depth +12012 0/imm32/no-stack-offset +12013 0x11/imm32/alloc-id:fake +12014 $Register-ebx/imm32/register +12015 +12016 Single-int-var-in-esi: # (payload list var) +12017 0x11/imm32/alloc-id:fake:payload +12018 0x11/imm32/alloc-id:fake +12019 Int-var-in-esi/imm32 +12020 0/imm32/next +12021 0/imm32/next +12022 +12023 Int-var-in-esi: # (payload list var) +12024 0x11/imm32/alloc-id:fake:payload +12025 0/imm32/name +12026 0/imm32/name +12027 0x11/imm32/alloc-id:fake +12028 Type-int/imm32 +12029 1/imm32/some-block-depth +12030 0/imm32/no-stack-offset +12031 0x11/imm32/alloc-id:fake +12032 $Register-esi/imm32/register +12033 +12034 Single-int-var-in-edi: # (payload list var) +12035 0x11/imm32/alloc-id:fake:payload +12036 0x11/imm32/alloc-id:fake +12037 Int-var-in-edi/imm32 +12038 0/imm32/next +12039 0/imm32/next +12040 +12041 Int-var-in-edi: # (payload list var) +12042 0x11/imm32/alloc-id:fake:payload +12043 0/imm32/name +12044 0/imm32/name +12045 0x11/imm32/alloc-id:fake +12046 Type-int/imm32 +12047 1/imm32/some-block-depth +12048 0/imm32/no-stack-offset +12049 0x11/imm32/alloc-id:fake +12050 $Register-edi/imm32/register +12051 +12052 Single-lit-var: # (payload list var) +12053 0x11/imm32/alloc-id:fake:payload +12054 0x11/imm32/alloc-id:fake +12055 Lit-var/imm32 +12056 0/imm32/next +12057 0/imm32/next +12058 +12059 Lit-var: # (payload var) +12060 0x11/imm32/alloc-id:fake:payload +12061 0/imm32/name +12062 0/imm32/name +12063 0x11/imm32/alloc-id:fake +12064 Type-literal/imm32 +12065 1/imm32/some-block-depth +12066 0/imm32/no-stack-offset +12067 0/imm32/no-register +12068 0/imm32/no-register +12069 +12070 Type-int: # (payload tree type-id) +12071 0x11/imm32/alloc-id:fake:payload +12072 1/imm32/left-is-atom +12073 1/imm32/value:int +12074 0/imm32/left:unused +12075 0/imm32/right:null +12076 0/imm32/right:null +12077 +12078 Type-literal: # (payload tree type-id) +12079 0x11/imm32/alloc-id:fake:payload +12080 1/imm32/is-atom +12081 0/imm32/value:literal +12082 0/imm32/left:unused +12083 0/imm32/right:null +12084 0/imm32/right:null +12085 +12086 Type-addr: # (payload tree type-id) +12087 0x11/imm32/alloc-id:fake:payload +12088 1/imm32/is-atom +12089 2/imm32/value:addr +12090 0/imm32/left:unused +12091 0/imm32/right:null +12092 0/imm32/right:null +12093 +12094 == code +12095 emit-subx-primitive: # out: (addr buffered-file), stmt: (addr stmt), primitive: (addr primitive) +12096 # . prologue +12097 55/push-ebp +12098 89/<- %ebp 4/r32/esp +12099 # . save registers +12100 50/push-eax +12101 51/push-ecx +12102 # ecx = primitive +12103 8b/-> *(ebp+0x10) 1/r32/ecx +12104 # emit primitive name +12105 (emit-indent *(ebp+8) *Curr-block-depth) +12106 (lookup *(ecx+0x18) *(ecx+0x1c)) # Primitive-subx-name Primitive-subx-name => eax +12107 (write-buffered *(ebp+8) %eax) +12108 # emit rm32 if necessary +12109 (emit-subx-rm32 *(ebp+8) *(ecx+0x20) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt +12110 # emit r32 if necessary +12111 (emit-subx-r32 *(ebp+8) *(ecx+0x24) *(ebp+0xc)) # out, Primitive-subx-r32, stmt +12112 # emit imm32 if necessary +12113 (emit-subx-imm32 *(ebp+8) *(ecx+0x28) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt +12114 # emit disp32 if necessary +12115 (emit-subx-disp32 *(ebp+8) *(ecx+0x2c) *(ebp+0xc)) # out, Primitive-subx-disp32, stmt +12116 (write-buffered *(ebp+8) Newline) +12117 $emit-subx-primitive:end: +12118 # . restore registers +12119 59/pop-to-ecx +12120 58/pop-to-eax +12121 # . epilogue +12122 89/<- %esp 5/r32/ebp +12123 5d/pop-to-ebp +12124 c3/return +12125 +12126 emit-subx-rm32: # out: (addr buffered-file), l: arg-location, stmt: (addr stmt) +12127 # . prologue +12128 55/push-ebp +12129 89/<- %ebp 4/r32/esp +12130 # . save registers +12131 50/push-eax +12132 # if (l == 0) return +12133 81 7/subop/compare *(ebp+0xc) 0/imm32 +12134 74/jump-if-= $emit-subx-rm32:end/disp8 +12135 # var v/eax: (addr stmt-var) +12136 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # => eax +12137 (emit-subx-var-as-rm32 *(ebp+8) %eax) +12138 $emit-subx-rm32:end: +12139 # . restore registers +12140 58/pop-to-eax +12141 # . epilogue +12142 89/<- %esp 5/r32/ebp +12143 5d/pop-to-ebp +12144 c3/return +12145 +12146 get-stmt-operand-from-arg-location: # stmt: (addr stmt), l: arg-location -> var/eax: (addr stmt-var) +12147 # . prologue +12148 55/push-ebp +12149 89/<- %ebp 4/r32/esp +12150 # . save registers +12151 51/push-ecx +12152 # eax = l +12153 8b/-> *(ebp+0xc) 0/r32/eax +12154 # ecx = stmt +12155 8b/-> *(ebp+8) 1/r32/ecx +12156 # if (l == 1) return stmt->inouts +12157 { +12158 3d/compare-eax-and 1/imm32 +12159 75/jump-if-!= break/disp8 +12160 $get-stmt-operand-from-arg-location:1: +12161 (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax +12162 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +12163 } +12164 # if (l == 2) return stmt->inouts->next +12165 { +12166 3d/compare-eax-and 2/imm32 +12167 75/jump-if-!= break/disp8 +12168 $get-stmt-operand-from-arg-location:2: +12169 (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax +12170 (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax +12171 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +12172 } +12173 # if (l == 3) return stmt->outputs +12174 { +12175 3d/compare-eax-and 3/imm32 +12176 75/jump-if-!= break/disp8 +12177 $get-stmt-operand-from-arg-location:3: +12178 (lookup *(ecx+0x14) *(ecx+0x18)) # Stmt1-outputs Stmt1-outputs => eax +12179 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +12180 } +12181 # abort +12182 e9/jump $get-stmt-operand-from-arg-location:abort/disp32 +12183 $get-stmt-operand-from-arg-location:end: +12184 # . restore registers +12185 59/pop-to-ecx +12186 # . epilogue +12187 89/<- %esp 5/r32/ebp +12188 5d/pop-to-ebp +12189 c3/return +12190 +12191 $get-stmt-operand-from-arg-location:abort: +12192 # error("invalid arg-location " eax) +12193 (write-buffered Stderr "invalid arg-location ") +12194 (print-int32-buffered Stderr %eax) +12195 (write-buffered Stderr Newline) +12196 (flush Stderr) +12197 # . syscall(exit, 1) +12198 bb/copy-to-ebx 1/imm32 +12199 b8/copy-to-eax 1/imm32/exit +12200 cd/syscall 0x80/imm8 +12201 # never gets here +12202 +12203 emit-subx-r32: # out: (addr buffered-file), l: arg-location, stmt: (addr stmt) +12204 # . prologue +12205 55/push-ebp +12206 89/<- %ebp 4/r32/esp +12207 # . save registers +12208 50/push-eax +12209 51/push-ecx +12210 # if (l == 0) return +12211 81 7/subop/compare *(ebp+0xc) 0/imm32 +12212 0f 84/jump-if-= $emit-subx-r32:end/disp32 +12213 # var v/eax: (addr stmt-var) +12214 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # => eax +12215 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax +12216 (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax +12217 (maybe-get Registers %eax 0xc) # => eax: (addr register-index) +12218 (write-buffered *(ebp+8) Space) +12219 (print-int32-buffered *(ebp+8) *eax) +12220 (write-buffered *(ebp+8) "/r32") +12221 $emit-subx-r32:end: +12222 # . restore registers +12223 59/pop-to-ecx +12224 58/pop-to-eax +12225 # . epilogue +12226 89/<- %esp 5/r32/ebp +12227 5d/pop-to-ebp +12228 c3/return +12229 +12230 emit-subx-imm32: # out: (addr buffered-file), l: arg-location, stmt: (addr stmt) +12231 # . prologue +12232 55/push-ebp +12233 89/<- %ebp 4/r32/esp +12234 # . save registers +12235 50/push-eax +12236 51/push-ecx +12237 # if (l == 0) return +12238 81 7/subop/compare *(ebp+0xc) 0/imm32 +12239 0f 84/jump-if-= $emit-subx-imm32:end/disp32 +12240 # var v/eax: (handle var) +12241 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # => eax +12242 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax +12243 (lookup *eax *(eax+4)) # Var-name Var-name => eax +12244 (write-buffered *(ebp+8) Space) +12245 (write-buffered *(ebp+8) %eax) +12246 (write-buffered *(ebp+8) "/imm32") +12247 $emit-subx-imm32:end: +12248 # . restore registers +12249 59/pop-to-ecx +12250 58/pop-to-eax +12251 # . epilogue +12252 89/<- %esp 5/r32/ebp +12253 5d/pop-to-ebp +12254 c3/return +12255 +12256 emit-subx-disp32: # out: (addr buffered-file), l: arg-location, stmt: (addr stmt) +12257 # . prologue +12258 55/push-ebp +12259 89/<- %ebp 4/r32/esp +12260 # . save registers +12261 50/push-eax +12262 51/push-ecx +12263 # if (location == 0) return +12264 81 7/subop/compare *(ebp+0xc) 0/imm32 +12265 0f 84/jump-if-= $emit-subx-disp32:end/disp32 +12266 # var v/eax: (addr stmt-var) +12267 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # => eax +12268 (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax +12269 (lookup *eax *(eax+4)) # Var-name Var-name => eax +12270 (write-buffered *(ebp+8) Space) +12271 (write-buffered *(ebp+8) %eax) +12272 # hack: if instruction operation starts with "break", emit ":break" +12273 # var name/ecx: (addr array byte) = lookup(stmt->operation) +12274 8b/-> *(ebp+0x10) 0/r32/eax +12275 (lookup *(eax+4) *(eax+8)) # Stmt1-operation Stmt1-operation => eax +12276 89/<- %ecx 0/r32/eax +12277 { +12278 (string-starts-with? %ecx "break") # => eax +12279 3d/compare-eax-and 0/imm32/false +12280 74/jump-if-= break/disp8 +12281 (write-buffered *(ebp+8) ":break") +12282 } +12283 # hack: if instruction operation starts with "loop", emit ":loop" +12284 { +12285 (string-starts-with? %ecx "loop") # => eax +12286 3d/compare-eax-and 0/imm32/false +12287 74/jump-if-= break/disp8 +12288 (write-buffered *(ebp+8) ":loop") +12289 } +12290 (write-buffered *(ebp+8) "/disp32") +12291 $emit-subx-disp32:end: +12292 # . restore registers +12293 59/pop-to-ecx +12294 58/pop-to-eax +12295 # . epilogue +12296 89/<- %esp 5/r32/ebp +12297 5d/pop-to-ebp +12298 c3/return +12299 +12300 emit-call: # out: (addr buffered-file), stmt: (addr stmt) +12301 # . prologue +12302 55/push-ebp +12303 89/<- %ebp 4/r32/esp +12304 # . save registers +12305 50/push-eax +12306 51/push-ecx +12307 # +12308 (emit-indent *(ebp+8) *Curr-block-depth) +12309 (write-buffered *(ebp+8) "(") +12310 # ecx = stmt +12311 8b/-> *(ebp+0xc) 1/r32/ecx +12312 # - emit function name +12313 (lookup *(ecx+4) *(ecx+8)) # Stmt1-operation Stmt1-operation => eax +12314 (write-buffered *(ebp+8) %eax) +12315 # - emit arguments +12316 # var curr/eax: (addr stmt-var) = lookup(stmt->inouts) +12317 (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax +12318 { +12319 # if (curr == null) break +12320 3d/compare-eax-and 0/imm32 +12321 74/jump-if-= break/disp8 +12322 # +12323 (emit-subx-call-operand *(ebp+8) %eax) +12324 # curr = lookup(curr->next) +12325 (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax +12326 eb/jump loop/disp8 +12327 } +12328 # +12329 (write-buffered *(ebp+8) ")\n") +12330 $emit-call:end: +12331 # . restore registers +12332 59/pop-to-ecx +12333 58/pop-to-eax +12334 # . epilogue +12335 89/<- %esp 5/r32/ebp +12336 5d/pop-to-ebp +12337 c3/return +12338 +12339 emit-subx-call-operand: # out: (addr buffered-file), s: (addr stmt-var) +12340 # shares code with emit-subx-var-as-rm32 +12341 # . prologue +12342 55/push-ebp +12343 89/<- %ebp 4/r32/esp +12344 # . save registers +12345 50/push-eax +12346 51/push-ecx +12347 56/push-esi +12348 # ecx = s +12349 8b/-> *(ebp+0xc) 1/r32/ecx +12350 # var operand/esi: (addr var) = lookup(s->value) +12351 (lookup *ecx *(ecx+4)) # Stmt-var-value Stmt-var-value => eax +12352 89/<- %esi 0/r32/eax +12353 # if (operand->register && !s->is-deref?) emit "%__" +12354 { +12355 $emit-subx-call-operand:check-for-register-direct: +12356 81 7/subop/compare *(esi+0x18) 0/imm32 # Var-register +12357 74/jump-if-= break/disp8 +12358 81 7/subop/compare *(ecx+0x10) 0/imm32/false # Stmt-var-is-deref +12359 75/jump-if-!= break/disp8 +12360 $emit-subx-call-operand:register-direct: +12361 (write-buffered *(ebp+8) " %") +12362 (lookup *(esi+0x18) *(esi+0x1c)) # Var-register Var-register => eax +12363 (write-buffered *(ebp+8) %eax) +12364 e9/jump $emit-subx-call-operand:end/disp32 +12365 } +12366 # else if (operand->register && s->is-deref?) emit "*__" +12367 { +12368 $emit-subx-call-operand:check-for-register-indirect: +12369 81 7/subop/compare *(esi+0x18) 0/imm32 # Var-register +12370 74/jump-if-= break/disp8 +12371 81 7/subop/compare *(ecx+0x10) 0/imm32/false # Stmt-var-is-deref +12372 74/jump-if-= break/disp8 +12373 $emit-subx-call-operand:register-indirect: +12374 (emit-subx-call-operand-register-indirect *(ebp+8) %esi) +12375 e9/jump $emit-subx-call-operand:end/disp32 +12376 } +12377 # else if (operand->stack-offset) emit "*(ebp+__)" +12378 { +12379 81 7/subop/compare *(esi+0x14) 0/imm32 # Var-offset +12380 74/jump-if-= break/disp8 +12381 $emit-subx-call-operand:stack: +12382 (emit-subx-call-operand-stack *(ebp+8) %esi) +12383 e9/jump $emit-subx-call-operand:end/disp32 +12384 } +12385 # else if (operand->type == literal) emit "__" +12386 { +12387 (lookup *(esi+8) *(esi+0xc)) # Var-type Var-type => eax +12388 81 7/subop/compare *(eax+4) 0/imm32 # Tree-left +12389 75/jump-if-!= break/disp8 +12390 $emit-subx-call-operand:literal: +12391 (write-buffered *(ebp+8) Space) +12392 (lookup *esi *(esi+4)) # Var-name Var-name => eax +12393 (write-buffered *(ebp+8) %eax) +12394 } +12395 $emit-subx-call-operand:end: +12396 # . restore registers +12397 5e/pop-to-esi +12398 59/pop-to-ecx +12399 58/pop-to-eax +12400 # . epilogue +12401 89/<- %esp 5/r32/ebp +12402 5d/pop-to-ebp +12403 c3/return +12404 +12405 emit-subx-call-operand-register-indirect: # out: (addr buffered-file), v: (addr var) +12406 # . prologue +12407 55/push-ebp +12408 89/<- %ebp 4/r32/esp +12409 # . save registers +12410 50/push-eax +12411 51/push-ecx +12412 56/push-esi +12413 # esi = v +12414 8b/-> *(ebp+0xc) 6/r32/esi +12415 # var size/ecx: int = size-of-deref(v) +12416 (size-of-deref %esi) # => eax +12417 89/<- %ecx 0/r32/eax +12418 # var reg-name/esi: (addr array byte) = lookup(v->register) +12419 (lookup *(esi+0x18) *(esi+0x1c)) # Var-register Var-register => eax +12420 89/<- %esi 0/r32/eax +12421 # TODO: assert size is a multiple of 4 +12422 # var i/eax: int = 0 +12423 b8/copy-to-eax 0/imm32 +12424 { +12425 $emit-subx-call-operand-register-indirect:loop: +12426 # if (i >= size) break +12427 39/compare %eax 1/r32/ecx +12428 7d/jump-if->= break/disp8 +12429 # emit " *(" v->register "+" i ")" +12430 (write-buffered *(ebp+8) " *(") +12431 (write-buffered *(ebp+8) %esi) +12432 (write-buffered *(ebp+8) "+") +12433 (print-int32-buffered *(ebp+8) %eax) +12434 (write-buffered *(ebp+8) ")") +12435 # i += 4 +12436 05/add-to-eax 4/imm32 +12437 # +12438 eb/jump loop/disp8 +12439 } +12440 $emit-subx-call-operand-register-indirect:end: +12441 # . restore registers +12442 5e/pop-to-esi +12443 59/pop-to-ecx +12444 58/pop-to-eax +12445 # . epilogue +12446 89/<- %esp 5/r32/ebp +12447 5d/pop-to-ebp +12448 c3/return +12449 +12450 emit-subx-call-operand-stack: # out: (addr buffered-file), v: (addr var) +12451 # . prologue +12452 55/push-ebp +12453 89/<- %ebp 4/r32/esp +12454 # . save registers +12455 50/push-eax +12456 51/push-ecx +12457 56/push-esi +12458 # esi = v +12459 8b/-> *(ebp+0xc) 6/r32/esi +12460 # var curr/ecx: int = v->offset +12461 8b/-> *(esi+0x14) 1/r32/ecx # Var-offset +12462 # var max/eax: int = v->offset + size-of(v) +12463 (size-of %esi) # => eax +12464 # TODO: assert size is a multiple of 4 +12465 01/add-to %eax 1/r32/ecx +12466 { +12467 $emit-subx-call-operand-stack:loop: +12468 # if (curr >= max) break +12469 39/compare %ecx 0/r32/eax +12470 7d/jump-if->= break/disp8 +12471 # emit " *(ebp+" curr ")" +12472 (write-buffered *(ebp+8) " *(ebp+") +12473 (print-int32-buffered *(ebp+8) %ecx) +12474 (write-buffered *(ebp+8) ")") +12475 # i += 4 +12476 81 0/subop/add %ecx 4/imm32 +12477 # +12478 eb/jump loop/disp8 +12479 } +12480 $emit-subx-call-operand-stack:end: +12481 # . restore registers +12482 5e/pop-to-esi +12483 59/pop-to-ecx +12484 58/pop-to-eax +12485 # . epilogue +12486 89/<- %esp 5/r32/ebp +12487 5d/pop-to-ebp +12488 c3/return +12489 +12490 emit-subx-var-as-rm32: # out: (addr buffered-file), s: (addr stmt-var) +12491 # . prologue +12492 55/push-ebp +12493 89/<- %ebp 4/r32/esp +12494 # . save registers +12495 50/push-eax +12496 51/push-ecx +12497 56/push-esi +12498 # ecx = s +12499 8b/-> *(ebp+0xc) 1/r32/ecx +12500 # var operand/esi: (addr var) = lookup(s->value) +12501 (lookup *ecx *(ecx+4)) # Stmt-var-value Stmt-var-value => eax +12502 89/<- %esi 0/r32/eax +12503 # if (operand->register && s->is-deref?) emit "*__" +12504 { +12505 $emit-subx-var-as-rm32:check-for-register-indirect: +12506 81 7/subop/compare *(esi+0x18) 0/imm32 # Var-register +12507 74/jump-if-= break/disp8 +12508 81 7/subop/compare *(ecx+0x10) 0/imm32/false # Stmt-var-is-deref +12509 74/jump-if-= break/disp8 +12510 $emit-subx-var-as-rm32:register-indirect: +12511 (write-buffered *(ebp+8) " *") +12512 (lookup *(esi+0x18) *(esi+0x1c)) # Var-register Var-register => eax +12513 (write-buffered *(ebp+8) %eax) +12514 e9/jump $emit-subx-var-as-rm32:end/disp32 +12515 } +12516 # if (operand->register && !s->is-deref?) emit "%__" +12517 { +12518 $emit-subx-var-as-rm32:check-for-register-direct: +12519 81 7/subop/compare *(esi+0x18) 0/imm32 # Var-register +12520 74/jump-if-= break/disp8 +12521 81 7/subop/compare *(ecx+0x10) 0/imm32/false # Stmt-var-is-deref +12522 75/jump-if-!= break/disp8 +12523 $emit-subx-var-as-rm32:register-direct: +12524 (write-buffered *(ebp+8) " %") +12525 (lookup *(esi+0x18) *(esi+0x1c)) # Var-register Var-register => eax +12526 (write-buffered *(ebp+8) %eax) +12527 e9/jump $emit-subx-var-as-rm32:end/disp32 +12528 } +12529 # else if (operand->stack-offset) emit "*(ebp+__)" +12530 { +12531 81 7/subop/compare *(esi+0x14) 0/imm32 # Var-offset +12532 74/jump-if-= break/disp8 +12533 $emit-subx-var-as-rm32:stack: +12534 (write-buffered *(ebp+8) Space) +12535 (write-buffered *(ebp+8) "*(ebp+") +12536 (print-int32-buffered *(ebp+8) *(esi+0x14)) # Var-offset +12537 (write-buffered *(ebp+8) ")") +12538 } +12539 $emit-subx-var-as-rm32:end: +12540 # . restore registers +12541 5e/pop-to-esi +12542 59/pop-to-ecx +12543 58/pop-to-eax +12544 # . epilogue +12545 89/<- %esp 5/r32/ebp +12546 5d/pop-to-ebp +12547 c3/return +12548 +12549 find-matching-primitive: # primitives: (addr primitive), stmt: (addr stmt) -> result/eax: (addr primitive) +12550 # . prologue +12551 55/push-ebp +12552 89/<- %ebp 4/r32/esp +12553 # . save registers +12554 51/push-ecx +12555 # var curr/ecx: (addr primitive) = primitives +12556 8b/-> *(ebp+8) 1/r32/ecx +12557 { +12558 $find-matching-primitive:loop: +12559 # if (curr == null) break +12560 81 7/subop/compare %ecx 0/imm32 +12561 0f 84/jump-if-= break/disp32 +12562 # if match(curr, stmt) return curr +12563 { +12564 (mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax +12565 3d/compare-eax-and 0/imm32/false +12566 74/jump-if-= break/disp8 +12567 89/<- %eax 1/r32/ecx +12568 eb/jump $find-matching-primitive:end/disp8 +12569 } +12570 $find-matching-primitive:next-primitive: +12571 # curr = curr->next +12572 (lookup *(ecx+0x34) *(ecx+0x38)) # Primitive-next Primitive-next => eax +12573 89/<- %ecx 0/r32/eax +12574 # +12575 e9/jump loop/disp32 +12576 } +12577 # return null +12578 b8/copy-to-eax 0/imm32 +12579 $find-matching-primitive:end: +12580 # . restore registers +12581 59/pop-to-ecx +12582 # . epilogue +12583 89/<- %esp 5/r32/ebp +12584 5d/pop-to-ebp +12585 c3/return +12586 +12587 mu-stmt-matches-primitive?: # stmt: (addr stmt), primitive: (addr primitive) -> result/eax: boolean +12588 # A mu stmt matches a primitive if the name matches, all the inout vars +12589 # match, and all the output vars match. +12590 # Vars match if types match and registers match. +12591 # In addition, a stmt output matches a primitive's output if types match +12592 # and the primitive has a wildcard register. +12593 # . prologue +12594 55/push-ebp +12595 89/<- %ebp 4/r32/esp +12596 # . save registers +12597 51/push-ecx +12598 52/push-edx +12599 53/push-ebx +12600 56/push-esi +12601 57/push-edi +12602 # ecx = stmt +12603 8b/-> *(ebp+8) 1/r32/ecx +12604 # edx = primitive +12605 8b/-> *(ebp+0xc) 2/r32/edx +12606 { +12607 $mu-stmt-matches-primitive?:check-name: +12608 # if (primitive->name != stmt->operation) return false +12609 # . var esi: (addr array byte) = lookup(stmt->operation) +12610 (lookup *(ecx+4) *(ecx+8)) # Stmt1-operation Stmt1-operation => eax +12611 89/<- %esi 0/r32/eax +12612 # . var edi: (addr array byte) = lookup(primitive->name) +12613 (lookup *edx *(edx+4)) # Primitive-name Primitive-name => eax +12614 89/<- %edi 0/r32/eax +12615 (string-equal? %esi %edi) # => eax +12616 3d/compare-eax-and 0/imm32/false +12617 75/jump-if-!= break/disp8 +12618 b8/copy-to-eax 0/imm32 +12619 e9/jump $mu-stmt-matches-primitive?:end/disp32 +12620 } +12621 # var curr/esi: (addr stmt-var) = lookup(stmt->inouts) +12622 (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax +12623 89/<- %esi 0/r32/eax +12624 # var curr2/edi: (addr list var) = lookup(primitive->inouts) +12625 (lookup *(edx+8) *(edx+0xc)) # Primitive-inouts Primitive-inouts => eax +12626 89/<- %edi 0/r32/eax +12627 { +12628 $mu-stmt-matches-primitive?:inouts-loop: +12629 # if (curr == 0 && curr2 == 0) move on to check outputs +12630 { +12631 $mu-stmt-matches-primitive?:check-both-inouts-null: +12632 81 7/subop/compare %esi 0/imm32 +12633 75/jump-if-!= break/disp8 +12634 $mu-stmt-matches-primitive?:stmt-inout-null: +12635 81 7/subop/compare %edi 0/imm32 +12636 0f 84/jump-if-= $mu-stmt-matches-primitive?:check-outputs/disp32 +12637 $mu-stmt-matches-primitive?:stmt-inout-null-and-prim-inout-not-null: +12638 # return false +12639 b8/copy-to-eax 0/imm32/false +12640 e9/jump $mu-stmt-matches-primitive?:end/disp32 +12641 } +12642 # if (curr2 == 0) return false +12643 { +12644 $mu-stmt-matches-primitive?:check-prim-inout-null: +12645 81 7/subop/compare %edi 0/imm32 +12646 75/jump-if-!= break/disp8 +12647 $mu-stmt-matches-primitive?:prim-inout-null: +12648 b8/copy-to-eax 0/imm32/false +12649 e9/jump $mu-stmt-matches-primitive?:end/disp32 +12650 } +12651 # if (curr != curr2) return false +12652 { +12653 $mu-stmt-matches-primitive?:check-inouts-match: +12654 (lookup *edi *(edi+4)) # List-value List-value => eax +12655 (operand-matches-primitive? %esi %eax) # => eax +12656 3d/compare-eax-and 0/imm32/false +12657 75/jump-if-!= break/disp8 +12658 $mu-stmt-matches-primitive?:inouts-match: +12659 b8/copy-to-eax 0/imm32/false +12660 e9/jump $mu-stmt-matches-primitive?:end/disp32 +12661 } +12662 $mu-stmt-matches-primitive?:next-inout: +12663 # curr = lookup(curr->next) +12664 (lookup *(esi+8) *(esi+0xc)) # Stmt-var-next Stmt-var-next => eax +12665 89/<- %esi 0/r32/eax +12666 # curr2 = lookup(curr2->next) +12667 (lookup *(edi+8) *(edi+0xc)) # List-next List-next => eax +12668 89/<- %edi 0/r32/eax +12669 # +12670 e9/jump loop/disp32 +12671 } +12672 $mu-stmt-matches-primitive?:check-outputs: +12673 # var curr/esi: (addr stmt-var) = lookup(stmt->outputs) +12674 (lookup *(ecx+0x14) *(ecx+0x18)) # Stmt1-outputs Stmt1-outputs => eax +12675 89/<- %esi 0/r32/eax +12676 # var curr2/edi: (addr list var) = lookup(primitive->outputs) +12677 (lookup *(edx+0x10) *(edx+0x14)) # Primitive-outputs Primitive-outputs => eax +12678 89/<- %edi 0/r32/eax +12679 { +12680 $mu-stmt-matches-primitive?:outputs-loop: +12681 # if (curr == 0) return (curr2 == 0) +12682 { +12683 $mu-stmt-matches-primitive?:check-both-outputs-null: +12684 81 7/subop/compare %esi 0/imm32 +12685 75/jump-if-!= break/disp8 +12686 { +12687 $mu-stmt-matches-primitive?:stmt-output-null: +12688 81 7/subop/compare %edi 0/imm32 +12689 75/jump-if-!= break/disp8 +12690 $mu-stmt-matches-primitive?:both-outputs-null: +12691 # return true +12692 b8/copy-to-eax 1/imm32 +12693 e9/jump $mu-stmt-matches-primitive?:end/disp32 +12694 } +12695 $mu-stmt-matches-primitive?:stmt-output-null-and-prim-output-not-null: +12696 # return false +12697 b8/copy-to-eax 0/imm32 +12698 e9/jump $mu-stmt-matches-primitive?:end/disp32 +12699 } +12700 # if (curr2 == 0) return false +12701 { +12702 $mu-stmt-matches-primitive?:check-prim-output-null: +12703 81 7/subop/compare %edi 0/imm32 +12704 75/jump-if-!= break/disp8 +12705 $mu-stmt-matches-primitive?:prim-output-is-null: +12706 b8/copy-to-eax 0/imm32 +12707 e9/jump $mu-stmt-matches-primitive?:end/disp32 +12708 } +12709 # if (curr != curr2) return false +12710 { +12711 $mu-stmt-matches-primitive?:check-outputs-match: +12712 (lookup *edi *(edi+4)) # List-value List-value => eax +12713 (operand-matches-primitive? %esi %eax) # => eax +12714 3d/compare-eax-and 0/imm32/false +12715 75/jump-if-!= break/disp8 +12716 $mu-stmt-matches-primitive?:outputs-match: +12717 b8/copy-to-eax 0/imm32 +12718 e9/jump $mu-stmt-matches-primitive?:end/disp32 +12719 } +12720 $mu-stmt-matches-primitive?:next-output: +12721 # curr = lookup(curr->next) +12722 (lookup *(esi+8) *(esi+0xc)) # Stmt-var-next Stmt-var-next => eax +12723 89/<- %esi 0/r32/eax +12724 # curr2 = lookup(curr2->next) +12725 (lookup *(edi+8) *(edi+0xc)) # List-next List-next => eax +12726 89/<- %edi 0/r32/eax +12727 # +12728 e9/jump loop/disp32 +12729 } +12730 $mu-stmt-matches-primitive?:return-true: +12731 b8/copy-to-eax 1/imm32 +12732 $mu-stmt-matches-primitive?:end: +12733 # . restore registers +12734 5f/pop-to-edi +12735 5e/pop-to-esi +12736 5b/pop-to-ebx +12737 5a/pop-to-edx +12738 59/pop-to-ecx +12739 # . epilogue +12740 89/<- %esp 5/r32/ebp +12741 5d/pop-to-ebp +12742 c3/return +12743 +12744 operand-matches-primitive?: # s: (addr stmt-var), prim-var: (addr var) -> result/eax: boolean +12745 # . prologue +12746 55/push-ebp +12747 89/<- %ebp 4/r32/esp +12748 # . save registers +12749 51/push-ecx +12750 52/push-edx +12751 53/push-ebx +12752 56/push-esi +12753 57/push-edi +12754 # ecx = s +12755 8b/-> *(ebp+8) 1/r32/ecx +12756 # var var/esi: (addr var) = lookup(s->value) +12757 (lookup *ecx *(ecx+4)) # Stmt-var-value Stmt-var-value => eax +12758 89/<- %esi 0/r32/eax +12759 # edi = prim-var +12760 8b/-> *(ebp+0xc) 7/r32/edi +12761 $operand-matches-primitive?:check-type: +12762 # if (var->type != prim-var->type) return false +12763 # . var vtype/ebx: (addr tree type-id) = lookup(var->type) +12764 (lookup *(esi+8) *(esi+0xc)) # Var-type Var-type => eax +12765 89/<- %ebx 0/r32/eax +12766 # . var ptype/eax: (addr tree type-id) = lookup(prim-var->type) +12767 (lookup *(edi+8) *(edi+0xc)) # Var-type Var-type => eax +12768 (subx-type-equal? %ebx %eax) # => eax +12769 3d/compare-eax-and 0/imm32/false +12770 0f 84/jump-if-= $operand-matches-primitive?:return-false/disp32 +12771 { +12772 $operand-matches-primitive?:check-register: +12773 # if prim-var is in memory and var is in register but dereference, match +12774 { +12775 81 7/subop/compare *(edi+0x18) 0/imm32 # Var-register +12776 0f 85/jump-if-!= break/disp32 +12777 81 7/subop/compare *(esi+0x18) 0/imm32 # Var-register +12778 74/jump-if-= break/disp8 +12779 81 7/subop/compare *(ecx+0x10) 0/imm32/false # Stmt-var-is-deref +12780 74/jump-if-= break/disp8 +12781 $operand-matches-primitive?:var-deref-match: +12782 e9/jump $operand-matches-primitive?:return-true/disp32 +12783 } +12784 # if prim-var is in register and var is in register but dereference, no match +12785 { +12786 81 7/subop/compare *(edi+0x18) 0/imm32 # Var-register +12787 0f 84/jump-if-= break/disp32 +12788 81 7/subop/compare *(esi+0x18) 0/imm32 # Var-register +12789 0f 84/jump-if-= break/disp32 +12790 81 7/subop/compare *(ecx+0x10) 0/imm32/false # Stmt-var-is-deref +12791 74/jump-if-= break/disp8 +12792 $operand-matches-primitive?:var-deref-no-match: +12793 e9/jump $operand-matches-primitive?:return-false/disp32 +12794 } +12795 # return false if var->register doesn't match prim-var->register +12796 { +12797 # if register addresses are equal, it's a match +12798 # var vreg/ebx: (addr array byte) = lookup(var->register) +12799 (lookup *(esi+0x18) *(esi+0x1c)) # Var-register Var-register => eax +12800 89/<- %ebx 0/r32/eax +12801 # var preg/ecx: (addr array byte) = lookup(prim-var->register) +12802 (lookup *(edi+0x18) *(edi+0x1c)) # Var-register Var-register => eax +12803 89/<- %ecx 0/r32/eax +12804 # if (vreg == preg) break +12805 39/compare %ecx 3/r32/ebx +12806 74/jump-if-= break/disp8 +12807 $operand-matches-primitive?:var-register-no-match: +12808 # if either address is 0, return false +12809 81 7/subop/compare %ebx 0/imm32 +12810 74/jump-if-= $operand-matches-primitive?:return-false/disp8 +12811 81 7/subop/compare %ecx 0/imm32 +12812 74/jump-if-= $operand-matches-primitive?:return-false/disp8 +12813 # if prim-var->register is wildcard, it's a match +12814 (string-equal? %ecx "*") # Any-register => eax +12815 3d/compare-eax-and 0/imm32/false +12816 75/jump-if-!= break/disp8 +12817 $operand-matches-primitive?:wildcard-no-match: +12818 # if string contents aren't equal, return false +12819 (string-equal? %ecx %ebx) # => eax +12820 3d/compare-eax-and 0/imm32/false +12821 74/jump-if-= $operand-matches-primitive?:return-false/disp8 +12822 } +12823 } +12824 $operand-matches-primitive?:return-true: +12825 b8/copy-to-eax 1/imm32/true +12826 eb/jump $operand-matches-primitive?:end/disp8 +12827 $operand-matches-primitive?:return-false: +12828 b8/copy-to-eax 0/imm32/false +12829 $operand-matches-primitive?:end: +12830 # . restore registers +12831 5f/pop-to-edi +12832 5e/pop-to-esi +12833 5b/pop-to-ebx +12834 5a/pop-to-edx +12835 59/pop-to-ecx +12836 # . epilogue +12837 89/<- %esp 5/r32/ebp +12838 5d/pop-to-ebp +12839 c3/return +12840 +12841 subx-type-equal?: # a: (addr tree type-id), b: (addr tree type-id) -> result/eax: boolean +12842 # . prologue +12843 55/push-ebp +12844 89/<- %ebp 4/r32/esp +12845 # . save registers +12846 51/push-ecx +12847 # var alit/ecx: boolean = is-literal-type?(a) +12848 (is-simple-mu-type? *(ebp+8) 0) # => eax +12849 89/<- %ecx 0/r32/eax +12850 # var blit/eax: boolean = is-literal-type?(b) +12851 (is-simple-mu-type? *(ebp+0xc) 0) # => eax +12852 # return alit == blit +12853 39/compare %eax 1/r32/ecx +12854 0f 94/set-byte-if-= %al +12855 81 4/subop/and %eax 0xff/imm32 +12856 $subx-type-equal?:end: +12857 # . restore registers +12858 59/pop-to-ecx +12859 # . epilogue +12860 89/<- %esp 5/r32/ebp +12861 5d/pop-to-ebp +12862 c3/return +12863 +12864 is-simple-mu-type?: # a: (addr tree type-id), n: type-id -> result/eax: boolean +12865 # . prologue +12866 55/push-ebp +12867 89/<- %ebp 4/r32/esp +12868 # . save registers +12869 51/push-ecx +12870 # ecx = n +12871 8b/-> *(ebp+0xc) 1/r32/ecx +12872 # return (a->value == n) +12873 8b/-> *(ebp+8) 0/r32/eax +12874 39/compare *(eax+4) 1/r32/ecx # Tree-value +12875 0f 94/set-byte-if-= %al +12876 81 4/subop/and %eax 0xff/imm32 +12877 $is-simple-mu-type?:end: +12878 # . restore registers +12879 59/pop-to-ecx +12880 # . epilogue +12881 89/<- %esp 5/r32/ebp +12882 5d/pop-to-ebp +12883 c3/return +12884 +12885 test-emit-subx-stmt-primitive: +12886 # Primitive operation on a variable on the stack. +12887 # increment foo +12888 # => +12889 # ff 0/subop/increment *(ebp-8) +12890 # +12891 # There's a variable on the var stack as follows: +12892 # name: 'foo' +12893 # type: int +12894 # stack-offset: -8 +12895 # +12896 # There's a primitive with this info: +12897 # name: 'increment' +12898 # inouts: int/mem +12899 # value: 'ff 0/subop/increment' +12900 # +12901 # . prologue +12902 55/push-ebp +12903 89/<- %ebp 4/r32/esp +12904 # setup +12905 (clear-stream _test-output-stream) +12906 (clear-stream $_test-output-buffered-file->buffer) +12907 # simulate allocated payloads starting with an initial fake alloc-id (0x11) +12908 $test-emit-subx-stmt-primitive:initialize-type: +12909 # var type/ecx: (payload tree type-id) = int +12910 68/push 0/imm32/right:null +12911 68/push 0/imm32/right:null +12912 68/push 0/imm32/left:unused +12913 68/push 1/imm32/value:int +12914 68/push 1/imm32/is-atom?:true +12915 68/push 0x11/imm32/alloc-id:fake:payload +12916 89/<- %ecx 4/r32/esp +12917 $test-emit-subx-stmt-primitive:initialize-var: +12918 # var var-foo/ecx: (payload var) = var(type) +12919 68/push 0/imm32/no-register +12920 68/push 0/imm32/no-register +12921 68/push -8/imm32/stack-offset +12922 68/push 1/imm32/block-depth +12923 51/push-ecx/type +12924 68/push 0x11/imm32/alloc-id:fake +12925 68/push 0/imm32/name +12926 68/push 0/imm32/name +12927 68/push 0x11/imm32/alloc-id:fake:payload +12928 89/<- %ecx 4/r32/esp +12929 $test-emit-subx-stmt-primitive:initialize-var-name: +12930 # var-foo->name = "foo" +12931 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 +12932 (copy-array Heap "foo" %eax) +12933 $test-emit-subx-stmt-primitive:initialize-stmt-var: +12934 # var operand/ebx: (payload stmt-var) = stmt-var(var-foo) +12935 68/push 0/imm32/is-deref:false +12936 68/push 0/imm32/next +12937 68/push 0/imm32/next +12938 51/push-ecx/var-foo +12939 68/push 0x11/imm32/alloc-id:fake +12940 68/push 0x11/imm32/alloc-id:fake:payload +12941 89/<- %ebx 4/r32/esp +12942 $test-emit-subx-stmt-primitive:initialize-stmt: +12943 # var stmt/esi: (addr statement) +12944 68/push 0/imm32/no-outputs +12945 68/push 0/imm32/no-outputs +12946 53/push-ebx/inouts +12947 68/push 0x11/imm32/alloc-id:fake +12948 68/push 0/imm32/operation +12949 68/push 0/imm32/operation +12950 68/push 1/imm32/tag +12951 89/<- %esi 4/r32/esp +12952 $test-emit-subx-stmt-primitive:initialize-stmt-operation: +12953 # stmt->operation = "increment" +12954 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation +12955 (copy-array Heap "increment" %eax) +12956 $test-emit-subx-stmt-primitive:initialize-primitive: +12957 # var primitives/ebx: (addr primitive) +12958 68/push 0/imm32/next +12959 68/push 0/imm32/next +12960 68/push 0/imm32/output-is-write-only +12961 68/push 0/imm32/no-disp32 +12962 68/push 0/imm32/no-imm32 +12963 68/push 0/imm32/no-r32 +12964 68/push 1/imm32/rm32-is-first-inout +12965 68/push 0/imm32/subx-name +12966 68/push 0/imm32/subx-name +12967 68/push 0/imm32/no-outputs +12968 68/push 0/imm32/no-outputs +12969 53/push-ebx/inouts # hack: reuse stmt-var from call stmt as (list var) in function declaration +12970 68/push 0x11/imm32/alloc-id:fake +12971 68/push 0/imm32/name +12972 68/push 0/imm32/name +12973 89/<- %ebx 4/r32/esp +12974 $test-emit-subx-stmt-primitive:initialize-primitive-name: +12975 # primitives->name = "increment" +12976 (copy-array Heap "increment" %ebx) # Primitive-name +12977 $test-emit-subx-stmt-primitive:initialize-primitive-subx-name: +12978 # primitives->subx-name = "ff 0/subop/increment" +12979 8d/copy-address *(ebx+0x18) 0/r32/eax # Primitive-subx-name +12980 (copy-array Heap "ff 0/subop/increment" %eax) +12981 # convert +12982 c7 0/subop/copy *Curr-block-depth 0/imm32 +12983 (emit-subx-stmt _test-output-buffered-file %esi %ebx) +12984 (flush _test-output-buffered-file) +12985 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +12991 # check output +12992 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-stmt-primitive") +12993 # . epilogue +12994 89/<- %esp 5/r32/ebp +12995 5d/pop-to-ebp +12996 c3/return +12997 +12998 test-emit-subx-stmt-primitive-register: +12999 # Primitive operation on a variable in a register. +13000 # foo <- increment +13001 # => +13002 # ff 0/subop/increment %eax # sub-optimal, but should suffice +13003 # +13004 # There's a variable on the var stack as follows: +13005 # name: 'foo' +13006 # type: int +13007 # register: 'eax' +13008 # +13009 # There's a primitive with this info: +13010 # name: 'increment' +13011 # out: int/reg +13012 # value: 'ff 0/subop/increment' +13013 # +13014 # . prologue +13015 55/push-ebp +13016 89/<- %ebp 4/r32/esp +13017 # setup +13018 (clear-stream _test-output-stream) +13019 (clear-stream $_test-output-buffered-file->buffer) +13020 $test-emit-subx-stmt-primitive-register:initialize-type: +13021 # var type/ecx: (payload tree type-id) = int +13022 68/push 0/imm32/right:null +13023 68/push 0/imm32/right:null +13024 68/push 0/imm32/left:unused +13025 68/push 1/imm32/value:int +13026 68/push 1/imm32/is-atom?:true +13027 68/push 0x11/imm32/alloc-id:fake:payload +13028 89/<- %ecx 4/r32/esp +13029 $test-emit-subx-stmt-primitive-register:initialize-var: +13030 # var var-foo/ecx: (payload var) +13031 68/push 0/imm32/register +13032 68/push 0/imm32/register +13033 68/push 0/imm32/no-stack-offset +13034 68/push 1/imm32/block-depth +13035 51/push-ecx +13036 68/push 0x11/imm32/alloc-id:fake +13037 68/push 0/imm32/name +13038 68/push 0/imm32/name +13039 68/push 0x11/imm32/alloc-id:fake:payload +13040 89/<- %ecx 4/r32/esp +13041 $test-emit-subx-stmt-primitive-register:initialize-var-name: +13042 # var-foo->name = "foo" +13043 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 +13044 (copy-array Heap "foo" %eax) +13045 $test-emit-subx-stmt-primitive-register:initialize-var-register: +13046 # var-foo->register = "eax" +13047 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 +13048 (copy-array Heap "eax" %eax) +13049 $test-emit-subx-stmt-primitive-register:initialize-stmt-var: +13050 # var operand/ebx: (payload stmt-var) +13051 68/push 0/imm32/is-deref:false +13052 68/push 0/imm32/next +13053 68/push 0/imm32/next +13054 51/push-ecx/var-foo +13055 68/push 0x11/imm32/alloc-id:fake +13056 68/push 0x11/imm32/alloc-id:fake:payload +13057 89/<- %ebx 4/r32/esp +13058 $test-emit-subx-stmt-primitive-register:initialize-stmt: +13059 # var stmt/esi: (addr statement) +13060 53/push-ebx/outputs +13061 68/push 0x11/imm32/alloc-id:fake +13062 68/push 0/imm32/no-inouts +13063 68/push 0/imm32/no-inouts +13064 68/push 0/imm32/operation +13065 68/push 0/imm32/operation +13066 68/push 1/imm32 +13067 89/<- %esi 4/r32/esp +13068 $test-emit-subx-stmt-primitive-register:initialize-stmt-operation: +13069 # stmt->operation = "increment" +13070 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation +13071 (copy-array Heap "increment" %eax) +13072 $test-emit-subx-stmt-primitive-register:initialize-formal-var: +13073 # var formal-var/ebx: (payload var) +13074 68/push 0/imm32/register +13075 68/push 0/imm32/register +13076 68/push 0/imm32/no-stack-offset +13077 68/push 1/imm32/block-depth +13078 ff 6/subop/push *(ecx+0x10) # Var-type + payload alloc id + handle alloc id +13079 68/push 0x11/imm32/alloc-id:fake +13080 68/push 0/imm32/name +13081 68/push 0/imm32/name +13082 68/push 0x11/imm32/alloc-id:fake:payload +13083 89/<- %ebx 4/r32/esp +13084 $test-emit-subx-stmt-primitive-register:initialize-formal-var-name: +13085 # formal-var->name = "dummy" +13086 8d/copy-address *(ebx+4) 0/r32/eax # Var-name + 4 +13087 (copy-array Heap "dummy" %eax) +13088 $test-emit-subx-stmt-primitive-register:initialize-formal-register: +13089 # formal-var->register = "*" +13090 8d/copy-address *(ebx+0x1c) 0/r32/eax # Var-register + 4 +13091 (copy-array Heap "*" %eax) # Any-register +13092 $test-emit-subx-stmt-primitive-register:initialize-var-list: +13093 # var formal-outputs/ebx: (payload list var) +13094 68/push 0/imm32/next +13095 68/push 0/imm32/next +13096 53/push-ebx/formal-var +13097 68/push 0x11/imm32/alloc-id:fake +13098 68/push 0x11/imm32/alloc-id:fake:payload +13099 89/<- %ebx 4/r32/esp +13100 $test-emit-subx-stmt-primitive-register:initialize-primitive: +13101 # var primitives/ebx: (addr primitive) +13102 68/push 0/imm32/next +13103 68/push 0/imm32/next +13104 68/push 0/imm32/output-is-write-only +13105 68/push 0/imm32/no-disp32 +13106 68/push 0/imm32/no-imm32 +13107 68/push 0/imm32/no-r32 +13108 68/push 3/imm32/rm32-is-first-output +13109 68/push 0/imm32/subx-name +13110 68/push 0/imm32/subx-name +13111 53/push-ebx/outputs +13112 68/push 0x11/imm32/alloc-id:fake +13113 68/push 0/imm32/no-inouts +13114 68/push 0/imm32/no-inouts +13115 68/push 0/imm32/name +13116 68/push 0/imm32/name +13117 89/<- %ebx 4/r32/esp +13118 $test-emit-subx-stmt-primitive-register:initialize-primitive-name: +13119 # primitives->name = "increment" +13120 (copy-array Heap "increment" %ebx) # Primitive-name +13121 $test-emit-subx-stmt-primitive-register:initialize-primitive-subx-name: +13122 # primitives->subx-name = "ff 0/subop/increment" +13123 8d/copy-address *(ebx+0x18) 0/r32/eax # Primitive-subx-name +13124 (copy-array Heap "ff 0/subop/increment" %eax) +13125 # convert +13126 c7 0/subop/copy *Curr-block-depth 0/imm32 +13127 (emit-subx-stmt _test-output-buffered-file %esi %ebx) +13128 (flush _test-output-buffered-file) +13129 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +13135 # check output +13136 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-primitive-register") +13137 # . epilogue +13138 89/<- %esp 5/r32/ebp +13139 5d/pop-to-ebp +13140 c3/return +13141 +13142 test-emit-subx-stmt-select-primitive: +13143 # Select the right primitive between overloads. +13144 # foo <- increment +13145 # => +13146 # ff 0/subop/increment %eax # sub-optimal, but should suffice +13147 # +13148 # There's a variable on the var stack as follows: +13149 # name: 'foo' +13150 # type: int +13151 # register: 'eax' +13152 # +13153 # There's two primitives, as follows: +13154 # - name: 'increment' +13155 # out: int/reg +13156 # value: 'ff 0/subop/increment' +13157 # - name: 'increment' +13158 # inout: int/mem +13159 # value: 'ff 0/subop/increment' +13160 # +13161 # . prologue +13162 55/push-ebp +13163 89/<- %ebp 4/r32/esp +13164 # setup +13165 (clear-stream _test-output-stream) +13166 (clear-stream $_test-output-buffered-file->buffer) +13167 $test-emit-subx-stmt-select-primitive:initialize-type: +13168 # var type/ecx: (payload tree type-id) = int +13169 68/push 0/imm32/right:null +13170 68/push 0/imm32/right:null +13171 68/push 0/imm32/left:unused +13172 68/push 1/imm32/value:int +13173 68/push 1/imm32/is-atom?:true +13174 68/push 0x11/imm32/alloc-id:fake:payload +13175 89/<- %ecx 4/r32/esp +13176 $test-emit-subx-stmt-select-primitive:initialize-var: +13177 # var var-foo/ecx: (payload var) +13178 68/push 0/imm32/register +13179 68/push 0/imm32/register +13180 68/push 0/imm32/no-stack-offset +13181 68/push 1/imm32/block-depth +13182 51/push-ecx +13183 68/push 0x11/imm32/alloc-id:fake +13184 68/push 0/imm32/name +13185 68/push 0/imm32/name +13186 68/push 0x11/imm32/alloc-id:fake:payload +13187 89/<- %ecx 4/r32/esp +13188 $test-emit-subx-stmt-select-primitive:initialize-var-name: +13189 # var-foo->name = "foo" +13190 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 +13191 (copy-array Heap "foo" %eax) +13192 $test-emit-subx-stmt-select-primitive:initialize-var-register: +13193 # var-foo->register = "eax" +13194 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 +13195 (copy-array Heap "eax" %eax) +13196 $test-emit-subx-stmt-select-primitive:initialize-stmt-var: +13197 # var operand/ebx: (payload stmt-var) +13198 68/push 0/imm32/is-deref:false +13199 68/push 0/imm32/next +13200 68/push 0/imm32/next +13201 51/push-ecx/var-foo +13202 68/push 0x11/imm32/alloc-id:fake +13203 68/push 0x11/imm32/alloc-id:fake:payload +13204 89/<- %ebx 4/r32/esp +13205 $test-emit-subx-stmt-select-primitive:initialize-stmt: +13206 # var stmt/esi: (addr statement) +13207 53/push-ebx/outputs +13208 68/push 0x11/imm32/alloc-id:fake +13209 68/push 0/imm32/no-inouts +13210 68/push 0/imm32/no-inouts +13211 68/push 0/imm32/operation +13212 68/push 0/imm32/operation +13213 68/push 1/imm32 +13214 89/<- %esi 4/r32/esp +13215 $test-emit-subx-stmt-select-primitive:initialize-stmt-operation: +13216 # stmt->operation = "increment" +13217 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation +13218 (copy-array Heap "increment" %eax) +13219 $test-emit-subx-stmt-select-primitive:initialize-formal-var: +13220 # var formal-var/ebx: (payload var) +13221 68/push 0/imm32/register +13222 68/push 0/imm32/register +13223 68/push 0/imm32/no-stack-offset +13224 68/push 1/imm32/block-depth +13225 ff 6/subop/push *(ecx+0x10) # Var-type + payload alloc id + handle alloc id +13226 68/push 0x11/imm32/alloc-id:fake +13227 68/push 0/imm32/name +13228 68/push 0/imm32/name +13229 68/push 0x11/imm32/alloc-id:fake:payload +13230 89/<- %ebx 4/r32/esp +13231 $test-emit-subx-stmt-select-primitive:initialize-formal-var-name: +13232 # formal-var->name = "dummy" +13233 8d/copy-address *(ebx+4) 0/r32/eax # Var-name + 4 +13234 (copy-array Heap "dummy" %eax) +13235 $test-emit-subx-stmt-select-primitive:initialize-formal-register: +13236 # formal-var->register = "*" +13237 8d/copy-address *(ebx+0x1c) 0/r32/eax # Var-register + 4 +13238 (copy-array Heap "*" %eax) # Any-register +13239 $test-emit-subx-stmt-select-primitive:initialize-var-list: +13240 # var formal-outputs/ebx: (payload list var) +13241 68/push 0/imm32/next +13242 68/push 0/imm32/next +13243 53/push-ebx/formal-var +13244 68/push 0x11/imm32/alloc-id:fake +13245 68/push 0x11/imm32/alloc-id:fake:payload +13246 89/<- %ebx 4/r32/esp +13247 $test-emit-subx-stmt-select-primitive:initialize-primitive2: +13248 # var primitive2/edi: (payload primitive) +13249 68/push 0/imm32/next +13250 68/push 0/imm32/next +13251 68/push 0/imm32/output-is-write-only +13252 68/push 0/imm32/no-disp32 +13253 68/push 0/imm32/no-imm32 +13254 68/push 0/imm32/no-r32 +13255 68/push 3/imm32/rm32-is-first-output +13256 68/push 0/imm32/subx-name +13257 68/push 0/imm32/subx-name +13258 53/push-ebx/outputs +13259 68/push 0x11/imm32/alloc-id:fake +13260 68/push 0/imm32/no-inouts +13261 68/push 0/imm32/no-inouts +13262 68/push 0/imm32/name +13263 68/push 0/imm32/name +13264 68/push 0x11/imm32/alloc-id:fake:payload +13265 89/<- %edi 4/r32/esp +13266 $test-emit-subx-stmt-select-primitive:initialize-primitive2-name: +13267 # primitives->name = "increment" +13268 8d/copy-address *(edi+4) 0/r32/eax # Primitive-name + 4 +13269 (copy-array Heap "increment" %eax) +13270 $test-emit-subx-stmt-select-primitive:initialize-primitive2-subx-name: +13271 # primitives->subx-name = "ff 0/subop/increment" +13272 8d/copy-address *(edi+0x1c) 0/r32/eax # Primitive-subx-name + 4 +13273 (copy-array Heap "ff 0/subop/increment" %eax) +13274 $test-emit-subx-stmt-select-primitive:initialize-primitive: +13275 # var primitives/ebx: (addr primitive) +13276 57/push-edi +13277 68/push 0x11/imm32/alloc-id:fake +13278 68/push 0/imm32/output-is-write-only +13279 68/push 0/imm32/no-disp32 +13280 68/push 0/imm32/no-imm32 +13281 68/push 0/imm32/no-r32 +13282 68/push 1/imm32/rm32-is-first-inout +13283 68/push 0/imm32/subx-name +13284 68/push 0/imm32/subx-name +13285 68/push 0/imm32/no-outputs +13286 68/push 0/imm32/no-outputs +13287 53/push-ebx/inouts # hack: reuse stmt-var from call stmt as (list var) in function declaration +13288 68/push 0x11/imm32/alloc-id:fake +13289 68/push 0/imm32/name +13290 68/push 0/imm32/name +13291 89/<- %ebx 4/r32/esp +13292 $test-emit-subx-stmt-select-primitive:initialize-primitive-name: +13293 # primitives->name = "increment" +13294 (copy-array Heap "increment" %ebx) # Primitive-name +13295 $test-emit-subx-stmt-select-primitive:initialize-primitive-subx-name: +13296 # primitives->subx-name = "ff 0/subop/increment" +13297 8d/copy-address *(ebx+0x18) 0/r32/eax # Primitive-subx-name +13298 (copy-array Heap "ff 0/subop/increment" %eax) +13299 # convert +13300 c7 0/subop/copy *Curr-block-depth 0/imm32 +13301 (emit-subx-stmt _test-output-buffered-file %esi %ebx) +13302 (flush _test-output-buffered-file) +13303 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +13309 # check output +13310 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive") +13311 # . epilogue +13312 89/<- %esp 5/r32/ebp +13313 5d/pop-to-ebp +13314 c3/return +13315 +13316 test-emit-subx-stmt-select-primitive-2: +13317 # Select the right primitive between overloads. +13318 # increment foo +13319 # => +13320 # ff 0/subop/increment %eax # sub-optimal, but should suffice +13321 # +13322 # There's a variable on the var stack as follows: +13323 # name: 'foo' +13324 # type: int +13325 # register: 'eax' +13326 # +13327 # There's two primitives, as follows: +13328 # - name: 'increment' +13329 # out: int/reg +13330 # value: 'ff 0/subop/increment' +13331 # - name: 'increment' +13332 # inout: int/mem +13333 # value: 'ff 0/subop/increment' +13334 # +13335 # . prologue +13336 55/push-ebp +13337 89/<- %ebp 4/r32/esp +13338 # setup +13339 (clear-stream _test-output-stream) +13340 (clear-stream $_test-output-buffered-file->buffer) +13341 $test-emit-subx-stmt-select-primitive-2:initialize-type: +13342 # var type/ecx: (payload tree type-id) = int +13343 68/push 0/imm32/right:null +13344 68/push 0/imm32/right:null +13345 68/push 0/imm32/left:unused +13346 68/push 1/imm32/value:int +13347 68/push 1/imm32/is-atom?:true +13348 68/push 0x11/imm32/alloc-id:fake:payload +13349 89/<- %ecx 4/r32/esp +13350 $test-emit-subx-stmt-select-primitive-2:initialize-var: +13351 # var var-foo/ecx: (payload var) +13352 68/push 0/imm32/register +13353 68/push 0/imm32/register +13354 68/push 0/imm32/no-stack-offset +13355 68/push 1/imm32/block-depth +13356 51/push-ecx +13357 68/push 0x11/imm32/alloc-id:fake +13358 68/push 0/imm32/name +13359 68/push 0/imm32/name +13360 68/push 0x11/imm32/alloc-id:fake:payload +13361 89/<- %ecx 4/r32/esp +13362 $test-emit-subx-stmt-select-primitive-2:initialize-var-name: +13363 # var-foo->name = "foo" +13364 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 +13365 (copy-array Heap "foo" %eax) +13366 $test-emit-subx-stmt-select-primitive-2:initialize-var-register: +13367 # var-foo->register = "eax" +13368 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 +13369 (copy-array Heap "eax" %eax) +13370 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-var: +13371 # var operand/ebx: (payload stmt-var) +13372 68/push 0/imm32/is-deref:false +13373 68/push 0/imm32/next +13374 68/push 0/imm32/next +13375 51/push-ecx/var-foo +13376 68/push 0x11/imm32/alloc-id:fake +13377 68/push 0x11/imm32/alloc-id:fake:payload +13378 89/<- %ebx 4/r32/esp +13379 $test-emit-subx-stmt-select-primitive-2:initialize-stmt: +13380 # var stmt/esi: (addr statement) +13381 68/push 0/imm32/no-outputs +13382 68/push 0/imm32/no-outputs +13383 53/push-ebx/inouts +13384 68/push 0x11/imm32/alloc-id:fake +13385 68/push 0/imm32/operation +13386 68/push 0/imm32/operation +13387 68/push 1/imm32 +13388 89/<- %esi 4/r32/esp +13389 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-operation: +13390 # stmt->operation = "increment" +13391 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation +13392 (copy-array Heap "increment" %eax) +13393 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var: +13394 # var formal-var/ebx: (payload var) +13395 68/push 0/imm32/register +13396 68/push 0/imm32/register +13397 68/push 0/imm32/no-stack-offset +13398 68/push 1/imm32/block-depth +13399 ff 6/subop/push *(ecx+0x10) # Var-type + payload alloc id + handle alloc id +13400 68/push 0x11/imm32/alloc-id:fake +13401 68/push 0/imm32/name +13402 68/push 0/imm32/name +13403 68/push 0x11/imm32/alloc-id:fake:payload +13404 89/<- %ebx 4/r32/esp +13405 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var-name: +13406 # formal-var->name = "dummy" +13407 8d/copy-address *(ebx+4) 0/r32/eax # Var-name + 4 +13408 (copy-array Heap "dummy" %eax) +13409 $test-emit-subx-stmt-select-primitive-2:initialize-formal-register: +13410 # formal-var->register = "*" +13411 8d/copy-address *(ebx+0x1c) 0/r32/eax # Var-register + 4 +13412 (copy-array Heap "*" %eax) # Any-register +13413 $test-emit-subx-stmt-select-primitive-2:initialize-var-list: +13414 # var formal-outputs/ebx: (payload list stmt-var) +13415 68/push 0/imm32/next +13416 68/push 0/imm32/next +13417 53/push-ebx/formal-var +13418 68/push 0x11/imm32/alloc-id:fake +13419 68/push 0x11/imm32/alloc-id:fake:payload +13420 89/<- %ebx 4/r32/esp +13421 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2: +13422 # var primitive2/edi: (payload primitive) +13423 68/push 0/imm32/next +13424 68/push 0/imm32/next +13425 68/push 0/imm32/output-is-write-only +13426 68/push 0/imm32/no-disp32 +13427 68/push 0/imm32/no-imm32 +13428 68/push 0/imm32/no-r32 +13429 68/push 3/imm32/rm32-is-first-output +13430 68/push 0/imm32/subx-name +13431 68/push 0/imm32/subx-name +13432 53/push-ebx/outputs +13433 68/push 0x11/imm32/alloc-id:fake +13434 68/push 0/imm32/no-inouts +13435 68/push 0/imm32/no-inouts +13436 68/push 0/imm32/name +13437 68/push 0/imm32/name +13438 68/push 0x11/imm32/alloc-id:fake:payload +13439 89/<- %edi 4/r32/esp +13440 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-name: +13441 # primitives->name = "increment" +13442 8d/copy-address *(edi+4) 0/r32/eax # Primitive-name + 4 +13443 (copy-array Heap "increment" %eax) +13444 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-subx-name: +13445 # primitives->subx-name = "ff 0/subop/increment" +13446 8d/copy-address *(edi+0x1c) 0/r32/eax # Primitive-subx-name + 4 +13447 (copy-array Heap "ff 0/subop/increment" %eax) +13448 $test-emit-subx-stmt-select-primitive-2:initialize-primitive: +13449 # var primitives/ebx: (addr primitive) +13450 57/push-edi +13451 68/push 0x11/imm32/alloc-id:fake +13452 68/push 0/imm32/output-is-write-only +13453 68/push 0/imm32/no-disp32 +13454 68/push 0/imm32/no-imm32 +13455 68/push 0/imm32/no-r32 +13456 68/push 1/imm32/rm32-is-first-inout +13457 68/push 0/imm32/subx-name +13458 68/push 0/imm32/subx-name +13459 68/push 0/imm32/no-outputs +13460 68/push 0/imm32/no-outputs +13461 53/push-ebx/inouts # hack: reuse stmt-var from call stmt as (list var) in function declaration +13462 68/push 0x11/imm32/alloc-id:fake +13463 68/push 0/imm32/name +13464 68/push 0/imm32/name +13465 89/<- %ebx 4/r32/esp +13466 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-name: +13467 # primitives->name = "increment" +13468 (copy-array Heap "increment" %ebx) # Primitive-name +13469 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-subx-name: +13470 # primitives->subx-name = "ff 0/subop/increment" +13471 8d/copy-address *(ebx+0x18) 0/r32/eax # Primitive-subx-name +13472 (copy-array Heap "ff 0/subop/increment" %eax) +13473 # convert +13474 c7 0/subop/copy *Curr-block-depth 0/imm32 +13475 (emit-subx-stmt _test-output-buffered-file %esi %ebx) +13476 (flush _test-output-buffered-file) +13477 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +13483 # check output +13484 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive-2") +13485 # . epilogue +13486 89/<- %esp 5/r32/ebp +13487 5d/pop-to-ebp +13488 c3/return +13489 +13490 test-increment-register: +13491 # Select the right register between overloads. +13492 # foo <- increment +13493 # => +13494 # 50/increment-eax +13495 # +13496 # There's a variable on the var stack as follows: +13497 # name: 'foo' +13498 # type: int +13499 # register: 'eax' +13500 # +13501 # Primitives are the global definitions. +13502 # +13503 # . prologue +13504 55/push-ebp +13505 89/<- %ebp 4/r32/esp +13506 # setup +13507 (clear-stream _test-output-stream) +13508 (clear-stream $_test-output-buffered-file->buffer) +13509 $test-increment-register:initialize-type: +13510 # var type/ecx: (payload tree type-id) = int +13511 68/push 0/imm32/right:null +13512 68/push 0/imm32/right:null +13513 68/push 0/imm32/left:unused +13514 68/push 1/imm32/value:int +13515 68/push 1/imm32/is-atom?:true +13516 68/push 0x11/imm32/alloc-id:fake:payload +13517 89/<- %ecx 4/r32/esp +13518 $test-increment-register:initialize-var: +13519 # var var-foo/ecx: (payload var) +13520 68/push 0/imm32/register +13521 68/push 0/imm32/register +13522 68/push 0/imm32/no-stack-offset +13523 68/push 1/imm32/block-depth +13524 51/push-ecx +13525 68/push 0x11/imm32/alloc-id:fake +13526 68/push 0/imm32/name +13527 68/push 0/imm32/name +13528 68/push 0x11/imm32/alloc-id:fake:payload +13529 89/<- %ecx 4/r32/esp +13530 $test-increment-register:initialize-var-name: +13531 # var-foo->name = "foo" +13532 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 +13533 (copy-array Heap "foo" %eax) +13534 $test-increment-register:initialize-var-register: +13535 # var-foo->register = "eax" +13536 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 +13537 (copy-array Heap "eax" %eax) +13538 $test-increment-register:initialize-stmt-var: +13539 # var operand/ebx: (payload stmt-var) +13540 68/push 0/imm32/is-deref:false +13541 68/push 0/imm32/next +13542 68/push 0/imm32/next +13543 51/push-ecx/var-foo +13544 68/push 0x11/imm32/alloc-id:fake +13545 68/push 0x11/imm32/alloc-id:fake:payload +13546 89/<- %ebx 4/r32/esp +13547 $test-increment-register:initialize-stmt: +13548 # var stmt/esi: (addr statement) +13549 53/push-ebx/outputs +13550 68/push 0x11/imm32/alloc-id:fake +13551 68/push 0/imm32/no-inouts +13552 68/push 0/imm32/no-inouts +13553 68/push 0/imm32/operation +13554 68/push 0/imm32/operation +13555 68/push 1/imm32 +13556 89/<- %esi 4/r32/esp +13557 $test-increment-register:initialize-stmt-operation: +13558 # stmt->operation = "increment" +13559 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation +13560 (copy-array Heap "increment" %eax) +13561 # convert +13562 c7 0/subop/copy *Curr-block-depth 0/imm32 +13563 (emit-subx-stmt _test-output-buffered-file %esi Primitives) +13564 (flush _test-output-buffered-file) +13565 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +13571 # check output +13572 (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register") +13573 # . epilogue +13574 89/<- %esp 5/r32/ebp +13575 5d/pop-to-ebp +13576 c3/return +13577 +13578 test-add-reg-to-reg: +13579 # var1/reg <- add var2/reg +13580 # => +13581 # 01/add-to %var1 var2 +13582 # +13583 # . prologue +13584 55/push-ebp +13585 89/<- %ebp 4/r32/esp +13586 # setup +13587 (clear-stream _test-output-stream) +13588 (clear-stream $_test-output-buffered-file->buffer) +13589 $test-add-reg-to-reg:initialize-type: +13590 # var type/ecx: (payload tree type-id) = int +13591 68/push 0/imm32/right:null +13592 68/push 0/imm32/right:null +13593 68/push 0/imm32/left:unused +13594 68/push 1/imm32/value:int +13595 68/push 1/imm32/is-atom?:true +13596 68/push 0x11/imm32/alloc-id:fake:payload +13597 89/<- %ecx 4/r32/esp +13598 $test-add-reg-to-reg:initialize-var1: +13599 # var var1/ecx: (payload var) +13600 68/push 0/imm32/register +13601 68/push 0/imm32/register +13602 68/push 0/imm32/no-stack-offset +13603 68/push 1/imm32/block-depth +13604 51/push-ecx +13605 68/push 0x11/imm32/alloc-id:fake +13606 68/push 0/imm32/name +13607 68/push 0/imm32/name +13608 68/push 0x11/imm32/alloc-id:fake:payload +13609 89/<- %ecx 4/r32/esp +13610 $test-add-reg-to-reg:initialize-var1-name: +13611 # var1->name = "var1" +13612 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 +13613 (copy-array Heap "var1" %eax) +13614 $test-add-reg-to-reg:initialize-var1-register: +13615 # var1->register = "eax" +13616 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 +13617 (copy-array Heap "eax" %eax) +13618 $test-add-reg-to-reg:initialize-var2: +13619 # var var2/edx: (payload var) +13620 68/push 0/imm32/register +13621 68/push 0/imm32/register +13622 68/push 0/imm32/no-stack-offset +13623 68/push 1/imm32/block-depth +13624 ff 6/subop/push *(ecx+0x10) +13625 68/push 0x11/imm32/alloc-id:fake +13626 68/push 0/imm32/name +13627 68/push 0/imm32/name +13628 68/push 0x11/imm32/alloc-id:fake:payload +13629 89/<- %edx 4/r32/esp +13630 $test-add-reg-to-reg:initialize-var2-name: +13631 # var2->name = "var2" +13632 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 +13633 (copy-array Heap "var2" %eax) +13634 $test-add-reg-to-reg:initialize-var2-register: +13635 # var2->register = "ecx" +13636 8d/copy-address *(edx+0x1c) 0/r32/eax # Var-register + 4 +13637 (copy-array Heap "ecx" %eax) +13638 $test-add-reg-to-reg:initialize-inouts: +13639 # var inouts/esi: (payload stmt-var) = [var2] +13640 68/push 0/imm32/is-deref:false +13641 68/push 0/imm32/next +13642 68/push 0/imm32/next +13643 52/push-edx/var2 +13644 68/push 0x11/imm32/alloc-id:fake +13645 68/push 0x11/imm32/alloc-id:fake:payload +13646 89/<- %esi 4/r32/esp +13647 $test-add-reg-to-reg:initialize-outputs: +13648 # var outputs/edi: (payload stmt-var) = [var1] +13649 68/push 0/imm32/is-deref:false +13650 68/push 0/imm32/next +13651 68/push 0/imm32/next +13652 51/push-ecx/var1 +13653 68/push 0x11/imm32/alloc-id:fake +13654 68/push 0x11/imm32/alloc-id:fake:payload +13655 89/<- %edi 4/r32/esp +13656 $test-add-reg-to-reg:initialize-stmt: +13657 # var stmt/esi: (addr statement) +13658 68/push 0/imm32/next +13659 68/push 0/imm32/next +13660 57/push-edi/outputs +13661 68/push 0x11/imm32/alloc-id:fake +13662 56/push-esi/inouts +13663 68/push 0x11/imm32/alloc-id:fake +13664 68/push 0/imm32/operation +13665 68/push 0/imm32/operation +13666 68/push 1/imm32/tag:stmt1 +13667 89/<- %esi 4/r32/esp +13668 $test-add-reg-to-reg:initialize-stmt-operation: +13669 # stmt->operation = "add" +13670 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation +13671 (copy-array Heap "add" %eax) +13672 # convert +13673 c7 0/subop/copy *Curr-block-depth 0/imm32 +13674 (emit-subx-stmt _test-output-buffered-file %esi Primitives) +13675 (flush _test-output-buffered-file) +13676 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +13682 # check output +13683 (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg") +13684 # . epilogue +13685 89/<- %esp 5/r32/ebp +13686 5d/pop-to-ebp +13687 c3/return +13688 +13689 test-add-reg-to-mem: +13690 # add-to var1 var2/reg +13691 # => +13692 # 01/add-to *(ebp+__) var2 +13693 # +13694 # . prologue +13695 55/push-ebp +13696 89/<- %ebp 4/r32/esp +13697 # setup +13698 (clear-stream _test-output-stream) +13699 (clear-stream $_test-output-buffered-file->buffer) +13700 $test-add-reg-to-mem:initialize-type: +13701 # var type/ecx: (payload tree type-id) = int +13702 68/push 0/imm32/right:null +13703 68/push 0/imm32/right:null +13704 68/push 0/imm32/left:unused +13705 68/push 1/imm32/value:int +13706 68/push 1/imm32/is-atom?:true +13707 68/push 0x11/imm32/alloc-id:fake:payload +13708 89/<- %ecx 4/r32/esp +13709 $test-add-reg-to-mem:initialize-var1: +13710 # var var1/ecx: (payload var) +13711 68/push 0/imm32/register +13712 68/push 0/imm32/register +13713 68/push 8/imm32/stack-offset +13714 68/push 1/imm32/block-depth +13715 51/push-ecx +13716 68/push 0x11/imm32/alloc-id:fake +13717 68/push 0/imm32/name +13718 68/push 0/imm32/name +13719 68/push 0x11/imm32/alloc-id:fake:payload +13720 89/<- %ecx 4/r32/esp +13721 $test-add-reg-to-mem:initialize-var1-name: +13722 # var1->name = "var1" +13723 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 +13724 (copy-array Heap "var1" %eax) +13725 $test-add-reg-to-mem:initialize-var2: +13726 # var var2/edx: (payload var) +13727 68/push 0/imm32/register +13728 68/push 0/imm32/register +13729 68/push 0/imm32/no-stack-offset +13730 68/push 1/imm32/block-depth +13731 ff 6/subop/push *(ecx+0x10) +13732 68/push 0x11/imm32/alloc-id:fake +13733 68/push 0/imm32/name +13734 68/push 0/imm32/name +13735 68/push 0x11/imm32/alloc-id:fake:payload +13736 89/<- %edx 4/r32/esp +13737 $test-add-reg-to-mem:initialize-var2-name: +13738 # var2->name = "var2" +13739 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 +13740 (copy-array Heap "var2" %eax) +13741 $test-add-reg-to-mem:initialize-var2-register: +13742 # var2->register = "ecx" +13743 8d/copy-address *(edx+0x1c) 0/r32/eax # Var-register + 4 +13744 (copy-array Heap "ecx" %eax) +13745 $test-add-reg-to-mem:initialize-inouts: +13746 # var inouts/esi: (payload stmt-var) = [var2] +13747 68/push 0/imm32/is-deref:false +13748 68/push 0/imm32/next +13749 68/push 0/imm32/next +13750 52/push-edx/var2 +13751 68/push 0x11/imm32/alloc-id:fake +13752 68/push 0x11/imm32/alloc-id:fake:payload +13753 89/<- %esi 4/r32/esp +13754 # inouts = [var1, var2] +13755 68/push 0/imm32/is-deref:false +13756 56/push-esi/next +13757 68/push 0x11/imm32/alloc-id:fake +13758 51/push-ecx/var1 +13759 68/push 0x11/imm32/alloc-id:fake +13760 68/push 0x11/imm32/alloc-id:fake:payload +13761 89/<- %esi 4/r32/esp +13762 $test-add-reg-to-mem:initialize-stmt: +13763 # var stmt/esi: (addr statement) +13764 68/push 0/imm32/next +13765 68/push 0/imm32/next +13766 68/push 0/imm32/outputs +13767 68/push 0/imm32/outputs +13768 56/push-esi/inouts +13769 68/push 0x11/imm32/alloc-id:fake +13770 68/push 0/imm32/operation +13771 68/push 0/imm32/operation +13772 68/push 1/imm32/tag:stmt1 +13773 89/<- %esi 4/r32/esp +13774 $test-add-reg-to-mem:initialize-stmt-operation: +13775 # stmt->operation = "add-to" +13776 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation +13777 (copy-array Heap "add-to" %eax) +13778 # convert +13779 c7 0/subop/copy *Curr-block-depth 0/imm32 +13780 (emit-subx-stmt _test-output-buffered-file %esi Primitives) +13781 (flush _test-output-buffered-file) +13782 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +13788 # check output +13789 (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem") +13790 # . epilogue +13791 89/<- %esp 5/r32/ebp +13792 5d/pop-to-ebp +13793 c3/return +13794 +13795 test-add-mem-to-reg: +13796 # var1/reg <- add var2 +13797 # => +13798 # 03/add *(ebp+__) var1 +13799 # +13800 # . prologue +13801 55/push-ebp +13802 89/<- %ebp 4/r32/esp +13803 # setup +13804 (clear-stream _test-output-stream) +13805 (clear-stream $_test-output-buffered-file->buffer) +13806 $test-add-mem-to-reg:initialize-type: +13807 # var type/ecx: (payload tree type-id) = int +13808 68/push 0/imm32/right:null +13809 68/push 0/imm32/right:null +13810 68/push 0/imm32/left:unused +13811 68/push 1/imm32/value:int +13812 68/push 1/imm32/is-atom?:true +13813 68/push 0x11/imm32/alloc-id:fake:payload +13814 89/<- %ecx 4/r32/esp +13815 $test-add-mem-to-reg:initialize-var: +13816 # var var1/ecx: (payload var) +13817 68/push 0/imm32/register +13818 68/push 0/imm32/register +13819 68/push 0/imm32/no-stack-offset +13820 68/push 1/imm32/block-depth +13821 51/push-ecx +13822 68/push 0x11/imm32/alloc-id:fake +13823 68/push 0/imm32/name +13824 68/push 0/imm32/name +13825 68/push 0x11/imm32/alloc-id:fake:payload +13826 89/<- %ecx 4/r32/esp +13827 $test-add-mem-to-reg:initialize-var-name: +13828 # var1->name = "foo" +13829 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 +13830 (copy-array Heap "var1" %eax) +13831 $test-add-mem-to-reg:initialize-var-register: +13832 # var1->register = "eax" +13833 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 +13834 (copy-array Heap "eax" %eax) +13835 $test-add-mem-to-reg:initialize-var2: +13836 # var var2/edx: (payload var) +13837 68/push 0/imm32/register +13838 68/push 0/imm32/register +13839 68/push 8/imm32/stack-offset +13840 68/push 1/imm32/block-depth +13841 ff 6/subop/push *(ecx+0x10) +13842 68/push 0x11/imm32/alloc-id:fake +13843 68/push 0/imm32/name +13844 68/push 0/imm32/name +13845 68/push 0x11/imm32/alloc-id:fake:payload +13846 89/<- %edx 4/r32/esp +13847 $test-add-mem-to-reg:initialize-var2-name: +13848 # var2->name = "var2" +13849 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 +13850 (copy-array Heap "var2" %eax) +13851 $test-add-mem-to-reg:initialize-inouts: +13852 # var inouts/esi: (payload stmt-var) = [var2] +13853 68/push 0/imm32/is-deref:false +13854 68/push 0/imm32/next +13855 68/push 0/imm32/next +13856 52/push-edx/var2 +13857 68/push 0x11/imm32/alloc-id:fake +13858 68/push 0x11/imm32/alloc-id:fake:payload +13859 89/<- %esi 4/r32/esp +13860 $test-add-mem-to-reg:initialize-outputs: +13861 # var outputs/edi: (payload stmt-var) = [var1] +13862 68/push 0/imm32/is-deref:false +13863 68/push 0/imm32/next +13864 68/push 0/imm32/next +13865 51/push-ecx/var1 +13866 68/push 0x11/imm32/alloc-id:fake +13867 68/push 0x11/imm32/alloc-id:fake:payload +13868 89/<- %edi 4/r32/esp +13869 $test-add-mem-to-reg:initialize-stmt: +13870 # var stmt/esi: (addr statement) +13871 68/push 0/imm32/next +13872 68/push 0/imm32/next +13873 57/push-edi/outputs +13874 68/push 0x11/imm32/alloc-id:fake +13875 56/push-esi/inouts +13876 68/push 0x11/imm32/alloc-id:fake +13877 68/push 0/imm32/operation +13878 68/push 0/imm32/operation +13879 68/push 1/imm32/tag:stmt1 +13880 89/<- %esi 4/r32/esp +13881 $test-add-mem-to-reg:initialize-stmt-operation: +13882 # stmt->operation = "add" +13883 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation +13884 (copy-array Heap "add" %eax) +13885 # convert +13886 c7 0/subop/copy *Curr-block-depth 0/imm32 +13887 (emit-subx-stmt _test-output-buffered-file %esi Primitives) +13888 (flush _test-output-buffered-file) +13889 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +13895 # check output +13896 (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg") +13897 # . epilogue +13898 89/<- %esp 5/r32/ebp +13899 5d/pop-to-ebp +13900 c3/return +13901 +13902 test-add-literal-to-eax: +13903 # var1/eax <- add 0x34 +13904 # => +13905 # 05/add-to-eax 0x34/imm32 +13906 # +13907 # . prologue +13908 55/push-ebp +13909 89/<- %ebp 4/r32/esp +13910 # setup +13911 (clear-stream _test-output-stream) +13912 (clear-stream $_test-output-buffered-file->buffer) +13913 $test-add-literal-to-eax:initialize-var-type: +13914 # var type/ecx: (payload tree type-id) = int +13915 68/push 0/imm32/right:null +13916 68/push 0/imm32/right:null +13917 68/push 0/imm32/left:unused +13918 68/push 1/imm32/value:int +13919 68/push 1/imm32/is-atom?:true +13920 68/push 0x11/imm32/alloc-id:fake:payload +13921 89/<- %ecx 4/r32/esp +13922 $test-add-literal-to-eax:initialize-var: +13923 # var v/ecx: (payload var) +13924 68/push 0/imm32/register +13925 68/push 0/imm32/register +13926 68/push 0/imm32/no-stack-offset +13927 68/push 1/imm32/block-depth +13928 51/push-ecx +13929 68/push 0x11/imm32/alloc-id:fake +13930 68/push 0/imm32/name +13931 68/push 0/imm32/name +13932 68/push 0x11/imm32/alloc-id:fake:payload +13933 89/<- %ecx 4/r32/esp +13934 $test-add-literal-to-eax:initialize-var-name: +13935 # v->name = "v" +13936 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 +13937 (copy-array Heap "v" %eax) +13938 $test-add-literal-to-eax:initialize-var-register: +13939 # v->register = "eax" +13940 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 +13941 (copy-array Heap "eax" %eax) +13942 $test-add-literal-to-eax:initialize-literal-type: +13943 # var type/edx: (payload tree type-id) = literal +13944 68/push 0/imm32/right:null +13945 68/push 0/imm32/right:null +13946 68/push 0/imm32/left:unused +13947 68/push 0/imm32/value:literal +13948 68/push 1/imm32/is-atom?:true +13949 68/push 0x11/imm32/alloc-id:fake:payload +13950 89/<- %edx 4/r32/esp +13951 $test-add-literal-to-eax:initialize-literal: +13952 # var l/edx: (payload var) +13953 68/push 0/imm32/register +13954 68/push 0/imm32/register +13955 68/push 0/imm32/no-stack-offset +13956 68/push 1/imm32/block-depth +13957 52/push-edx +13958 68/push 0x11/imm32/alloc-id:fake +13959 68/push 0/imm32/name +13960 68/push 0/imm32/name +13961 68/push 0x11/imm32/alloc-id:fake:payload +13962 89/<- %edx 4/r32/esp +13963 $test-add-literal-to-eax:initialize-literal-value: +13964 # l->name = "0x34" +13965 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 +13966 (copy-array Heap "0x34" %eax) +13967 $test-add-literal-to-eax:initialize-inouts: +13968 # var inouts/esi: (payload stmt-var) = [l] +13969 68/push 0/imm32/is-deref:false +13970 68/push 0/imm32/next +13971 68/push 0/imm32/next +13972 52/push-edx/l +13973 68/push 0x11/imm32/alloc-id:fake +13974 68/push 0x11/imm32/alloc-id:fake:payload +13975 89/<- %esi 4/r32/esp +13976 $test-add-literal-to-eax:initialize-outputs: +13977 # var outputs/edi: (payload stmt-var) = [v] +13978 68/push 0/imm32/is-deref:false +13979 68/push 0/imm32/next +13980 68/push 0/imm32/next +13981 51/push-ecx/v +13982 68/push 0x11/imm32/alloc-id:fake +13983 68/push 0x11/imm32/alloc-id:fake:payload +13984 89/<- %edi 4/r32/esp +13985 $test-add-literal-to-eax:initialize-stmt: +13986 # var stmt/esi: (addr statement) +13987 68/push 0/imm32/next +13988 68/push 0/imm32/next +13989 57/push-edi/outputs +13990 68/push 0x11/imm32/alloc-id:fake +13991 56/push-esi/inouts +13992 68/push 0x11/imm32/alloc-id:fake +13993 68/push 0/imm32/operation +13994 68/push 0/imm32/operation +13995 68/push 1/imm32/tag:stmt1 +13996 89/<- %esi 4/r32/esp +13997 $test-add-literal-to-eax:initialize-stmt-operation: +13998 # stmt->operation = "add" +13999 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation +14000 (copy-array Heap "add" %eax) +14001 # convert +14002 c7 0/subop/copy *Curr-block-depth 0/imm32 +14003 (emit-subx-stmt _test-output-buffered-file %esi Primitives) +14004 (flush _test-output-buffered-file) +14005 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +14011 # check output +14012 (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax") +14013 # . epilogue +14014 89/<- %esp 5/r32/ebp +14015 5d/pop-to-ebp +14016 c3/return +14017 +14018 test-add-literal-to-reg: +14019 # var1/ecx <- add 0x34 +14020 # => +14021 # 81 0/subop/add %ecx 0x34/imm32 +14022 # +14023 # . prologue +14024 55/push-ebp +14025 89/<- %ebp 4/r32/esp +14026 # setup +14027 (clear-stream _test-output-stream) +14028 (clear-stream $_test-output-buffered-file->buffer) +14029 $test-add-literal-to-reg:initialize-var-type: +14030 # var type/ecx: (payload tree type-id) = int +14031 68/push 0/imm32/right:null +14032 68/push 0/imm32/right:null +14033 68/push 0/imm32/left:unused +14034 68/push 1/imm32/value:int +14035 68/push 1/imm32/is-atom?:true +14036 68/push 0x11/imm32/alloc-id:fake:payload +14037 89/<- %ecx 4/r32/esp +14038 $test-add-literal-to-reg:initialize-var: +14039 # var v/ecx: (payload var) +14040 68/push 0/imm32/register +14041 68/push 0/imm32/register +14042 68/push 0/imm32/no-stack-offset +14043 68/push 1/imm32/block-depth +14044 51/push-ecx +14045 68/push 0x11/imm32/alloc-id:fake +14046 68/push 0/imm32/name +14047 68/push 0/imm32/name +14048 68/push 0x11/imm32/alloc-id:fake:payload +14049 89/<- %ecx 4/r32/esp +14050 $test-add-literal-to-reg:initialize-var-name: +14051 # v->name = "v" +14052 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 +14053 (copy-array Heap "v" %eax) +14054 $test-add-literal-to-reg:initialize-var-register: +14055 # v->register = "ecx" +14056 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 +14057 (copy-array Heap "ecx" %eax) +14058 $test-add-literal-to-reg:initialize-literal-type: +14059 # var type/edx: (payload tree type-id) = literal +14060 68/push 0/imm32/right:null +14061 68/push 0/imm32/right:null +14062 68/push 0/imm32/left:unused +14063 68/push 0/imm32/value:literal +14064 68/push 1/imm32/is-atom?:true +14065 68/push 0x11/imm32/alloc-id:fake:payload +14066 89/<- %edx 4/r32/esp +14067 $test-add-literal-to-reg:initialize-literal: +14068 # var l/edx: (payload var) +14069 68/push 0/imm32/register +14070 68/push 0/imm32/register +14071 68/push 0/imm32/no-stack-offset +14072 68/push 1/imm32/block-depth +14073 52/push-edx +14074 68/push 0x11/imm32/alloc-id:fake +14075 68/push 0/imm32/name +14076 68/push 0/imm32/name +14077 68/push 0x11/imm32/alloc-id:fake:payload +14078 89/<- %edx 4/r32/esp +14079 $test-add-literal-to-reg:initialize-literal-value: +14080 # l->name = "0x34" +14081 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 +14082 (copy-array Heap "0x34" %eax) +14083 $test-add-literal-to-reg:initialize-inouts: +14084 # var inouts/esi: (payload stmt-var) = [l] +14085 68/push 0/imm32/is-deref:false +14086 68/push 0/imm32/next +14087 68/push 0/imm32/next +14088 52/push-edx/l +14089 68/push 0x11/imm32/alloc-id:fake +14090 68/push 0x11/imm32/alloc-id:fake:payload +14091 89/<- %esi 4/r32/esp +14092 $test-add-literal-to-reg:initialize-outputs: +14093 # var outputs/edi: (payload stmt-var) = [v] +14094 68/push 0/imm32/is-deref:false +14095 68/push 0/imm32/next +14096 68/push 0/imm32/next +14097 51/push-ecx/v +14098 68/push 0x11/imm32/alloc-id:fake +14099 68/push 0x11/imm32/alloc-id:fake:payload +14100 89/<- %edi 4/r32/esp +14101 $test-add-literal-to-reg:initialize-stmt: +14102 # var stmt/esi: (addr statement) +14103 68/push 0/imm32/next +14104 68/push 0/imm32/next +14105 57/push-edi/outputs +14106 68/push 0x11/imm32/alloc-id:fake +14107 56/push-esi/inouts +14108 68/push 0x11/imm32/alloc-id:fake +14109 68/push 0/imm32/operation +14110 68/push 0/imm32/operation +14111 68/push 1/imm32/tag:stmt1 +14112 89/<- %esi 4/r32/esp +14113 $test-add-literal-to-reg:initialize-stmt-operation: +14114 # stmt->operation = "add" +14115 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation +14116 (copy-array Heap "add" %eax) +14117 # convert +14118 c7 0/subop/copy *Curr-block-depth 0/imm32 +14119 (emit-subx-stmt _test-output-buffered-file %esi Primitives) +14120 (flush _test-output-buffered-file) +14121 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +14127 # check output +14128 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg") +14129 # . epilogue +14130 89/<- %esp 5/r32/ebp +14131 5d/pop-to-ebp +14132 c3/return +14133 +14134 test-add-literal-to-mem: +14135 # add-to var1, 0x34 +14136 # => +14137 # 81 0/subop/add %eax 0x34/imm32 +14138 # +14139 # . prologue +14140 55/push-ebp +14141 89/<- %ebp 4/r32/esp +14142 # setup +14143 (clear-stream _test-output-stream) +14144 (clear-stream $_test-output-buffered-file->buffer) +14145 $test-add-literal-to-mem:initialize-type: +14146 # var type/ecx: (payload tree type-id) = int +14147 68/push 0/imm32/right:null +14148 68/push 0/imm32/right:null +14149 68/push 0/imm32/left:unused +14150 68/push 1/imm32/value:int +14151 68/push 1/imm32/is-atom?:true +14152 68/push 0x11/imm32/alloc-id:fake:payload +14153 89/<- %ecx 4/r32/esp +14154 $test-add-literal-to-mem:initialize-var1: +14155 # var var1/ecx: (payload var) +14156 68/push 0/imm32/register +14157 68/push 0/imm32/register +14158 68/push 8/imm32/stack-offset +14159 68/push 1/imm32/block-depth +14160 51/push-ecx +14161 68/push 0x11/imm32/alloc-id:fake +14162 68/push 0/imm32/name +14163 68/push 0/imm32/name +14164 68/push 0x11/imm32/alloc-id:fake:payload +14165 89/<- %ecx 4/r32/esp +14166 $test-add-literal-to-mem:initialize-var1-name: +14167 # var1->name = "var1" +14168 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 +14169 (copy-array Heap "var1" %eax) +14170 $test-add-literal-to-mem:initialize-literal-type: +14171 # var type/edx: (payload tree type-id) = literal +14172 68/push 0/imm32/right:null +14173 68/push 0/imm32/right:null +14174 68/push 0/imm32/left:unused +14175 68/push 0/imm32/value:literal +14176 68/push 1/imm32/is-atom?:true +14177 68/push 0x11/imm32/alloc-id:fake:payload +14178 89/<- %edx 4/r32/esp +14179 $test-add-literal-to-mem:initialize-literal: +14180 # var l/edx: (payload var) +14181 68/push 0/imm32/register +14182 68/push 0/imm32/register +14183 68/push 0/imm32/no-stack-offset +14184 68/push 1/imm32/block-depth +14185 52/push-edx +14186 68/push 0x11/imm32/alloc-id:fake +14187 68/push 0/imm32/name +14188 68/push 0/imm32/name +14189 68/push 0x11/imm32/alloc-id:fake:payload +14190 89/<- %edx 4/r32/esp +14191 $test-add-literal-to-mem:initialize-literal-value: +14192 # l->name = "0x34" +14193 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 +14194 (copy-array Heap "0x34" %eax) +14195 $test-add-literal-to-mem:initialize-inouts: +14196 # var inouts/esi: (payload stmt-var) = [l] +14197 68/push 0/imm32/is-deref:false +14198 68/push 0/imm32/next +14199 68/push 0/imm32/next +14200 52/push-edx/l +14201 68/push 0x11/imm32/alloc-id:fake +14202 68/push 0x11/imm32/alloc-id:fake:payload +14203 89/<- %esi 4/r32/esp +14204 # var inouts = (handle stmt-var) = [var1, var2] +14205 68/push 0/imm32/is-deref:false +14206 56/push-esi/next +14207 68/push 0x11/imm32/alloc-id:fake +14208 51/push-ecx/var1 +14209 68/push 0x11/imm32/alloc-id:fake +14210 68/push 0x11/imm32/alloc-id:fake:payload +14211 89/<- %esi 4/r32/esp +14212 $test-add-literal-to-mem:initialize-stmt: +14213 # var stmt/esi: (addr statement) +14214 68/push 0/imm32/next +14215 68/push 0/imm32/next +14216 68/push 0/imm32/outputs +14217 68/push 0/imm32/outputs +14218 56/push-esi/inouts +14219 68/push 0x11/imm32/alloc-id:fake +14220 68/push 0/imm32/operation +14221 68/push 0/imm32/operation +14222 68/push 1/imm32/tag:stmt1 +14223 89/<- %esi 4/r32/esp +14224 $test-add-literal-to-mem:initialize-stmt-operation: +14225 # stmt->operation = "add-to" +14226 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation +14227 (copy-array Heap "add-to" %eax) +14228 # convert +14229 c7 0/subop/copy *Curr-block-depth 0/imm32 +14230 (emit-subx-stmt _test-output-buffered-file %esi Primitives) +14231 (flush _test-output-buffered-file) +14232 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +14238 # check output +14239 (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem") +14240 # . epilogue +14241 89/<- %esp 5/r32/ebp +14242 5d/pop-to-ebp +14243 c3/return +14244 +14245 test-compare-mem-with-reg: +14246 # compare var1, var2/eax +14247 # => +14248 # 39/compare *(ebp+___) 0/r32/eax +14249 # +14250 # . prologue +14251 55/push-ebp +14252 89/<- %ebp 4/r32/esp +14253 # setup +14254 (clear-stream _test-output-stream) +14255 (clear-stream $_test-output-buffered-file->buffer) +14256 $test-compare-mem-with-reg:initialize-type: +14257 # var type/ecx: (payload tree type-id) = int +14258 68/push 0/imm32/right:null +14259 68/push 0/imm32/right:null +14260 68/push 0/imm32/left:unused +14261 68/push 1/imm32/value:int +14262 68/push 1/imm32/is-atom?:true +14263 68/push 0x11/imm32/alloc-id:fake:payload +14264 89/<- %ecx 4/r32/esp +14265 $test-compare-mem-with-reg:initialize-var1: +14266 # var var1/ecx: (payload var) +14267 68/push 0/imm32/register +14268 68/push 0/imm32/register +14269 68/push 8/imm32/stack-offset +14270 68/push 1/imm32/block-depth +14271 51/push-ecx +14272 68/push 0x11/imm32/alloc-id:fake +14273 68/push 0/imm32/name +14274 68/push 0/imm32/name +14275 68/push 0x11/imm32/alloc-id:fake:payload +14276 89/<- %ecx 4/r32/esp +14277 $test-compare-mem-with-reg:initialize-var1-name: +14278 # var1->name = "var1" +14279 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 +14280 (copy-array Heap "var1" %eax) +14281 $test-compare-mem-with-reg:initialize-var2: +14282 # var var2/edx: (payload var) +14283 68/push 0/imm32/register +14284 68/push 0/imm32/register +14285 68/push 0/imm32/no-stack-offset +14286 68/push 1/imm32/block-depth +14287 ff 6/subop/push *(ecx+0x10) +14288 68/push 0x11/imm32/alloc-id:fake +14289 68/push 0/imm32/name +14290 68/push 0/imm32/name +14291 68/push 0x11/imm32/alloc-id:fake:payload +14292 89/<- %edx 4/r32/esp +14293 $test-compare-mem-with-reg:initialize-var2-name: +14294 # var2->name = "var2" +14295 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 +14296 (copy-array Heap "var2" %eax) +14297 $test-compare-mem-with-reg:initialize-var2-register: +14298 # var2->register = "eax" +14299 8d/copy-address *(edx+0x1c) 0/r32/eax # Var-register + 4 +14300 (copy-array Heap "eax" %eax) +14301 $test-compare-mem-with-reg:initialize-inouts: +14302 # var inouts/esi: (payload stmt-var) = [var2] +14303 68/push 0/imm32/is-deref:false +14304 68/push 0/imm32/next +14305 68/push 0/imm32/next +14306 52/push-edx/var2 +14307 68/push 0x11/imm32/alloc-id:fake +14308 68/push 0x11/imm32/alloc-id:fake:payload +14309 89/<- %esi 4/r32/esp +14310 # inouts = [var1, var2] +14311 68/push 0/imm32/is-deref:false +14312 56/push-esi/next +14313 68/push 0x11/imm32/alloc-id:fake +14314 51/push-ecx/var1 +14315 68/push 0x11/imm32/alloc-id:fake +14316 68/push 0x11/imm32/alloc-id:fake:payload +14317 89/<- %esi 4/r32/esp +14318 $test-compare-mem-with-reg:initialize-stmt: +14319 # var stmt/esi: (addr statement) +14320 68/push 0/imm32/next +14321 68/push 0/imm32/next +14322 68/push 0/imm32/outputs +14323 68/push 0/imm32/outputs +14324 56/push-esi/inouts +14325 68/push 0x11/imm32/alloc-id:fake +14326 68/push 0/imm32/operation +14327 68/push 0/imm32/operation +14328 68/push 1/imm32/tag:stmt1 +14329 89/<- %esi 4/r32/esp +14330 $test-compare-mem-with-reg:initialize-stmt-operation: +14331 # stmt->operation = "compare" +14332 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation +14333 (copy-array Heap "compare" %eax) +14334 # convert +14335 c7 0/subop/copy *Curr-block-depth 0/imm32 +14336 (emit-subx-stmt _test-output-buffered-file %esi Primitives) +14337 (flush _test-output-buffered-file) +14338 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +14344 # check output +14345 (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg") +14346 # . epilogue +14347 89/<- %esp 5/r32/ebp +14348 5d/pop-to-ebp +14349 c3/return +14350 +14351 test-compare-reg-with-mem: +14352 # compare var1/eax, var2 +14353 # => +14354 # 3b/compare<- *(ebp+___) 0/r32/eax +14355 # +14356 # . prologue +14357 55/push-ebp +14358 89/<- %ebp 4/r32/esp +14359 # setup +14360 (clear-stream _test-output-stream) +14361 (clear-stream $_test-output-buffered-file->buffer) +14362 $test-compare-reg-with-mem:initialize-type: +14363 # var type/ecx: (payload tree type-id) = int +14364 68/push 0/imm32/right:null +14365 68/push 0/imm32/right:null +14366 68/push 0/imm32/left:unused +14367 68/push 1/imm32/value:int +14368 68/push 1/imm32/is-atom?:true +14369 68/push 0x11/imm32/alloc-id:fake:payload +14370 89/<- %ecx 4/r32/esp +14371 $test-compare-reg-with-mem:initialize-var1: +14372 # var var1/ecx: (payload var) +14373 68/push 0/imm32/register +14374 68/push 0/imm32/register +14375 68/push 0/imm32/no-stack-offset +14376 68/push 1/imm32/block-depth +14377 51/push-ecx +14378 68/push 0x11/imm32/alloc-id:fake +14379 68/push 0/imm32/name +14380 68/push 0/imm32/name +14381 68/push 0x11/imm32/alloc-id:fake:payload +14382 89/<- %ecx 4/r32/esp +14383 $test-compare-reg-with-mem:initialize-var1-name: +14384 # var1->name = "var1" +14385 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 +14386 (copy-array Heap "var1" %eax) +14387 $test-compare-reg-with-mem:initialize-var1-register: +14388 # var1->register = "eax" +14389 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 +14390 (copy-array Heap "eax" %eax) +14391 $test-compare-reg-with-mem:initialize-var2: +14392 # var var2/edx: (payload var) +14393 68/push 0/imm32/register +14394 68/push 0/imm32/register +14395 68/push 8/imm32/stack-offset +14396 68/push 1/imm32/block-depth +14397 ff 6/subop/push *(ecx+0x10) +14398 68/push 0x11/imm32/alloc-id:fake +14399 68/push 0/imm32/name +14400 68/push 0/imm32/name +14401 68/push 0x11/imm32/alloc-id:fake:payload +14402 89/<- %edx 4/r32/esp +14403 $test-compare-reg-with-mem:initialize-var2-name: +14404 # var2->name = "var2" +14405 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 +14406 (copy-array Heap "var2" %eax) +14407 $test-compare-reg-with-mem:initialize-inouts: +14408 # var inouts/esi: (payload stmt-var) = [var2] +14409 68/push 0/imm32/is-deref:false +14410 68/push 0/imm32/next +14411 68/push 0/imm32/next +14412 52/push-edx/var2 +14413 68/push 0x11/imm32/alloc-id:fake +14414 68/push 0x11/imm32/alloc-id:fake:payload +14415 89/<- %esi 4/r32/esp +14416 # inouts = [var1, var2] +14417 68/push 0/imm32/is-deref:false +14418 56/push-esi/next +14419 68/push 0x11/imm32/alloc-id:fake +14420 51/push-ecx/var1 +14421 68/push 0x11/imm32/alloc-id:fake +14422 68/push 0x11/imm32/alloc-id:fake:payload +14423 89/<- %esi 4/r32/esp +14424 $test-compare-reg-with-mem:initialize-stmt: +14425 # var stmt/esi: (addr statement) +14426 68/push 0/imm32/next +14427 68/push 0/imm32/next +14428 68/push 0/imm32/outputs +14429 68/push 0/imm32/outputs +14430 56/push-esi/inouts +14431 68/push 0x11/imm32/alloc-id:fake +14432 68/push 0/imm32/operation +14433 68/push 0/imm32/operation +14434 68/push 1/imm32/tag:stmt1 +14435 89/<- %esi 4/r32/esp +14436 $test-compare-reg-with-mem:initialize-stmt-operation: +14437 # stmt->operation = "compare" +14438 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation +14439 (copy-array Heap "compare" %eax) +14440 # convert +14441 c7 0/subop/copy *Curr-block-depth 0/imm32 +14442 (emit-subx-stmt _test-output-buffered-file %esi Primitives) +14443 (flush _test-output-buffered-file) +14444 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +14450 # check output +14451 (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem") +14452 # . epilogue +14453 89/<- %esp 5/r32/ebp +14454 5d/pop-to-ebp +14455 c3/return +14456 +14457 test-compare-mem-with-literal: +14458 # compare var1, 0x34 +14459 # => +14460 # 81 7/subop/compare *(ebp+___) 0x34/imm32 +14461 # +14462 # . prologue +14463 55/push-ebp +14464 89/<- %ebp 4/r32/esp +14465 # setup +14466 (clear-stream _test-output-stream) +14467 (clear-stream $_test-output-buffered-file->buffer) +14468 $test-compare-mem-with-literal:initialize-type: +14469 # var type/ecx: (payload tree type-id) = int +14470 68/push 0/imm32/right:null +14471 68/push 0/imm32/right:null +14472 68/push 0/imm32/left:unused +14473 68/push 1/imm32/value:int +14474 68/push 1/imm32/is-atom?:true +14475 68/push 0x11/imm32/alloc-id:fake:payload +14476 89/<- %ecx 4/r32/esp +14477 $test-compare-mem-with-literal:initialize-var1: +14478 # var var1/ecx: (payload var) +14479 68/push 0/imm32/register +14480 68/push 0/imm32/register +14481 68/push 8/imm32/stack-offset +14482 68/push 1/imm32/block-depth +14483 51/push-ecx +14484 68/push 0x11/imm32/alloc-id:fake +14485 68/push 0/imm32/name +14486 68/push 0/imm32/name +14487 68/push 0x11/imm32/alloc-id:fake:payload +14488 89/<- %ecx 4/r32/esp +14489 $test-compare-mem-with-literal:initialize-var1-name: +14490 # var1->name = "var1" +14491 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 +14492 (copy-array Heap "var1" %eax) +14493 $test-compare-mem-with-literal:initialize-literal-type: +14494 # var type/edx: (payload tree type-id) = literal +14495 68/push 0/imm32/right:null +14496 68/push 0/imm32/right:null +14497 68/push 0/imm32/left:unused +14498 68/push 0/imm32/value:literal +14499 68/push 1/imm32/is-atom?:true +14500 68/push 0x11/imm32/alloc-id:fake:payload +14501 89/<- %edx 4/r32/esp +14502 $test-compare-mem-with-literal:initialize-literal: +14503 # var l/edx: (payload var) +14504 68/push 0/imm32/register +14505 68/push 0/imm32/register +14506 68/push 0/imm32/no-stack-offset +14507 68/push 1/imm32/block-depth +14508 52/push-edx +14509 68/push 0x11/imm32/alloc-id:fake +14510 68/push 0/imm32/name +14511 68/push 0/imm32/name +14512 68/push 0x11/imm32/alloc-id:fake:payload +14513 89/<- %edx 4/r32/esp +14514 $test-compare-mem-with-literal:initialize-literal-value: +14515 # l->name = "0x34" +14516 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 +14517 (copy-array Heap "0x34" %eax) +14518 $test-compare-mem-with-literal:initialize-inouts: +14519 # var inouts/esi: (payload stmt-var) = [l] +14520 68/push 0/imm32/is-deref:false +14521 68/push 0/imm32/next +14522 68/push 0/imm32/next +14523 52/push-edx/l +14524 68/push 0x11/imm32/alloc-id:fake +14525 68/push 0x11/imm32/alloc-id:fake:payload +14526 89/<- %esi 4/r32/esp +14527 # var inouts = (handle stmt-var) = [var1, var2] +14528 68/push 0/imm32/is-deref:false +14529 56/push-esi/next +14530 68/push 0x11/imm32/alloc-id:fake +14531 51/push-ecx/var1 +14532 68/push 0x11/imm32/alloc-id:fake +14533 68/push 0x11/imm32/alloc-id:fake:payload +14534 89/<- %esi 4/r32/esp +14535 $test-compare-mem-with-literal:initialize-stmt: +14536 # var stmt/esi: (addr statement) +14537 68/push 0/imm32/next +14538 68/push 0/imm32/next +14539 68/push 0/imm32/outputs +14540 68/push 0/imm32/outputs +14541 56/push-esi/inouts +14542 68/push 0x11/imm32/alloc-id:fake +14543 68/push 0/imm32/operation +14544 68/push 0/imm32/operation +14545 68/push 1/imm32/tag:stmt1 +14546 89/<- %esi 4/r32/esp +14547 $test-compare-mem-with-literal:initialize-stmt-operation: +14548 # stmt->operation = "compare" +14549 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation +14550 (copy-array Heap "compare" %eax) +14551 # convert +14552 c7 0/subop/copy *Curr-block-depth 0/imm32 +14553 (emit-subx-stmt _test-output-buffered-file %esi Primitives) +14554 (flush _test-output-buffered-file) +14555 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +14561 # check output +14562 (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal") +14563 # . epilogue +14564 89/<- %esp 5/r32/ebp +14565 5d/pop-to-ebp +14566 c3/return +14567 +14568 test-compare-eax-with-literal: +14569 # compare var1/eax 0x34 +14570 # => +14571 # 3d/compare-eax-with 0x34/imm32 +14572 # +14573 # . prologue +14574 55/push-ebp +14575 89/<- %ebp 4/r32/esp +14576 # setup +14577 (clear-stream _test-output-stream) +14578 (clear-stream $_test-output-buffered-file->buffer) +14579 $test-compare-eax-with-literal:initialize-type: +14580 # var type/ecx: (payload tree type-id) = int +14581 68/push 0/imm32/right:null +14582 68/push 0/imm32/right:null +14583 68/push 0/imm32/left:unused +14584 68/push 1/imm32/value:int +14585 68/push 1/imm32/is-atom?:true +14586 68/push 0x11/imm32/alloc-id:fake:payload +14587 89/<- %ecx 4/r32/esp +14588 $test-compare-eax-with-literal:initialize-var1: +14589 # var var1/ecx: (payload var) +14590 68/push 0/imm32/register +14591 68/push 0/imm32/register +14592 68/push 0/imm32/no-stack-offset +14593 68/push 1/imm32/block-depth +14594 51/push-ecx +14595 68/push 0x11/imm32/alloc-id:fake +14596 68/push 0/imm32/name +14597 68/push 0/imm32/name +14598 68/push 0x11/imm32/alloc-id:fake:payload +14599 89/<- %ecx 4/r32/esp +14600 $test-compare-eax-with-literal:initialize-var1-name: +14601 # var1->name = "var1" +14602 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 +14603 (copy-array Heap "var1" %eax) +14604 $test-compare-eax-with-literal:initialize-var1-register: +14605 # v->register = "eax" +14606 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 +14607 (copy-array Heap "eax" %eax) +14608 $test-compare-eax-with-literal:initialize-literal-type: +14609 # var type/edx: (payload tree type-id) = literal +14610 68/push 0/imm32/right:null +14611 68/push 0/imm32/right:null +14612 68/push 0/imm32/left:unused +14613 68/push 0/imm32/value:literal +14614 68/push 1/imm32/is-atom?:true +14615 68/push 0x11/imm32/alloc-id:fake:payload +14616 89/<- %edx 4/r32/esp +14617 $test-compare-eax-with-literal:initialize-literal: +14618 # var l/edx: (payload var) +14619 68/push 0/imm32/register +14620 68/push 0/imm32/register +14621 68/push 0/imm32/no-stack-offset +14622 68/push 1/imm32/block-depth +14623 52/push-edx +14624 68/push 0x11/imm32/alloc-id:fake +14625 68/push 0/imm32/name +14626 68/push 0/imm32/name +14627 68/push 0x11/imm32/alloc-id:fake:payload +14628 89/<- %edx 4/r32/esp +14629 $test-compare-eax-with-literal:initialize-literal-value: +14630 # l->name = "0x34" +14631 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 +14632 (copy-array Heap "0x34" %eax) +14633 $test-compare-eax-with-literal:initialize-inouts: +14634 # var inouts/esi: (payload stmt-var) = [l] +14635 68/push 0/imm32/is-deref:false +14636 68/push 0/imm32/next +14637 68/push 0/imm32/next +14638 52/push-edx/l +14639 68/push 0x11/imm32/alloc-id:fake +14640 68/push 0x11/imm32/alloc-id:fake:payload +14641 89/<- %esi 4/r32/esp +14642 # var inouts = (handle stmt-var) = [var1, var2] +14643 68/push 0/imm32/is-deref:false +14644 56/push-esi/next +14645 68/push 0x11/imm32/alloc-id:fake +14646 51/push-ecx/var1 +14647 68/push 0x11/imm32/alloc-id:fake +14648 68/push 0x11/imm32/alloc-id:fake:payload +14649 89/<- %esi 4/r32/esp +14650 $test-compare-eax-with-literal:initialize-stmt: +14651 # var stmt/esi: (addr statement) +14652 68/push 0/imm32/next +14653 68/push 0/imm32/next +14654 68/push 0/imm32/outputs +14655 68/push 0/imm32/outputs +14656 56/push-esi/inouts +14657 68/push 0x11/imm32/alloc-id:fake +14658 68/push 0/imm32/operation +14659 68/push 0/imm32/operation +14660 68/push 1/imm32/tag:stmt1 +14661 89/<- %esi 4/r32/esp +14662 $test-compare-eax-with-literal:initialize-stmt-operation: +14663 # stmt->operation = "compare" +14664 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation +14665 (copy-array Heap "compare" %eax) +14666 # convert +14667 c7 0/subop/copy *Curr-block-depth 0/imm32 +14668 (emit-subx-stmt _test-output-buffered-file %esi Primitives) +14669 (flush _test-output-buffered-file) +14670 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +14676 # check output +14677 (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal") +14678 # . epilogue +14679 89/<- %esp 5/r32/ebp +14680 5d/pop-to-ebp +14681 c3/return +14682 +14683 test-compare-reg-with-literal: +14684 # compare var1/ecx 0x34 +14685 # => +14686 # 81 7/subop/compare %ecx 0x34/imm32 +14687 # +14688 # . prologue +14689 55/push-ebp +14690 89/<- %ebp 4/r32/esp +14691 # setup +14692 (clear-stream _test-output-stream) +14693 (clear-stream $_test-output-buffered-file->buffer) +14694 $test-compare-reg-with-literal:initialize-type: +14695 # var type/ecx: (payload tree type-id) = int +14696 68/push 0/imm32/right:null +14697 68/push 0/imm32/right:null +14698 68/push 0/imm32/left:unused +14699 68/push 1/imm32/value:int +14700 68/push 1/imm32/is-atom?:true +14701 68/push 0x11/imm32/alloc-id:fake:payload +14702 89/<- %ecx 4/r32/esp +14703 $test-compare-reg-with-literal:initialize-var1: +14704 # var var1/ecx: (payload var) +14705 68/push 0/imm32/register +14706 68/push 0/imm32/register +14707 68/push 0/imm32/no-stack-offset +14708 68/push 1/imm32/block-depth +14709 51/push-ecx +14710 68/push 0x11/imm32/alloc-id:fake +14711 68/push 0/imm32/name +14712 68/push 0/imm32/name +14713 68/push 0x11/imm32/alloc-id:fake:payload +14714 89/<- %ecx 4/r32/esp +14715 $test-compare-reg-with-literal:initialize-var1-name: +14716 # var1->name = "var1" +14717 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 +14718 (copy-array Heap "var1" %eax) +14719 $test-compare-reg-with-literal:initialize-var1-register: +14720 # v->register = "ecx" +14721 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 +14722 (copy-array Heap "ecx" %eax) +14723 $test-compare-reg-with-literal:initialize-literal-type: +14724 # var type/edx: (payload tree type-id) = literal +14725 68/push 0/imm32/right:null +14726 68/push 0/imm32/right:null +14727 68/push 0/imm32/left:unused +14728 68/push 0/imm32/value:literal +14729 68/push 1/imm32/is-atom?:true +14730 68/push 0x11/imm32/alloc-id:fake:payload +14731 89/<- %edx 4/r32/esp +14732 $test-compare-reg-with-literal:initialize-literal: +14733 # var l/edx: (payload var) +14734 68/push 0/imm32/register +14735 68/push 0/imm32/register +14736 68/push 0/imm32/no-stack-offset +14737 68/push 1/imm32/block-depth +14738 52/push-edx +14739 68/push 0x11/imm32/alloc-id:fake +14740 68/push 0/imm32/name +14741 68/push 0/imm32/name +14742 68/push 0x11/imm32/alloc-id:fake:payload +14743 89/<- %edx 4/r32/esp +14744 $test-compare-reg-with-literal:initialize-literal-value: +14745 # l->name = "0x34" +14746 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 +14747 (copy-array Heap "0x34" %eax) +14748 $test-compare-reg-with-literal:initialize-inouts: +14749 # var inouts/esi: (payload stmt-var) = [l] +14750 68/push 0/imm32/is-deref:false +14751 68/push 0/imm32/next +14752 68/push 0/imm32/next +14753 52/push-edx/l +14754 68/push 0x11/imm32/alloc-id:fake +14755 68/push 0x11/imm32/alloc-id:fake:payload +14756 89/<- %esi 4/r32/esp +14757 # var inouts = (handle stmt-var) = [var1, var2] +14758 68/push 0/imm32/is-deref:false +14759 56/push-esi/next +14760 68/push 0x11/imm32/alloc-id:fake +14761 51/push-ecx/var1 +14762 68/push 0x11/imm32/alloc-id:fake +14763 68/push 0x11/imm32/alloc-id:fake:payload +14764 89/<- %esi 4/r32/esp +14765 $test-compare-reg-with-literal:initialize-stmt: +14766 # var stmt/esi: (addr statement) +14767 68/push 0/imm32/next +14768 68/push 0/imm32/next +14769 68/push 0/imm32/outputs +14770 68/push 0/imm32/outputs +14771 56/push-esi/inouts +14772 68/push 0x11/imm32/alloc-id:fake +14773 68/push 0/imm32/operation +14774 68/push 0/imm32/operation +14775 68/push 1/imm32/tag:stmt1 +14776 89/<- %esi 4/r32/esp +14777 $test-compare-reg-with-literal:initialize-stmt-operation: +14778 # stmt->operation = "compare" +14779 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation +14780 (copy-array Heap "compare" %eax) +14781 # convert +14782 c7 0/subop/copy *Curr-block-depth 0/imm32 +14783 (emit-subx-stmt _test-output-buffered-file %esi Primitives) +14784 (flush _test-output-buffered-file) +14785 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +14791 # check output +14792 (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal") +14793 # . epilogue +14794 89/<- %esp 5/r32/ebp +14795 5d/pop-to-ebp +14796 c3/return +14797 +14798 test-emit-subx-stmt-function-call: +14799 # Call a function on a variable on the stack. +14800 # f foo +14801 # => +14802 # (f *(ebp-8)) +14803 # (Changing the function name supports overloading in general, but here it +14804 # just serves to help disambiguate things.) +14805 # +14806 # There's a variable on the var stack as follows: +14807 # name: 'foo' +14808 # type: int +14809 # stack-offset: -8 +14810 # +14811 # There's nothing in primitives. +14812 # +14813 # We don't perform any checking here on the type of 'f'. +14814 # +14815 # . prologue +14816 55/push-ebp +14817 89/<- %ebp 4/r32/esp +14818 # setup +14819 (clear-stream _test-output-stream) +14820 (clear-stream $_test-output-buffered-file->buffer) +14821 $test-emit-subx-function-call:initialize-type: +14822 # var type/ecx: (payload tree type-id) = int +14823 68/push 0/imm32/right:null +14824 68/push 0/imm32/right:null +14825 68/push 0/imm32/left:unused +14826 68/push 1/imm32/value:int +14827 68/push 1/imm32/is-atom?:true +14828 68/push 0x11/imm32/alloc-id:fake:payload +14829 89/<- %ecx 4/r32/esp +14830 $test-emit-subx-function-call:initialize-var: +14831 # var var-foo/ecx: (payload var) = var(type) +14832 68/push 0/imm32/no-register +14833 68/push 0/imm32/no-register +14834 68/push -8/imm32/stack-offset +14835 68/push 1/imm32/block-depth +14836 51/push-ecx/type +14837 68/push 0x11/imm32/alloc-id:fake +14838 68/push 0/imm32/name +14839 68/push 0/imm32/name +14840 68/push 0x11/imm32/alloc-id:fake:payload +14841 89/<- %ecx 4/r32/esp +14842 $test-emit-subx-function-call:initialize-var-name: +14843 # var-foo->name = "foo" +14844 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 +14845 (copy-array Heap "foo" %eax) +14846 $test-emit-subx-function-call:initialize-stmt-var: +14847 # var operand/ebx: (payload stmt-var) = stmt-var(var-foo) +14848 68/push 0/imm32/is-deref:false +14849 68/push 0/imm32/next +14850 68/push 0/imm32/next +14851 51/push-ecx/var-foo +14852 68/push 0x11/imm32/alloc-id:fake +14853 68/push 0x11/imm32/alloc-id:fake:payload +14854 89/<- %ebx 4/r32/esp +14855 $test-emit-subx-function-call:initialize-stmt: +14856 # var stmt/esi: (addr statement) +14857 68/push 0/imm32/no-outputs +14858 68/push 0/imm32/no-outputs +14859 53/push-ebx/inouts +14860 68/push 0x11/imm32/alloc-id:fake +14861 68/push 0/imm32/operation +14862 68/push 0/imm32/operation +14863 68/push 1/imm32/tag +14864 89/<- %esi 4/r32/esp +14865 $test-emit-subx-function-call:initialize-stmt-operation: +14866 # stmt->operation = "f" +14867 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation +14868 (copy-array Heap "f" %eax) +14869 # convert +14870 c7 0/subop/copy *Curr-block-depth 0/imm32 +14871 (emit-subx-stmt _test-output-buffered-file %esi 0) +14872 (flush _test-output-buffered-file) +14873 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +14879 # check output +14880 (check-next-stream-line-equal _test-output-stream "(f *(ebp+0xfffffff8))" "F - test-emit-subx-stmt-function-call") +14881 # . epilogue +14882 89/<- %esp 5/r32/ebp +14883 5d/pop-to-ebp +14884 c3/return +14885 +14886 test-emit-subx-stmt-function-call-with-literal-arg: +14887 # Call a function on a literal. +14888 # f 0x34 +14889 # => +14890 # (f2 0x34) +14891 # +14892 # . prologue +14893 55/push-ebp +14894 89/<- %ebp 4/r32/esp +14895 # setup +14896 (clear-stream _test-output-stream) +14897 (clear-stream $_test-output-buffered-file->buffer) +14898 $test-emit-subx-function-call-with-literal-arg:initialize-type: +14899 # var type/ecx: (payload tree type-id) = int +14900 68/push 0/imm32/right:null +14901 68/push 0/imm32/right:null +14902 68/push 0/imm32/left:unused +14903 68/push 0/imm32/value:literal +14904 68/push 1/imm32/is-atom?:true +14905 68/push 0x11/imm32/alloc-id:fake:payload +14906 89/<- %ecx 4/r32/esp +14907 $test-emit-subx-function-call-with-literal-arg:initialize-var: +14908 # var var-foo/ecx: (payload var) = var(lit) +14909 68/push 0/imm32/no-register +14910 68/push 0/imm32/no-register +14911 68/push 0/imm32/no-stack-offset +14912 68/push 1/imm32/block-depth +14913 51/push-ecx/type +14914 68/push 0x11/imm32/alloc-id:fake +14915 68/push 0/imm32/name +14916 68/push 0/imm32/name +14917 68/push 0x11/imm32/alloc-id:fake:payload +14918 89/<- %ecx 4/r32/esp +14919 $test-emit-subx-function-call-with-literal-arg:initialize-var-name: +14920 # var-foo->name = "0x34" +14921 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 +14922 (copy-array Heap "0x34" %eax) +14923 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-var: +14924 # var operand/ebx: (payload stmt-var) = stmt-var(var-foo) +14925 68/push 0/imm32/is-deref:false +14926 68/push 0/imm32/next +14927 68/push 0/imm32/next +14928 51/push-ecx/var-foo +14929 68/push 0x11/imm32/alloc-id:fake +14930 68/push 0x11/imm32/alloc-id:fake:payload +14931 89/<- %ebx 4/r32/esp +14932 $test-emit-subx-function-call-with-literal-arg:initialize-stmt: +14933 # var stmt/esi: (addr statement) +14934 68/push 0/imm32/no-outputs +14935 68/push 0/imm32/no-outputs +14936 53/push-ebx/inouts +14937 68/push 0x11/imm32/alloc-id:fake +14938 68/push 0/imm32/operation +14939 68/push 0/imm32/operation +14940 68/push 1/imm32/tag +14941 89/<- %esi 4/r32/esp +14942 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-operation: +14943 # stmt->operation = "f" +14944 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation +14945 (copy-array Heap "f" %eax) +14946 # convert +14947 c7 0/subop/copy *Curr-block-depth 0/imm32 +14948 (emit-subx-stmt _test-output-buffered-file %esi 0 %ebx) +14949 (flush _test-output-buffered-file) +14950 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +14956 # check output +14957 (check-next-stream-line-equal _test-output-stream "(f 0x34)" "F - test-emit-subx-stmt-function-call-with-literal-arg") +14958 # . epilogue +14959 89/<- %esp 5/r32/ebp +14960 5d/pop-to-ebp +14961 c3/return +14962 +14963 emit-indent: # out: (addr buffered-file), n: int +14964 # . prologue +14965 55/push-ebp +14966 89/<- %ebp 4/r32/esp +14967 # . save registers +14968 50/push-eax +14969 # var i/eax: int = n +14970 8b/-> *(ebp+0xc) 0/r32/eax +14971 { +14972 # if (i <= 0) break +14973 3d/compare-eax-with 0/imm32 +14974 7e/jump-if-<= break/disp8 +14975 (write-buffered *(ebp+8) " ") +14976 48/decrement-eax +14977 eb/jump loop/disp8 +14978 } +14979 $emit-indent:end: +14980 # . restore registers +14981 58/pop-to-eax +14982 # . epilogue +14983 89/<- %esp 5/r32/ebp +14984 5d/pop-to-ebp +14985 c3/return +14986 +14987 emit-subx-prologue: # out: (addr buffered-file) +14988 # . prologue +14989 55/push-ebp +14990 89/<- %ebp 4/r32/esp +14991 # +14992 (write-buffered *(ebp+8) " # . prologue\n") +14993 (write-buffered *(ebp+8) " 55/push-ebp\n") +14994 (write-buffered *(ebp+8) " 89/<- %ebp 4/r32/esp\n") +14995 $emit-subx-prologue:end: +14996 # . epilogue +14997 89/<- %esp 5/r32/ebp +14998 5d/pop-to-ebp +14999 c3/return +15000 +15001 emit-subx-epilogue: # out: (addr buffered-file) +15002 # . prologue +15003 55/push-ebp +15004 89/<- %ebp 4/r32/esp +15005 # +15006 (write-buffered *(ebp+8) " # . epilogue\n") +15007 (write-buffered *(ebp+8) " 89/<- %esp 5/r32/ebp\n") +15008 (write-buffered *(ebp+8) " 5d/pop-to-ebp\n") +15009 (write-buffered *(ebp+8) " c3/return\n") +15010 $emit-subx-epilogue:end: +15011 # . epilogue +15012 89/<- %esp 5/r32/ebp +15013 5d/pop-to-ebp +15014 c3/return diff --git a/html/mu-init-test.subx.html b/html/mu-init-test.subx.html index e0475d7b..025b5f71 100644 --- a/html/mu-init-test.subx.html +++ b/html/mu-init-test.subx.html @@ -15,10 +15,10 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } -.LineNr { } -.SpecialChar { color: #d70000; } -.subxS1Comment { color: #0000af; } .subxFunction { color: #af5f00; text-decoration: underline; } +.LineNr { } +.subxS1Comment { color: #0000af; } +.SpecialChar { color: #d70000; } .Constant { color: #008787; } --> @@ -58,10 +58,10 @@ if ('onhashchange' in window) { 1 # Just a test stub for mu-init.subx 2 # 3 # Try it out like this: - 4 # $ ./translate_subx init.linux 0*.subx mu-init.subx mu-init-test.subx + 4 # $ ./translate_subx init.linux [0-9]*.subx mu-init.subx mu-init-test.subx 5 # $ ./a.elf # should run all tests 6 - 7 main: # args: (address array kernel-string) -> result/ebx: int + 7 main: # args: (addr array (addr array byte)) -> result/ebx: int 8 # . prologue 9 55/push-ebp 10 89/<- %ebp 4/r32/esp @@ -72,10 +72,10 @@ if ('onhashchange' in window) { 15 8b/-> *(ebp+8) 6/r32/esi 16 { 17 # if (argc <= 1) break -18 81 7/subop/compare *esi 1/imm32 +18 81 7/subop/compare *esi 4/imm32 19 7e/jump-if-<= break/disp8 20 # if (argv[1] != "test") break -21 (kernel-string-equal? *(esi+8) "test") # => eax +21 (string-equal? *(esi+8) "test") # => eax 22 3d/compare-eax-and 0/imm32 23 74/jump-if-= break/disp8 24 # diff --git a/html/mu-init.subx.html b/html/mu-init.subx.html index 324210e4..ef844eec 100644 --- a/html/mu-init.subx.html +++ b/html/mu-init.subx.html @@ -17,6 +17,8 @@ a { color:inherit; } .subxComment { color: #005faf; } .LineNr { } .SpecialChar { color: #d70000; } +.Constant { color: #008787; } +.subxH1Comment { color: #005faf; text-decoration: underline; } --> @@ -57,7 +59,7 @@ if ('onhashchange' in window) { 3 # See translate_mu for how this file is used. 4 # 5 # Mu programs start at a function called 'main' with this signature: - 6 # fn main args: (addr array kernel-string) -> exit-status/ebx: int + 6 # fn main args: (addr array (addr array byte)) -> exit-status/ebx: int 7 # If your program doesn't need commandline arguments you can drop it: 8 # fn main -> exit-status/ebx: int 9 # @@ -69,14 +71,49 @@ if ('onhashchange' in window) { 15 Entry: 16 # we don't use ebp in Entry; just initialize it 17 bd/copy-to-ebp 0/imm32 -18 # var args/eax: (addr array kernel-string) -19 89/<- %eax 4/r32/esp -20 # initialize the heap -21 (new-segment *Heap-size Heap) -22 # run Mu program -23 (main %eax) -24 # exit -25 (syscall_exit) +18 # - save argc and argv +19 # var argc-and-argv/esi +20 89/<- %esi 4/r32/esp +21 $Entry:initialize-heap: +22 # - initialize the heap +23 (new-segment *Heap-size Heap) +24 $Entry:initialize-args: +25 # - convert argv from null-terminated 'kernel' strings to length-prefixed Mu strings +26 # var argc/edx: int +27 8b/-> *esi 2/r32/edx +28 # argc is in words; convert it to bytes +29 c1/shift 4/subop/left %edx 2/imm8 +30 # var tmp/eax: handle +31 68/push 0/imm32 +32 68/push 0/imm32 +33 89/<- %eax 4/r32/esp +34 # var args/edi: (addr array (addr array byte)) +35 (allocate-array Heap %edx %eax) +36 8b/-> *(eax+4) 7/r32/edi +37 # var curr/ecx: (addr kernel-string) = argv +38 8d/copy-address *(esi+4) 1/r32/ecx +39 # var max/edx: (addr kernel-string) = argv+4+argc +40 8d/copy-address *(ecx+edx) 2/r32/edx +41 # var dest/esi: (addr (addr array byte)) = args+4 +42 8d/copy-address *(edi+4) 6/r32/esi +43 { +44 # if (curr >= max) break +45 39/compare %ecx 2/r32/edx +46 73/jump-if-addr>= break/disp8 +47 # *dest = kernel-string-to-string(*curr) +48 (kernel-string-to-string Heap *ecx) # => eax +49 89/<- *esi 0/r32/eax +50 # curr += 4 +51 81 0/subop/add %ecx 4/imm32 +52 # dest += 4 +53 81 0/subop/add %esi 4/imm32 +54 # +55 eb/jump loop/disp8 +56 } +57 # - run Mu program +58 (main %edi) # => ebx +59 # - exit +60 (syscall_exit) diff --git a/html/run_one_test.subx.html b/html/run_one_test.subx.html index 2d539fe5..d375dae2 100644 --- a/html/run_one_test.subx.html +++ b/html/run_one_test.subx.html @@ -65,8 +65,8 @@ if ('onhashchange' in window) { 8 Entry: 9 # Heap = new-segment(64KB) 10 # . . push args -11 68/push Heap/imm32 -12 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Heap-size/disp32 # push *Heap-size +11 68/push Heap/imm32 +12 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Heap-size/disp32 # push *Heap-size 13 # . . call 14 e8/call new-segment/disp32 15 # . . discard args