.. _aot: ==================================================== Ahead of time 编译和 C++作绑定 ==================================================== 为了实现最佳性能和无缝集成,Daslang 能够提前编译,即生成 C++ 文件,这些文件在语义上等同于模拟的 Daslang 节点。 输出 C++ 设计为在某种程度上是人类可读的。 在大多数情况下,Daslang 会自动生成 AOT,但自定义类型可能需要一些集成工作。 此外,可以通过额外的集成工作实现某些性能优化。 Daslang AOT 集成是在 AST 表达式树级别完成的,而不是在模拟节点级别完成的。 --------- das_index --------- ``das_index`` 模板用于提供 ``ExprAt`` 和 ``ExprSafeAt`` AST 节点的实现。 给定输入类型 `VecT`,输出结果 `TT`,索引类型为 int32_t,``das_index`` 需要实现以下函数:: // regular index static __forceinline TT & at ( VecT & value, int32_t index, Context * __context__ ); static __forceinline const TT & at ( const VecT & value, int32_t index, Context * __context__ ); // safe index static __forceinline TT * safe_at ( VecT * value, int32_t index, Context * ); static __forceinline const TT * safe_at ( const VecT * value, int32_t index, Context * ); 请注意,有时可能有多个索引类型。 在这种情况下,需要为每个索引类型实现。 请注意 const 和 not const 版本如何可用。 此外,可能需要 ``das_index`` 模板本身的 const 和非 const 版本。 ------------ das_iterator ------------ ``das_iterator`` 模板用于为 ``ExprFor`` 源提供 for 循环后端。 让我们回顾一下以下示例,该示例在 range 类型上实现迭代:: template <> struct das_iterator { __forceinline das_iterator(const range & r) : that(r) {} __forceinline bool first ( Context *, int32_t & i ) { i = that.from; return i!=that.to; } __forceinline bool next ( Context *, int32_t & i ) { i++; return i!=that.to; } __forceinline void close ( Context *, int32_t & ) {} range that; }; ``das_iterator``模板需要实现指定类型的构造函数,以及 ``first``, ``next``, 和 ``close``函数,类似于 Iterator 的函数。 将提供 ``das_iterator`` 模板的 const 和 regular 版本:: template <> struct das_iterator : das_iterator { __forceinline das_iterator(const range & r) : das_iterator(r) {} }; Ref 迭代器返回类型是 C++ 指针:: template struct das_iterator> { __forceinline bool first(Context * __context__, TT * & i) { 开箱即用,``das_iterator`` 为所有集成类型实现。 --------------------- AOT 模板功能 --------------------- 默认情况下,AOT 生成的函数希望将块作为 C++ TBlock 类传递(参阅 :ref:`Blocks `). 这会产生显著的性能开销,而 AOT 模板机制可以减少这种开销。 让我们回顾一下以下示例:: void peek_das_string(const string & str, const TBlock> & block, Context * context) { vec4f args[1]; args[0] = cast::from(str.c_str()); context->invoke(block, args, nullptr); } 开销包括类型封送处理以及上下文块调用。 但是,以下模板可以像这样调用:: template void peek_das_string_T(const string & str, TT && block, Context *) { block((char *)str.c_str()); } 在这里,块是模板化的,可以在没有任何编组的情况下调用。 为此,需要修改模块中的函数注册:: addExtern(*this, lib, "peek", SideEffects::modifyExternal,"peek_das_string_T")->setAotTemplate(); ------------------------------------- 单个功能的 AOT 设置 ------------------------------------- 有几个函数注释可以控制函数 AOT 的生成方式。 ``[hybrid]`` 注释表示函数始终通过完整的 Daslang 互作 ABI(较慢)调用,而不是通过 C++ 语言构造直接调用函数(较快)。 这样做可以消除语义哈希中两个函数之间的依赖关系,从而只允许将其中一个函数替换为模拟版本。 ``[no_aot]`` 注解表示不会生成函数的 AOT 版本。 这对于解决 AOT 代码生成问题以及在内置模块开发期间非常有用。 --------------------- AOT 前缀和后缀 --------------------- 函数或类型特征表达式可以具有自定义注释,以指定生成的调用周围的前缀和后缀文本。 这对于完全替换调用本身、提供其他类型转换或执行其他自定义可能是必要的。 让我们回顾一下以下示例:: struct ClassInfoMacro : TypeInfoMacro { .... virtual void aotPrefix ( TextWriter & ss, const ExpressionPtr & ) override { ss << "(void *)(&"; } virtual void aotSuffix ( TextWriter & ss, const ExpressionPtr & ) override { ss << ")"; } 在这里,类 info 宏将请求的类型信息转换为 `void *`。 类机制的这一部分允许类的 ``__rtti`` 指针保持为空,而不在包含类的所有位置都包含 RTTI。 --------------------------- AOT 字段前缀和后缀 --------------------------- ``ExprField`` 被 handled 类型注释中的以下函数覆盖(参阅 :ref:`Handles `):: virtual void aotPreVisitGetField ( TextWriter &, const string & fieldName ) virtual void aotPreVisitGetFieldPtr ( TextWriter &, const string & fieldName ) virtual void aotVisitGetField ( TextWriter & ss, const string & fieldName ) virtual void aotVisitGetFieldPtr ( TextWriter & ss, const string & fieldName ) 默认情况下,前缀函数不执行任何作,后缀函数会相应地附加 `.fieldName` 和 `->fieldName` 。 请注意,``ExprSafeField`` 还没有被覆盖,它将在某个时候为 AOT 实现。