use of com.oracle.svm.core.graal.code.amd64.AMD64InstructionPatcher in project graal by oracle.
the class NativeImageCodeCache method patchMethods.
/**
* Patch references from code to other code and constant data. Generate relocation information
* in the process. More patching can be done, and correspondingly fewer relocation records
* generated, if the caller passes a non-null rodataDisplacementFromText.
*
* @param relocs a relocation map
*/
public void patchMethods(RelocatableBuffer relocs) {
// in each compilation result...
for (Entry<HostedMethod, CompilationResult> entry : compilations.entrySet()) {
HostedMethod method = entry.getKey();
CompilationResult compilation = entry.getValue();
// the codecache-relative offset of the compilation
int compStart = method.getCodeAddressOffset();
AMD64InstructionPatcher patcher = new AMD64InstructionPatcher(compilation);
// ... patch direct call sites.
for (Infopoint infopoint : compilation.getInfopoints()) {
if (infopoint instanceof Call && ((Call) infopoint).direct) {
Call call = (Call) infopoint;
// NOTE that for the moment, we don't make static calls to external
// (e.g. native) functions. So every static call site has a target
// which is also in the code cache (a.k.a. a section-local call).
// This will change, and we will have to case-split here... but not yet.
int callTargetStart = ((HostedMethod) call.target).getCodeAddressOffset();
// Patch a PC-relative call.
// This code handles the case of section-local calls only.
int pcDisplacement = callTargetStart - (compStart + call.pcOffset);
patcher.findPatchData(call.pcOffset, pcDisplacement).apply(compilation.getTargetCode());
}
}
// ... and patch references to constant data
for (DataPatch dataPatch : compilation.getDataPatches()) {
/*
* Constants are allocated offsets in a separate space, which can be emitted as
* read-only (.rodata) section.
*/
AMD64InstructionPatcher.PatchData patchData = patcher.findPatchData(dataPatch.pcOffset, 0);
/*
* The relocation site is some offset into the instruction, which is some offset
* into the method, which is some offset into the text section (a.k.a. code cache).
* The offset we get out of the RelocationSiteInfo accounts for the first two, since
* we pass it the whole method. We add the method start to get the section-relative
* offset.
*/
long siteOffset = compStart + patchData.operandPosition;
/*
* Do we have an addend? Yes; it's constStart. BUT x86/x86-64 PC-relative references
* are relative to the *next* instruction. So, if the next instruction starts n
* bytes from the relocation site, we want to subtract n bytes from our addend.
*/
long addend = (patchData.nextInstructionPosition - patchData.operandPosition);
relocs.addPCRelativeRelocationWithAddend((int) siteOffset, patchData.operandSize, addend, dataPatch.reference);
}
}
}
use of com.oracle.svm.core.graal.code.amd64.AMD64InstructionPatcher in project graal by oracle.
the class InstalledCodeBuilder method installOperation.
@SuppressWarnings("try")
private void installOperation() {
AMD64InstructionPatcher patcher = new AMD64InstructionPatcher(compilation);
patchData(patcher);
int updatedCodeSize = patchCalls(patcher);
assert updatedCodeSize <= constantsOffset;
// Store the compiled code
for (int index = 0; index < updatedCodeSize; index++) {
code.writeByte(index, compiledBytes[index]);
}
/* Primitive constants are written directly to the code memory. */
ByteBuffer constantsBuffer = SubstrateUtil.wrapAsByteBuffer(code.add(constantsOffset), compilation.getDataSection().getSectionSize());
/*
* Object constants are stored in an Object[] array first, because we have to be careful
* that they are always exposed as roots to the GC.
*/
ObjectConstantsHolder objectConstants = new ObjectConstantsHolder(compilation);
compilation.getDataSection().buildDataSection(constantsBuffer, (position, constant) -> {
objectConstants.add(position, KnownIntrinsics.convertUnknownValue(SubstrateObjectConstant.asObject(constant), Object.class));
});
// Open the PinnedAllocator for the meta-information.
metaInfoAllocator.open();
try {
runtimeMethodInfo = metaInfoAllocator.newInstance(RuntimeMethodInfo.class);
constantsWalker = metaInfoAllocator.newInstance(ConstantsWalker.class);
ReferenceMapEncoder encoder = new ReferenceMapEncoder();
encoder.add(objectConstants.referenceMap);
constantsWalker.referenceMapEncoding = encoder.encodeAll(metaInfoAllocator);
constantsWalker.referenceMapIndex = encoder.lookupEncoding(objectConstants.referenceMap);
constantsWalker.constantsAddr = code.add(constantsOffset);
constantsWalker.constantsSize = compilation.getDataSection().getSectionSize();
Heap.getHeap().getGC().registerObjectReferenceWalker(constantsWalker);
/*
* We now have the constantsWalker initialized and registered, but it is still inactive.
* Writing the actual object constants to the code memory needs to be atomic regarding
* to GC. After everything is written, we activate the constantsWalker.
*/
try (NoAllocationVerifier verifier = NoAllocationVerifier.factory("InstalledCodeBuilder.install")) {
writeObjectConstantsToCode(objectConstants);
}
createCodeChunkInfos();
InstalledCodeObserver.InstalledCodeObserverHandle[] observerHandles = InstalledCodeObserverSupport.installObservers(codeObservers, metaInfoAllocator);
runtimeMethodInfo.setData((CodePointer) code, WordFactory.unsigned(codeSize), installedCode, constantsWalker, metaInfoAllocator, observerHandles);
} finally {
metaInfoAllocator.close();
}
Throwable[] errorBox = { null };
VMOperation.enqueueBlockingSafepoint("Install code", () -> {
try {
CodeInfoTable.getRuntimeCodeCache().addMethod(runtimeMethodInfo);
/*
* This call makes the new code visible, i.e., other threads can start executing it
* immediately. So all metadata must be registered at this point.
*/
installedCode.setAddress(code.rawValue(), method);
} catch (Throwable e) {
errorBox[0] = e;
}
});
if (errorBox[0] != null) {
throw rethrow(errorBox[0]);
}
compilation = null;
}
Aggregations