Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package jdk.graal.compiler.hotspot.test;

import org.junit.Before;
import org.junit.Test;

import jdk.graal.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl;
import jdk.graal.compiler.hotspot.nodes.InvokeStaticJavaMethodNode;
import jdk.graal.compiler.nodes.ValueNode;
import jdk.graal.compiler.nodes.extended.ForeignCallNode;
import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext;
import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin;
import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.ResolvedJavaMethod;

/**
* Verifies that deoptimization functions correctly when triggered during a method call invoked by
* an {@link InvokeStaticJavaMethodNode}.
*/
public class HotSpotDeoptBoundJavaMethodCallerTest extends HotSpotInvokeBoundJavaMethodBaseTest {

/**
* Calling {@link #getForeignCallInvokerMethod()} will deoptimize the calling frame. We will
* deoptimize to {@link InvokeStaticJavaMethodNode#stateBefore()}.
*/
@Override
protected boolean invocationPluginApply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg, JavaKind kind) {
InvokeStaticJavaMethodNode node = InvokeStaticJavaMethodNode.create(b, getForeignCallInvokerMethod(), b.bci());
b.add(node);
// add the arg to the stack as the method has a return value
b.addPush(kind, arg);
return false;
}

@Override
protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
invocationPlugins.register(HotSpotDeoptBoundJavaMethodCallerTest.class, new InvocationPlugin("testCallInt", int.class) {

@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
ForeignCallNode node = new ForeignCallNode(HotSpotForeignCallsProviderImpl.TEST_DEOPTIMIZE_CALLER_OF_CALLER, arg);
b.addPush(JavaKind.Int, node);
return true;
}
});
super.registerInvocationPlugins(invocationPlugins);
}

public static int testCallInt(int value) {
return value;
}

public static void invokeForeignCall() {
testCallInt(3);
}

public ResolvedJavaMethod getForeignCallInvokerMethod() {
return getResolvedJavaMethod(HotSpotDeoptBoundJavaMethodCallerTest.class, "invokeForeignCall");
}

@Before
public void before() {
getCode(getForeignCallInvokerMethod(), null, true, true, getInitialOptions());
}

@Test
@Override
public void testMany() {
super.testMany();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.graal.compiler.hotspot.test;

import jdk.graal.compiler.nodes.ValueNode;
import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext;
import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin;
import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.ResolvedJavaMethod;

/**
* Base class for tests involving calls to bound methods.
*/
public abstract class HotSpotInvokeBoundJavaMethodBaseTest extends HotSpotGraalCompilerTest {

public static final JavaKind[] KINDS = {JavaKind.Boolean, JavaKind.Byte, JavaKind.Short, JavaKind.Char, JavaKind.Int, JavaKind.Long, JavaKind.Object};

@Override
protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
for (JavaKind kind : KINDS) {
String name = kind.isObject() ? "passingObject" : "passing" + capitalize(kind.getJavaName());
Class<?> argType = kind.isObject() ? Object.class : kind.toJavaClass();
invocationPlugins.register(HotSpotInvokeBoundJavaMethodBaseTest.class, new InvocationPlugin(name, argType) {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg) {
invocationPluginApply(b, targetMethod, receiver, arg, kind);
return true;
}
});
}
super.registerInvocationPlugins(invocationPlugins);
}

private static String capitalize(String s) {
return Character.toUpperCase(s.charAt(0)) + s.substring(1);
}

protected abstract boolean invocationPluginApply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg, JavaKind kind);

static boolean[] booleanValues = new boolean[]{Boolean.TRUE, Boolean.FALSE};

static boolean passingBoolean(boolean arg) {
return arg;
}

public static boolean passingBooleanSnippet(boolean arg) {
return passingBoolean(arg);
}

public void testPassingBoolean() {
for (boolean value : booleanValues) {
test("passingBooleanSnippet", value);
}
}

static byte[] byteValues = new byte[]{Byte.MAX_VALUE, -1, 0, 1, Byte.MIN_VALUE};

static byte passingByte(byte arg) {
return arg;
}

public static byte passingByteSnippet(byte arg) {
return passingByte(arg);
}

public void testPassingByte() {
for (byte value : byteValues) {
test("passingByteSnippet", value);
}
}

static short[] shortValues = new short[]{Short.MAX_VALUE, -1, 0, 1, Short.MIN_VALUE};

static short passingShort(short arg) {
return arg;
}

public static short passingShortSnippet(short arg) {
return passingShort(arg);
}

public void testPassingShort() {
for (short value : shortValues) {
test("passingShortSnippet", value);
}
}

