如何实现Rust的每个动态检查方面?

Qor*_*ros 5 typechecking rust

Rust使用动态检查方法来检查很多东西.一个这样的例子是数组的边界检查.

以此代码为例,

fn test_dynamic_checking() -> i32 {
    let x = [1, 2, 3, 4];
    x[1]
}
Run Code Online (Sandbox Code Playgroud)

由此产生的LLVM IR是:

; Function Attrs: uwtable
define internal i32 @_ZN10dynamic_ck21test_dynamic_checking17hcef32a1e8c339e2aE() unnamed_addr #0 {
entry-block:
  %x = alloca [5 x i32]
  %0 = bitcast [5 x i32]* %x to i8*
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* bitcast ([5 x i32]* @const7091 to i8*), i64 20, i32 4, i1 false)
  %1 = getelementptr inbounds [5 x i32], [5 x i32]* %x, i32 0, i32 0
  %2 = call i1 @llvm.expect.i1(i1 false, i1 false)
  br i1 %2, label %cond, label %next

next:                                             ; preds = %entry-block
  %3 = getelementptr inbounds i32, i32* %1, i64 1
  %4 = load i32, i32* %3
  ret i32 %4

cond:                                             ; preds = %entry-block
  call void @_ZN4core9panicking18panic_bounds_check17hcc71f10000bd8e6fE({ %str_slice, i32 }* noalias readonly dereferenceable(24) @panic_bounds_check_loc7095, i64 1, i64 5)
  unreachable
}
Run Code Online (Sandbox Code Playgroud)

插入分支指令以确定索引是否超出边界,这在clang编译的LLVM IR中不存在.

这是我的问题:

  1. Rust在什么情况下实现动态检查?
  2. Rust如何在不同情况下实现动态检查?
  3. 有没有办法关闭动态检查?

use*_*342 8

从概念上讲,Rust对每个阵列访问执行数组绑定检查.但是,编译器非常善于优化掉检查,因为它可以证明这样做是安全的.

LLVM中间输出具有误导性,因为在生成机器组件之前,LLVM的优化机制仍会对其进行优化.检查程序集输出的更好方法是使用调用生成最终程序集,例如rustc -O --emit asm --crate-type=lib.您的函数汇编输出只是:

        push    rbp
        mov     rbp, rsp
        mov     eax, 2
        pop     rbp
        ret
Run Code Online (Sandbox Code Playgroud)

不仅没有绑定检查,没有数组开始,编译器已经优化了整个函数return 2i32!要强制绑定检查,需要编写函数,以便Rust无法证明它可以被省略:

pub fn test_dynamic_checking(ind: usize) -> i32 () {
   let x = [1, 2, 3, 4];
   x[ind]
}
Run Code Online (Sandbox Code Playgroud)

这会导致更大的程序集,其中绑定检查实现为以下两个指令:

        cmp     rax, 3    ; compare index with 3
        ja      .LBB0_2   ; if greater, jump to panic code
Run Code Online (Sandbox Code Playgroud)

这是有效的.关闭绑定检查很少是一个好主意,因为它很容易导致程序崩溃.它可以完成,但只能在unsafe块或函数的范围内明确地完成:

pub unsafe fn test_dynamic_checking(ind: usize) -> i32 () {
   let x = [1, 2, 3, 4];
   *x.get_unchecked(ind)
}
Run Code Online (Sandbox Code Playgroud)

所述生成组件示出了错误检查,以完全省略:

        push    rbp
        mov     rbp, rsp
        lea     rax, [rip + const3141]
        mov     eax, dword ptr [rax + 4*rdi]
        pop     rbp
        ret

const3141:
        .long   1
        .long   2
        .long   3
        .long   4
Run Code Online (Sandbox Code Playgroud)