diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java index 60a35920fe752bd1d1c47db79bd5fdd29af4cb5b..edd3314671962989ab151741e632bf6caad0b808 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java @@ -78,15 +78,34 @@ public class RCommand { // CheckStyle: stop system..print check public static void main(String[] args) { - RCmdOptions options = RCmdOptions.parseArguments(RCmdOptions.Client.R, args); - options.printHelpAndVersion(); - ContextInfo info = createContextInfoFromCommandLine(options); + PolyglotEngine vm = createPolyglotEngine(args); // never returns - readEvalPrint(info); + readEvalPrint(vm); throw RInternalError.shouldNotReachHere(); } - static ContextInfo createContextInfoFromCommandLine(RCmdOptions options) { + /** + * This exists as a separate method to support the Rembedded API. + */ + static PolyglotEngine createPolyglotEngine(String[] args) { + RCmdOptions options = RCmdOptions.parseArguments(RCmdOptions.Client.R, args); + options.printHelpAndVersion(); + PolyglotEngine vm = createContextInfoFromCommandLine(options); + return vm; + } + + /** + * Creates the PolyglotEngine and initializes it. Called from native code when FastR is + * embedded. + */ + static PolyglotEngine initialize(String[] args) { + PolyglotEngine vm = createPolyglotEngine(args); + // Any expression will do to initialize the engine. + doEcho(vm); + return vm; + } + + static PolyglotEngine createContextInfoFromCommandLine(RCmdOptions options) { if (options.getBoolean(SLAVE)) { options.setValue(QUIET, true); options.setValue(NO_SAVE, true); @@ -170,7 +189,7 @@ public class RCommand { consoleHandler = new DefaultConsoleHandler(consoleInput, consoleOutput); } } - return ContextInfo.create(options, ContextKind.SHARE_NOTHING, null, consoleHandler); + return ContextInfo.create(options, ContextKind.SHARE_NOTHING, null, consoleHandler).apply(PolyglotEngine.newBuilder()).build(); } private static final Source GET_ECHO = Source.fromText("invisible(getOption('echo'))", RInternalSourceDescriptions.GET_ECHO).withMimeType(TruffleRLanguage.MIME); @@ -187,9 +206,8 @@ public class RCommand { * In case 2, we must implicitly execute a {@code quit("default, 0L, TRUE} command before * exiting. So,in either case, we never return. */ - static void readEvalPrint(ContextInfo info) { - PolyglotEngine vm = info.apply(PolyglotEngine.newBuilder()).build(); - ConsoleHandler consoleHandler = info.getConsoleHandler(); + static void readEvalPrint(PolyglotEngine vm) { + ConsoleHandler consoleHandler = getContextInfo(vm).getConsoleHandler(); Source source = Source.fromAppendableText(consoleHandler.getInputDescription()); try { // console.println("initialize time: " + (System.currentTimeMillis() - start)); @@ -280,6 +298,14 @@ public class RCommand { } } + private static ContextInfo getContextInfo(PolyglotEngine vm) { + try { + return (ContextInfo) vm.findGlobalSymbol(ContextInfo.GLOBAL_SYMBOL).get(); + } catch (IOException ex) { + throw RInternalError.shouldNotReachHere(); + } + } + private static boolean doEcho(PolyglotEngine vm) { PolyglotEngine.Value echoValue; try { diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RStartParams.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RStartParams.java new file mode 100644 index 0000000000000000000000000000000000000000..3c59c0dfb2a1dc371022c9ff4004a158b12a32b2 --- /dev/null +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RStartParams.java @@ -0,0 +1,75 @@ +/* + * 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-2015, The R Core Team + * Copyright (c) 2003, The R Foundation + * Copyright (c) 2016, 2016, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.engine.shell; + +/** + * Support for Rembedded. Defines startup parameters that can be customized by embedding apps. + */ +public class RStartParams { + + public enum SA_TYPE { + NORESTORE, + RESTORE, + DEFAULT, + NOSAVE, + SAVE, + SAVEASK, + SUICIDE + } + + private boolean quiet; + private boolean slave; + private boolean interactive = true; + private boolean verbose; + private boolean loadSiteFile = true; + private boolean loadInitFile = true; + private boolean debugInitFile; + private SA_TYPE restoreAction = SA_TYPE.RESTORE; + private SA_TYPE saveAction = SA_TYPE.SAVEASK; + private boolean noRenviron; + + private static RStartParams active; + + private RStartParams() { + + } + + /** + * Only upcalled from native code. + */ + public RStartParams(boolean quiet, boolean slave, boolean interactive, boolean verbose, boolean loadSiteFile, + boolean loadInitFile, boolean debugInitFile, int restoreAction, + int saveAction, boolean noRenviron) { + this.quiet = quiet; + this.slave = slave; + this.interactive = interactive; + this.verbose = verbose; + this.loadSiteFile = loadSiteFile; + this.loadInitFile = loadInitFile; + this.debugInitFile = debugInitFile; + this.restoreAction = SA_TYPE.values()[restoreAction]; + this.saveAction = SA_TYPE.values()[saveAction]; + this.noRenviron = noRenviron; + } + + public static RStartParams getActive() { + if (active == null) { + active = new RStartParams(); + } + return active; + } + + public static void setParams(RStartParams rs) { + active = rs; + } + +} diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RscriptCommand.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RscriptCommand.java index 0039a35912cdde32906fcd7f142f17f3dae33837..33108b010f1203946be2f97259c337e5c2e67254 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RscriptCommand.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RscriptCommand.java @@ -31,10 +31,10 @@ import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.VERSION; import java.util.ArrayList; +import com.oracle.truffle.api.vm.PolyglotEngine; import com.oracle.truffle.r.runtime.RCmdOptions; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RVersionNumber; -import com.oracle.truffle.r.runtime.context.ContextInfo; /** * Emulates the (Gnu)Rscript command as precisely as possible. in GnuR, Rscript is a genuine wrapper @@ -101,9 +101,9 @@ public class RscriptCommand { // Handle --help and --version specially, as they exit. RCmdOptions options = RCmdOptions.parseArguments(RCmdOptions.Client.RSCRIPT, args); preprocessRScriptOptions(options); - ContextInfo info = RCommand.createContextInfoFromCommandLine(options); + PolyglotEngine vm = RCommand.createContextInfoFromCommandLine(options); // never returns - RCommand.readEvalPrint(info); + RCommand.readEvalPrint(vm); throw RInternalError.shouldNotReachHere(); } diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c b/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c index 0b78deb4265ac2eea47ae6ae315953e63296944b..d071862f1cd4b368754dcf6699eaeab6caf8194a 100644 --- a/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c +++ b/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c @@ -1,58 +1,72 @@ /* - * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * 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 * - * 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. + * Copyright (c) 1995-2015, The R Core Team + * Copyright (c) 2003, The R Foundation + * Copyright (c) 2016, 2016, Oracle and/or its affiliates * - * 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. + * All rights reserved. */ -#include <rffiutils.h> #include <dlfcn.h> #include <sys/utsname.h> +#include <rffiutils.h> +#include <R_ext/RStartup.h> + static JavaVM *javaVM; +static JNIEnv *jniEnv; +static jobject engine; +static int initialized = 0; -int Rf_initEmbeddedR(int argc, char *argv[]) { +static jclass rcommandClass; +static jclass rStartParamsClass; + +typedef jint (JNICALL *JNI_CreateJavaVMFunc) + (JavaVM **pvm, void **penv, void *args); + +static void *dlopen_jvmlib(char *libpath) { + void *handle = dlopen(libpath, RTLD_GLOBAL | RTLD_NOW); + if (handle == NULL) { + printf("Rf_initialize_R: cannot dlopen %s: %s\n", libpath, dlerror()); + exit(1); + } + return handle; +} + +int Rf_initialize_R(int argc, char *argv[]) { + if (initialized) { + fprintf(stderr, "%s", "R is already initialized\n"); + exit(1); + } struct utsname utsname; uname(&utsname); - printf("is: %s\n", utsname.sysname); - char *jvmlib_path = malloc(256); - char *fastr_java_vm = getenv("FASTR_JAVA_VM"); - if (fastr_java_vm == NULL) { - char *java_home = getenv("JAVA_HOME"); - if (java_home == NULL) { - printf("Rf_initEmbeddedR: can't find a Java VM"); - exit(1); - } - strcpy(jvmlib_path, java_home); - if (strcmp(utsname.sysname, "Linux")) { - strcat(jvmlib_path, "/jre/lib/amd64/server/libjvm.so"); - } else if (strcmp(utsname.sysname, "Darwin")) { - strcat(jvmlib_path, "/jre/lib/server/libjvm.dylib"); - } else { - printf("unsupported OS: %s\n"utsname.sysname); - exit(1); - } + char jvmlib_path[256]; + char *java_home = getenv("JAVA_HOME"); + if (java_home == NULL) { + printf("Rf_initialize_R: can't find JAVA_HOME"); + exit(1); + } + strcpy(jvmlib_path, java_home); + if (strcmp(utsname.sysname, "Linux") == 0) { + strcat(jvmlib_path, "/jre/lib/amd64/server/libjvm.so"); + } else if (strcmp(utsname.sysname, "Darwin") == 0) { + strcat(jvmlib_path, "/jre/lib/server/libjvm.dylib"); + // Must also load libjli to avoid going through framework + // and failing to find our JAVA_HOME runtime + char jlilib_path[256]; + strcpy(jlilib_path, java_home); + strcat(jlilib_path, "/jre/lib/jli/libjli.dylib"); + dlopen_jvmlib(jlilib_path); } else { - strcpy(jvmlib_path, fastr_java_vm); + printf("unsupported OS: %s\n", utsname.sysname); + exit(1); } - void *vm_handle = dlopen(jvmlib_path, RTLD_GLOBAL | RTLD_NOW); - if (vm_handle == NULL) { - printf("Rf_initEmbeddedR: cannot dlopen %s: %s\n", jvmlib_path, dlerror()); + void *vm_handle = dlopen_jvmlib(jvmlib_path); + JNI_CreateJavaVMFunc createJavaVMFunc = (JNI_CreateJavaVMFunc) dlsym(vm_handle, "JNI_CreateJavaVM"); + if (createJavaVMFunc == NULL) { + printf("Rf_initialize_R: cannot find JNI_CreateJavaVM\n"); exit(1); } @@ -60,7 +74,7 @@ int Rf_initEmbeddedR(int argc, char *argv[]) { JavaVMOption vm_options[1]; char *vm_cp = getenv("FASTR_CLASSPATH"); if (vm_cp == NULL) { - printf("Rf_initEmbeddedR: FASTR_CLASSPATH env var not set\n"); + printf("Rf_initialize_R: FASTR_CLASSPATH env var not set\n"); exit(1); } int cplen = (int) strlen(vm_cp); @@ -78,24 +92,113 @@ int Rf_initEmbeddedR(int argc, char *argv[]) { vm_args.options = vm_options; vm_args.ignoreUnrecognized = JNI_TRUE; - JNIEnv *jniEnv; - long flag = JNI_CreateJavaVM(&javaVM, (void**) + jint flag = (*createJavaVMFunc)(&javaVM, (void**) &jniEnv, &vm_args); if (flag == JNI_ERR) { - printf("Rf_initEmbeddedR: error creating VM, exiting...\n"); + printf("Rf_initEmbeddedR: error creating Java VM, exiting...\n"); return 1; } - jclass mainClass = checkFindClass(jniEnv, "com/oracle/truffle/r/engine/shell/RCommand"); + + rcommandClass = checkFindClass(jniEnv, "com/oracle/truffle/r/engine/shell/RCommand"); + rStartParamsClass = checkFindClass(jniEnv, "com/oracle/truffle/r/engine/shell/RStartParams"); jclass stringClass = checkFindClass(jniEnv, "java/lang/String"); - jmethodID mainMethod = checkGetMethodID(jniEnv, mainClass, "main", "([Ljava/lang/String;)V", 1); + jmethodID initializeMethod = checkGetMethodID(jniEnv, rcommandClass, "initialize", + "([Ljava/lang/String;)Lcom/oracle/truffle/api/vm/PolyglotEngine;", 1); int argLength = 0; jobjectArray argsArray = (*jniEnv)->NewObjectArray(jniEnv, argLength, stringClass, NULL); - (*jniEnv)->CallStaticVoidMethod(jniEnv, mainClass, mainMethod, argsArray); + engine = checkRef(jniEnv, (*jniEnv)->CallStaticObjectMethod(jniEnv, rcommandClass, initializeMethod, argsArray)); + initialized++; return 0; } +void setup_Rmainloop(void) { + // In GnuR R_initialize_R and setup_Rmainloop do different things. + // In FastR we don't (yet?) have the distinction, so there is nothing more to do here +} + +void R_DefParams(Rstart rs) { +// jmethodID getActiveMethod = checkGetMethodId(jniEnv, rStartParamsClass, "getActive", "(V)Lcom/oracle/truffle/r/engine/shell/RStartParams;", 1); + rs->R_Quiet = FALSE; + rs->R_Slave = FALSE; + rs->R_Interactive = TRUE; + rs->R_Verbose = FALSE; + rs->RestoreAction = SA_RESTORE; + rs->SaveAction = SA_SAVEASK; + rs->LoadSiteFile = TRUE; + rs->LoadInitFile = TRUE; + rs->DebugInitFile = FALSE; +// rs->vsize = R_VSIZE; +// rs->nsize = R_NSIZE; +// rs->max_vsize = R_SIZE_T_MAX; +// rs->max_nsize = R_SIZE_T_MAX; +// rs->ppsize = R_PPSSIZE; + rs->NoRenviron = FALSE; +// R_SizeFromEnv(Rp); +} + +void R_SetParams(Rstart rs) { + jmethodID setParamsMethodID = checkGetMethodID(jniEnv, rStartParamsClass, "setParams", "(Lcom/oracle/truffle/r/engine/shell/RStartParams;)V", 1); + jmethodID consMethodID = checkGetMethodID(jniEnv, rStartParamsClass, "<init>", "(ZZZZZZZIIZ)V", 0); + jobject javaRSParams = (*jniEnv)->NewObject(jniEnv, rStartParamsClass, consMethodID, rs->R_Quiet, rs->R_Slave, rs->R_Interactive, + rs->R_Verbose, rs->LoadSiteFile, rs->LoadInitFile, rs->DebugInitFile, + rs->RestoreAction, rs->SaveAction, rs->NoRenviron); + (*jniEnv)->CallStaticVoidMethod(jniEnv, rStartParamsClass, setParamsMethodID, javaRSParams); +} + +void R_SizeFromEnv(Rstart rs) { + unimplemented("R_SizeFromEnv"); +} + +void R_common_command_line(int *a, char **b, Rstart rs) { + unimplemented("R_common_command_line"); +} + +void R_set_command_line_arguments(int argc, char **argv) { + unimplemented("R_set_command_line_arguments"); +} + + +int Rf_initEmbeddedR(int argc, char *argv[]) { + Rf_initialize_R(argc, argv); +// R_Interactive = TRUE; + setup_Rmainloop(); + return 1; +} + void Rf_endEmbeddedR(int fatal) { (*javaVM)->DestroyJavaVM(javaVM); //TODO fatal } + +void Rf_mainloop(void) { + jmethodID readEvalPrintMethod = checkGetMethodID(jniEnv, rcommandClass, "readEvalPrint", "(Lcom/oracle/truffle/api/vm/PolyglotEngine;)V", 1); + (*jniEnv)->CallStaticVoidMethod(jniEnv, rcommandClass, readEvalPrintMethod, engine); +} + +// function ptrs that can be assigned by an embedded client to change behavior +void (*ptr_R_Suicide)(const char *); +void (*ptr_R_ShowMessage)(const char *); +int (*ptr_R_ReadConsole)(const char *, unsigned char *, int, int); +void (*ptr_R_WriteConsole)(const char *, int); +void (*ptr_R_WriteConsoleEx)(const char *, int, int); +void (*ptr_R_ResetConsole)(void); +void (*ptr_R_FlushConsole)(void); +void (*ptr_R_ClearerrConsole)(void); +void (*ptr_R_Busy)(int); +void (*ptr_R_CleanUp)(SA_TYPE, int, int); +int (*ptr_R_ShowFiles)(int, const char **, const char **, + const char *, Rboolean, const char *); +int (*ptr_R_ChooseFile)(int, char *, int); +int (*ptr_R_EditFile)(const char *); +void (*ptr_R_loadhistory)(SEXP, SEXP, SEXP, SEXP); +void (*ptr_R_savehistory)(SEXP, SEXP, SEXP, SEXP); +void (*ptr_R_addhistory)(SEXP, SEXP, SEXP, SEXP); + +int (*ptr_R_EditFiles)(int, const char **, const char **, const char *); + +SEXP (*ptr_do_selectlist)(SEXP, SEXP, SEXP, SEXP); +SEXP (*ptr_do_dataentry)(SEXP, SEXP, SEXP, SEXP); +SEXP (*ptr_do_dataviewer)(SEXP, SEXP, SEXP, SEXP); +void (*ptr_R_ProcessEvents)(); + diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java index e725f80386447912401b2a090425d39c93e1a23e..632570262291c58849151f99fdea3233aebf44f4 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java @@ -40,7 +40,7 @@ import com.oracle.truffle.r.runtime.context.RContext.ContextKind; * symbol). */ public final class ContextInfo implements TruffleObject { - static final String GLOBAL_SYMBOL = "fastrContextInfo"; + public static final String GLOBAL_SYMBOL = "fastrContextInfo"; private static final ConcurrentHashMap<Integer, ContextInfo> contextInfos = new ConcurrentHashMap<>(); private static final AtomicInteger contextInfoIds = new AtomicInteger(); diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides index e852287e55fedbb8fd458bb6fb83bca3f8a59999..bac61dc04dec6fd5d5d85ab667d32a878d80a5de 100644 --- a/mx.fastr/copyrights/overrides +++ b/mx.fastr/copyrights/overrides @@ -1,3 +1,4 @@ +com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RStartParams.java,gnu_r.copyright com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/BaseGraphicsSystem.java,gnu_r_graphics.copyright com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/AbstractGraphicsSystem.java,gnu_r_graphics.copyright com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/drawables/CoordinatesDrawableObject.java,gnu_r_graphics.copyright @@ -75,6 +76,7 @@ com.oracle.truffle.r.native/fficall/src/include/rlocale.h,gnu_r_gentleman_ihaka. com.oracle.truffle.r.native/fficall/src/variable_defs/variable_defs.h,gnu_r.copyright com.oracle.truffle.r.native/fficall/src/jni/Memory.c,gnu_r.copyright com.oracle.truffle.r.native/fficall/src/jni/Rdynload_fastr.c,gnu_r.copyright +com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c,gnu_r.copyright com.oracle.truffle.r.native/include/src/libintl.h,no.copyright com.oracle.truffle.r.native/library/base/src/registration.c,no.copyright com.oracle.truffle.r.native/library/grDevices/src/gzio.c,gnu_r_gentleman_ihaka.copyright