This post describes Relocation; as mentioned in the previous post, it is one of the two actions the JVM must perform to generate and execute AOT code. Because Validations are a bit more involved, we first focus on the task of relocating code before delving into the complexities and subtleties of validations.
What is Relocation?
Relocation is “the process of assigning load addresses to position-dependent code and data of a program and adjusting the code and data to reflect the assigned addresses”1. For example, a linker performs relocation along with symbol resolution.
How to Relocate?
In OpenJ9, a specific relocation is described by a Relocation Record. There are several types of relocations, and so there are several relocation records. The general process of relocation is as follows:
- During compilation, the compiler generates External Relocations (
TR::ExternalRelocation)2. These contain information that the AOT infrastructure uses to generate the Relocation Records. In general, it creates these via the
- After code binary encoding,
J9::CodeGenerator::processRelocationsis called, which calls
TR::ExternalRelocation::addExternalRelocationon each of the External Relocations. This effectively groups similar External Relocations into Iterated External Relocations (
TR::ExternalRelocation::applyis called on each of the External Relocations. This stores into a buffer the offsets (of the AOT code) of the various locations that need to be updated with the same value. This ensures that if there are multiple locations that have be updated with the same value, they are described by only one Relocation Record.
TR::initializeAOTRelocationHeaderis called, which writes into the buffer the header information for each of the Iterated External Relocations. The header provides the information needed to materialize the value used to relocate a location in the code in the subsequent AOT load run.
- Finally, the buffer containing the Relocation Records, along with the AOT code, is written out to the shared class cache (SCC).
Thus, a Relocation Record consists of a header as well as offsets into the code that requires the relocation. In OpenJ9, Relocation Records are described by three data structures:
TR_RelocationRecord: This is used to perform the relocation
TR_RelocationRecordBinaryTemplate: This describes the structure of the header of the Relocation Record
TR_RelocationRecordPrivateData: This is used to cache data that is required when relocating multiple locations
After validation, the AOT infrastructure goes through buffer of Relocation Records loaded from the SCC. For each record:
preparePrivateDatais called, which uses the binary templates to obtain the data from the buffer and caches it
applyRelocationAtAllOffsetsis called, which does the work of relocating all the necessary locations
Depending on the type of relocation,
applyRelocationAtAllOffsets can range from simply computing the new pointer valid in current address space and updating the location, to adding runtime assumptions and/or patching guards if the assumptions are no longer valid.
There is a reason why there are three structures to describe the Relocation Record.
TR_RelocationRecord has many child classes that override its APIs. Thus, the specific child of
TR_RelocationRecord that needs to be instantiated depends on the type of the Relocation Record. Additionally, to allow for the potential of cross compilation, for example perhaps with JIT-as-a-Service, it is better to access the data via an API that can handle endianness, and other platform specific subtleties.
TR_RelocationRecord is instantiated on the stack (to prevent fragmentation caused by several small dynamic allocations), and uses APIs along with the binary template to access the data. The reason
TR_RelocationRecordPrivateData exists is because in order to allow
TR_RelocationRecord or its child classes to be instantiated on the stack, all of these classes have to be the same size. However, some relocations require data that has to be queried (either from the Relocation Records loaded from the SCC or the environment). In order to prevent unnecessarily repeated computation, the
TR_RelocationRecordPrivateData serves, in essence, as private member variables.
Hopefully this gives you a general understanding of the relocation process. The next post will cover Validations, and all of the complexities therein.
2. The term External Relocation exists because the
TR::ExternalRelocation class inherits from
TR::Relocation which the compiler uses for labels.
3. Similar here means that the location is different, but the value that gets applied is the same