| ============================== | 
 | FaultMaps and implicit checks | 
 | ============================== | 
 |  | 
 | .. contents:: | 
 |    :local: | 
 |    :depth: 2 | 
 |  | 
 | Motivation | 
 | ========== | 
 |  | 
 | Code generated by managed language runtimes tend to have checks that | 
 | are required for safety but never fail in practice.  In such cases, it | 
 | is profitable to make the non-failing case cheaper even if it makes | 
 | the failing case significantly more expensive.  This asymmetry can be | 
 | exploited by folding such safety checks into operations that can be | 
 | made to fault reliably if the check would have failed, and recovering | 
 | from such a fault by using a signal handler. | 
 |  | 
 | For example, Java requires null checks on objects before they are read | 
 | from or written to.  If the object is ``null`` then a | 
 | ``NullPointerException`` has to be thrown, interrupting normal | 
 | execution.  In practice, however, dereferencing a ``null`` pointer is | 
 | extremely rare in well-behaved Java programs, and typically the null | 
 | check can be folded into a nearby memory operation that operates on | 
 | the same memory location. | 
 |  | 
 | The Fault Map Section | 
 | ===================== | 
 |  | 
 | Information about implicit checks generated by LLVM are put in a | 
 | special "fault map" section.  On Darwin this section is named | 
 | ``__llvm_faultmaps``. | 
 |  | 
 | The format of this section is | 
 |  | 
 | .. code-block:: none | 
 |  | 
 |   Header { | 
 |     uint8  : Fault Map Version (current version is 1) | 
 |     uint8  : Reserved (expected to be 0) | 
 |     uint16 : Reserved (expected to be 0) | 
 |   } | 
 |   uint32 : NumFunctions | 
 |   FunctionInfo[NumFunctions] { | 
 |     uint64 : FunctionAddress | 
 |     uint32 : NumFaultingPCs | 
 |     uint32 : Reserved (expected to be 0) | 
 |     FunctionFaultInfo[NumFaultingPCs] { | 
 |       uint32  : FaultKind | 
 |       uint32  : FaultingPCOffset | 
 |       uint32  : HandlerPCOffset | 
 |     } | 
 |   } | 
 |  | 
 | FailtKind describes the reason of expected fault. Currently three kind | 
 | of faults are supported: | 
 |  | 
 |   1. ``FaultMaps::FaultingLoad`` - fault due to load from memory. | 
 |   2. ``FaultMaps::FaultingLoadStore`` - fault due to instruction load and store. | 
 |   3. ``FaultMaps::FaultingStore`` - fault due to store to memory. | 
 |  | 
 | The ``ImplicitNullChecks`` pass | 
 | =============================== | 
 |  | 
 | The ``ImplicitNullChecks`` pass transforms explicit control flow for | 
 | checking if a pointer is ``null``, like: | 
 |  | 
 | .. code-block:: llvm | 
 |  | 
 |     %ptr = call i32* @get_ptr() | 
 |     %ptr_is_null = icmp i32* %ptr, null | 
 |     br i1 %ptr_is_null, label %is_null, label %not_null, !make.implicit !0 | 
 |    | 
 |   not_null: | 
 |     %t = load i32, i32* %ptr | 
 |     br label %do_something_with_t | 
 |      | 
 |   is_null: | 
 |     call void @HFC() | 
 |     unreachable | 
 |    | 
 |   !0 = !{} | 
 |  | 
 | to control flow implicit in the instruction loading or storing through | 
 | the pointer being null checked: | 
 |  | 
 | .. code-block:: llvm | 
 |  | 
 |     %ptr = call i32* @get_ptr() | 
 |     %t = load i32, i32* %ptr  ;; handler-pc = label %is_null | 
 |     br label %do_something_with_t | 
 |      | 
 |   is_null: | 
 |     call void @HFC() | 
 |     unreachable | 
 |  | 
 | This transform happens at the ``MachineInstr`` level, not the LLVM IR | 
 | level (so the above example is only representative, not literal).  The | 
 | ``ImplicitNullChecks`` pass runs during codegen, if | 
 | ``-enable-implicit-null-checks`` is passed to ``llc``. | 
 |  | 
 | The ``ImplicitNullChecks`` pass adds entries to the | 
 | ``__llvm_faultmaps`` section described above as needed. | 
 |  | 
 | ``make.implicit`` metadata | 
 | -------------------------- | 
 |  | 
 | Making null checks implicit is an aggressive optimization, and it can | 
 | be a net performance pessimization if too many memory operations end | 
 | up faulting because of it.  A language runtime typically needs to | 
 | ensure that only a negligible number of implicit null checks actually | 
 | fault once the application has reached a steady state.  A standard way | 
 | of doing this is by healing failed implicit null checks into explicit | 
 | null checks via code patching or recompilation.  It follows that there | 
 | are two requirements an explicit null check needs to satisfy for it to | 
 | be profitable to convert it to an implicit null check: | 
 |  | 
 |   1. The case where the pointer is actually null (i.e. the "failing" | 
 |      case) is extremely rare. | 
 |  | 
 |   2. The failing path heals the implicit null check into an explicit | 
 |      null check so that the application does not repeatedly page | 
 |      fault. | 
 |  | 
 | The frontend is expected to mark branches that satisfy (1) and (2) | 
 | using a ``!make.implicit`` metadata node (the actual content of the | 
 | metadata node is ignored).  Only branches that are marked with | 
 | ``!make.implicit`` metadata are considered as candidates for | 
 | conversion into implicit null checks. | 
 |  | 
 | (Note that while we could deal with (1) using profiling data, dealing | 
 | with (2) requires some information not present in branch profiles.) |