package com.oracle.svm.hosted.code.amd64;
import java.util.function.Consumer;
import org.graalvm.compiler.asm.Assembler;
import org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.AddressDisplacementAnnotation;
import org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandDataAnnotation;
import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
import org.graalvm.nativeimage.hosted.Feature;
import com.oracle.objectfile.ObjectFile;
import com.oracle.svm.core.SubstrateOptions;
import com.oracle.svm.core.annotate.AutomaticFeature;
import com.oracle.svm.core.annotate.Uninterruptible;
import com.oracle.svm.core.graal.code.CGlobalDataReference;
import com.oracle.svm.core.graal.code.PatchConsumerFactory;
import com.oracle.svm.core.meta.SubstrateObjectConstant;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.hosted.code.HostedImageHeapConstantPatch;
import com.oracle.svm.hosted.code.HostedPatcher;
import com.oracle.svm.hosted.image.RelocatableBuffer;
import jdk.vm.ci.code.site.ConstantReference;
import jdk.vm.ci.code.site.DataSectionReference;
import jdk.vm.ci.code.site.Reference;
@AutomaticFeature
@Platforms({Platform.AMD64.class})
class AMD64HostedPatcherFeature implements Feature {
@Override
public void afterRegistration(AfterRegistrationAccess access) {
ImageSingletons.add(PatchConsumerFactory.HostedPatchConsumerFactory.class, new PatchConsumerFactory.HostedPatchConsumerFactory() {
@Override
public Consumer<Assembler.CodeAnnotation> newConsumer(CompilationResult compilationResult) {
return new Consumer<Assembler.CodeAnnotation>() {
@Override
public void accept(Assembler.CodeAnnotation annotation) {
if (annotation instanceof OperandDataAnnotation) {
compilationResult.addAnnotation(new AMD64HostedPatcher((OperandDataAnnotation) annotation));
} else if (annotation instanceof AddressDisplacementAnnotation) {
AddressDisplacementAnnotation dispAnnotation = (AddressDisplacementAnnotation) annotation;
compilationResult.addAnnotation(new HostedImageHeapConstantPatch(dispAnnotation.operandPosition, (SubstrateObjectConstant) dispAnnotation.annotation));
}
}
};
}
});
}
}
public class AMD64HostedPatcher extends CompilationResult.CodeAnnotation implements HostedPatcher {
private final OperandDataAnnotation annotation;
public AMD64HostedPatcher(OperandDataAnnotation annotation) {
super(annotation.instructionPosition);
this.annotation = annotation;
}
@Uninterruptible(reason = ".")
@Override
public void patch(int codePos, int relative, byte[] code) {
int curValue = relative - (annotation.nextInstructionPosition - annotation.instructionPosition);
for (int i = 0; i < annotation.operandSize; i++) {
assert code[annotation.operandPosition + i] == 0;
code[annotation.operandPosition + i] = (byte) (curValue & 0xFF);
curValue = curValue >>> 8;
}
assert curValue == 0;
}
@Override
public boolean equals(Object obj) {
return obj == this;
}
@Override
public void relocate(Reference ref, RelocatableBuffer relocs, int compStart) {
long siteOffset = compStart + annotation.operandPosition;
if (ref instanceof DataSectionReference || ref instanceof CGlobalDataReference) {
long addend = (annotation.nextInstructionPosition - annotation.operandPosition);
relocs.addRelocationWithAddend((int) siteOffset, ObjectFile.RelocationKind.getPCRelative(annotation.operandSize), addend, ref);
} else if (ref instanceof ConstantReference) {
assert SubstrateOptions.SpawnIsolates.getValue() : "Inlined object references must be base-relative";
relocs.addRelocationWithoutAddend((int) siteOffset, ObjectFile.RelocationKind.getDirect(annotation.operandSize), ref);
} else {
throw VMError.shouldNotReachHere("Unknown type of reference in code");
}
}
}