Pet*_*vaz 12 lisp assembly sbcl common-lisp
在Windows上使用64位Steel Bank Common Lisp进行简单的身份识别时:
(defun a (x)
(declare (fixnum x))
(declare (optimize (speed 3) (safety 0)))
(the fixnum x))
Run Code Online (Sandbox Code Playgroud)
我发现反汇编如下:
* (disassemble 'a)
; disassembly for A
; Size: 13 bytes
; 02D7DFA6: 84042500000F20 TEST AL, [#x200F0000] ; safepoint
; no-arg-parsing entry point
; AD: 488BE5 MOV RSP, RBP
; B0: F8 CLC
; B1: 5D POP RBP
; B2: C3 RET
Run Code Online (Sandbox Code Playgroud)
我理解的是:
mov rsp, rbp
pop rbp
ret
Run Code Online (Sandbox Code Playgroud)
从函数操作执行标准返回,但我不明白为什么有这些行:
TEST AL, [#x200F0000] // My understanding is that this sets flags based on bitwise and of AL and contents of memory 0x200F0000
Run Code Online (Sandbox Code Playgroud)
和
CLC // My understanding is that this clears the carry flag.
Run Code Online (Sandbox Code Playgroud)
正如反汇编程序提示的那样,TEST
指令是一个安全点.它用于同步垃圾收集器的线程.安全点插入编译器知道线程处于安全状态以进行垃圾收集的位置.
safepoint的形式在compiler/x86-64/macros.lisp中定义:
#!+sb-safepoint
(defun emit-safepoint ()
(inst test al-tn (make-ea :byte :disp sb!vm::gc-safepoint-page-addr)))
Run Code Online (Sandbox Code Playgroud)
您当然对未使用的操作结果是正确的.在这种情况下,SBCL对操作的副作用感兴趣.具体来说,如果包含地址的页面碰巧受到保护,则该指令会产生页面错误.如果页面可以被访问,指令只是浪费了非常小的时间量.我应该指出,这可能比简单地检查全局变量要快得多.
在Windows中,C函数map_gc_page
和unmap_gc_page
在运行时/ Win32的os.c用于映射和取消映射的页面:
void map_gc_page()
{
DWORD oldProt;
AVER(VirtualProtect((void*) GC_SAFEPOINT_PAGE_ADDR, sizeof(lispobj),
PAGE_READWRITE, &oldProt));
}
void unmap_gc_page()
{
DWORD oldProt;
AVER(VirtualProtect((void*) GC_SAFEPOINT_PAGE_ADDR, sizeof(lispobj),
PAGE_NOACCESS, &oldProt));
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,我无法追踪页面错误处理程序,但一般的想法似乎是当需要一个集合时,unmap_gc_page
将被调用.每个线程将继续运行,直到它遇到其中一个安全点,然后发生页面错误.大概是页面错误处理程序然后暂停该线程,然后当所有线程都被暂停时,垃圾收集运行,然后map_gc_page
再次调用,并允许线程恢复.
学分文件向Anton Kovalenko介绍了这种机制.
在Linux和Mac OS X上,默认使用不同的同步机制,这就是为什么不在这些平台的默认构建上生成指令的原因.(我不确定PowerPC端口默认情况下是否使用安全点,但显然他们不使用x86指令).
另一方面,我不知道该CLC
指令.
我对 一无所知TEST AL, [#x200F0000]
,但我相信这CLC
是针对返回一个值的函数。SBCL 内部手册,“未知值返回”,建议函数在返回多个值时设置进位标志,如果返回一个值则清除进位标志。
我正在使用 OpenBSD 和 x86-64 运行 SBCL 1.1.14。我可以看到CLC
,SEC
如果我反汇编一个返回一个值的函数和一个返回多个值的函数:
CL-USER> (disassemble (lambda () 100))
; disassembly for (LAMBDA ())
; Size: 16 bytes
; 04B36F64: BAC8000000 MOV EDX, 200 ; no-arg-parsing entry point
; 69: 488BE5 MOV RSP, RBP
; 6C: F8 CLC
; 6D: 5D POP RBP
; 6E: C3 RET
; 6F: CC0A BREAK 10 ; error trap
; 71: 02 BYTE #X02
; 72: 19 BYTE #X19 ; INVALID-ARG-COUNT-ERROR
; 73: 9A BYTE #X9A ; RCX
NIL
Run Code Online (Sandbox Code Playgroud)
这个有CLC
(清除进位),因为它返回一个值。
CL-USER> (disassemble (lambda () (values 100 200)))
; disassembly for (LAMBDA ())
; Size: 35 bytes
; 04B82BD4: BAC8000000 MOV EDX, 200 ; no-arg-parsing entry point
; D9: BF90010000 MOV EDI, 400
; DE: 488D5D10 LEA RBX, [RBP+16]
; E2: B904000000 MOV ECX, 4
; E7: BE17001020 MOV ESI, 537919511
; EC: F9 STC
; ED: 488BE5 MOV RSP, RBP
; F0: 5D POP RBP
; F1: C3 RET
; F2: CC0A BREAK 10 ; error trap
; F4: 02 BYTE #X02
; F5: 19 BYTE #X19 ; INVALID-ARG-COUNT-ERROR
; F6: 9A BYTE #X9A ; RCX
NIL
Run Code Online (Sandbox Code Playgroud)
这个有STC
(set Carry) 因为它返回两个值。