为啥没有“外国进口 prim 不安全”?
Posted
技术标签:
【中文标题】为啥没有“外国进口 prim 不安全”?【英文标题】:Why is there no 'foreign import prim unsafe'?为什么没有“外国进口 prim 不安全”? 【发布时间】:2017-05-22 13:04:29 【问题描述】:这是我之前的问题here 的后续。我已经能够根据Reid Barton's answer 得到一些工作,但我注意到在核心中我看到了__pkg_ccall_GC
:
case __pkg_ccall_GC hashabler-2.0.0 sipRound_s_x2 Word#
-> Word#
-> Word#
-> Word#
-> (# Word#, Word#, Word#, Word# #)
ww1 ww2 ww3 (xor# ww4 b1)
我认为您对“安全” ffi 通话的期望是什么。然而,不允许在外部导入字符串中添加“不安全”(尽管错误消息没有说明原因):
src/Data/Hashabler/SipHash.hs:60:1: error:
• The safe/unsafe annotation should not be used with `foreign import prim'.
• When checking declaration:
foreign import prim unsafe "static sipRound_s_x4" sipRound_s_x4#
:: Word#
-> Word# -> Word# -> Word# -> (# Word#, Word#, Word#, Word# #)
我的外国程序只是一点点但有点混乱,所以我不认为我想要_GC
给我的任何东西。我看过的一些相关的 GHC 源代码、FWIW 和背景:
compiler/prelude/ForeignCall.hs:只有“Risky”省略了“_GC”
data Safety
= PlaySafe -- Might invoke Haskell GC, or do a call back, or
-- switch threads, etc. So make sure things are
-- tidy before the call. Additionally, in the threaded
-- RTS we arrange for the external call to be executed
-- by a separate OS thread, i.e., _concurrently_ to the
-- execution of other Haskell threads.
| PlayInterruptible -- Like PlaySafe, but additionally
-- the worker thread running this foreign call may
-- be unceremoniously killed, so it must be scheduled
-- on an unbound thread.
| PlayRisky -- None of the above can happen; the call will return
-- without interacting with the runtime system at all
deriving ( Eq, Show, Data )
-- Show used just for Show Lex.Token, I think
我还在 GHC 树中看到了一些 foreign import prim unsafe
和 ... safe
,尽管我认为这是死代码。例如testsuite/tests/printer/Ppr046.hs
.
所以我的问题是:
-
在这种情况下,
__pkg_ccall_GC
与 __pkg_ccall
生成的代码之间有什么区别(我正在做 foreign import prim
而不是 ccall
)?和here描述的一样吗?
为什么似乎不支持foreign import prim unsafe
?
假设我理解 (1):有没有办法解决这个问题,既能有效地返回多个值,又能避免 (1) 中发生的任何簿记?
编辑:查看-ddump-asm
的程序集清楚地表明没有发生任何事情(不应该害怕查看程序集),支持 Reid Barton 在下面的评论:
movq %rdi,%rax
movq %r8,%rdi
xorq %r9,%rdi
movq %rsi,%rcx
movq %rax,%rsi
movq %r14,%rax
movq %rcx,%r14
movq %rbx,%rcx
movq %rax,%rbx
movq %r9,-8(%rbp)
movq %rcx,(%rbp)
addq $-16,%rbp
jmp sipRound_s_x2
顶部的xorq
对应于haskell xor
。不过,所有那些movq
看起来确实是个无赖……
【问题讨论】:
如果您查看生成的 Cmm,则在安全呼叫周围没有任何suspendThread
/resumeThread
内容。我不知道为什么它在Core中显示__pkg_ccall_GC
,可能只是一个显示错误。
不是那些movq
在尾调用之前将参数放入正确的寄存器吗?在我看来,它们并不多余。
可能值得提交一个错误是的——看起来prim
导入被解析器标记为PlaySafe
,这可能大部分被忽略了,并且在代码生成期间肯定会被忽略。但只要不被忽视,就可能存在错误。
您必须进行全局寄存器分配以避免参数改组。我不认为 ghc 这样做。你试过 llvm 代码生成器吗?
是的,不过我很难比较它们
【参考方案1】:
正如 Reid Barton 指出的那样,__pkg_ccall_GC
没有任何意义。生成的代码不会像您在 safe
FFI 调用中看到的那样进行记账。
【讨论】:
以上是关于为啥没有“外国进口 prim 不安全”?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我没有 NotSerializableException?