diff options
Diffstat (limited to 'apps/mu.subx')
-rw-r--r-- | apps/mu.subx | 493 |
1 files changed, 487 insertions, 6 deletions
diff --git a/apps/mu.subx b/apps/mu.subx index ca4dc4b0..11114777 100644 --- a/apps/mu.subx +++ b/apps/mu.subx @@ -378,7 +378,7 @@ Max-type-id: 0x10000/imm32 Type-id: # (stream (address array byte)) - 0x18/imm32/write + 0x1c/imm32/write 0/imm32/read 0x100/imm32/length # data @@ -388,7 +388,7 @@ Type-id: # (stream (address array byte)) "array"/imm32 # 3 "handle"/imm32 # 4 "boolean"/imm32 # 5 - 0/imm32 + "constant"/imm32 # 6: like a literal, but replaced with its value in Var-offset 0/imm32 # 0x20 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 @@ -399,10 +399,14 @@ Type-id: # (stream (address array byte)) 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +# Program->types contains some typeinfo for each type definition. # Types contain vars with types, but can't specify registers. Typeinfo-id: # type-id 0/imm32 -Typeinfo-fields: # (handle list var) +# each field of a type is represented using two var's: +# 1. the input var: expected type of the field; convenient for creating using parse-var-with-type +# 2. the output var: a constant containing the byte offset; convenient for code-generation +Typeinfo-fields: # (handle table string {(handle var), (handle var)}) 4/imm32 Typeinfo-next: # (handle typeinfo) 8/imm32 @@ -1963,6 +1967,62 @@ test-convert-index-into-array: 5d/pop-to-ebp c3/return +test-convert-type-definition: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + c7 0/subop/copy *Next-block-index 1/imm32 + # + (write _test-input-stream "fn foo a: (addr t) {\n") + (write _test-input-stream " var _a/eax: (addr t) <- copy a\n") + (write _test-input-stream " var b/ecx: (addr int) <- get _a, x\n") + (write _test-input-stream " var c/ecx: (addr int) <- get _a, y\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: int\n") + (write _test-input-stream " y: int\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-user-defined-type/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-user-defined-type/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-user-defined-type/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-user-defined-type/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-user-defined-type/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-user-defined-type/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-function-with-user-defined-type/6") + (check-next-stream-line-equal _test-output-stream " 8b/copy-from *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-function-with-user-defined-type/7") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-with-user-defined-type/8") + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + 0x00000000) 0x00000001/r32" "F - test-convert-function-with-user-defined-type/9") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-with-user-defined-type/10") + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + 0x00000004) 0x00000001/r32" "F - test-convert-function-with-user-defined-type/11") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-with-user-defined-type/12") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-with-user-defined-type/13") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-function-with-user-defined-type/14") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-user-defined-type/15") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-user-defined-type/16") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-user-defined-type/17") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-user-defined-type/18") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-user-defined-type/19") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-user-defined-type/20") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + ####################################################### # Parsing ####################################################### @@ -1990,6 +2050,12 @@ parse-mu: # in: (addr buffered-file) # assert(vars->top == 0) # *curr-function = new-function # curr-function = &new-function->next + # else if slice-equal?(word-slice, "type") + # word-slice = next-mu-token(line) + # type-id = pos-or-insert-slice(Type-id, word-slice) + # var new-type: (handle typeinfo) = find-or-create-typeinfo(type-id) + # assert(next-word(line) == "{") + # populate-mu-type(in, new-type) # else # abort() # @@ -2066,6 +2132,21 @@ $parse-mu:fn: 8d/address-> *(eax+0x14) 7/r32/edi # Function-next e9/jump $parse-mu:line-loop/disp32 } + # if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition + { +$parse-mu:type: + (slice-equal? %edx "type") + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= break/disp32 + (next-mu-token %ecx %edx) + # var type-id/eax: int + (pos-or-insert-slice Type-id %edx) # => eax + # var new-type/eax: (handle typeinfo) + (find-or-create-typeinfo %eax) # => eax + # TODO: ensure that 'line' has nothing else but '{' + (populate-mu-type *(ebp+8) %eax) # => eax + e9/jump $parse-mu:line-loop/disp32 + } # otherwise abort e9/jump $parse-mu:error1/disp32 } # end line loop @@ -2632,7 +2713,7 @@ parse-type: # ad: (address allocation-descriptor), in: (addr stream byte) -> re 3d/compare-eax-and 0/imm32/false 75/jump-if-!= break/disp8 # result->left = pos-or-insert-slice(Type-id, s) - (pos-or-insert-slice Type-id %ecx) + (pos-or-insert-slice Type-id %ecx) # => eax #? (write-buffered Stderr "=> {") #? (print-int32-buffered Stderr %eax) #? (write-buffered Stderr ", 0}\n") @@ -2909,7 +2990,7 @@ $pos-or-insert-slice:end: 5d/pop-to-ebp c3/return -# return the index in an array of strings matching 's' +# return the index in an array of strings matching 's', -1 if not found # index is denominated in elements, not bytes pos-slice: # arr: (addr stream (handle array byte)), s: (addr slice) -> index/eax: int # . prologue @@ -4054,6 +4135,7 @@ add-operation-and-inputs-to-stmt: # stmt: (handle stmt), line: (addr stream byt 50/push-eax 51/push-ecx 52/push-edx + 53/push-ebx 57/push-edi # edi = stmt 8b/-> *(ebp+8) 7/r32/edi @@ -4067,6 +4149,9 @@ $add-operation-and-inputs-to-stmt:read-operation: (next-mu-token *(ebp+0xc) %ecx) (slice-to-string Heap %ecx) # => eax 89/<- *(edi+4) 0/r32/eax # Stmt1-operation or Regvardef-operation + # var is-get?/ebx: boolean = (name == "get") + (slice-equal? %ecx "get") # => eax + 89/<- %ebx 0/r32/eax { $add-operation-and-inputs-to-stmt:read-inouts: # name = next-mu-token(line) @@ -4079,6 +4164,21 @@ $add-operation-and-inputs-to-stmt:read-inouts: (slice-equal? %ecx "<-") 3d/compare-eax-and 0/imm32/false 0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32 + # if (is-get? && second operand) lookup or create offset + { + 81 7/subop/compare %ebx 0/imm32/false + 74/jump-if-= break/disp8 + 81 7/subop/compare *(edi+8) 0/imm32 # Stmt1-inouts or Regvardef-inouts + 74/jump-if-= break/disp8 + (lookup-or-create-constant *(edi+8) %ecx) # Stmt1-inouts => eax +#? (write-buffered Stderr "creating new output var ") +#? (print-int32-buffered Stderr %eax) +#? (write-buffered Stderr " for field called ") +#? (write-slice-buffered Stderr %ecx) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + e9/jump $add-operation-and-inputs-to-stmt:save-var/disp32 + } # is-deref? = false ba/copy-to-edx 0/imm32/false # if (slice-starts-with?(name, '*')) ++name->start and set is-deref? @@ -4103,6 +4203,7 @@ $add-operation-and-inputs-to-stmt:end: 81 0/subop/add %esp 8/imm32 # . restore registers 5f/pop-to-edi + 5b/pop-to-ebx 5a/pop-to-edx 59/pop-to-ecx 58/pop-to-eax @@ -4489,7 +4590,7 @@ $new-function:end: 5d/pop-to-ebp c3/return -new-var: # ad: (addr allocation-descriptor), name: (addr array byte), type: (addr tree type-id), block: int, stack-offset: int, register: (addr array byte) -> result/eax: (handle var) +new-var: # ad: (addr allocation-descriptor), name: (addr array byte), type: (addr tree type-id), block: int, offset: int, register: (addr array byte) -> result/eax: (handle var) # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp @@ -4771,6 +4872,334 @@ $append-to-block:end: 5d/pop-to-ebp c3/return +## Parsing types +# We need to create metadata on user-defined types, and we need to use this +# metadata as we parse instructions. +# However, we also want to allow types to be used before their definitions. +# This means we can't ever assume any type data structures exist. + +lookup-or-create-constant: # container: (handle stmt-var), field-name: (addr slice) -> result/eax: (handle var) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 56/push-esi + # var container-type/esi: type-id + (container-type *(ebp+8)) # => eax +#? (write-buffered Stderr "lookup-or-create-constant: container type-id: ") +#? (print-int32-buffered Stderr %eax) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + 89/<- %esi 0/r32/eax + # var typeinfo/eax: (addr typeinfo) + (find-or-create-typeinfo %esi) # => eax +#? (write-buffered Stderr "lookup-or-create-constant: typeinfo: ") +#? (print-int32-buffered Stderr %eax) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + # result = find-or-create-typeinfo-constant(typeinfo, field-name) + (find-or-create-typeinfo-constant %eax *(ebp+0xc)) # => eax +$lookup-or-create-constant:end: + # . restore registers + 5e/pop-to-esi + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# container->var->type->right->left->value +container-type: # container: (handle stmt-var) -> result/eax: type-id + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # + 8b/-> *(ebp+8) 0/r32/eax + 8b/-> *eax 0/r32/eax # Stmt-var-value + 8b/-> *(eax+4) 0/r32/eax # Var-type + 8b/-> *(eax+4) 0/r32/eax # Tree-right + 8b/-> *eax 0/r32/eax # Tree-left + 8b/-> *eax 0/r32/eax # Atom-value +$container-type:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +find-or-create-typeinfo: # t: type-id -> result/eax: (handle typeinfo) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # eax = find-typeinfo(t) + (find-typeinfo *(ebp+8)) # => eax + { + # if (curr != 0) break + 3d/compare-eax-and 0/imm32 + 75/jump-if-!= break/disp8 +$find-or-create-typeinfo:create: + (allocate Heap *Typeinfo-size) # => eax + (zero-out %eax *Typeinfo-size) + # result->id = t + 8b/-> *(ebp+8) 1/r32/ecx + 89/<- *eax 1/r32/ecx # Typeinfo-id + # result->fields = new table + 50/push-eax + (new-stream Heap 0x40 0xc) # => eax + 89/<- %ecx 0/r32/eax + 58/pop-to-eax + 89/<- *(eax+4) 1/r32/ecx + # result->next = Program->types + 8b/-> *_Program-types 1/r32/ecx + 89/<- *(eax+8) 1/r32/ecx # Typeinfo-next + # Program->types = result + 89/<- *_Program-types 0/r32/eax + } +$find-or-create-typeinfo:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +find-typeinfo: # t: type-id -> result/eax: (handle typeinfo) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # ecx = t + 8b/-> *(ebp+8) 1/r32/ecx + # var curr/eax: (handle typeinfo) = Program->types + 8b/-> *_Program-types 0/r32/eax + { + # if (curr == 0) break + 3d/compare-eax-and 0/imm32 + 74/jump-if-= break/disp8 + # if (curr->id == t) return curr + 39/compare *eax 1/r32/ecx # Typeinfo-id + 0f 84/jump-if-= $find-or-create-typeinfo:end/disp32 + # curr = curr->next + 8b/-> *(eax+8) 0/r32/eax + # + eb/jump loop/disp8 + } +$find-typeinfo:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +find-or-create-typeinfo-constant: # T: (handle typeinfo), f: (addr slice) -> result/eax: (handle var) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + 56/push-esi + # esi = T->fields + 8b/-> *(ebp+8) 6/r32/esi + 8b/-> *(esi+4) 6/r32/esi # Typeinfo-fields + # esi = get-or-insert(T->fields, f) + (leaky-get-or-insert-slice %esi *(ebp+0xc) 0xc) # => eax + 89/<- %esi 0/r32/eax + # if output var exists, return it + 81 7/subop/compare *(esi+4) 0/imm32 # output var + 8b/-> *(esi+4) 0/r32/eax # output var + 75/jump-if-!= $find-or-create-typeinfo-constant:end/disp8 + # var type/ecx: (handle tree type-id) = new var("dummy name", constant type, -1 offset) + (allocate Heap *Tree-size) # => eax + c7 0/subop/copy *eax 6/imm32/constant # Atom-value + c7 0/subop/copy *(eax+4) 0/imm32 # Tree-right + (new-var Heap "field" %eax 0 -1 0) # => eax + # offset (constant value) isn't filled out yet + # save output var in row + 89/<- *(esi+4) 0/r32/eax +$find-or-create-typeinfo-constant:end: + # . restore registers + 5e/pop-to-esi + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +populate-mu-type: # in: (addr stream byte), t: (handle typeinfo) + # pseudocode: + # var line: (stream byte 512) + # curr-offset = 0 + # while true + # clear-stream(line) + # read-line-buffered(in, line) + # if line->write == 0 + # abort + # word-slice = next-mu-token(line) + # if slice-empty?(word-slice) # end of line + # continue + # if slice-equal?(word-slice, "}") + # break + # var v: (handle var) = parse-var-with-type(word-slice, line) + # var r: (addr {(handle var) (handle var)}) = get-or-insert(t, v->name, row-size=12) + # TODO: ensure that r->first is null + # r->first = v + # if r->second == 0 + # r->second = new var("dummy name", constant type, -1 offset) + # r->second->offset = curr-offset + # curr-offset += size-of(existing) + # TODO: ensure nothing else in line + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # edi = t + 8b/-> *(ebp+0xc) 7/r32/edi + # var line/ecx: (stream byte 512) + 81 5/subop/subtract %esp 0x200/imm32 + 68/push 0x200/imm32/length + 68/push 0/imm32/read + 68/push 0/imm32/write + 89/<- %ecx 4/r32/esp + # var word-slice/edx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %edx 4/r32/esp + # var curr-offset/ebx: int = 0 + bb/copy-to-ebx 0/imm32 + { +$populate-mu-type:line-loop: + (clear-stream %ecx) + (read-line-buffered *(ebp+8) %ecx) + # if (line->write == 0) abort + 81 7/subop/compare *ecx 0/imm32 + 0f 84/jump-if-= $populate-mu-type:abort/disp32 +#? # dump line {{{ +#? (write 2 "parse-mu: ^") +#? (write-stream 2 %ecx) +#? (write 2 "$\n") +#? (rewind-stream %ecx) +#? # }}} + (next-mu-token %ecx %edx) + # if slice-empty?(word-slice) continue + (slice-empty? %edx) + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= loop/disp32 + # if slice-equal?(word-slice, "}") break + (slice-equal? %edx "}") + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= break/disp32 + # var v/esi: (handle var) = parse-var-with-type(word-slice, first-line) + (parse-var-with-type %edx %ecx) # => eax + 89/<- %esi 0/r32/eax + # var r/eax: (addr {(handle var) (handle var)}) +#? (write-buffered Stderr "populate-mu-type: typeinfo: ") +#? (print-int32-buffered Stderr %edi) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + (get-or-insert *(edi+4) *esi 0xc) # Typeinfo-fields Var-name => eax + # r->first = v + 89/<- *eax 6/r32/esi + # if (r->second == 0) create a new var with some placeholder data + { + 81 7/subop/compare *(eax+4) 0/imm32 + 75/jump-if-!= break/disp8 + # temporarily spill r to esi + 89/<- %esi 0/r32/eax + (new-literal Heap %edx) # => eax + 89/<- *(esi+4) 0/r32/eax + 89/<- %eax 6/r32/esi +#? (write-buffered Stderr "creating new output var ") +#? (print-int32-buffered Stderr %eax) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + } + # r->second->offset = curr-offset + 8b/-> *(eax+4) 0/r32/eax +#? (write-buffered Stderr "writing offset ") +#? (print-int32-buffered Stderr %ebx) +#? (write-buffered Stderr " to output var ") +#? (print-int32-buffered Stderr %eax) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + 89/<- *(eax+0xc) 3/r32/ebx + # curr-offset += size-of(v) + 50/push-eax + (size-of %eax) # => eax + 01/add-to %ebx 0/r32/eax + 58/pop-to-eax + # + e9/jump loop/disp32 + } +$populate-mu-type:end: + # . reclaim locals + 81 0/subop/add %esp 0x214/imm32 + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$populate-mu-type:abort: + # error("unexpected top-level command: " word-slice "\n") + (write-buffered Stderr "incomplete type definition '") + (type-name *edi) # Typeinfo-id => eax + (write-buffered Stderr %eax) + (write-buffered Stderr "\n") + (flush Stderr) + # . syscall(exit, 1) + bb/copy-to-ebx 1/imm32 + b8/copy-to-eax 1/imm32/exit + cd/syscall 0x80/imm8 + # never gets here + +type-name: # index: int -> result/eax: (addr array byte) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # + (index Type-id *(ebp+8)) +$type-name:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +index: # arr: (addr stream (handle array byte)), index: int -> result/eax: (addr array byte) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 56/push-esi + # TODO: bounds-check index + # esi = arr + 8b/-> *(ebp+8) 6/r32/esi + # eax = index + 8b/-> *(ebp+0xc) 0/r32/eax + # eax = *(arr + 12 + index) + 8b/-> *(esi+eax+0xc) 0/r32/eax +$index:end: + # . restore registers + 5e/pop-to-esi + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + ####################################################### # Type-checking ####################################################### @@ -5626,6 +6055,32 @@ $emit-subx-stmt-list:index: e9/jump $emit-subx-stmt:end/disp32 } # }}} + # get field from record {{{ + { + # if (!string-equal?(var->operation, "get")) break + (string-equal? *(ecx+4) "get") # Stmt1-operation => eax + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= break/disp32 +$emit-subx-stmt-list:get: + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "8d/copy-address *(") + # inouts[0]->register " + " + 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts + 8b/-> *eax 0/r32/eax # Stmt-var-value + (write-buffered *(ebp+8) *(eax+0x10)) # Var-register => eax + # + (write-buffered *(ebp+8) " + ") + (print-mu-get-offset *(ebp+8) %ecx) + (write-buffered *(ebp+8) ") ") + # outputs[0] "/r32" + 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs + 8b/-> *eax 0/r32/eax # List-value + (get Registers *(eax+0x10) 8 "Registers") # Var-register => eax + (print-int32-buffered *(ebp+8) *eax) + (write-buffered *(ebp+8) "/r32\n") + e9/jump $emit-subx-stmt:end/disp32 + } + # }}} # if stmt matches a primitive, emit it { $emit-subx-stmt:check-for-primitive: @@ -5670,6 +6125,32 @@ $emit-subx-stmt:abort: cd/syscall 0x80/imm8 # never gets here +print-mu-get-offset: # out: (addr buffered-file), stmt: (handle stmt) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + # var second-inout/eax: (handle stmt-var) = stmt->inouts->next + 8b/-> *(ebp+0xc) 0/r32/eax + 8b/-> *(eax+8) 0/r32/eax # Stmt1-inouts + 8b/-> *(eax+4) 0/r32/eax # Stmt-var-next + # var output-var/eax: (handle var) = second-inout->value + 8b/-> *eax 0/r32/eax # Stmt-var-value + # print offset +#? (write-buffered Stderr "emitting offset from output var ") +#? (print-int32-buffered Stderr %eax) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-offset +$emit-get-offset:end: + # . restore registers + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + emit-subx-block: # out: (addr buffered-file), block: (handle block), vars: (addr stack (handle var)) # . prologue 55/push-ebp |