common-lisp - 如果正在使用该函数,SBCL 何时会用更新的版本替换已编译的函数?

标签 common-lisp sbcl

例如,如果循环正在运行,每次迭代都调用 'FOO,并且我在循环退出之前重新编译 'FOO,会发生什么?

SBCL 处理此类情况的具体机制是什么?

最佳答案

SBCL 是一个只编译的实现,所以你的问题的答案很容易发现:

* (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

如您所见,反汇编中提到 #<FDEFINITION object for FOO> (与 #<FUNCTION FOO> 返回的对象 (fdefinition 'foo) 相反),所以,显然, fdefinition在每次迭代中调用。

这可以通过比较这两个反汇编来确认:

* (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

第一个肯定是 fdefinition而第二个肯定不会,而第一个更接近循环的反汇编。

最后,可以使用 Paulo Madeira 的显式测试:

(progn (sb-thread:make-thread (lambda () (sleep 5.1) (defun foo (x) (print (1+ x))))) 
       (dotimes (i 10) (sleep 1) (foo 1))) 

开始显示 2。

关于common-lisp - 如果正在使用该函数,SBCL 何时会用更新的版本替换已编译的函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25037033/

相关文章:

common-lisp - 如何自定义SBCL REPL?

utf-8 - 如何让 quicklisp 在 Slime 中加载 rfc2388?

macros - Common Lisp (SBCL) 中的素数宏

lisp - 普通口齿不清 : loop through pairs of a list

lisp - 如何在 Common Lisp 中重用 gethash 查找?

common-lisp - sbcl - 如何消除 "undefined variable"警告?

lisp - 步骤 Eval Common Lisp

macros - 《Let over Lambda》一书中的 sortf 中绑定(bind)的 'a1' 在哪里?

function - Lisp 标签函数在使用前被删除

function - Common Lisp : The Remove Function, 它是如何使用的?