diff --git a/com.oracle.truffle.r.native/fficall/src/jni/userrng.c b/com.oracle.truffle.r.native/fficall/src/jni/userrng.c new file mode 100644 index 0000000000000000000000000000000000000000..35d4e2bd9128da1be5cba8a53251026f43945d8d --- /dev/null +++ b/com.oracle.truffle.r.native/fficall/src/jni/userrng.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016, 2016, 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. + * + * 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. + */ + +#include <rffiutils.h> + +typedef void (*call_init)(int seed); +typedef double* (*call_rand)(void); +typedef int* (*call_nSeed)(void); +typedef int* (*call_seeds)(void); + +JNIEXPORT void JNICALL +Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1UserRng_init(JNIEnv *env, jclass c, jlong address, jint seed) { + call_init f = (call_init) address; + f(seed); +} + +JNIEXPORT double JNICALL +Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1UserRng_rand(JNIEnv *env, jclass c, jlong address) { + call_rand f = (call_rand) address; + double* dp = f(); + return *dp; +} + +JNIEXPORT jint JNICALL +Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1UserRng_nSeed(JNIEnv *env, jclass c, jlong address) { + call_nSeed f = (call_nSeed) address; + int *pn = f(); + return *pn; +} + +JNIEXPORT void JNICALL +Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1UserRng_seeds(JNIEnv *env, jclass c, jlong address, jintArray seedsArray) { + call_seeds f = (call_seeds) address; + int *pseeds = f(); + int seedslen = (*env)->GetArrayLength(env, seedsArray); + int *data = (*env)->GetIntArrayElements(env, seedsArray, NULL); + for (int i = 0; i < seedslen; i++) { + data[i] = pseeds[i]; + } + (*env)->ReleaseIntArrayElements(env, seedsArray, data, 0); +} diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_UserRng.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNI_UserRng.java similarity index 50% rename from com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_UserRng.java rename to com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNI_UserRng.java index ff50fa1416cd3935c2afbe2f0b9915aeb257a3db..fcb6c4c8d6f3ed744a912944823950b842892264 100644 --- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_UserRng.java +++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNI_UserRng.java @@ -22,82 +22,41 @@ */ package com.oracle.truffle.r.runtime.ffi.jnr; +import static com.oracle.truffle.r.runtime.rng.user.UserRNG.Function; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.r.runtime.ffi.UserRngRFFI; -import jnr.ffi.LibraryLoader; -import jnr.ffi.Pointer; -import jnr.ffi.annotations.In; - -//Checkstyle: stop method name -public class JNR_UserRng implements UserRngRFFI { - public interface UserRng { - void user_unif_init(@In int seed); - - Pointer user_unif_rand(); - - Pointer user_unif_nseed(); - - Pointer user_unif_seedloc(); - } - - private static class UserRngProvider { - private static String libPath; - private static UserRng userRng; - - UserRngProvider(String libPath) { - UserRngProvider.libPath = libPath; - } - - @TruffleBoundary - private static UserRng createAndLoadLib() { - return LibraryLoader.create(UserRng.class).load(libPath); - } - - static UserRng userRng() { - if (userRng == null) { - userRng = createAndLoadLib(); - } - return userRng; - } - } - - private static UserRng userRng() { - return UserRngProvider.userRng(); - } - - @Override - @SuppressWarnings("unused") - public void setLibrary(String path) { - new UserRngProvider(path); - - } - +public class JNI_UserRng implements UserRngRFFI { @Override @TruffleBoundary public void init(int seed) { - userRng().user_unif_init(seed); + init(Function.Init.getAddress(), seed); + } @Override @TruffleBoundary public double rand() { - Pointer pDouble = userRng().user_unif_rand(); - return pDouble.getDouble(0); + return rand(Function.Rand.getAddress()); } @Override @TruffleBoundary public int nSeed() { - return userRng().user_unif_nseed().getInt(0); + return nSeed(Function.NSeed.getAddress()); } @Override @TruffleBoundary public void seeds(int[] n) { - Pointer pInt = userRng().user_unif_seedloc(); - for (int i = 0; i < n.length; i++) { - n[i] = pInt.getInt(i * 4); - } + seeds(Function.Seedloc.getAddress(), n); } + + private static native void init(long address, int seed); + + private static native double rand(long address); + + private static native int nSeed(long address); + + private static native void seeds(long address, int[] n); } diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java index 05a093a010bd91d13ab53b115f77be56f86458b5..19aba1169678bd8cdfffd5d9d8e2c4c5ed5aec24 100644 --- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java +++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java @@ -164,7 +164,7 @@ public class JNR_RFFIFactory extends RFFIFactory implements RFFI { public UserRngRFFI getUserRngRFFI() { if (userRngRFFI == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - userRngRFFI = new JNR_UserRng(); + userRngRFFI = new JNI_UserRng(); } return userRngRFFI; } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/UserRngRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/UserRngRFFI.java index b3b7dc0dc3eb98c14bad2cc40154a93d2c95b23f..dc692727fcfe6b46100e854a859d63ec0abaa700 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/UserRngRFFI.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/UserRngRFFI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, 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 @@ -23,13 +23,10 @@ package com.oracle.truffle.r.runtime.ffi; /** - * Explicit statically typed interface to user-supplied random number generators. TODO This could - * eventually be subsumed by {@link CRFFI}. + * Explicit statically typed interface to user-supplied random number generators. */ public interface UserRngRFFI { - void setLibrary(String path); - void init(int seed); double rand(); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/user/UserRNG.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/user/UserRNG.java index bc649e2415f24676d88609143feee3c1f02631ab..9e1f745d769433b28be59b45398e497348bf8cce 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/user/UserRNG.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/user/UserRNG.java @@ -35,42 +35,68 @@ import com.oracle.truffle.r.runtime.rng.RRNG.Kind; * Interface to a user-supplied RNG. */ public final class UserRNG extends RNGInitAdapter { - - private static final String USER_UNIF_RAND = "user_unif_rand"; - private static final String USER_UNIF_INIT = "user_unif_init"; private static final boolean OPTIONAL = true; - @SuppressWarnings("unused") private long userUnifRand; - @SuppressWarnings("unused") private long userUnifInit; - private long userUnifNSeed; - private long userUnifSeedloc; + public enum Function { + Rand(!OPTIONAL), + Init(OPTIONAL), + NSeed(OPTIONAL), + Seedloc(OPTIONAL); + + private long address; + private final String symbol; + private final boolean optional; + + Function(boolean optional) { + this.symbol = "user_unif_" + name().toLowerCase(); + this.optional = optional; + } + + private boolean isDefined() { + return address != 0; + } + + public long getAddress() { + return address; + } + + private void setAddress(DLLInfo dllInfo) { + this.address = findSymbol(symbol, dllInfo, optional); + } + + } + private UserRngRFFI userRngRFFI; private int nSeeds = 0; @Override @TruffleBoundary public void init(int seed) { - DLLInfo dllInfo = DLL.findLibraryContainingSymbol(USER_UNIF_RAND); + DLLInfo dllInfo = DLL.findLibraryContainingSymbol(Function.Rand.symbol); if (dllInfo == null) { - throw RError.error(RError.NO_CALLER, RError.Message.RNG_SYMBOL, USER_UNIF_RAND); + throw RError.error(RError.NO_CALLER, RError.Message.RNG_SYMBOL, Function.Rand.symbol); + } + for (Function f : Function.values()) { + f.setAddress(dllInfo); } - userUnifRand = findSymbol(USER_UNIF_RAND, dllInfo, !OPTIONAL); - userUnifInit = findSymbol(USER_UNIF_INIT, dllInfo, OPTIONAL); - userUnifNSeed = findSymbol(USER_UNIF_INIT, dllInfo, OPTIONAL); - userUnifSeedloc = findSymbol(USER_UNIF_INIT, dllInfo, OPTIONAL); userRngRFFI = RFFIFactory.getRFFI().getUserRngRFFI(); - userRngRFFI.setLibrary(dllInfo.path); - userRngRFFI.init(seed); - if (userUnifSeedloc != 0 && userUnifNSeed == 0) { + if (Function.Init.isDefined()) { + userRngRFFI.init(seed); + } + if (Function.Seedloc.isDefined() && !Function.NSeed.isDefined()) { RError.warning(RError.NO_CALLER, RError.Message.RNG_READ_SEEDS); } - int ns = userRngRFFI.nSeed(); - if (ns < 0 || ns > 625) { - RError.warning(RError.NO_CALLER, RError.Message.GENERIC, "seed length must be in 0...625; ignored"); - } else { - nSeeds = ns; - // TODO: if we ever (initially) share iSeed (as GNU R does) we may need to assign this - // generator's iSeed here + if (Function.NSeed.isDefined()) { + int ns = userRngRFFI.nSeed(); + if (ns < 0 || ns > 625) { + RError.warning(RError.NO_CALLER, RError.Message.GENERIC, "seed length must be in 0...625; ignored"); + } else { + nSeeds = ns; + /* + * TODO: if we ever (initially) share iSeed (as GNU R does) we may need to assign + * this generator's iSeed here + */ + } } } @@ -95,7 +121,7 @@ public final class UserRNG extends RNGInitAdapter { @Override public int[] getSeeds() { - if (userUnifSeedloc == 0) { + if (!Function.Seedloc.isDefined()) { return null; } int[] result = new int[nSeeds];