annotate llvm/docs/FaultMaps.rst @ 164:fdfabb438fbf

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