package org.graalvm.compiler.replacements.test;
import java.util.Objects;
import org.junit.Assert;
import org.junit.Test;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.core.test.GraalCompilerTest;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
import org.graalvm.compiler.replacements.Snippets;
import org.graalvm.compiler.word.Word;
import org.graalvm.compiler.word.nodes.WordCastNode;
import jdk.vm.ci.meta.ResolvedJavaMethod;
public class DerivedOopTest extends GraalCompilerTest implements Snippets {
private static class Pointers {
public long basePointer;
public long internalPointer;
public long delta() {
return internalPointer - basePointer;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Pointers)) {
return false;
}
Pointers other = (Pointers) obj;
return this.delta() == other.delta();
}
@Override
public int hashCode() {
return (int) delta();
}
}
private static class Result {
public Pointers beforeGC;
public Pointers afterGC;
Result() {
beforeGC = new Pointers();
afterGC = new Pointers();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((afterGC == null) ? 0 : afterGC.hashCode());
result = prime * result + ((beforeGC == null) ? 0 : beforeGC.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Result)) {
return false;
}
Result other = (Result) obj;
return Objects.equals(this.beforeGC, other.beforeGC) && Objects.equals(this.afterGC, other.afterGC);
}
}
@Test
public void testFieldOffset() {
for (int i = 0; i < 4; i++) {
Result r = new Result();
test("fieldOffsetSnippet", r, 16L);
Assert.assertEquals(r.beforeGC.delta(), r.afterGC.delta());
}
}
static long getRawPointer(Object obj) {
return obj.hashCode();
}
static long getRawPointerIntrinsic(Object obj) {
return Word.objectToTrackedPointer(obj).rawValue();
}
public static Result fieldOffsetSnippet(Result obj, long offset) {
long internalPointer = getRawPointer(obj) + offset;
GraalDirectives.blackhole(internalPointer);
obj.beforeGC.basePointer = getRawPointer(obj);
obj.beforeGC.internalPointer = internalPointer;
System.gc();
obj.afterGC.basePointer = getRawPointer(obj);
obj.afterGC.internalPointer = internalPointer;
return obj;
}
@Override
protected Plugins getDefaultGraphBuilderPlugins() {
Plugins plugins = super.getDefaultGraphBuilderPlugins();
Registration r = new Registration(plugins.getInvocationPlugins(), DerivedOopTest.class);
ResolvedJavaMethod intrinsic = getResolvedJavaMethod("getRawPointerIntrinsic");
r.register1("getRawPointer", Object.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
return b.intrinsify(getReplacements().getReplacementBytecodeProvider(), targetMethod, intrinsic, receiver, new ValueNode[]{arg});
}
});
return plugins;
}
@Override
protected boolean checkHighTierGraph(StructuredGraph graph) {
assert graph.getNodes().filter(WordCastNode.class).count() > 0 : "DerivedOopTest.toLong should be intrinsified";
return super.checkHighTierGraph(graph);
}
}