Copying the contents of an inlined object into its container
potentially alters aliasing relations, and we must ensure that such
copying is safe. A common case is an object is initialized and then
assigned to an inlined slot and from then on is accessed via the
container (this happens in Figure 5). To handle such
cases, we analyze to determine method arguments that can be passed by
value; if the argument to the field's mutator
method may be passed in
by value, we can copy it into the inlined fields safely.
Our analysis is defined in terms of contours, which represent method calls, edges which map arguments between caller and callee, and uses, which are primitive operations, in particular calls and assignments. The basic idea behind this analysis is that objects may be passed by value if they have not previously been stored and are not subsequently used. We first define some local operations upon specific values and contours that form the groundwork for our analysis:
Given these operations, we define a NoStore predicate that is true if a given value v is not stored in persistent state (all such state in our model is either an instance variable or a global variable).
Valuability for locally created objects (results of new operations within a given contour) can be checked by looking at all the uses of such objects within the contour. Once an object is passed in by value, we can copy it, and hence it is, effectively, created locally. The following helper predicate reflects this:
We are now ready to define valuability: an argument is callable by value if it can be passed by value from each call site. PassByValue and CallByValue formalize the criterion set out above:
A given field may be inlined only if the mutator method has its value argument passed in by value.