2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
23 * Here's how all the type scanner machinery works at a high level:
25 * - All "countable" types (basically ones with explicitly managed ref-counts)
26 * have MarkCollectable<> instantiations.
28 * - Any call to getIndexForMalloc<T> or getIndexForScan<T> present in the
29 * source results in an Indexer<> instantiation, which provides a static
30 * storage location for the type index. The type index is assigned
31 * "kIndexUnknown" at start-up (conveniently this has value 0, so they can be
32 * stored in the .bss).
34 * - The type annotation macros spit out various static fields and member
35 * functions with special names. These static fields may have special types
36 * which are template instantiations containing other types.
38 * - The scanner generator is run during the build, after the final link where
39 * the executable is produced. It parses the debug information inside the
40 * final executable, and sees all the MarkCollectable<T> and Indexer<T>
41 * instantiations. Using these instantiations, as well as the presence of the
42 * specially named fields and member functions, the scanner generator
43 * generates scanning functions. Every Indexer<T> instantiation is assigned a
44 * type-index and a scanner function.
46 * - These generated functions, along with metadata to map the type-index to the
47 * function, is emitted as C++ code and compiled into a shared object. The
48 * shared object includes an initialization function which sets all the static
49 * Indexer<T>::s_index instances to the proper type-index. This can be done
50 * because the fixed address of the static instances can be found in the debug
53 * - Since the final executable has already been produced, the shared object is
54 * embedded into the executable in a custom section. The reason for the shared
55 * object and loading at start-up is due to build system limitations. In
56 * addition, generating the scanner functions after the final executable is
57 * produced provides certain advantages (such as having the final relocated
58 * addresses available).
60 * - Sometime at start-up, the init() function is called. This function finds
61 * the shared object in the custom section, loads it dynamically, and calls
62 * the initialization function within it. This function, as described above,
63 * initializes all the type indices to their generated values.
65 * - The memory manager calls getIndexForMalloc<T> for all allocations, and
66 * stores the returned type-index somewhere it can be retrieved later.
68 * - The garbage collector instantiates Scanner, calls Scanner::scan() for
69 * roots, and Scanner::scanByIndex() for values on the request heap (using the
70 * stored type-index). The Scanner is populated with pointers found by the
71 * scanners (both automatically generated and custom). The GC uses these
72 * pointers to further populate the worklist.
75 namespace HPHP::type_scan
{
77 ////////////////////////////////////////////////////////////////////////////////
83 ////////////////////////////////////////////////////////////////////////////////
85 // A special action used internally to designate that this type index does not
86 // represent a type being allocated on the heap. Instead, the type index will
87 // just be used for scanning. This is useful because we won't consider pointers
88 // to such types as being "interesting" (because they can't be sitting in the
93 * Instantiations of Indexer<> is the signal to the scanner generator to
94 * allocate a type-index for that particular type and to generate a matching
97 * The static member "s_index" stores the assigned type-index corresponding to
98 * this Indexer<>. At start-up, all Indexer<>::s_index instantiations default to
99 * kIndexUnknown, but when the type scanning infrastructure is initialized, the
100 * generated code will overwrite all the s_index instances with their proper
101 * type-indices. (It can do this because it knows the addresses of all the
102 * instances from the debug information).
104 #pragma GCC diagnostic push
105 #pragma GCC diagnostic ignored "-Wignored-attributes"
106 template <typename T
, typename A
> struct Indexer
{
107 static volatile Index
108 ATTRIBUTE_USED ATTRIBUTE_UNUSED EXTERNALLY_VISIBLE s_index
;
109 // This is never used, but Clang needs it or it emits *no* debug information
113 #pragma GCC diagnostic pop
115 template <typename T
, typename A
>
116 volatile Index ATTRIBUTE_USED Indexer
<T
, A
>::s_index
= kIndexUnknown
;
118 // Empty types used as part of type annotations. These types don't really
119 // matter, as the behavior is inferred from the field names.
120 struct IgnoreField
{};
121 struct ConservativeField
{};
122 struct FlexibleArrayField
{};
123 template <typename
... T
> struct IgnoreBase
{};
124 template <typename
... T
> struct CustomBase
{};
125 template <typename
... T
> struct Custom
{};
126 template <typename
... T
> struct SilenceForbiddenBase
{};
128 // Template metaprogramming to determine statically if a type is
129 // uninteresting. This is mainly primitive types (like int), and pointers or
130 // references to such. Also includes some overloads to handle types of such like
131 // pair, tuple, or array.
133 template <typename T
, typename
= void>
134 struct UninterestingImpl
: std::false_type
{};
136 template <typename T
>
137 struct UninterestingImpl
<
139 typename
std::enable_if
<std::is_pointer
<T
>::value
>::type
140 > : std::conditional
<
141 std::is_void
<typename
std::remove_pointer
<T
>::type
>::value
,
144 typename
std::remove_cv
<typename
std::remove_pointer
<T
>::type
>::type
148 template <typename T
>
149 struct UninterestingImpl
<
151 typename
std::enable_if
<std::is_reference
<T
>::value
>::type
152 > : UninterestingImpl
<
153 typename
std::remove_cv
<typename
std::remove_reference
<T
>::type
>::type
156 template <typename T
>
157 struct UninterestingImpl
<
159 typename
std::enable_if
<std::is_array
<T
>::value
>::type
160 > : UninterestingImpl
<
161 typename
std::remove_cv
<typename
std::remove_all_extents
<T
>::type
>::type
164 template <typename T
, std::size_t N
>
165 struct UninterestingImpl
<std::array
<T
, N
>> :
166 UninterestingImpl
<typename
std::remove_cv
<T
>::type
> {};
168 template <typename T
, typename U
>
169 struct UninterestingImpl
<std::pair
<T
, U
>> : std::conditional
<
170 UninterestingImpl
<typename
std::remove_cv
<T
>::type
>::value
,
171 UninterestingImpl
<typename
std::remove_cv
<U
>::type
>,
175 template <typename T
, typename
... U
>
176 struct UninterestingImpl
<std::tuple
<T
, U
...>> : std::conditional
<
177 UninterestingImpl
<typename
std::remove_cv
<T
>::type
>::value
,
178 UninterestingImpl
<std::tuple
<typename
std::remove_cv
<U
>::type
...>>,
181 template <> struct UninterestingImpl
<std::tuple
<>> : std::true_type
{};
183 template <typename T
>
184 struct UninterestingImpl
<
186 typename
std::enable_if
<
187 std::is_fundamental
<T
>::value
||
188 std::is_enum
<T
>::value
||
189 std::is_member_pointer
<T
>::value
||
190 std::is_function
<T
>::value
192 > : std::true_type
{};
194 template <typename T
> using Uninteresting
=
195 UninterestingImpl
<typename
std::remove_cv
<T
>::type
>;
197 // Template metaprogramming to determine if a type is some kind of pointer to
198 // void. IE, void*, void**, etc, etc, as well as some overloads to handle types
199 // like pair/tuple/array of such.
200 template <typename T
, typename
= void>
201 struct IsVoidImpl
: std::false_type
{};
203 template <typename T
>
206 typename
std::enable_if
<std::is_pointer
<T
>::value
>::type
207 > : std::conditional
<
208 std::is_void
<typename
std::remove_pointer
<T
>::type
>::value
,
211 typename
std::remove_cv
<typename
std::remove_pointer
<T
>::type
>::type
215 template <typename T
>
218 typename
std::enable_if
<std::is_reference
<T
>::value
>::type
220 typename
std::remove_cv
<typename
std::remove_reference
<T
>::type
>::type
223 template <typename T
>
226 typename
std::enable_if
<std::is_array
<T
>::value
>::type
228 typename
std::remove_cv
<typename
std::remove_all_extents
<T
>::type
>::type
231 template <typename T
, std::size_t N
>
232 struct IsVoidImpl
<std::array
<T
, N
>> :
233 IsVoidImpl
<typename
std::remove_cv
<T
>::type
> {};
235 template <typename T
, typename U
>
236 struct IsVoidImpl
<std::pair
<T
, U
>> : std::conditional
<
237 IsVoidImpl
<typename
std::remove_cv
<T
>::type
>::value
,
239 IsVoidImpl
<typename
std::remove_cv
<U
>::type
>
242 template <typename T
, typename
... U
>
243 struct IsVoidImpl
<std::tuple
<T
, U
...>> : std::conditional
<
244 IsVoidImpl
<typename
std::remove_cv
<T
>::type
>::value
,
246 IsVoidImpl
<std::tuple
<typename
std::remove_cv
<U
>::type
...>>
248 template <> struct IsVoidImpl
<std::tuple
<>> : std::false_type
{};
250 template <typename T
> using IsVoid
=
251 IsVoidImpl
<typename
std::remove_cv
<T
>::type
>;
253 // Template metaprogramming to check for unbounded arrays (arrays with no
255 template <typename T
> struct UnboundedArrayImpl
: std::false_type
{};
256 template <typename T
> struct UnboundedArrayImpl
<T
[]> : std::true_type
{};
257 // ??? GCC considers a flexible array member as an array of size 0 (not
259 template <typename T
> struct UnboundedArrayImpl
<T
[0]> : std::true_type
{};
261 template <typename T
> using UnboundedArray
=
262 UnboundedArrayImpl
<typename
std::remove_cv
<T
>::type
>;
264 // Table of type names and scanner function pointers indexed by type-index. At
265 // start-up, this table will just have two fixed entries (for the two "unknown"
266 // type-indices), but initializating the type scanning machinery will replace it
267 // with the proper table.
269 const char* const m_name
;
270 void (*m_scan
)(Scanner
&, const void*, std::size_t);
272 extern const Metadata
* g_metadata_table
;
273 extern std::size_t g_metadata_table_size
;
275 // Check if a type with the given name is on the list of explicitly ignored
276 // types. Certain types might give the scanner generator problems, but we can't
277 // add annotations because we do not control its definition (IE, a third-party
278 // type). These types usually aren't relevant to GC, so a list of types to
279 // explicitly ignore is maintained. The template portion (if any) of the type
281 bool isIgnoredType(const std::string
& name
);
283 // Check if a type with the given name is on the list of template types which
284 // cannot contain request heap allocated types. This is mainly for templates
285 // (like the standard containers) where we have request heap aware versions and
286 // is to prevent people accidently using the standard kind.
287 bool isForbiddenTemplate(const std::string
& name
);
289 // Check if a type with the given name is on the list of template types which
290 // will always be scanned conservatively.
291 bool isForcedConservativeTemplate(const std::string
& name
);
293 // Macro trickery to generate field names for type annotations.
294 #define TYPE_SCAN_BUILD_NAME(A,B) TYPE_SCAN_BUILD_NAME_HIDDEN(A,B)
295 #define TYPE_SCAN_BUILD_NAME_HIDDEN(A,B) A##B##_
297 #define TYPE_SCAN_CUSTOM_GUARD_NAME _type_scan_custom_guard_
298 #define TYPE_SCAN_CUSTOM_NAME _type_scan_custom_
299 #define TYPE_SCAN_CUSTOM_FIELD_NAME _type_scan_custom_field_
300 #define TYPE_SCAN_CUSTOM_BASES_NAME _type_scan_custom_bases_
301 #define TYPE_SCAN_CUSTOM_BASES_SCANNER_NAME _type_scan_custom_bases_scanner_
302 #define TYPE_SCAN_IGNORE_NAME _type_scan_ignore_
303 #define TYPE_SCAN_IGNORE_FIELD_NAME _type_scan_ignore_field_
304 #define TYPE_SCAN_IGNORE_BASE_NAME _type_scan_ignore_base_
305 #define TYPE_SCAN_CONSERVATIVE_NAME _type_scan_conservative_
306 #define TYPE_SCAN_CONSERVATIVE_FIELD_NAME _type_scan_conservative_field_
307 #define TYPE_SCAN_FLEXIBLE_ARRAY_FIELD_NAME _type_scan_flexible_array_field_
308 #define TYPE_SCAN_SILENCE_FORBIDDEN_BASE_NAME _type_scan_silence_forbidden_base_
310 constexpr const char* const kInitFuncName
= "hphp_type_scan_module_init";
312 #define TYPE_SCAN_STRINGIFY(X) TYPE_SCAN_STRINGIFY_HIDDEN(X)
313 #define TYPE_SCAN_STRINGIFY_HIDDEN(X) #X
315 // Store all the special field names which act as type annotations as static
316 // constants. This lets us the scanner generator use them while ignoring the
318 constexpr const char* const kCustomGuardName
=
319 TYPE_SCAN_STRINGIFY(TYPE_SCAN_CUSTOM_GUARD_NAME
);
320 constexpr const char* const kCustomName
=
321 TYPE_SCAN_STRINGIFY(TYPE_SCAN_CUSTOM_NAME
);
322 constexpr const char* const kCustomFieldName
=
323 TYPE_SCAN_STRINGIFY(TYPE_SCAN_CUSTOM_FIELD_NAME
);
324 constexpr const char* const kCustomBasesName
=
325 TYPE_SCAN_STRINGIFY(TYPE_SCAN_CUSTOM_BASES_NAME
);
326 constexpr const char* const kCustomBasesScannerName
=
327 TYPE_SCAN_STRINGIFY(TYPE_SCAN_CUSTOM_BASES_SCANNER_NAME
);
328 constexpr const char* const kIgnoreName
=
329 TYPE_SCAN_STRINGIFY(TYPE_SCAN_IGNORE_NAME
);
330 constexpr const char* const kIgnoreFieldName
=
331 TYPE_SCAN_STRINGIFY(TYPE_SCAN_IGNORE_FIELD_NAME
);
332 constexpr const char* const kIgnoreBaseName
=
333 TYPE_SCAN_STRINGIFY(TYPE_SCAN_IGNORE_BASE_NAME
);
334 constexpr const char* const kConservativeName
=
335 TYPE_SCAN_STRINGIFY(TYPE_SCAN_CONSERVATIVE_NAME
);
336 constexpr const char* const kConservativeFieldName
=
337 TYPE_SCAN_STRINGIFY(TYPE_SCAN_CONSERVATIVE_FIELD_NAME
);
338 constexpr const char* const kFlexibleArrayFieldName
=
339 TYPE_SCAN_STRINGIFY(TYPE_SCAN_FLEXIBLE_ARRAY_FIELD_NAME
);
340 constexpr const char* const kSilenceForbiddenBaseName
=
341 TYPE_SCAN_STRINGIFY(TYPE_SCAN_SILENCE_FORBIDDEN_BASE_NAME
);
343 #undef TYPE_SCAN_STRINGIFY_HIDDEN
344 #undef TYPE_SCAN_STRINGIFY
346 ////////////////////////////////////////////////////////////////////////////////