Memoization Options
The __Memoize
and __MemoizeLSB
attributes in Hack support experimental options that control how the function behaves with respect to an Implicit Context value.
Introduction
The Implicit Context (IC) is an experimental feature. It is a value that can be associated with the execution of code and propagated implicitly from caller to callee in a way that is safe for concurrently running code.
In order to prevent the problem of "memoization cache poisoning" where results computed using one IC value are available to callers using a different IC value, we require that memoized functions executed with an IC value are explicit about how they should behave relative to the IC value. Broadly, functions can specify one of two choices:
- This function's memoization cache key should incorporate the propagated IC value.
- This function's memoization cache key should not incorporate the propagated IC value AND this function and its dependencies cannot depend on the propagated IC value.
These requirements are enforced at runtime via thrown exceptions and not statically by the typechecker.
If static requirements are desired, one can make use of special contexts and capabilities specifically zoned
.
Available Options
A memoized function may specify its behavior relative to the IC by passing an option to the __Memoize
(or __MemoizeLSB
) attribute.
<<__Memoize(#MakeICInaccessible)>>
function get_same_random_int(): int {
return HH\Lib\PseudoRandom\int();
}
There are two options that are compatible with propagating an IC value — #KeyedByIC
and #MakeICInaccessible
— and two options that are not — #SoftMakeICInaccessible
and #Uncategorized
. Functions with one of the former pair of options are considered “categorized” while functions with one of the latter pair of options is considered “uncategorized.” See below for the treatment of memoized functions that do not pass an argument to the memoize attribute.
#KeyedByIC
indicates that the function’s memoization cache should include the IC value in the cache key.- Memoized functions that depend on the IC should use this option.
- Memoized functions with the
[zoned]
context must use this option. - A function must have one of the following contexts to use this option:
defaults
(implicitly or explicitly),zoned
,zoned_local
,zoned_shallow
- Note that the cache may also be keyed on metadata necessary for sufficiently complete migration logging and so you should not assume that just because your function isn’t currently being called with a propagated IC value that it is only called once.
#MakeICInaccessible
indicates that the function’s memoization cache should not include the IC value in the cache key and that the function does not access the IC.- Any direct or indirect calls to the builtin function that fetches the IC will result in an exception.
- Any direct or indirect calls to an uncategorized memoized function will throw.
- A function must have one of the following contexts to use this option:
defaults
(implicitly or explicitly),leak_safe_shallow
,leak_safe_local
#SoftMakeICInaccessible
is a migration option for functions that are intended to be marked with#MakeICInaccessible
.- The function’s memoization cache will not include the IC value in the cache key.
- In circumstances in which using
#MakeICInaccessible
will throw, using#SoftMakeICInaccessible
instead will result in runtime logs. - Note that functions using this operation are still considered “uncategorized.”
#Uncategorized
is an option that explicitly indicates that a function has not yet described its intended behavior relative to the IC.- If no option is provided, the function’s memoization cache will not include the IC value, but whether or not it is considered “categorized” or “uncategorized” will depend on the function’s context list.
- If the functions’ context already prevents the function from fetching the IC which requires the
[zoned]
context (i.e. the function is as capable as or less capable than[leak_safe, globals]
) then no option is allowed and the function is considered categorized. - Otherwise, the function is considered uncategorized.
- If the functions’ context already prevents the function from fetching the IC which requires the
Note that this syntax uses “enum class labels” as arguments. Currently, only the memoization attributes are allowed to use labels as arguments.
Related classes and functions
- Executing code with an IC value and accessing the propagated value is done by extending and using methods of the class
HH\ImplicitContext
. - Functions
HH\ImplicitContext\soft_run_with
andHH\ImplicitContext\soft_run_with_async
are used to execute code in a migratory state ahead of usingHH\ImplicitContext::runWith
orHH\ImplicitContext::runWithAsync
-- in this migratory state, calls to uncategorized memoized functions produce runtime warnings instead of exceptions.