Reputation: 325
For instance, if a loop is running that calls 'FOO at every iteration, and I recompile 'FOO before the loop exits, what happens?
What are the specific mechanism SBCL uses to handle such situations?
Upvotes: 2
Views: 296
Reputation: 60004
SBCL is a compile-only implementation, so the answer to your question is easy to discover:
* (defun foo (x) (print x))
FOO
* (describe 'foo)
COMMON-LISP-USER::FOO
[symbol]
FOO names a compiled function:
Lambda-list: (X)
Derived type: (FUNCTION (T) (VALUES T &OPTIONAL))
Source form:
(SB-INT:NAMED-LAMBDA FOO
(X)
(BLOCK FOO (PRINT X)))
* (disassemble (lambda ()(loop repeat 10 do (foo 1))))
; disassembly for (LAMBDA ())
; Size: 91 bytes. Origin: #x1002F7F564
; 64: BE14000000 MOV ESI, 20 ; no-arg-parsing entry point
; 69: EB3E JMP L1
; 6B: 0F1F440000 NOP
; 70: L0: 488BCE MOV RCX, RSI
; 73: 4883E902 SUB RCX, 2
; 77: 488BF1 MOV RSI, RCX
; 7A: 488D5C24F0 LEA RBX, [RSP-16]
; 7F: 4883EC18 SUB RSP, 24
; 83: BA02000000 MOV EDX, 2
; 88: 488975F8 MOV [RBP-8], RSI
; 8C: 488B057DFFFFFF MOV RAX, [RIP-131] ; #<FDEFINITION object for FOO>
; 93: B902000000 MOV ECX, 2
; 98: 48892B MOV [RBX], RBP
; 9B: 488BEB MOV RBP, RBX
; 9E: FF5009 CALL QWORD PTR [RAX+9]
; A1: 480F42E3 CMOVB RSP, RBX
; A5: 488B75F8 MOV RSI, [RBP-8]
; A9: L1: 4885F6 TEST RSI, RSI
; AC: 7FC2 JNLE L0
; AE: BA17001020 MOV EDX, 537919511
; B3: 488BE5 MOV RSP, RBP
; B6: F8 CLC
; B7: 5D POP RBP
; B8: C3 RET
; B9: 0F0B0A BREAK 10 ; error trap
; BC: 02 BYTE #X02
; BD: 19 BYTE #X19 ; INVALID-ARG-COUNT-ERROR
; BE: 9A BYTE #X9A ; RCX
NIL
As you can see, the disassembly mentions #<FDEFINITION object for FOO>
(as opposed to a the object #<FUNCTION FOO>
returned by (fdefinition 'foo)
), so, apparently, fdefinition
is called on each iteration.
This can be confirmed by comparing these two disassmeblies:
* (disassemble (lambda () (fdefinition 'foo)))
; disassembly for (LAMBDA ())
; Size: 31 bytes. Origin: #x1002FF99F4
; 9F4: 488B15A5FFFFFF MOV RDX, [RIP-91] ; 'FOO
; no-arg-parsing entry point
; 9FB: 488B05A6FFFFFF MOV RAX, [RIP-90] ; #<FDEFINITION object for FDEFINITION>
; A02: B902000000 MOV ECX, 2
; A07: FF7508 PUSH QWORD PTR [RBP+8]
; A0A: FF6009 JMP QWORD PTR [RAX+9]
; A0D: 0F0B0A BREAK 10 ; error trap
; A10: 02 BYTE #X02
; A11: 19 BYTE #X19 ; INVALID-ARG-COUNT-ERROR
; A12: 9A BYTE #X9A ; RCX
NIL
* (disassemble (lambda () #.(fdefinition 'foo)))
; disassembly for (LAMBDA ())
; Size: 19 bytes. Origin: #x1003020214
; 14: 488B15A5FFFFFF MOV RDX, [RIP-91] ; #<FUNCTION FOO>
; no-arg-parsing entry point
; 1B: 488BE5 MOV RSP, RBP
; 1E: F8 CLC
; 1F: 5D POP RBP
; 20: C3 RET
; 21: 0F0B0A BREAK 10 ; error trap
; 24: 02 BYTE #X02
; 25: 19 BYTE #X19 ; INVALID-ARG-COUNT-ERROR
; 26: 9A BYTE #X9A ; RCX
NIL
the first definitely calls fdefinition
and the second definitely does not, and the first is closer to the disassembly of the loop.
Finally, one can use the explicit test by Paulo Madeira:
(progn (sb-thread:make-thread (lambda () (sleep 5.1) (defun foo (x) (print (1+ x)))))
(dotimes (i 10) (sleep 1) (foo 1)))
starts showing 2.
Upvotes: 6