From 232124028b99821322d68551ab9b48640a944d31 Mon Sep 17 00:00:00 2001 From: Mick Jordan <mick.jordan@oracle.com> Date: Thu, 21 Aug 2014 10:51:56 -0700 Subject: [PATCH] add fledgling com.oracle.truffle.r.runtime.ffi.native package --- .../builtin/processor/BuiltinProcessor.java | 18 ++- .../nodes/builtin/base/ForeignFunctions.java | 43 ++++-- .../.project | 11 ++ .../Makefile | 32 ++++ .../jni/call/src/Makefile | 70 +++++++++ .../jni/call/src/call.c | 139 ++++++++++++++++++ .../jni/include/R.h | 15 ++ .../jni/include/Rdefines.h | 20 +++ .../jni/include/Rinternals.h | 71 +++++++++ .../r/runtime/ffi/jnr/CallRFFIWithJNI.java | 132 +++++++++++++++++ .../r/runtime/ffi/jnr/JNR_RFFIFactory.java | 21 ++- .../truffle/r/runtime/ffi/CallRFFI.java | 50 +++++++ .../oracle/truffle/r/runtime/ffi/RFFI.java | 3 + .../truffle/r/runtime/ffi/RFFIFactory.java | 7 +- com.oracle.truffle.r.test.native/.project | 11 ++ mx.fastr/copyrights/overrides | 4 + mx.fastr/projects | 5 + 17 files changed, 630 insertions(+), 22 deletions(-) create mode 100644 com.oracle.truffle.r.runtime.ffi.native/.project create mode 100644 com.oracle.truffle.r.runtime.ffi.native/Makefile create mode 100644 com.oracle.truffle.r.runtime.ffi.native/jni/call/src/Makefile create mode 100644 com.oracle.truffle.r.runtime.ffi.native/jni/call/src/call.c create mode 100644 com.oracle.truffle.r.runtime.ffi.native/jni/include/R.h create mode 100644 com.oracle.truffle.r.runtime.ffi.native/jni/include/Rdefines.h create mode 100644 com.oracle.truffle.r.runtime.ffi.native/jni/include/Rinternals.h create mode 100644 com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIWithJNI.java create mode 100644 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CallRFFI.java create mode 100644 com.oracle.truffle.r.test.native/.project diff --git a/com.oracle.truffle.r.nodes.builtin.processor/src/com/oracle/truffle/r/nodes/builtin/processor/BuiltinProcessor.java b/com.oracle.truffle.r.nodes.builtin.processor/src/com/oracle/truffle/r/nodes/builtin/processor/BuiltinProcessor.java index 406cd57aba..1b6b1146bd 100644 --- a/com.oracle.truffle.r.nodes.builtin.processor/src/com/oracle/truffle/r/nodes/builtin/processor/BuiltinProcessor.java +++ b/com.oracle.truffle.r.nodes.builtin.processor/src/com/oracle/truffle/r/nodes/builtin/processor/BuiltinProcessor.java @@ -51,9 +51,10 @@ public class BuiltinProcessor extends AbstractProcessor { /** * Set true to trace processor. */ - private static boolean trace = false; + private static boolean trace = true; private Map<PackageElement, PackageBuiltins> map; + private boolean writtenBuiltinsFile; private static class PackageBuiltins { PackageElement packageElement; @@ -68,6 +69,7 @@ public class BuiltinProcessor extends AbstractProcessor { public synchronized void init(ProcessingEnvironment pe) { super.init(pe); map = new HashMap<>(); + writtenBuiltinsFile = false; note("BuiltinProcessor.init"); } @@ -75,15 +77,16 @@ public class BuiltinProcessor extends AbstractProcessor { public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { try { note("BuiltinProcessor.process"); - if (roundEnv.processingOver()) { + if (roundEnv.processingOver() && !writtenBuiltinsFile) { checkRBuiltin(); - note("writing RBUILTINS"); + note("writing RBuiltinClasses"); writeBuiltinsFiles(); + writtenBuiltinsFile = true; return true; } - boolean added = false; note("BuiltinProcessor: analyzing RBuiltins"); TypeElement rBuiltinType = processingEnv.getElementUtils().getTypeElement("com.oracle.truffle.r.runtime.RBuiltin"); + int addCount = 0; for (Element element : roundEnv.getElementsAnnotatedWith(rBuiltinType)) { TypeElement classElement = (TypeElement) element; PackageElement packageElement = getPackage(classElement); @@ -93,11 +96,11 @@ public class BuiltinProcessor extends AbstractProcessor { map.put(packageElement, packageBuiltins); } packageBuiltins.builtinClassElements.add(classElement); - added = true; + addCount++; } - note("BuiltinProcessor.process added=" + added); + note("BuiltinProcessor.process added=" + addCount); } catch (Exception ex) { - error("error generating RBUILTINS: " + ex); + error("error generating RBuiltinClasses: " + ex); StackTraceElement[] elements = ex.getStackTrace(); for (StackTraceElement element : elements) { error(element.toString()); @@ -111,6 +114,7 @@ public class BuiltinProcessor extends AbstractProcessor { String packageName = packageBuiltins.packageElement.getQualifiedName().toString(); // Read the previous file content if any SortedSet<String> classNames = readBuiltinsClass(packageName); + note("read " + classNames.size() + " from existing in " + packageName); // add in the classes from this step for (TypeElement builtinClassElement : packageBuiltins.builtinClassElements) { String qualName = builtinClassElement.getQualifiedName().toString(); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForeignFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForeignFunctions.java index 41645c3723..3405f3717a 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForeignFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForeignFunctions.java @@ -30,6 +30,7 @@ import com.oracle.truffle.r.nodes.access.*; import com.oracle.truffle.r.nodes.builtin.*; import com.oracle.truffle.r.nodes.unary.*; import com.oracle.truffle.r.runtime.*; +import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.data.*; import com.oracle.truffle.r.runtime.data.model.*; import com.oracle.truffle.r.runtime.ffi.*; @@ -43,14 +44,7 @@ import com.oracle.truffle.r.runtime.ffi.DLL.SymbolInfo; * href="https://stat.ethz.ch/R-manual/R-devel/library/base/html/Foreign.html">here</a>. */ public class ForeignFunctions { - public abstract static class Adapter extends RBuiltinNode { - protected static final String[] PARAMETER_NAMES = new String[]{".NAME", "...", "NAOK", "DUP", "PACKAGE", "ENCODING"}; - - @Override - public Object[] getParameterNames() { - return PARAMETER_NAMES; - } - + public abstract static class FortranCAdapter extends RBuiltinNode { @Override public RNode[] getParameterValues() { return new RNode[]{ConstantNode.create(RMissing.instance), ConstantNode.create(EMPTY_OBJECT_ARRAY), ConstantNode.create(RRuntime.LOGICAL_FALSE), @@ -80,7 +74,7 @@ public class ForeignFunctions { * For now, just some special case functions that are built in to the implementation. */ @RBuiltin(name = ".Fortran", kind = RBuiltinKind.PRIMITIVE, parameterNames = {".NAME", "...", "NAOK", "DUP", "PACKAGE", "ENCODING"}) - public abstract static class Fortran extends Adapter { + public abstract static class Fortran extends FortranCAdapter { private static final String E = RRuntime.NAMES_ATTR_EMPTY_VALUE; private static final RStringVector DQRDC2_NAMES = RDataFactory.createStringVector(new String[]{"qr", E, E, E, E, "rank", "qraux", "pivot", E}, RDataFactory.COMPLETE_VECTOR); @@ -172,7 +166,7 @@ public class ForeignFunctions { } @RBuiltin(name = ".C", kind = RBuiltinKind.PRIMITIVE, parameterNames = {".NAME", "...", "NAOK", "DUP", "PACKAGE", "ENCODING"}) - public abstract static class C extends Adapter { + public abstract static class C extends FortranCAdapter { private static final int SCALAR_DOUBLE = 0; private static final int SCALAR_INT = 1; @@ -285,12 +279,17 @@ public class ForeignFunctions { * For now, just some special case functions that are built in to the implementation. */ @RBuiltin(name = ".Call", kind = RBuiltinKind.PRIMITIVE, parameterNames = {".NAME", "...", "PACKAGE"}) - public abstract static class Call extends Adapter { + public abstract static class Call extends RBuiltinNode { @Child private CastComplexNode castComplex; @Child private CastLogicalNode castLogical; @Child private CastToVectorNode castVector; + @Override + public RNode[] getParameterValues() { + return new RNode[]{ConstantNode.create(RMissing.instance), ConstantNode.create(EMPTY_OBJECT_ARRAY), ConstantNode.create(RMissing.instance)}; + } + private Object castComplex(VirtualFrame frame, Object operand) { if (castComplex == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -318,7 +317,7 @@ public class ForeignFunctions { // TODO: handle more argument types (this is sufficient to run the b25 benchmarks) @SuppressWarnings("unused") @Specialization(guards = "fft") - public RComplexVector callFFT(VirtualFrame frame, RList f, Object[] args) { + public RComplexVector callFFT(VirtualFrame frame, RList f, Object[] args, RMissing packageName) { controlVisibility(); RComplexVector zVec = (RComplexVector) castComplex(frame, castVector(frame, args[0])); double[] z = zVec.isTemporary() ? zVec.getDataWithoutCopying() : zVec.getDataCopy(); @@ -398,7 +397,7 @@ public class ForeignFunctions { // Translated from GnuR: library/methods/src/methods_list_dispatch.c @SuppressWarnings("unused") @Specialization(guards = "methodsPackageMetaName") - public String callMethodsPackageMetaName(VirtualFrame frame, RList f, Object[] args) { + public String callMethodsPackageMetaName(VirtualFrame frame, RList f, Object[] args, RMissing packageName) { controlVisibility(); // TODO proper error checks String prefixString = (String) args[0]; @@ -415,6 +414,24 @@ public class ForeignFunctions { return matchName(f, "R_methodsPackageMetaName"); } + @Specialization + public Object callNamedFunction(VirtualFrame frame, String name, Object[] args, @SuppressWarnings("unused") RMissing packageName) { + return callNamedFunctionWithPackage(frame, name, args, null); + } + + @Specialization + public Object callNamedFunctionWithPackage(VirtualFrame frame, String name, Object[] args, String packageName) { + SymbolInfo symbolInfo = DLL.findSymbolInfo(name, packageName); + if (symbolInfo == null) { + throw RError.error(frame, getEncapsulatingSourceSection(), Message.GENERIC, ".Call %s not found", name); + } + try { + return RFFIFactory.getRFFI().getCallRFFI().invokeCall(symbolInfo, args); + } catch (Throwable t) { + throw RError.error(frame, getEncapsulatingSourceSection(), RError.Message.NATIVE_CALL_FAILED, t.getMessage()); + } + } + } } diff --git a/com.oracle.truffle.r.runtime.ffi.native/.project b/com.oracle.truffle.r.runtime.ffi.native/.project new file mode 100644 index 0000000000..38c243b362 --- /dev/null +++ b/com.oracle.truffle.r.runtime.ffi.native/.project @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>com.oracle.truffle.r.runtime.ffi.native</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + </buildSpec> + <natures> + </natures> +</projectDescription> diff --git a/com.oracle.truffle.r.runtime.ffi.native/Makefile b/com.oracle.truffle.r.runtime.ffi.native/Makefile new file mode 100644 index 0000000000..87f1734188 --- /dev/null +++ b/com.oracle.truffle.r.runtime.ffi.native/Makefile @@ -0,0 +1,32 @@ +# +# Copyright (c) 2014, 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. +# + +.PHONY: urand clean + +export TOPDIR = $(CURDIR) + +jnicall: + $(MAKE) -C jni/call/src + +clean: + $(MAKE) -C jni/call/src clean diff --git a/com.oracle.truffle.r.runtime.ffi.native/jni/call/src/Makefile b/com.oracle.truffle.r.runtime.ffi.native/jni/call/src/Makefile new file mode 100644 index 0000000000..ed564bda71 --- /dev/null +++ b/com.oracle.truffle.r.runtime.ffi.native/jni/call/src/Makefile @@ -0,0 +1,70 @@ +# +# Copyright (c) 2014, 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. +# + +.PHONY: all clean + +HOSTOS = $(shell uname) +ifeq ($(HOSTOS),Darwin) + HOSTOS_LC = darwin +endif +ifeq ($(HOSTOS),Linux) + HOSTOS_LC = linux +endif + +ifeq ($(TOPDIR),) + TOPDIR = $(abspath ../../..) +endif + +BIN = ../bin/$(HOSTOS_LC) +SRC = $(CURDIR) +C_SOURCES := $(wildcard *.c) +ifneq ($(HOSTOS), Darwin) + C_LIBNAME := lib$(C_SOURCES:.c=.so) +else + C_LIBNAME := lib$(C_SOURCES:.c=.dylib) +endif +C_OBJECTS := $(BIN)/$(C_SOURCES:.c=.o) +C_LIB := $(BIN)/$(C_LIBNAME) + +JNI_INCLUDES = -I $(JAVA_HOME)/include -I $(JAVA_HOME)/include/$(HOSTOS_LC) +FFI_INCLUDES = -I$(TOPDIR)/jni/include + +INCLUDE_DIR := $(JNI_INCLUDES) $(FFI_INCLUDES) + +all: $(C_LIB) + +$(C_LIB): $(BIN) $(C_OBJECTS) +ifneq ($HOSTOS, Darwin) + gcc -fPIC -shared -o $(C_LIB) $(C_OBJECTS) +else + gcc -dynamiclib -undefined dynamic_lookup -o $(C_LIB) $(C_OBJECTS) +endif + +$(BIN): + mkdir -p $(BIN) + +$(BIN)/%.o: %.c + gcc $(INCLUDE_DIR) -fPIC -O2 -c $< -o $@ + +clean: + rm -rf $(BIN) diff --git a/com.oracle.truffle.r.runtime.ffi.native/jni/call/src/call.c b/com.oracle.truffle.r.runtime.ffi.native/jni/call/src/call.c new file mode 100644 index 0000000000..efaee487a0 --- /dev/null +++ b/com.oracle.truffle.r.runtime.ffi.native/jni/call/src/call.c @@ -0,0 +1,139 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (c) 1995-2012, The R Core Team + * Copyright (c) 2003, The R Foundation + * Copyright (c) 2014, Oracle and/or its affiliates + * + * All rights reserved. + */ + +#include <string.h> +#include <Rinternals.h> + +/* + * All calls pass through one of the call(N) methods, which carry the JNIEnv value. + * This needs to be saved for reuse in the many R functions such as Rf_allocVector. + * FastR is not currently multi-threaded so the value can be stored in a static. + */ + +typedef SEXP (*call0func)(); +typedef SEXP (*call1func)(SEXP arg1); +typedef SEXP (*call2func)(SEXP arg1, SEXP arg2); + +static JNIEnv *curenv = NULL; + +JNIEnv *getEnv() { + return curenv; +} + +JNIEXPORT jobject JNICALL +Java_com_oracle_truffle_r_runtime_ffi_jnr_CallRFFIWithJNI_call(JNIEnv *env, jclass c, jlong address, jobjectArray args) { + curenv = env; + jsize len = (*env)->GetArrayLength(env, args); + switch (len) { + case 0: { + call0func call0 = (call0func) address; + return (*call0)(); + } + + case 1: { + jobject arg1 = (*env)->GetObjectArrayElement(env, args, 0); + call1func call1 = (call1func) address; + return (*call1)(arg1); + } + + case 2: { + jobject arg1 = (*env)->GetObjectArrayElement(env, args, 0); + jobject arg2 = (*env)->GetObjectArrayElement(env, args, 1); + call2func call2 = (call2func) address; + return (*call2)(arg1, arg2); + } + + default: + (*env)->FatalError(env, "call(JNI): unexpected number of arguments"); + return NULL; + } + +} + +JNIEXPORT jobject JNICALL +Java_com_oracle_truffle_r_runtime_ffi_jnr_CallRFFIWithJNI_call0(JNIEnv *env, jclass c, jlong address) { + curenv = env; + call0func call0 = (call0func) address; + return (*call0)(); +} + +JNIEXPORT jobject JNICALL +Java_com_oracle_truffle_r_runtime_ffi_jnr_CallRFFIWithJNI_call1(JNIEnv *env, jclass c, jlong address, jobject arg1) { + curenv = env; + call1func call1 = (call1func) address; + return (*call1)(arg1); +} + +JNIEXPORT jobject JNICALL +Java_com_oracle_truffle_r_runtime_ffi_jnr_CallRFFIWithJNI_call2(JNIEnv *env, jclass c, jlong address, jobject arg1, jobject arg2) { + curenv = env; + call2func call2 = (call2func) address; + return (*call2)(arg1, arg2); +} + +static jclass checkFindClass(JNIEnv *env, const char *name) { + jclass klass = (*env)->FindClass(env, name); + if (klass == NULL) { + char buf[1024]; + strcpy(buf, "failed to find class "); + strcat(buf, name); + (*env)->FatalError(env, buf); + } + return klass; +} + +static jmethodID checkGetMethodID(JNIEnv *env, jclass klass, const char *name, const char *sig, int isStatic) { + jmethodID methodID = isStatic ? (*env)->GetStaticMethodID(env, klass, name, sig) : (*env)->GetMethodID(env, klass, name, sig); + if (methodID == NULL) { + char buf[1024]; + strcpy(buf, "failed to find "); + strcat(buf, isStatic ? "static" : "instance"); + strcat(buf, " method "); + strcat(buf, name); + strcat(buf, "("); + strcat(buf, sig); + strcat(buf, ")"); + (*env)->FatalError(env, buf); + } + return methodID; +} + +SEXP Rf_allocVector(SEXPTYPE t, R_xlen_t len) { + JNIEnv *thisenv = getEnv(); + jclass dfClass = checkFindClass(thisenv, "com/oracle/truffle/r/runtime/data/RDataFactory"); + switch (t) { + case INTSXP: { + jmethodID createIntArrayMethodID = checkGetMethodID(thisenv, dfClass, "createIntVector", "(I)Lcom/oracle/truffle/r/runtime/data/RIntVector;", 1); + return (*thisenv)->CallStaticObjectMethod(thisenv, dfClass, createIntArrayMethodID, len); + default: + (*thisenv)->FatalError(thisenv, "vector type not handled"); + return NULL; + } + } +} + +SEXP SET_VECTOR_ELT(SEXP x, R_xlen_t i, SEXP v) { + // This assumes int + JNIEnv *thisenv = getEnv(); + jclass callClass = checkFindClass(thisenv, "com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIWithJNI"); + jmethodID updateDataAtMethodID = checkGetMethodID(thisenv, callClass, "updateIntDataAt", "(Lcom/oracle/truffle/r/runtime/data/RIntVector;II)V", 1); + (*thisenv)->CallVoidMethod(thisenv, callClass, updateDataAtMethodID, x, 0, (int) v); + return v; +} + +int Rf_asInteger(SEXP x) { + JNIEnv *thisenv = getEnv(); + jclass callClass = checkFindClass(thisenv, "com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIWithJNI"); + jmethodID getIntDataAtZeroID = checkGetMethodID(thisenv, callClass, "getIntDataAtZero", "(Ljava/lang/Object;)I", 1); + return (*thisenv)->CallStaticIntMethod(thisenv, callClass, getIntDataAtZeroID, x); +} + diff --git a/com.oracle.truffle.r.runtime.ffi.native/jni/include/R.h b/com.oracle.truffle.r.runtime.ffi.native/jni/include/R.h new file mode 100644 index 0000000000..4dcf4059ce --- /dev/null +++ b/com.oracle.truffle.r.runtime.ffi.native/jni/include/R.h @@ -0,0 +1,15 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (c) 1995-2012, The R Core Team + * Copyright (c) 2003, The R Foundation + * Copyright (c) 2014, Oracle and/or its affiliates + * + * All rights reserved. + */ +#ifndef R_R_H +#define R_R_H + +#endif /* !R_R_H */ diff --git a/com.oracle.truffle.r.runtime.ffi.native/jni/include/Rdefines.h b/com.oracle.truffle.r.runtime.ffi.native/jni/include/Rdefines.h new file mode 100644 index 0000000000..67ff96ba98 --- /dev/null +++ b/com.oracle.truffle.r.runtime.ffi.native/jni/include/Rdefines.h @@ -0,0 +1,20 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (c) 1995-2012, The R Core Team + * Copyright (c) 2003, The R Foundation + * Copyright (c) 2014, Oracle and/or its affiliates + * + * All rights reserved. + */ +#ifndef R_DEFINES_H +#define R_DEFINES_H + +#include <Rinternals.h> + +#define INTEGER_VALUE(x) asInteger(x) +#define NEW_INTEGER(n) allocVector(INTSXP,n) + +#endif diff --git a/com.oracle.truffle.r.runtime.ffi.native/jni/include/Rinternals.h b/com.oracle.truffle.r.runtime.ffi.native/jni/include/Rinternals.h new file mode 100644 index 0000000000..40156519ed --- /dev/null +++ b/com.oracle.truffle.r.runtime.ffi.native/jni/include/Rinternals.h @@ -0,0 +1,71 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (c) 1995-2012, The R Core Team + * Copyright (c) 2003, The R Foundation + * Copyright (c) 2014, Oracle and/or its affiliates + * + * All rights reserved. + */ +#ifndef R_INTERNALS_H_ +#define R_INTERNALS_H_ + +// The FastR JNI Rinternals + +#include <jni.h> + +typedef unsigned int SEXPTYPE; + +#define NILSXP 0 /* nil = NULL */ +#define SYMSXP 1 /* symbols */ +#define LISTSXP 2 /* lists of dotted pairs */ +#define CLOSXP 3 /* closures */ +#define ENVSXP 4 /* environments */ +#define PROMSXP 5 /* promises: [un]evaluated closure arguments */ +#define LANGSXP 6 /* language constructs (special lists) */ +#define SPECIALSXP 7 /* special forms */ +#define BUILTINSXP 8 /* builtin non-special forms */ +#define CHARSXP 9 /* "scalar" string type (internal only)*/ +#define LGLSXP 10 /* logical vectors */ +/* 11 and 12 were factors and ordered factors in the 1990s */ +#define INTSXP 13 /* integer vectors */ +#define REALSXP 14 /* real variables */ +#define CPLXSXP 15 /* complex variables */ +#define STRSXP 16 /* string vectors */ +#define DOTSXP 17 /* dot-dot-dot object */ +#define ANYSXP 18 /* make "any" args work. + Used in specifying types for symbol + registration to mean anything is okay */ +#define VECSXP 19 /* generic vectors */ +#define EXPRSXP 20 /* expressions vectors */ +#define BCODESXP 21 /* byte code */ +#define EXTPTRSXP 22 /* external pointer */ +#define WEAKREFSXP 23 /* weak reference */ +#define RAWSXP 24 /* raw bytes */ +#define S4SXP 25 /* S4, non-vector */ + +/* used for detecting PROTECT issues in memory.c */ +#define NEWSXP 30 /* fresh node creaed in new page */ +#define FREESXP 31 /* node released by GC */ + +#define FUNSXP 99 /* Closure or Builtin or Special */ + +typedef int R_xlen_t; + +typedef jobject SEXP; + +#define PROTECT(x) (x) +#define UNPROTECT(x) + +#define allocVector Rf_allocVector +#define asInteger Rf_asInteger + +int Rf_asInteger(SEXP x); + +SEXP Rf_allocVector(SEXPTYPE, R_xlen_t); + +SEXP SET_VECTOR_ELT(SEXP x, R_xlen_t i, SEXP v); + +#endif diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIWithJNI.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIWithJNI.java new file mode 100644 index 0000000000..06bee7f302 --- /dev/null +++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIWithJNI.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2014, 2014, 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. + */ +package com.oracle.truffle.r.runtime.ffi.jnr; + +import java.nio.file.*; + +import com.oracle.truffle.api.CompilerDirectives.SlowPath; +import com.oracle.truffle.r.runtime.*; +import com.oracle.truffle.r.runtime.data.*; +import com.oracle.truffle.r.runtime.ffi.*; +import com.oracle.truffle.r.runtime.ffi.DLL.SymbolInfo; +import com.oracle.truffle.r.runtime.ops.na.*; + +/** + * The only variety in the signatures for {@code .Call} is the number of arguments. GnuR supports a + * maximum number of args. We could perhaps be clever using {@ode jnr-invoke} but for simple + * functions a straight JNI interface is adequate. + */ +public class CallRFFIWithJNI implements CallRFFI { + + CallRFFIWithJNI() { + loadLibrary(); + } + + @SlowPath + private static void loadLibrary() { +// System.loadLibrary("call"); + String rHome = REnvVars.rHome(); + String packageName = "com.oracle.truffle.r.runtime.ffi.native"; + String osName = System.getProperty("os.name"); + String libExt = "so"; + String subDir = null; + switch (osName) { + case "Mac OS X": + subDir = "darwin"; + libExt = "dylib"; + break; + + case "Linux": + subDir = "linux"; + break; + + default: + Utils.fail("CallRFFI: unsupported OS: " + osName); + } + Path path = FileSystems.getDefault().getPath(rHome, packageName, "jni", "call", "bin", subDir, "libCall." + libExt); + System.load(path.toString()); + } + + /** + * Helper function that handles {@link Integer} and {@link RIntVector} "vectors". + * + * @return value at logical index 0 + */ + public static int getIntDataAtZero(Object x) { + if (x instanceof Integer) { + return ((Integer) x).intValue(); + } else if (x instanceof RIntVector) { + return ((RIntVector) x).getDataAt(0); + } else { + assert false; + return 0; + } + } + + private static final NACheck elementNACheck = NACheck.create(); + + /** + * Helper function for updating arrays. + */ + public static void updateIntDataAt(RIntVector x, int index, int value) { + elementNACheck.enable(x); + x.updateDataAt(index, value, elementNACheck); + } + + // @formatter:off + public Object invokeCall(SymbolInfo symbolInfo, Object[] args) throws Throwable { + switch (args.length) { + case 0: return call0(symbolInfo.getAddress()); + case 1: return call1(symbolInfo.getAddress(), args[0]); + case 2: return call2(symbolInfo.getAddress(), args[0], args[1]); + case 3: return call3(symbolInfo.getAddress(), args[0], args[1], args[2]); + case 4: return call4(symbolInfo.getAddress(), args[0], args[1], args[2], args[3]); + case 5: return call5(symbolInfo.getAddress(), args[0], args[1], args[2], args[3], args[4]); + case 6: return call6(symbolInfo.getAddress(), args[0], args[1], args[2], args[3], args[4], args[5]); + case 7: return call7(symbolInfo.getAddress(), args[0], args[1], args[2], args[3], args[4], args[5], args[6]); + case 8: return call8(symbolInfo.getAddress(), args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); + case 9: return call9(symbolInfo.getAddress(), args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); + default: + assert false; + return null; + } + } + + public Object invokeExternal(SymbolInfo symbolInfo, Object[] args) throws Throwable { + assert false; + return null; + } + + private static native Object call(long address, Object[] args); + private static native Object call0(long address); + private static native Object call1(long address, Object arg1); + private static native Object call2(long address, Object arg1, Object arg2); + private static native Object call3(long address, Object arg1, Object arg2, Object arg3); + private static native Object call4(long address, Object arg1, Object arg2, Object arg3, Object arg4); + private static native Object call5(long address, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5); + private static native Object call6(long address, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6); + private static native Object call7(long address, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7); + private static native Object call8(long address, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8); + private static native Object call9(long address, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9); + +} 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 e0df51148e..a39ee21667 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 @@ -39,6 +39,11 @@ import com.oracle.truffle.r.runtime.ffi.*; */ public class JNR_RFFIFactory extends RFFIFactory implements RFFI, BaseRFFI, RDerivedRFFI, LapackRFFI, UserRngRFFI { + public JNR_RFFIFactory() { + // This must load early as package libraries reference symbols in it. + getCallRFFI(); + } + // Base @Override @@ -568,7 +573,7 @@ public class JNR_RFFIFactory extends RFFIFactory implements RFFI, BaseRFFI, RDer } /* - * CCall methods + * .C methods */ private static CRFFI cRFFI; @@ -581,6 +586,20 @@ public class JNR_RFFIFactory extends RFFIFactory implements RFFI, BaseRFFI, RDer return cRFFI; } + /* + * .C methods + */ + + private static CallRFFI callRFFI; + + @Override + public CallRFFI getCallRFFI() { + if (callRFFI == null) { + callRFFI = new CallRFFIWithJNI(); + } + return callRFFI; + } + // zip public interface Zip { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CallRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CallRFFI.java new file mode 100644 index 0000000000..a7ffd89a46 --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CallRFFI.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014, 2014, 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. + */ +package com.oracle.truffle.r.runtime.ffi; + +/** + * Support for the {.Call} and {.External} calls. + */ +public interface CallRFFI { + /** + * Invoke the native method identified by {@code symbolInfo} passing it the arguments in + * {@code args}. The values in {@code args} can be any of the types used to represent {@code R} + * values in the implementation. + * + * @param symbolInfo identifies the symbol and the defining library + * @param args arguments + * @throws Throwable on any error during the call + */ + Object invokeCall(DLL.SymbolInfo symbolInfo, Object[] args) throws Throwable; + + /** + * Variant of {@link #invokeCall} for {@code .External}, where args are wrapped up as a single + * argument to the native call. + * + * @param symbolInfo + * @param args + * @throws Throwable + */ + Object invokeExternal(DLL.SymbolInfo symbolInfo, Object[] args) throws Throwable; + +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFI.java index b7e3a055af..cd6df58bfa 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFI.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFI.java @@ -33,6 +33,7 @@ package com.oracle.truffle.r.runtime.ffi; * <li>{@link RDerivedRFFI}: the specific, typed, foreign functions required by the built-in * {@code Linpack} functions.</li> * <li>{@link CRFFI}: {@code .C} and {@code .Fortran} call interface. + * <li>{@link CallRFFI}: {@code .Call} and {@code .External} call interface. * <li>{@link UserRngRFFI}: specific interface to user-supplied random number generator. * </ul> * @@ -48,6 +49,8 @@ public interface RFFI { CRFFI getCRFFI(); + CallRFFI getCallRFFI(); + UserRngRFFI getUserRngRFFI(); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java index 6edb8539e4..6689c311fd 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java @@ -56,7 +56,12 @@ public abstract class RFFIFactory { } public CRFFI getCRFFI() { - Utils.fail("getCCallRFFI not implemented"); + Utils.fail("getCRFFI not implemented"); + return null; + } + + public CallRFFI getCallRFFI() { + Utils.fail("getCallRFFI not implemented"); return null; } diff --git a/com.oracle.truffle.r.test.native/.project b/com.oracle.truffle.r.test.native/.project new file mode 100644 index 0000000000..f15e63fc58 --- /dev/null +++ b/com.oracle.truffle.r.test.native/.project @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>com.oracle.truffle.r.test.native</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + </buildSpec> + <natures> + </natures> +</projectDescription> diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides index 341732708b..b839a9cf14 100644 --- a/mx.fastr/copyrights/overrides +++ b/mx.fastr/copyrights/overrides @@ -120,6 +120,10 @@ com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RGroupGenerics.jav com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java,gnu_r.copyright com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java,gnu_r_purdue.copyright com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/UnaryArithmetic.java,gnu_r_unary.copyright +com.oracle.truffle.r.runtime.ffi.native/jni/call/src/call.c,gnu_r.copyright +com.oracle.truffle.r.runtime.ffi.native/jni/include/R.h,gnu_r.copyright +com.oracle.truffle.r.runtime.ffi.native/jni/include/Rdefines.h,gnu_r.copyright +com.oracle.truffle.r.runtime.ffi.native/jni/include/Rinternals.h,gnu_r.copyright com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java,purdue.copyright com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/all/AllTests.java,no.copyright com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/failing/FailingTests.java,no.copyright diff --git a/mx.fastr/projects b/mx.fastr/projects index eca237fc57..b763b89f92 100644 --- a/mx.fastr/projects +++ b/mx.fastr/projects @@ -168,6 +168,11 @@ project@com.oracle.truffle.r.runtime.ffi@checkstyle=com.oracle.truffle.r.runtime project@com.oracle.truffle.r.runtime.ffi@javaCompliance=1.8 project@com.oracle.truffle.r.runtime.ffi@workingSets=Truffle,FastR +# com.oracle.truffle.r.runtime.ffi.native +project@com.oracle.truffle.r.runtime.ffi.native@sourceDirs= +project@com.oracle.truffle.r.runtime.ffi.native@native=true +project@com.oracle.truffle.r.runtime.ffi.native@workingSets=FastR + # com.oracle.truffle.r.native project@com.oracle.truffle.r.native@sourceDirs= project@com.oracle.truffle.r.native@native=true -- GitLab