Rework how HHBBC analyzes public static properties
Summary:
HHBBC analyzes public static properties differently than private
static/non-static properties (public non-static properties aren't analyzed at
all). Those can be analyzed from Bottom to a fixed point while doing class
analysis because its guaranteed all of their accesses will be within that
class. No such guarantee exists for a public static property.
Instead the analysis is performed closer to that of a function's return
value. That is, the type starts out as TGen in the Index, and it is refined as a
result of the accesses seen during the analysis round. Like anything out in the
Index, this guarantees that the type is always correct (we don't have to reach a
fixed point).
HHBBC performs one full set of analysis rounds knowing nothing about public
static property types (the Index returns TGen). Then it performs a single
analysis round (not a full set), gathering all of the mutations of public static
properties. These mutations then refine the types in the Index, and another full
set of analysis rounds are performed, using the updated public static
information in the Index.
This all works, but its inefficient. First of all, we have to perform an extra
single analysis round over all of the functions. Then, we have to perform an
extra full set of analysis. This is because we do not record any dependencies of
which functions are actually using the public static property information, so we
have to schedule everything. This second full set convergences relatively
quickly, but the first round still takes a while. Finally, all this extra work
is of little benefit because we only iterate on the public static property
information once.
Let's do this a bit differently. First of all, record dependencies between
functions and the public static property information they query. This involves
adding a new type dependency representing a public static property name. Discard
the separate public static property pass. Instead every function analysis round
always records the public static property mutations it sees in its
FuncAnalysis. The Index stores the gathered mutations for each function. As the
analysis is completed, the Index is updated with the mutations from the
FuncAnalysis. If a function hasn't been analyzed in the current round, its
gathered set of mutations will persist from when it was last analyzed. Once all
functions have been such processed, we refine the public static property
information in the Index by unioning together all the mutations for each
property. Any property which has a type refined will reschedule any function
with a dependency on it.
With this change we only need to perform one full set of analysis and we'll
continue until all the public static properties stop refining. This exposed a
bug in that we weren't recording possible public static property mutations when
updating base information in interp-minstr.cpp which we probably only got away
with because we only iterated once. Fix that.
Reviewed By: markw65
Differential Revision:
D13620784
fbshipit-source-id:
6151b13fd54a0faf1f4bc7a6adc6cd8972f2dbb5