Search in sources :

Example 1 with HostedPatcher

use of com.oracle.svm.hosted.code.HostedPatcher in project graal by oracle.

the class LIRNativeImageCodeCache 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
 */
@Override
@SuppressWarnings("try")
public void patchMethods(DebugContext debug, RelocatableBuffer relocs, ObjectFile objectFile) {
    // 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();
        // Build an index of PatchingAnnoations
        Map<Integer, HostedPatcher> patches = new HashMap<>();
        ByteBuffer targetCode = null;
        for (CodeAnnotation codeAnnotation : compilation.getCodeAnnotations()) {
            if (codeAnnotation instanceof HostedPatcher) {
                HostedPatcher priorValue = patches.put(codeAnnotation.getPosition(), (HostedPatcher) codeAnnotation);
                VMError.guarantee(priorValue == null, "Registering two patchers for same position.");
            } else if (codeAnnotation instanceof HostedImageHeapConstantPatch) {
                HostedImageHeapConstantPatch patch = (HostedImageHeapConstantPatch) codeAnnotation;
                ObjectInfo objectInfo = imageHeap.getObjectInfo(SubstrateObjectConstant.asObject(patch.constant));
                long objectAddress = objectInfo.getAddress();
                if (targetCode == null) {
                    targetCode = ByteBuffer.wrap(compilation.getTargetCode()).order(target.arch.getByteOrder());
                }
                int originalValue = targetCode.getInt(patch.getPosition());
                long newValue = originalValue + objectAddress;
                VMError.guarantee(NumUtil.isInt(newValue), "Image heap size is limited to 2 GByte");
                targetCode.putInt(patch.getPosition(), (int) newValue);
            }
        }
        int patchesHandled = 0;
        HashSet<Integer> patchedOffsets = new HashSet<>();
        // ... 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);
                patches.get(call.pcOffset).patch(compStart, pcDisplacement, compilation.getTargetCode());
                boolean noPriorMatch = patchedOffsets.add(call.pcOffset);
                VMError.guarantee(noPriorMatch, "Patching same offset twice.");
                patchesHandled++;
            }
        }
        for (DataPatch dataPatch : compilation.getDataPatches()) {
            Reference ref = dataPatch.reference;
            /*
                 * Constants are allocated offsets in a separate space, which can be emitted as
                 * read-only (.rodata) section.
                 */
            patches.get(dataPatch.pcOffset).relocate(ref, relocs, compStart);
            boolean noPriorMatch = patchedOffsets.add(dataPatch.pcOffset);
            VMError.guarantee(noPriorMatch, "Patching same offset twice.");
            patchesHandled++;
        }
        VMError.guarantee(patchesHandled == patches.size(), "Not all patches applied.");
        try (DebugContext.Scope ds = debug.scope("After Patching", method.asJavaMethod())) {
            debug.dump(DebugContext.BASIC_LEVEL, compilation, "After patching");
        } catch (Throwable e) {
            throw VMError.shouldNotReachHere(e);
        }
    }
}
Also used : CodeAnnotation(org.graalvm.compiler.code.CompilationResult.CodeAnnotation) Call(jdk.vm.ci.code.site.Call) HashMap(java.util.HashMap) Reference(jdk.vm.ci.code.site.Reference) Infopoint(jdk.vm.ci.code.site.Infopoint) DebugContext(org.graalvm.compiler.debug.DebugContext) HostedPatcher(com.oracle.svm.hosted.code.HostedPatcher) ByteBuffer(java.nio.ByteBuffer) Infopoint(jdk.vm.ci.code.site.Infopoint) ObjectInfo(com.oracle.svm.hosted.image.NativeImageHeap.ObjectInfo) DataPatch(jdk.vm.ci.code.site.DataPatch) HostedMethod(com.oracle.svm.hosted.meta.HostedMethod) HostedImageHeapConstantPatch(com.oracle.svm.hosted.code.HostedImageHeapConstantPatch) CompilationResult(org.graalvm.compiler.code.CompilationResult) HashSet(java.util.HashSet)

Aggregations

HostedImageHeapConstantPatch (com.oracle.svm.hosted.code.HostedImageHeapConstantPatch)1 HostedPatcher (com.oracle.svm.hosted.code.HostedPatcher)1 ObjectInfo (com.oracle.svm.hosted.image.NativeImageHeap.ObjectInfo)1 HostedMethod (com.oracle.svm.hosted.meta.HostedMethod)1 ByteBuffer (java.nio.ByteBuffer)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 Call (jdk.vm.ci.code.site.Call)1 DataPatch (jdk.vm.ci.code.site.DataPatch)1 Infopoint (jdk.vm.ci.code.site.Infopoint)1 Reference (jdk.vm.ci.code.site.Reference)1 CompilationResult (org.graalvm.compiler.code.CompilationResult)1 CodeAnnotation (org.graalvm.compiler.code.CompilationResult.CodeAnnotation)1 DebugContext (org.graalvm.compiler.debug.DebugContext)1