Home | History | Annotate | Download | only in docs
      1 ==============================
      2 FaultMaps and implicit checks
      3 ==============================
      4 
      5 .. contents::
      6    :local:
      7    :depth: 2
      8 
      9 Motivation
     10 ==========
     11 
     12 Code generated by managed language runtimes tend to have checks that
     13 are required for safety but never fail in practice.  In such cases, it
     14 is profitable to make the non-failing case cheaper even if it makes
     15 the failing case significantly more expensive.  This asymmetry can be
     16 exploited by folding such safety checks into operations that can be
     17 made to fault reliably if the check would have failed, and recovering
     18 from such a fault by using a signal handler.
     19 
     20 For example, Java requires null checks on objects before they are read
     21 from or written to.  If the object is ``null`` then a
     22 ``NullPointerException`` has to be thrown, interrupting normal
     23 execution.  In practice, however, dereferencing a ``null`` pointer is
     24 extremely rare in well-behaved Java programs, and typically the null
     25 check can be folded into a nearby memory operation that operates on
     26 the same memory location.
     27 
     28 The Fault Map Section
     29 =====================
     30 
     31 Information about implicit checks generated by LLVM are put in a
     32 special "fault map" section.  On Darwin this section is named
     33 ``__llvm_faultmaps``.
     34 
     35 The format of this section is
     36 
     37 .. code-block:: none
     38 
     39   Header {
     40     uint8  : Fault Map Version (current version is 1)
     41     uint8  : Reserved (expected to be 0)
     42     uint16 : Reserved (expected to be 0)
     43   }
     44   uint32 : NumFunctions
     45   FunctionInfo[NumFunctions] {
     46     uint64 : FunctionAddress
     47     uint32 : NumFaultingPCs
     48     uint32 : Reserved (expected to be 0)
     49     FunctionFaultInfo[NumFaultingPCs] {
     50       uint32  : FaultKind = FaultMaps::FaultingLoad (only legal value currently)
     51       uint32  : FaultingPCOffset
     52       uint32  : HandlerPCOffset
     53     }
     54   }
     55 
     56 
     57 The ``ImplicitNullChecks`` pass
     58 ===============================
     59 
     60 The ``ImplicitNullChecks`` pass transforms explicit control flow for
     61 checking if a pointer is ``null``, like:
     62 
     63 .. code-block:: llvm
     64 
     65     %ptr = call i32* @get_ptr()
     66     %ptr_is_null = icmp i32* %ptr, null
     67     br i1 %ptr_is_null, label %is_null, label %not_null, !make.implicit !0
     68   
     69   not_null:
     70     %t = load i32, i32* %ptr
     71     br label %do_something_with_t
     72     
     73   is_null:
     74     call void @HFC()
     75     unreachable
     76   
     77   !0 = !{}
     78 
     79 to control flow implicit in the instruction loading or storing through
     80 the pointer being null checked:
     81 
     82 .. code-block:: llvm
     83 
     84     %ptr = call i32* @get_ptr()
     85     %t = load i32, i32* %ptr  ;; handler-pc = label %is_null
     86     br label %do_something_with_t
     87     
     88   is_null:
     89     call void @HFC()
     90     unreachable
     91 
     92 This transform happens at the ``MachineInstr`` level, not the LLVM IR
     93 level (so the above example is only representative, not literal).  The
     94 ``ImplicitNullChecks`` pass runs during codegen, if
     95 ``-enable-implicit-null-checks`` is passed to ``llc``.
     96 
     97 The ``ImplicitNullChecks`` pass adds entries to the
     98 ``__llvm_faultmaps`` section described above as needed.
     99 
    100 ``make.implicit`` metadata
    101 --------------------------
    102 
    103 Making null checks implicit is an aggressive optimization, and it can
    104 be a net performance pessimization if too many memory operations end
    105 up faulting because of it.  A language runtime typically needs to
    106 ensure that only a negligible number of implicit null checks actually
    107 fault once the application has reached a steady state.  A standard way
    108 of doing this is by healing failed implicit null checks into explicit
    109 null checks via code patching or recompilation.  It follows that there
    110 are two requirements an explicit null check needs to satisfy for it to
    111 be profitable to convert it to an implicit null check:
    112 
    113   1. The case where the pointer is actually null (i.e. the "failing"
    114      case) is extremely rare.
    115 
    116   2. The failing path heals the implicit null check into an explicit
    117      null check so that the application does not repeatedly page
    118      fault.
    119 
    120 The frontend is expected to mark branches that satisfy (1) and (2)
    121 using a ``!make.implicit`` metadata node (the actual content of the
    122 metadata node is ignored).  Only branches that are marked with
    123 ``!make.implicit`` metadata are considered as candidates for
    124 conversion into implicit null checks.
    125 
    126 (Note that while we could deal with (1) using profiling data, dealing
    127 with (2) requires some information not present in branch profiles.)
    128