在阅读Crystal-lang内部代码时,我遇到了一些片段,如:
@[Primitive(:some_name)]
def some_method
end
有人可以向我解释Primitive
属性的作用以及它的工作方式(例如,告诉编译器使用LLVM函数)吗?
答案 0 :(得分:5)
这是无法用纯Crystal表示的功能。每当出现对这种方法的调用时,都需要由编译器直接将其替换为低级指令(LLVM IR),而不是由实际函数来支持。
这是必需的,因为某些操作已经处于最低级别。例如,如何实现两个数字的加法?嗯,a+b
?等等,但这就是我们要实现的。因此,除了诉诸if a==1 && b==1 ...
之类的荒谬事物之外,还需要将其推迟到CPU(通过LLVM IR)。
文件primitives.cr仅包含此类方法的空shell,以及它们的文档,因此它们看起来像标准库的正常部分。它们由注释标记,供编译器知道何时替换它们。真正的动作发生在compiler/crystal/codegen/primitives.cr中:每个注解名称都有一个case
分支,这会导致代码生成适当的代码。
为完整起见,以下是primitives.cr的摘录:
此处定义的方法是基元,因为它们是:
- 不能用Crystal表示(需要用LLVM表示)。例如一元 二元数学运算符属于此类。
出于性能原因,- 应始终内联LLVM指令,甚至 在非发行版中。例如
Char#ord
,可以实现 在Crystal中,通过为变量分配self
并将其指针转换为Int32
, 然后读回值。
旁注:
这不是编译器实现非标准stdlib方法的唯一方法。对于obj.is_a?
,on a syntactic level之类的伪方法,也会发生这种情况。这甚至是一个“更强”的功能,并且它假装为一种方法的伪装(在Object's documentation中找不到is_a?
)。这种构造与编译器紧密相关,可以affect type information。