static char[] charValues = new char[]{Character.MAX_VALUE, 1, Character.MIN_VALUE};

static char passingChar(char arg) {
return arg;
}

public static char passingCharSnippet(char arg) {
return passingChar(arg);
}

public void testPassingChar() {
for (char value : charValues) {
test("passingCharSnippet", value);
}
}

static int[] intValues = new int[]{Integer.MAX_VALUE, -1, 0, 1, Integer.MIN_VALUE};

static int passingInt(int arg) {
return arg;
}

public static int passingIntSnippet(int arg) {
return passingInt(arg);
}

public void testPassingInt() {
for (int value : intValues) {
test("passingIntSnippet", value);
}
}

static long[] longValues = new long[]{Long.MAX_VALUE, -1, 0, 1, Long.MIN_VALUE};

static long passingLong(long arg) {
return arg;
}

public static long passingLongSnippet(long arg) {
return passingLong(arg);
}

public void testPassingLong() {
for (long value : longValues) {
test("passingLongSnippet", value);
}
}

static Object[] objectValues = new Object[]{null, "String", Integer.valueOf(-1)};

static Object passingObject(Object arg) {
return arg;
}

public static Object passingObjectSnippet(Object arg) {
return passingObject(arg);
}

public void testPassingObject() {
for (Object value : objectValues) {
test("passingObjectSnippet", value);
}
}

public void testMany() {
testPassingObject();
testPassingInt();
testPassingByte();
testPassingChar();
testPassingLong();
testPassingBoolean();
testPassingShort();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.graal.compiler.hotspot.test;

import org.junit.Test;

import jdk.graal.compiler.hotspot.nodes.InvokeStaticJavaMethodNode;
import jdk.graal.compiler.nodes.Invoke;
import jdk.graal.compiler.nodes.ValueNode;
import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext;
import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.ResolvedJavaMethod;

/**
* Tests that using an {@link InvokeStaticJavaMethodNode} instead of an {@link Invoke} to call a
* side-effect-free static method produces identical behavior.
*/
public class HotSpotInvokeBoundJavaMethodTest extends HotSpotInvokeBoundJavaMethodBaseTest {

@Override
protected boolean invocationPluginApply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg, JavaKind kind) {
InvokeStaticJavaMethodNode node = InvokeStaticJavaMethodNode.create(b, targetMethod, b.bci(), arg);
b.addPush(kind, node);
return false;
}

@Test
@Override
public void testMany() {
super.testMany();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,7 @@ private long getZGCAddressField(String name) {
public final long validateObject = getAddress("JVMCIRuntime::validate_object");

public final long testDeoptimizeCallInt = getAddress("JVMCIRuntime::test_deoptimize_call_int");
public final long testDeoptimizeCallerOfCaller = getAddress("JVMCIRuntime::test_deoptimize_caller_of_caller");

public final long registerFinalizerAddress = getAddress("SharedRuntime::register_finalizer");
public final long exceptionHandlerForReturnAddressAddress = getAddress("SharedRuntime::exception_handler_for_return_address");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ public abstract class HotSpotForeignCallsProviderImpl implements HotSpotForeignC
Word.class);

public static final HotSpotForeignCallDescriptor TEST_DEOPTIMIZE_CALL_INT = new HotSpotForeignCallDescriptor(SAFEPOINT, NO_SIDE_EFFECT, any(), "test_deoptimize_call_int", int.class, int.class);
public static final HotSpotForeignCallDescriptor TEST_DEOPTIMIZE_CALLER_OF_CALLER = new HotSpotForeignCallDescriptor(SAFEPOINT, NO_SIDE_EFFECT, any(), "test_deoptimize_caller_of_caller",
int.class, int.class);

protected final HotSpotJVMCIRuntime jvmciRuntime;
protected final HotSpotGraalRuntimeProvider runtime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,7 @@ public void initialize(HotSpotProviders providers, OptionValues options) {
linkForeignCall(options, providers, VALIDATE_OBJECT, c.validateObject, PREPEND_THREAD);

linkForeignCall(options, providers, TEST_DEOPTIMIZE_CALL_INT, c.testDeoptimizeCallInt, PREPEND_THREAD);
linkForeignCall(options, providers, TEST_DEOPTIMIZE_CALLER_OF_CALLER, c.testDeoptimizeCallerOfCaller, PREPEND_THREAD);

registerArrayCopy(JavaKind.Byte, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy);
registerArrayCopy(JavaKind.Boolean, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy);
Expand Down
Loading
Loading