package com.oracle.svm.core.graal.aarch64;
import java.util.function.Consumer;
import org.graalvm.compiler.asm.Assembler;
import org.graalvm.compiler.asm.aarch64.AArch64Assembler.SingleInstructionAnnotation;
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
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.svm.core.annotate.AutomaticFeature;
import com.oracle.svm.core.graal.code.NativeImagePatcher;
import com.oracle.svm.core.graal.code.PatchConsumerFactory;
import com.oracle.svm.core.util.VMError;
@AutomaticFeature
@Platforms({Platform.AARCH64.class})
public class AArch64NativeImagePatcher implements Feature {
@Override
public void afterRegistration(AfterRegistrationAccess access) {
ImageSingletons.add(PatchConsumerFactory.NativePatchConsumerFactory.class, new PatchConsumerFactory.NativePatchConsumerFactory() {
@Override
public Consumer<Assembler.CodeAnnotation> newConsumer(CompilationResult compilationResult) {
return new Consumer<Assembler.CodeAnnotation>() {
@Override
public void accept(Assembler.CodeAnnotation annotation) {
if (annotation instanceof SingleInstructionAnnotation) {
compilationResult.addAnnotation(new SingleInstructionNativeImagePatcher((SingleInstructionAnnotation) annotation));
} else if (annotation instanceof AArch64MacroAssembler.MovSequenceAnnotation) {
compilationResult.addAnnotation(new MovSequenceNativeImagePatcher((AArch64MacroAssembler.MovSequenceAnnotation) annotation));
} else if (annotation instanceof AArch64MacroAssembler.AdrpLdrMacroInstruction) {
compilationResult.addAnnotation(new AdrpLdrMacroInstructionNativeImagePatcher((AArch64MacroAssembler.AdrpLdrMacroInstruction) annotation));
} else if (annotation instanceof AArch64MacroAssembler.AdrpAddMacroInstruction) {
compilationResult.addAnnotation(new AdrpAddMacroInstructionNativeImagePatcher((AArch64MacroAssembler.AdrpAddMacroInstruction) annotation));
}
}
};
}
});
}
}
class SingleInstructionNativeImagePatcher extends CompilationResult.CodeAnnotation implements NativeImagePatcher {
private final SingleInstructionAnnotation annotation;
SingleInstructionNativeImagePatcher(SingleInstructionAnnotation annotation) {
super(annotation.instructionPosition);
this.annotation = annotation;
}
@Override
public int getOffset() {
return annotation.instructionPosition + annotation.offsetBits;
}
@Override
public int getLength() {
assert annotation.operandSizeBits % 8 == 0 : "operandSize is not a byte size";
return annotation.operandSizeBits / 8;
}
@Override
public void patchCode(int relative, byte[] code) {
annotation.patch(annotation.instructionPosition, relative, code);
}
@Override
public boolean equals(Object obj) {
return obj == this;
}
}
class AdrpLdrMacroInstructionNativeImagePatcher extends CompilationResult.CodeAnnotation implements NativeImagePatcher {
private final AArch64MacroAssembler.AdrpLdrMacroInstruction macroInstruction;
AdrpLdrMacroInstructionNativeImagePatcher(AArch64MacroAssembler.AdrpLdrMacroInstruction macroInstruction) {
super(macroInstruction.instructionPosition);
this.macroInstruction = macroInstruction;
}
@Override
public void patchCode(int relative, byte[] code) {
macroInstruction.patch(macroInstruction.instructionPosition, relative, code);
}
@Override
public boolean equals(Object obj) {
return obj == this;
}
@Override
public int getOffset() {
throw VMError.unsupportedFeature("trying to get offset of adrp ldr macro instruction");
}
@Override
public int getLength() {
throw VMError.unsupportedFeature("trying to get length of adrp ldr macro instruction");
}
}
class AdrpAddMacroInstructionNativeImagePatcher extends CompilationResult.CodeAnnotation implements NativeImagePatcher {
private final AArch64MacroAssembler.AdrpAddMacroInstruction macroInstruction;
AdrpAddMacroInstructionNativeImagePatcher(AArch64MacroAssembler.AdrpAddMacroInstruction macroInstruction) {
super(macroInstruction.instructionPosition);
this.macroInstruction = macroInstruction;
}
@Override
public void patchCode(int relative, byte[] code) {
macroInstruction.patch(macroInstruction.instructionPosition, relative, code);
}
@Override
public boolean equals(Object obj) {
return obj == this;
}
@Override
public int getOffset() {
throw VMError.unsupportedFeature("trying to get offset of adrp add instruction");
}
@Override
public int getLength() {
throw VMError.unsupportedFeature("trying to get length of adrp add instruction");
}
}
class MovSequenceNativeImagePatcher extends CompilationResult.CodeAnnotation implements NativeImagePatcher {
private final AArch64MacroAssembler.MovSequenceAnnotation annotation;
MovSequenceNativeImagePatcher(AArch64MacroAssembler.MovSequenceAnnotation annotation) {
super(annotation.instructionPosition);
this.annotation = annotation;
}
@Override
public void patchCode(int relative, byte[] code) {
annotation.patch(annotation.instructionPosition, relative, code);
}
@Override
public boolean equals(Object obj) {
return obj == this;
}
@Override
public int getOffset() {
throw VMError.unsupportedFeature("trying to get offset of move sequence");
}
@Override
public int getLength() {
throw VMError.unsupportedFeature("trying to get length of move sequence");
}
}