diff --git a/308allocate-array.subx b/308allocate-array.subx index 7040106c..01eb1dc3 100644 --- a/308allocate-array.subx +++ b/308allocate-array.subx @@ -1,6 +1,6 @@ # 2-arg version of allocate-array. -allocate-array2: # ad: (addr allocation-descriptor), elem-size: int, array-len: int, out: (addr handle array _) +allocate-array2: # ad: (addr allocation-descriptor), array-len: int, elem-size: int, out: (addr handle array _) # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp diff --git a/400.mu b/400.mu index 83661b56..369e29cd 100644 --- a/400.mu +++ b/400.mu @@ -78,7 +78,7 @@ sig copy-handle src: (handle _T), dest: (addr handle _T) #sig allocate-array ad: (addr allocation-descriptor), n: int, out: (addr handle _) sig copy-array ad: (addr allocation-descriptor), src: (addr array _T), out: (addr handle array _T) #sig zero-out start: (addr byte), size: int -sig new-stream ad: (addr allocation-descriptor), length: int, elemsize: int, out: (addr handle stream _) +#sig new-stream ad: (addr allocation-descriptor), length: int, elemsize: int, out: (addr handle stream _) sig read-line-buffered f: (addr buffered-file), s: (addr stream byte) sig read-line f: (addr stream byte), s: (addr stream byte) sig slice-empty? s: (addr slice) -> result/eax: boolean @@ -156,4 +156,4 @@ sig enable-keyboard-immediate-mode sig enable-keyboard-type-mode sig read-key -> result/eax: byte sig open filename: (addr array byte), write?: boolean, out: (addr handle buffered-file) -sig size in: (addr array _) -> result/eax: int +#sig size in: (addr array _) -> result/eax: int diff --git a/apps/mu b/apps/mu index 7ae8daf3..70271920 100755 Binary files a/apps/mu and b/apps/mu differ diff --git a/apps/mu.subx b/apps/mu.subx index 536bca5d..2f13b3cb 100644 --- a/apps/mu.subx +++ b/apps/mu.subx @@ -407,8 +407,11 @@ Type-id: # (stream (addr array byte)) # Not to be used directly, so we don't include a name here. 0/imm32 # 10 reserved for type parameters; value is (address array byte) in Type-tree-value2. # Not to be used directly, so we don't include a name here. + # some SubX types deliberately left undefined in Mu; they can only be operated on using SubX primitives + "stream"/imm32 # 11 + "slice"/imm32 # 12 # Keep Primitive-type-ids in sync if you add types here. - 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 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 @@ -417,7 +420,7 @@ Type-id: # (stream (addr array byte)) 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 Primitive-type-ids: # (addr int) - 0x2c + 0x34 # == Type definitions # Program->types contains some typeinfo for each type definition. @@ -10789,6 +10792,18 @@ $populate-mu-type:parse-element: (is-mu-array-type? %eax) # => eax 3d/compare-eax-and 0/imm32/false 0f 85/jump-if-!= $populate-mu-type:error3/disp32 + # if v is a slice, abort + (lookup *esi *(esi+4)) # => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 0xc) # slice => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-type:error4/disp32 + # if v is a stream, abort (we could support it, but initialization gets even more complex) + (lookup *esi *(esi+4)) # => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + (is-mu-stream-type? %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-type:error5/disp32 # var tmp/ecx 51/push-ecx $populate-mu-type:create-typeinfo-fields: @@ -10876,6 +10891,26 @@ $populate-mu-type:error3: (stop *(ebp+0x14) 1) # never gets here +$populate-mu-type:error4: + # error("type " t->name ": invalid type 'array'\n") + (write-buffered *(ebp+0x10) "type ") + (type-name *edi) # Typeinfo-id => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": invalid type 'slice'\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$populate-mu-type:error5: + # error("type " t->name ": invalid type 'array'\n") + (write-buffered *(ebp+0x10) "type ") + (type-name *edi) # Typeinfo-id => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": invalid type 'stream'\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + type-name: # index: int -> result/eax: (addr array byte) # . prologue 55/push-ebp @@ -11085,6 +11120,13 @@ compute-size-of-type-id: # t: type-id -> result/eax: int b8/copy-to-eax 8/imm32 eb/jump $compute-size-of-type-id:end/disp8 # eax changes type from type-id to int } + # if t is a slice, return 8 + 3d/compare-eax-and 0xc/imm32/slice + { + 75/jump-if-!= break/disp8 + b8/copy-to-eax 8/imm32 + eb/jump $compute-size-of-type-id:end/disp8 # eax changes type from type-id to int + } # if t is a user-defined type, compute its size # TODO: support non-atom type (find-typeinfo %eax %ecx) @@ -12773,6 +12815,14 @@ size-of: # v: (addr var) -> result/eax: int (size-of-array %ecx) # => eax eb/jump $size-of:end/disp8 } + # if is-mu-stream?(t) return size-of-stream(t) + { + (is-mu-stream? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (size-of-stream %ecx) # => eax + eb/jump $size-of:end/disp8 + } # if (!t->is-atom?) t = lookup(t->left) { 81 7/subop/compare *ecx 0/imm32/false # Type-tree-is-atom @@ -12812,6 +12862,14 @@ size-of-deref: # v: (addr var) -> result/eax: int (size-of-array %ecx) # => eax eb/jump $size-of-deref:end/disp8 } + # if is-mu-stream?(t) return size-of-stream(t) + { + (is-mu-stream? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (size-of-stream %ecx) # => eax + eb/jump $size-of-deref:end/disp8 + } # if (!t->is-atom?) t = lookup(t->left) { 81 7/subop/compare *ecx 0/imm32/false # Type-tree-is-atom @@ -12859,6 +12917,7 @@ $is-mu-array?:end: 5d/pop-to-ebp c3/return +# size of a statically allocated array where the size is part of the type expression size-of-array: # a: (addr type-tree) -> result/eax: int # . prologue 55/push-ebp @@ -12892,6 +12951,50 @@ $size-of-array:end: 5d/pop-to-ebp c3/return +is-mu-stream?: # t: (addr type-tree) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # ecx = t + 8b/-> *(ebp+8) 1/r32/ecx + # if t->is-atom?, return false + 81 7/subop/compare *ecx 0/imm32/false # Type-tree-is-atom + 75/jump-if-!= $is-mu-stream?:return-false/disp8 + # if !t->left->is-atom?, return false + (lookup *(ecx+4) *(ecx+8)) # Type-tree-left Type-tree-left => eax + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + 74/jump-if-= $is-mu-stream?:return-false/disp8 + # return t->left->value == stream + 81 7/subop/compare *(eax+4) 0xb/imm32/stream-type-id # Type-tree-value + 0f 94/set-if-= %al + 81 4/subop/and %eax 0xff/imm32 + eb/jump $is-mu-stream?:end/disp8 +$is-mu-stream?:return-false: + b8/copy-to-eax 0/imm32/false +$is-mu-stream?:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# size of a statically allocated stream where the size is part of the type expression +size-of-stream: # a: (addr type-tree) -> result/eax: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # + (size-of-array *(ebp+8)) # assumes we ignore the actual type name 'array' in the type + 05/add-to-eax 8/imm32 # for read/write pointers +$size-of-stream:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + size-of-type-id: # t: type-id -> result/eax: int # . prologue 55/push-ebp @@ -14268,7 +14371,7 @@ emit-subx-var-def: # out: (addr buffered-file), stmt: (addr stmt) # v->offset = *Curr-local-stack-offset 8b/-> *Curr-local-stack-offset 0/r32/eax 89/<- *(ecx+0x14) 0/r32/eax # Var-offset - # if v is an array, do something special + # if v is an array, do something special to initialize it { (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax (is-mu-array? %eax) # => eax @@ -14276,14 +14379,26 @@ emit-subx-var-def: # out: (addr buffered-file), stmt: (addr stmt) 0f 84/jump-if-= break/disp32 # var array-size-without-size/edx: int = n-4 81 5/subop/subtract %edx 4/imm32 + # + (emit-array-data-initialization *(ebp+8) %edx) + e9/jump $emit-subx-var-def:end/disp32 + } + # another special-case for initializing streams + # a stream is an array with 2 extra pointers + { + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + (is-mu-stream? %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 + # var array-size-without-size/edx: int = n-12 + 81 5/subop/subtract %edx 0xc/imm32 + (emit-array-data-initialization *(ebp+8) %edx) + # emit read and write pointers (emit-indent *(ebp+8) *Curr-block-depth) - (write-buffered *(ebp+8) "(push-n-zero-bytes ") - (write-int32-hex-buffered *(ebp+8) %edx) - (write-buffered *(ebp+8) ")\n") + (write-buffered *(ebp+8) "68/push 0/imm32\n") (emit-indent *(ebp+8) *Curr-block-depth) - (write-buffered *(ebp+8) "68/push ") - (write-int32-hex-buffered *(ebp+8) %edx) - (write-buffered *(ebp+8) "/imm32\n") + (write-buffered *(ebp+8) "68/push 0/imm32\n") + # eb/jump $emit-subx-var-def:end/disp8 } # while n > 0 @@ -14307,6 +14422,25 @@ $emit-subx-var-def:end: 5d/pop-to-ebp c3/return +emit-array-data-initialization: # out: (addr buffered-file), n: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "(push-n-zero-bytes ") + (write-int32-hex-buffered *(ebp+8) *(ebp+0xc)) + (write-buffered *(ebp+8) ")\n") + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "68/push ") + (write-int32-hex-buffered *(ebp+8) *(ebp+0xc)) + (write-buffered *(ebp+8) "/imm32\n") +$emit-array-data-initialization:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + emit-subx-stmt: # out: (addr buffered-file), stmt: (addr stmt), primitives: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor) # . prologue 55/push-ebp @@ -14373,6 +14507,15 @@ emit-subx-stmt: # out: (addr buffered-file), stmt: (addr stmt), primitives: (ad (translate-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18)) e9/jump $emit-subx-stmt:end/disp32 } + # allocate stream + { + # if (!string-equal?(stmt->operation, "populate-stream")) break + (string-equal? %ecx "populate-stream") # => eax + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= break/disp32 + (translate-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18)) + e9/jump $emit-subx-stmt:end/disp32 + } # - if stmt matches a primitive, emit it { $emit-subx-stmt:check-for-primitive: @@ -15210,6 +15353,42 @@ $translate-mu-populate-stmt:end: 5d/pop-to-ebp c3/return +translate-mu-populate-stream-stmt: # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 56/push-esi + 57/push-edi + # esi = stmt + 8b/-> *(ebp+0xc) 6/r32/esi + # var target/edi: (addr stmt-var) = stmt->inouts[0] + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %edi 0/r32/eax + # var len/ecx: (addr stmt-var) = stmt->inouts[1] + (lookup *(edi+8) *(edi+0xc)) # Stmt-var-next Stmt-var-next => eax + 89/<- %ecx 0/r32/eax + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "(new-stream Heap ") + (addr-handle-array-payload-size %edi *(ebp+0x10) *(ebp+0x14)) # => eax + (write-int32-hex-buffered *(ebp+8) %eax) + (emit-subx-call-operand *(ebp+8) %ecx) + (emit-subx-call-operand *(ebp+8) %edi) + (write-buffered *(ebp+8) ")\n") +$translate-mu-populate-stream-stmt:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + addr-handle-array-payload-size: # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int # . prologue 55/push-ebp @@ -19568,6 +19747,28 @@ $is-mu-array-type?:end: 5d/pop-to-ebp c3/return +is-mu-stream-type?: # a: (addr type-tree) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # eax = a + 8b/-> *(ebp+8) 0/r32/eax + # if (!a->is-atom?) a = a->left + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + # return (a->value == stream) + 81 7/subop/compare *(eax+4) 0xb/imm32/stream # Type-tree-value + 0f 94/set-byte-if-= %al + 81 4/subop/and %eax 0xff/imm32 +$is-mu-stream-type?:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + test-emit-subx-stmt-primitive: # Primitive operation on a variable on the stack. # increment foo