Skip to content

Commit

Permalink
[GR-28138] Intrinsic for retrieving native function pointer.
Browse files Browse the repository at this point in the history
PullRequest: graal/8003
  • Loading branch information
Palez committed Jan 19, 2021
2 parents 82ee668 + 38bbe26 commit 21a3c29
Show file tree
Hide file tree
Showing 7 changed files with 275 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2020, Oracle and/or its affiliates.
* Copyright (c) 2019, 2021, Oracle and/or its affiliates.
*
* All rights reserved.
*
Expand Down Expand Up @@ -52,3 +52,7 @@ bool _graalvm_llvm_is_handle(void *nativeHandle) {
bool _graalvm_llvm_points_to_handle_space(void *nativeHandle) {
return false;
}
void *_graalvm_llvm_resolve_function(void *nativeHandle) {
should_not_reach();
return NULL;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates.
* Copyright (c) 2020, 2021, Oracle and/or its affiliates.
*
* All rights reserved.
*
Expand Down Expand Up @@ -121,6 +121,14 @@ static bool is_handle(void *nativeHandle);
*/
static bool points_to_handle_space(void *nativeHandle);

/**
* Resolve a function back to the function descriptor.
*
* This function will return the managedObject pointer of the function that the nativePointer is
* pointing to.
*/
static void *resolve_function(void *nativePointer);

#include <graalvm/llvm/internal/handles-impl.h>

#if defined(__cplusplus)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates.
* Copyright (c) 2020, 2021, Oracle and/or its affiliates.
*
* All rights reserved.
*
Expand Down Expand Up @@ -45,6 +45,7 @@ __attribute__((noinline)) void _graalvm_llvm_release_handle(void *nativeHandle);
__attribute__((noinline)) void *_graalvm_llvm_create_deref_handle(void *managedObject);
__attribute__((noinline)) bool _graalvm_llvm_is_handle(void *nativeHandle);
__attribute__((noinline)) bool _graalvm_llvm_points_to_handle_space(void *nativeHandle);
__attribute__((noinline)) void *_graalvm_llvm_resolve_function(void *nativeHandle);

__attribute__((always_inline)) static inline void *create_handle(void *managedObject) {
return _graalvm_llvm_create_handle(managedObject);
Expand All @@ -69,3 +70,7 @@ __attribute__((always_inline)) static inline bool is_handle(void *nativeHandle)
__attribute__((always_inline)) static inline bool points_to_handle_space(void *nativeHandle) {
return _graalvm_llvm_points_to_handle_space(nativeHandle);
}

__attribute__((always_inline)) static inline void *resolve_function(void *nativeHandle) {
return _graalvm_llvm_resolve_function(nativeHandle);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates.
* Copyright (c) 2017, 2021, Oracle and/or its affiliates.
*
* All rights reserved.
*
Expand Down Expand Up @@ -86,6 +86,7 @@
import com.oracle.truffle.llvm.runtime.nodes.intrinsics.handles.GraalVMIsHandleNodeGen;
import com.oracle.truffle.llvm.runtime.nodes.intrinsics.handles.GraalVMPointsToHandleSpaceNodeGen;
import com.oracle.truffle.llvm.runtime.nodes.intrinsics.handles.GraalVMReleaseHandleNodeGen;
import com.oracle.truffle.llvm.runtime.nodes.intrinsics.handles.GraalVMResolveFunctionNodeGen;
import com.oracle.truffle.llvm.runtime.nodes.intrinsics.handles.GraalVMResolveHandleNodeGen;
import com.oracle.truffle.llvm.runtime.nodes.intrinsics.handles.LLVMTruffleCannotBeHandle;
import com.oracle.truffle.llvm.runtime.nodes.intrinsics.interop.LLVMPolyglotAsPrimitive;
Expand Down Expand Up @@ -455,6 +456,7 @@ private static void registerManagedAllocationIntrinsics() {
add("_graalvm_llvm_create_deref_handle", "truffle_deref_handle_for_managed", (args, nodeFactory) -> GraalVMCreateDerefHandleNodeGen.create(args.get(1)));
add("_graalvm_llvm_is_handle", "truffle_is_handle_to_managed", (args, nodeFactory) -> GraalVMIsHandleNodeGen.create(args.get(1)));
add("_graalvm_llvm_points_to_handle_space", (args, nodeFactory) -> GraalVMPointsToHandleSpaceNodeGen.create(args.get(1)));
add("_graalvm_llvm_resolve_function", (args, nodeFactory) -> GraalVMResolveFunctionNodeGen.create(args.get(1)));

// deprecated
add("truffle_cannot_be_handle", (args, nodeFactory) -> LLVMTruffleCannotBeHandle.create(args.get(1)));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.oracle.truffle.llvm.runtime.nodes.intrinsics.handles;

import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.llvm.runtime.LLVMContext;
import com.oracle.truffle.llvm.runtime.LLVMFunctionDescriptor;
import com.oracle.truffle.llvm.runtime.LLVMLanguage;
import com.oracle.truffle.llvm.runtime.except.LLVMPolyglotException;
import com.oracle.truffle.llvm.runtime.nodes.api.LLVMExpressionNode;
import com.oracle.truffle.llvm.runtime.nodes.intrinsics.llvm.LLVMIntrinsic;
import com.oracle.truffle.llvm.runtime.pointer.LLVMManagedPointer;
import com.oracle.truffle.llvm.runtime.pointer.LLVMNativePointer;
import com.oracle.truffle.llvm.runtime.pointer.LLVMPointer;

@NodeChild(type = LLVMExpressionNode.class)
public abstract class GraalVMResolveFunction extends LLVMIntrinsic {

@Specialization
protected Object doNativeResolve(LLVMNativePointer pointer,
@CachedContext(LLVMLanguage.class) LLVMContext context) {
return LLVMManagedPointer.create(context.getFunctionDescriptor(pointer));
}

@Specialization(guards = "pointsToFunctionDescriptor(pointer)")
protected Object doManagedResolve(LLVMManagedPointer pointer) {
return pointer;
}

@Specialization(guards = "pointsToLong(pointer)")
protected Object doNativePointerResolve(LLVMPointer pointer,
@CachedContext(LLVMLanguage.class) LLVMContext context) {
LLVMManagedPointer object = LLVMManagedPointer.cast(pointer);
Object pointerValue = object.getObject();
LLVMNativePointer nativePointer = LLVMNativePointer.create((long) pointerValue);
return LLVMManagedPointer.create(context.getFunctionDescriptor(nativePointer));
}

@Fallback
protected Object doError(Object pointer) {
throw new LLVMPolyglotException(this, "Cannot resolve pointer %s to a function.", pointer);
}

protected boolean pointsToFunctionDescriptor(LLVMManagedPointer pointer) {
return pointer.getObject() instanceof LLVMFunctionDescriptor;
}

protected boolean pointsToLong(LLVMPointer pointer) {
if (LLVMManagedPointer.isInstance(pointer)) {
return LLVMManagedPointer.cast(pointer).getObject() instanceof Long;
}
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <graalvm/llvm/handles.h>

int fortytwo() {
return 42;
}

int max(int a, int b) {
if (a > b) {
return a;
}
return b;
}

void *test_native_fortytwo_function() {
return resolve_function(fortytwo);
}

void *test_resolve_function(void *function) {
return resolve_function(function);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.oracle.truffle.llvm.tests.interop;

import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.interop.InteropException;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.llvm.runtime.LLVMFunctionDescriptor;
import com.oracle.truffle.llvm.runtime.pointer.LLVMManagedPointer;
import com.oracle.truffle.tck.TruffleRunner;
import com.oracle.truffle.tck.TruffleRunner.Inject;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(TruffleRunner.class)
public class ResolveFunctionTest extends InteropTestBase {

private static Object testLibrary;
private static Object fortyTwoFunction;
private static Object maxFunction;

@BeforeClass
public static void loadTestBitcode() {
testLibrary = loadTestBitcodeInternal("createResolveFunction.c");
try {
fortyTwoFunction = InteropLibrary.getFactory().getUncached().readMember(testLibrary, "fortytwo");
maxFunction = InteropLibrary.getFactory().getUncached().readMember(testLibrary, "max");
} catch (InteropException ex) {
throw new AssertionError(ex);
}
}

public static class FortyTwoFunctionNode extends SulongTestNode {
public FortyTwoFunctionNode() {
super(testLibrary, "test_native_fortytwo_function");
}
}

@Test
public void testFunctionFortyTwo(@Inject(FortyTwoFunctionNode.class) CallTarget function) throws InteropException {
Object ret = function.call();
Assert.assertTrue(LLVMManagedPointer.isInstance(ret));
LLVMFunctionDescriptor retFunction = (LLVMFunctionDescriptor) LLVMManagedPointer.cast(ret).getObject();
String name = retFunction.getLLVMFunction().getName();
Assert.assertEquals("fortytwo", name);
Assert.assertEquals(42, InteropLibrary.getUncached().execute(retFunction));
}

public class ResolveFunctionNode extends SulongTestNode {
public ResolveFunctionNode() {
super(testLibrary, "test_resolve_function");
}
}

@Test
public void testResolveFunctionFortytwo(@Inject(ResolveFunctionNode.class) CallTarget function) throws InteropException {
Object ret = function.call(fortyTwoFunction);
Assert.assertTrue(LLVMManagedPointer.isInstance(ret));
LLVMFunctionDescriptor retFunction = (LLVMFunctionDescriptor) LLVMManagedPointer.cast(ret).getObject();
Assert.assertEquals(42, InteropLibrary.getUncached().execute(retFunction));
}

@Test
public void testResolveNativeFunctionFortytwo(@Inject(ResolveFunctionNode.class) CallTarget function) throws InteropException {
InteropLibrary.getUncached().toNative(fortyTwoFunction);
long pointer = InteropLibrary.getUncached().asPointer(fortyTwoFunction);
Object ret = function.call(pointer);
Assert.assertTrue(LLVMManagedPointer.isInstance(ret));
LLVMFunctionDescriptor retFunction = (LLVMFunctionDescriptor) LLVMManagedPointer.cast(ret).getObject();
Assert.assertEquals(42, InteropLibrary.getUncached().execute(retFunction));
}

@Test
public void testResolveNativeFunctionMax(@Inject(ResolveFunctionNode.class) CallTarget function) throws InteropException {
InteropLibrary.getUncached().toNative(maxFunction);
long pointer = InteropLibrary.getUncached().asPointer(maxFunction);
Object ret = function.call(pointer);
Assert.assertTrue(LLVMManagedPointer.isInstance(ret));
LLVMFunctionDescriptor retFunction = (LLVMFunctionDescriptor) LLVMManagedPointer.cast(ret).getObject();
Assert.assertEquals(42, InteropLibrary.getUncached().execute(retFunction, 1, 42));
}

@Test
public void testResolveFunctionMax(@Inject(ResolveFunctionNode.class) CallTarget function) throws InteropException {
Object ret = function.call(maxFunction);
Assert.assertTrue(LLVMManagedPointer.isInstance(ret));
LLVMFunctionDescriptor retFunction = (LLVMFunctionDescriptor) LLVMManagedPointer.cast(ret).getObject();
Assert.assertEquals(42, InteropLibrary.getUncached().execute(retFunction, 1, 42));
}
}

0 comments on commit 21a3c29

Please sign in to comment.