126 lines
2.6 KiB
Plaintext
126 lines
2.6 KiB
Plaintext
; This test attempts to confirm that as subtle potential bug in the hybrid JIT
|
|
; implementation is not present.
|
|
;
|
|
; The potential problem is as follows:
|
|
; - we decide to JIT some code
|
|
; - we take a snapshot of memory
|
|
; - we kick off a JIT thread which *works off the main memory array*, not the
|
|
; snapshot
|
|
; - in the meantime the interpreter executes some code which modifies the code
|
|
; being JITted before it is actually jitted.
|
|
; - we JIT the modified version of the code
|
|
; - the interpreter then executes some code which reverts the change (A)
|
|
; - we decide to execute the JITted function. We check memory against the memory
|
|
; snapshot taken when we started JITting and find no differences in any
|
|
; addresses which contain code, because of the previous step marked (A).
|
|
; - boom, our JITted code is not doing what it should.
|
|
;
|
|
; The fix for this problem is simply to ensure that the JIT thread works off
|
|
; the snapshot of memory taken when we launched the JIT thread. Note that even
|
|
; if we fail to do this, self-modifying code which doesn't "undo" itself will
|
|
; be noticed when we use the memory snapshot to decide if the JITted code is
|
|
; still valid.
|
|
;
|
|
; This test case should execute correctly in all modes (of course), but in
|
|
; hybrid mode it should *fail* if the implementation is temporarily changed to
|
|
; JIT from mpu->memory and not memory_snapshot. At the time of writing it does.
|
|
|
|
|
|
|
|
#include "config.xa"
|
|
|
|
COUNT1 = $71
|
|
COUNT2 = $72
|
|
COUNT3 = $73
|
|
|
|
; We loop lots to get as much chance of a problem occurring as possible.
|
|
STZ COUNT1
|
|
LOOP1
|
|
LDY #0
|
|
LOOP2
|
|
LDX #0
|
|
LOOP3
|
|
|
|
; The heart of the test. We LDA #n, then CMP <address of n>. If the two don't
|
|
; match we have a problem.
|
|
LDAOP
|
|
LDA #3
|
|
CMP LDAOP+1
|
|
BNE FAIL
|
|
|
|
; We now modify the LDA operand...
|
|
INC LDAOP+1
|
|
|
|
; ... and occupy as much of the interpreter's time as possible while the JIT
|
|
; thread picks up the modified version (if it's not working from the snapshot).
|
|
; In reality we probably go round multiple times before the JIT completes.
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
|
|
; We now put the operand back. Since we only switch from interpreting to JITting
|
|
; on a control transfer, we know the transition will occur at a point when we've
|
|
; put the operand back, which is helpful.
|
|
DEC LDAOP+1
|
|
|
|
; And round and round we go.
|
|
DEX
|
|
BNE LOOP3
|
|
DEY
|
|
BNE LOOP2
|
|
DEC COUNT1
|
|
BNE LOOP1
|
|
|
|
OK
|
|
LDA #'Y'
|
|
JSR OSWRCH
|
|
JMP QUIT
|
|
FAIL
|
|
LDA #'N'
|
|
JSR OSWRCH
|
|
JMP QUIT
|