25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

443 satır
9.3KB

  1. ; E06-S06: interface lifetime and failure paths in x128.
  2. ;
  3. ; Runs under CR=$0E with a 4K heap at $4000. It checks:
  4. ; - delete through an interface value calls the class destructor once, frees
  5. ; the complete object, and clears the value so it cannot delete twice;
  6. ; - delete on a canonical null interface value is a no-op;
  7. ; - one object reachable through two interface tables is freed once, and the
  8. ; other value is refused afterwards;
  9. ; - an alias (a copy of the value) that outlives the deletion is a detectable
  10. ; failure: IF_ERR_FREED, no second destructor call, no heap change;
  11. ; - a null interface call faults predictably with IF_ERR_NULL, executes no
  12. ; target, and leaves dispatch working.
  13. ;
  14. ; MB_DATA flags 0..4 report the five phases.
  15. .setcpu "6502"
  16. .include "../../src/common/c128.inc"
  17. .include "../../src/common/mailbox.inc"
  18. .include "../../src/common/print.inc"
  19. .include "../../src/common/heap.inc"
  20. .include "../../src/common/class.inc"
  21. .include "../../src/common/frames.inc"
  22. .include "../../src/common/interfaces.inc"
  23. .import pr_char, pr_cr, pr_text
  24. .import heap_init, heap_free_total, heap_error
  25. .import frame_init
  26. .import obj_new, obj_init_ptr
  27. .import if_call, if_error
  28. .import if_delete
  29. HEAP_BASE = $4000
  30. HEAP_PAGES = 16
  31. .macro TEXT src, len
  32. lda #<src
  33. ldx #>src
  34. ldy #len
  35. jsr pr_text
  36. .endmacro
  37. .macro PHASE n
  38. lda #n
  39. sta MB_CODE
  40. lda #$00
  41. sta MB_CODE+1
  42. .endmacro
  43. .macro MARK n
  44. lda #n
  45. sta MB_ADDR
  46. .endmacro
  47. .macro FAIL_CS
  48. bcc :+
  49. jmp @fail
  50. :
  51. .endmacro
  52. .macro FAIL_CC
  53. bcs :+
  54. jmp @fail
  55. :
  56. .endmacro
  57. .macro FAIL_NE
  58. beq :+
  59. jmp @fail
  60. :
  61. .endmacro
  62. ; A word in A/X must equal the two bytes at addr.
  63. .macro CHK_WORD addr
  64. cmp addr
  65. bne @bad
  66. txa
  67. cmp addr+1
  68. beq @ok
  69. @bad: jmp @fail
  70. @ok:
  71. .endmacro
  72. .segment "LOADADDR"
  73. .word $1C01
  74. .segment "EXEHDR"
  75. .word basic_end
  76. .word 10
  77. .byte $9E
  78. .byte "7181"
  79. .byte $00
  80. basic_end:
  81. .word $0000
  82. .segment "MAILBOX"
  83. .res MB_SIZE
  84. .segment "STARTUP"
  85. .export test_entry, test_end
  86. test_entry:
  87. php
  88. sei
  89. ldx #MB_SIZE - 1
  90. lda #$00
  91. @clr: sta MB_BASE,x
  92. dex
  93. bpl @clr
  94. lda #MB_MAGIC0_VALUE
  95. sta MB_MAGIC0
  96. lda #MB_MAGIC1_VALUE
  97. sta MB_MAGIC1
  98. lda #MB_PROD_PROGRAM
  99. sta MB_PRODUCER
  100. lda #MB_ST_RUNNING
  101. sta MB_STATUS
  102. lda #$00
  103. sta MB_CODE
  104. sta MB_CODE+1
  105. sta destroy_count
  106. sta hit_count
  107. ldx #$04
  108. @flags: sta MB_DATA,x
  109. dex
  110. bpl @flags
  111. lda MMU_CR
  112. sta saved_cr
  113. lda #CR_RAM0_KERNAL
  114. sta MMU_CR
  115. lda #PR_CLEAR
  116. jsr pr_char
  117. TEXT title, title_len
  118. jsr pr_cr
  119. PHASE 1
  120. lda #$00
  121. ldx #>HEAP_BASE
  122. ldy #HEAP_PAGES
  123. jsr heap_init
  124. FAIL_CS
  125. MARK $01
  126. jsr frame_init
  127. lda #$00
  128. sta obj_init_ptr
  129. sta obj_init_ptr+1
  130. ; 1: delete through an interface frees once and clears the value.
  131. MARK $02
  132. lda #<desc_life
  133. ldx #>desc_life
  134. jsr obj_new
  135. FAIL_CS
  136. sta live_obj
  137. stx live_obj+1
  138. jsr make_foo
  139. MARK $03
  140. lda #<val_foo
  141. ldx #>val_foo
  142. jsr if_delete
  143. bcc :+
  144. lda if_error
  145. sta MB_CODE
  146. lda #$08
  147. sta MB_ADDR
  148. jmp @fail
  149. : MARK $04
  150. lda if_error
  151. FAIL_NE
  152. lda destroy_count
  153. cmp #1
  154. FAIL_NE
  155. MARK $05
  156. lda destroy_self
  157. cmp live_obj
  158. FAIL_NE
  159. lda destroy_self+1
  160. cmp live_obj+1
  161. FAIL_NE
  162. lda heap_free_total
  163. cmp #$00
  164. FAIL_NE
  165. lda heap_free_total+1
  166. cmp #$10
  167. FAIL_NE
  168. MARK $06
  169. jsr chk_zero
  170. FAIL_CS
  171. MARK $07
  172. lda #$01
  173. sta MB_DATA+0
  174. ; 2: delete on a canonical null value is a no-op.
  175. PHASE 2
  176. MARK $11
  177. ; BSS is not part of the PRG image, so state the null values here.
  178. ldx #$03
  179. lda #$00
  180. @init2: sta val_null,x
  181. sta val_objnull,x
  182. dex
  183. bpl @init2
  184. lda #$C0
  185. sta val_objnull+IF_TABLE
  186. lda #<val_null
  187. ldx #>val_null
  188. jsr if_delete
  189. FAIL_CS
  190. MARK $12
  191. lda if_error
  192. FAIL_NE
  193. lda destroy_count
  194. cmp #1
  195. FAIL_NE
  196. ; A value with a table but no object is still null for deletion.
  197. lda #<val_objnull
  198. ldx #>val_objnull
  199. jsr if_delete
  200. FAIL_CS
  201. lda destroy_count
  202. cmp #1
  203. FAIL_NE
  204. lda #$01
  205. sta MB_DATA+1
  206. ; 3: one object, two interface tables: the first delete frees it, the
  207. ; second value is refused rather than reading a freed destructor.
  208. PHASE 3
  209. lda #<desc_life
  210. ldx #>desc_life
  211. jsr obj_new
  212. FAIL_CS
  213. sta live_obj
  214. stx live_obj+1
  215. jsr make_foo
  216. lda live_obj
  217. sta val_bar
  218. lda live_obj+1
  219. sta val_bar+1
  220. lda #<tab_bar
  221. sta val_bar+IF_TABLE
  222. lda #>tab_bar
  223. sta val_bar+IF_TABLE+1
  224. lda #<val_bar
  225. ldx #>val_bar
  226. jsr if_delete
  227. FAIL_CS
  228. lda destroy_count
  229. cmp #2
  230. FAIL_NE
  231. lda heap_free_total+1
  232. cmp #$10
  233. FAIL_NE
  234. lda #<val_foo
  235. ldx #>val_foo
  236. jsr if_delete
  237. FAIL_CC
  238. lda if_error
  239. cmp #IF_ERR_FREED
  240. FAIL_NE
  241. lda destroy_count
  242. cmp #2
  243. FAIL_NE
  244. lda heap_free_total+1
  245. cmp #$10
  246. FAIL_NE
  247. lda #$01
  248. sta MB_DATA+2
  249. ; 4: an alias copy that outlives the deletion is detected.
  250. PHASE 4
  251. lda #<desc_life
  252. ldx #>desc_life
  253. jsr obj_new
  254. FAIL_CS
  255. sta live_obj
  256. stx live_obj+1
  257. jsr make_foo
  258. ldx #$00
  259. @alias: lda val_foo,x
  260. sta val_alias,x
  261. inx
  262. cpx #IF_VALUE_SIZE
  263. bne @alias
  264. lda #<val_foo
  265. ldx #>val_foo
  266. jsr if_delete
  267. FAIL_CS
  268. lda destroy_count
  269. cmp #3
  270. FAIL_NE
  271. lda #<val_alias
  272. ldx #>val_alias
  273. jsr if_delete
  274. FAIL_CC
  275. lda if_error
  276. cmp #IF_ERR_FREED
  277. FAIL_NE
  278. lda destroy_count
  279. cmp #3
  280. FAIL_NE
  281. lda heap_free_total
  282. cmp #$00
  283. FAIL_NE
  284. lda heap_free_total+1
  285. cmp #$10
  286. FAIL_NE
  287. lda #$01
  288. sta MB_DATA+3
  289. ; 5: a null call faults before any target runs, and dispatch recovers.
  290. PHASE 5
  291. lda #<val_null
  292. ldx #>val_null
  293. ldy #$00
  294. jsr if_call
  295. FAIL_CC
  296. lda if_error
  297. cmp #IF_ERR_NULL
  298. FAIL_NE
  299. lda hit_count
  300. FAIL_NE
  301. lda #<desc_life
  302. ldx #>desc_life
  303. jsr obj_new
  304. FAIL_CS
  305. sta live_obj
  306. stx live_obj+1
  307. jsr make_foo
  308. lda #<val_foo
  309. ldx #>val_foo
  310. ldy #$00
  311. jsr if_call
  312. FAIL_NE
  313. lda if_error
  314. FAIL_NE
  315. lda hit_count
  316. cmp #1
  317. FAIL_NE
  318. lda #<val_foo
  319. ldx #>val_foo
  320. jsr if_delete
  321. FAIL_CS
  322. lda destroy_count
  323. cmp #4
  324. FAIL_NE
  325. lda #$01
  326. sta MB_DATA+4
  327. TEXT ok_msg, ok_len
  328. jsr pr_cr
  329. lda #MB_ST_PASS
  330. sta MB_STATUS
  331. lda #$00
  332. sta MB_CODE
  333. sta MB_CODE+1
  334. jmp @restore
  335. @fail:
  336. lda #MB_ST_FAIL
  337. sta MB_STATUS
  338. TEXT fail_msg, fail_len
  339. jsr pr_cr
  340. @restore:
  341. lda saved_cr
  342. sta MMU_CR
  343. plp
  344. rts
  345. ; val_foo = live_obj + tab_foo.
  346. make_foo:
  347. lda live_obj
  348. sta val_foo
  349. lda live_obj+1
  350. sta val_foo+1
  351. lda #<tab_foo
  352. sta val_foo+IF_TABLE
  353. lda #>tab_foo
  354. sta val_foo+IF_TABLE+1
  355. rts
  356. ; C=1 unless the four bytes at val_foo are zero.
  357. chk_zero:
  358. ldx #$00
  359. @z: lda val_foo,x
  360. bne @nz
  361. inx
  362. cpx #IF_VALUE_SIZE
  363. bne @z
  364. clc
  365. rts
  366. @nz: sec
  367. rts
  368. .segment "CODE"
  369. ; Destructor: records how often and for which object it ran.
  370. destroy_life:
  371. sta destroy_self
  372. stx destroy_self+1
  373. inc destroy_count
  374. rts
  375. ; Slot 0 target used by the null-call check.
  376. m_hit:
  377. inc hit_count
  378. lda #$11
  379. ldx #$00
  380. rts
  381. .segment "DATA"
  382. desc_life:
  383. .word 4 ; header + one word field
  384. .word destroy_life
  385. .byte 0
  386. .word 0
  387. .byte 0
  388. .assert * - desc_life = CLASS_DESC_SIZE, error, "life descriptor size"
  389. tab_foo: .word m_hit
  390. tab_bar: .word m_hit
  391. .assert tab_bar - tab_foo = IF_SLOT_SIZE, error, "one slot per table"
  392. .segment "RODATA"
  393. title: .byte "NOVA128 LIFETIME TEST"
  394. title_len = * - title
  395. ok_msg: .byte "LIFETIME OK"
  396. ok_len = * - ok_msg
  397. fail_msg: .byte "LIFETIME FAIL"
  398. fail_len = * - fail_msg
  399. .segment "BSS"
  400. saved_cr: .res 1
  401. live_obj: .res 2
  402. destroy_count: .res 1
  403. destroy_self: .res 2
  404. hit_count: .res 1
  405. val_foo: .res IF_VALUE_SIZE
  406. val_bar: .res IF_VALUE_SIZE
  407. val_alias: .res IF_VALUE_SIZE
  408. val_null: .res IF_VALUE_SIZE
  409. val_objnull: .res IF_VALUE_SIZE
  410. test_end:

Powered by TurnKey Linux.