You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

208 lines
5.4KB

  1. ; construct.s - runtime object construction and deletion (E05-S03).
  2. ;
  3. ; This layer sits above the E05-S01 heap and the E05-S02 descriptor ABI. It
  4. ; deliberately does not depend on the compiler: generated code will call it
  5. ; after evaluating constructor arguments.
  6. ;
  7. ; API:
  8. ; obj_new A/X = class descriptor pointer. The caller has already
  9. ; pushed constructor arguments right-to-left on the software
  10. ; frame stack and set obj_init_ptr to the init entry (or 0).
  11. ; Allocates the descriptor's instance size, zeroes it (heap
  12. ; contract), stores the descriptor at object+0, then calls
  13. ; init with A/X = self. Returns A/X = object, C=0. On failure
  14. ; A/X=0, C=1 and obj_error is OBJ_ERR_HEAP or OBJ_ERR_BAD.
  15. ; init is never called on failure.
  16. ; obj_delete A/X = object. Null is a no-op. Reads the optional
  17. ; destructor from the descriptor, calls it once with A/X =
  18. ; self, then frees the complete object. Returns C=0 and
  19. ; A/X=0; C=1 with obj_error on a bad object or heap error.
  20. ; obj_init_ptr init entry selected by the caller; 0 = no init.
  21. ; obj_error OBJ_OK, OBJ_ERR_HEAP, or OBJ_ERR_BAD.
  22. ;
  23. ; Constructor arguments remain on the caller's frame stack. init uses the
  24. ; normal frame_enter/frame_leave contract and sees them at FP+2. The caller
  25. ; discards the argument bytes after obj_new returns. obj_delete and obj_new
  26. ; use obj_call, a synthetic-return indirect call, because the 8502 has no
  27. ; JSR (address). obj_call takes its entry from co_vec because A/X already
  28. ; carry the callee's self pointer; it preserves A/X and only needs one level
  29. ; of synthetic return, so E06-S02 can reuse it for interface dispatch.
  30. .setcpu "6502"
  31. .include "../common/class.inc"
  32. .import heap_alloc, heap_free, obj_class
  33. .export obj_new, obj_delete, obj_init_ptr, obj_error
  34. .segment "ZEROPAGE"
  35. co_vec: .res 2 ; indirect target for obj_call
  36. co_desc: .res 2 ; descriptor pointer
  37. co_ptr: .res 2 ; object header writer
  38. co_self: .res 2 ; A/X passed through obj_call
  39. .segment "CODE"
  40. ; A/X = descriptor. Allocate and construct; see the API above.
  41. obj_new:
  42. sta co_desc
  43. stx co_desc+1
  44. lda #OBJ_OK
  45. sta obj_error
  46. ldy #CD_INSTANCE_SIZE
  47. lda (co_desc),y
  48. sta co_size
  49. iny
  50. lda (co_desc),y
  51. sta co_size+1
  52. ora co_size
  53. beq @bad
  54. lda co_size
  55. ldx co_size+1
  56. jsr heap_alloc
  57. bcs @heap_fail
  58. sta co_obj
  59. stx co_obj+1
  60. lda co_obj ; object+0 = descriptor
  61. sta co_ptr
  62. lda co_obj+1
  63. sta co_ptr+1
  64. ldy #OBJ_DESCRIPTOR
  65. lda co_desc
  66. sta (co_ptr),y
  67. iny
  68. lda co_desc+1
  69. sta (co_ptr),y
  70. lda obj_init_ptr
  71. ora obj_init_ptr+1
  72. beq @ok
  73. lda obj_init_ptr
  74. sta co_vec
  75. lda obj_init_ptr+1
  76. sta co_vec+1
  77. lda co_obj
  78. ldx co_obj+1
  79. jsr obj_call
  80. @ok:
  81. lda co_obj
  82. ldx co_obj+1
  83. clc
  84. rts
  85. @heap_fail:
  86. lda #OBJ_ERR_HEAP
  87. sta obj_error
  88. lda #$00
  89. tax
  90. sec
  91. rts
  92. @bad:
  93. lda #OBJ_ERR_BAD
  94. sta obj_error
  95. lda #$00
  96. tax
  97. sec
  98. rts
  99. ; A/X = object. Optional destructor, then free. Null is successful.
  100. obj_delete:
  101. sta co_obj
  102. stx co_obj+1
  103. lda #OBJ_OK
  104. sta obj_error
  105. lda co_obj
  106. ora co_obj+1
  107. bne :+
  108. jmp @null
  109. :
  110. lda co_obj ; reload: the null test left A = low|high
  111. ldx co_obj+1
  112. jsr obj_class
  113. bcc :+
  114. jmp @bad
  115. :
  116. sta co_desc
  117. stx co_desc+1
  118. ldy #CD_INSTANCE_SIZE
  119. lda (co_desc),y
  120. sta co_size
  121. iny
  122. lda (co_desc),y
  123. sta co_size+1
  124. ora co_size
  125. bne :+
  126. jmp @bad
  127. :
  128. ldy #CD_DESTRUCTOR
  129. lda (co_desc),y
  130. sta co_destroy
  131. iny
  132. lda (co_desc),y
  133. sta co_destroy+1
  134. lda co_destroy
  135. ora co_destroy+1
  136. bne :+
  137. jmp @free
  138. :
  139. lda co_destroy
  140. sta co_vec
  141. lda co_destroy+1
  142. sta co_vec+1
  143. lda co_obj
  144. ldx co_obj+1
  145. jsr obj_call
  146. @free:
  147. lda co_obj
  148. ldx co_obj+1
  149. jsr heap_free
  150. bcs @heap_fail
  151. @null:
  152. lda #$00
  153. tax
  154. clc
  155. rts
  156. @heap_fail:
  157. lda #OBJ_ERR_HEAP
  158. sta obj_error
  159. lda #$00
  160. tax
  161. sec
  162. rts
  163. @bad:
  164. lda #OBJ_ERR_BAD
  165. sta obj_error
  166. lda #$00
  167. tax
  168. sec
  169. rts
  170. ; Entry in co_vec. A/X pass through to the callee, so the caller passes self
  171. ; there. Push a synthetic return address, then JMP (co_vec): the callee's RTS
  172. ; returns to @ret, whose RTS returns to the original caller. co_vec must not
  173. ; straddle a page because of the 6502 JMP-indirect bug.
  174. obj_call:
  175. sta co_self
  176. stx co_self+1
  177. lda #>(@ret - 1)
  178. pha
  179. lda #<(@ret - 1)
  180. pha
  181. lda co_self
  182. ldx co_self+1
  183. jmp (co_vec)
  184. @ret: rts
  185. .assert <co_vec <> $FF, error, "co_vec must not straddle a page"
  186. .segment "BSS"
  187. co_obj: .res 2
  188. co_size: .res 2
  189. co_destroy: .res 2
  190. obj_init_ptr: .res 2
  191. obj_error: .res 1

Powered by TurnKey Linux.