Skip to content
Snippets Groups Projects
Commit c88307dd authored by Mick Jordan's avatar Mick Jordan
Browse files

Embedded: fix darwin startup, refactor Command to separate initialization/mainloop

parent b5d5eb25
Branches
No related tags found
No related merge requests found
...@@ -78,15 +78,34 @@ public class RCommand { ...@@ -78,15 +78,34 @@ public class RCommand {
// CheckStyle: stop system..print check // CheckStyle: stop system..print check
public static void main(String[] args) { public static void main(String[] args) {
RCmdOptions options = RCmdOptions.parseArguments(RCmdOptions.Client.R, args); PolyglotEngine vm = createPolyglotEngine(args);
options.printHelpAndVersion();
ContextInfo info = createContextInfoFromCommandLine(options);
// never returns // never returns
readEvalPrint(info); readEvalPrint(vm);
throw RInternalError.shouldNotReachHere(); 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)) { if (options.getBoolean(SLAVE)) {
options.setValue(QUIET, true); options.setValue(QUIET, true);
options.setValue(NO_SAVE, true); options.setValue(NO_SAVE, true);
...@@ -170,7 +189,7 @@ public class RCommand { ...@@ -170,7 +189,7 @@ public class RCommand {
consoleHandler = new DefaultConsoleHandler(consoleInput, consoleOutput); 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); private static final Source GET_ECHO = Source.fromText("invisible(getOption('echo'))", RInternalSourceDescriptions.GET_ECHO).withMimeType(TruffleRLanguage.MIME);
...@@ -187,9 +206,8 @@ public class RCommand { ...@@ -187,9 +206,8 @@ public class RCommand {
* In case 2, we must implicitly execute a {@code quit("default, 0L, TRUE} command before * In case 2, we must implicitly execute a {@code quit("default, 0L, TRUE} command before
* exiting. So,in either case, we never return. * exiting. So,in either case, we never return.
*/ */
static void readEvalPrint(ContextInfo info) { static void readEvalPrint(PolyglotEngine vm) {
PolyglotEngine vm = info.apply(PolyglotEngine.newBuilder()).build(); ConsoleHandler consoleHandler = getContextInfo(vm).getConsoleHandler();
ConsoleHandler consoleHandler = info.getConsoleHandler();
Source source = Source.fromAppendableText(consoleHandler.getInputDescription()); Source source = Source.fromAppendableText(consoleHandler.getInputDescription());
try { try {
// console.println("initialize time: " + (System.currentTimeMillis() - start)); // console.println("initialize time: " + (System.currentTimeMillis() - start));
...@@ -280,6 +298,14 @@ public class RCommand { ...@@ -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) { private static boolean doEcho(PolyglotEngine vm) {
PolyglotEngine.Value echoValue; PolyglotEngine.Value echoValue;
try { try {
......
/*
* 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;
}
}
...@@ -31,10 +31,10 @@ import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.VERSION; ...@@ -31,10 +31,10 @@ import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.VERSION;
import java.util.ArrayList; import java.util.ArrayList;
import com.oracle.truffle.api.vm.PolyglotEngine;
import com.oracle.truffle.r.runtime.RCmdOptions; import com.oracle.truffle.r.runtime.RCmdOptions;
import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RInternalError;
import com.oracle.truffle.r.runtime.RVersionNumber; 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 * Emulates the (Gnu)Rscript command as precisely as possible. in GnuR, Rscript is a genuine wrapper
...@@ -101,9 +101,9 @@ public class RscriptCommand { ...@@ -101,9 +101,9 @@ public class RscriptCommand {
// Handle --help and --version specially, as they exit. // Handle --help and --version specially, as they exit.
RCmdOptions options = RCmdOptions.parseArguments(RCmdOptions.Client.RSCRIPT, args); RCmdOptions options = RCmdOptions.parseArguments(RCmdOptions.Client.RSCRIPT, args);
preprocessRScriptOptions(options); preprocessRScriptOptions(options);
ContextInfo info = RCommand.createContextInfoFromCommandLine(options); PolyglotEngine vm = RCommand.createContextInfoFromCommandLine(options);
// never returns // never returns
RCommand.readEvalPrint(info); RCommand.readEvalPrint(vm);
throw RInternalError.shouldNotReachHere(); throw RInternalError.shouldNotReachHere();
} }
......
/* /*
* Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved. * This material is distributed under the GNU General Public License
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * 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 * Copyright (c) 1995-2015, The R Core Team
* under the terms of the GNU General Public License version 2 only, as * Copyright (c) 2003, The R Foundation
* published by the Free Software Foundation. * Copyright (c) 2016, 2016, Oracle and/or its affiliates
* *
* This code is distributed in the hope that it will be useful, but WITHOUT * All rights reserved.
* 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>
#include <dlfcn.h> #include <dlfcn.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#include <rffiutils.h>
#include <R_ext/RStartup.h>
static JavaVM *javaVM; 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; struct utsname utsname;
uname(&utsname); uname(&utsname);
printf("is: %s\n", utsname.sysname); char jvmlib_path[256];
char *jvmlib_path = malloc(256); char *java_home = getenv("JAVA_HOME");
char *fastr_java_vm = getenv("FASTR_JAVA_VM"); if (java_home == NULL) {
if (fastr_java_vm == NULL) { printf("Rf_initialize_R: can't find JAVA_HOME");
char *java_home = getenv("JAVA_HOME"); exit(1);
if (java_home == NULL) { }
printf("Rf_initEmbeddedR: can't find a Java VM"); strcpy(jvmlib_path, java_home);
exit(1); if (strcmp(utsname.sysname, "Linux") == 0) {
} strcat(jvmlib_path, "/jre/lib/amd64/server/libjvm.so");
strcpy(jvmlib_path, java_home); } else if (strcmp(utsname.sysname, "Darwin") == 0) {
if (strcmp(utsname.sysname, "Linux")) { strcat(jvmlib_path, "/jre/lib/server/libjvm.dylib");
strcat(jvmlib_path, "/jre/lib/amd64/server/libjvm.so"); // Must also load libjli to avoid going through framework
} else if (strcmp(utsname.sysname, "Darwin")) { // and failing to find our JAVA_HOME runtime
strcat(jvmlib_path, "/jre/lib/server/libjvm.dylib"); char jlilib_path[256];
} else { strcpy(jlilib_path, java_home);
printf("unsupported OS: %s\n"utsname.sysname); strcat(jlilib_path, "/jre/lib/jli/libjli.dylib");
exit(1); dlopen_jvmlib(jlilib_path);
}
} else { } 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); void *vm_handle = dlopen_jvmlib(jvmlib_path);
if (vm_handle == NULL) { JNI_CreateJavaVMFunc createJavaVMFunc = (JNI_CreateJavaVMFunc) dlsym(vm_handle, "JNI_CreateJavaVM");
printf("Rf_initEmbeddedR: cannot dlopen %s: %s\n", jvmlib_path, dlerror()); if (createJavaVMFunc == NULL) {
printf("Rf_initialize_R: cannot find JNI_CreateJavaVM\n");
exit(1); exit(1);
} }
...@@ -60,7 +74,7 @@ int Rf_initEmbeddedR(int argc, char *argv[]) { ...@@ -60,7 +74,7 @@ int Rf_initEmbeddedR(int argc, char *argv[]) {
JavaVMOption vm_options[1]; JavaVMOption vm_options[1];
char *vm_cp = getenv("FASTR_CLASSPATH"); char *vm_cp = getenv("FASTR_CLASSPATH");
if (vm_cp == NULL) { 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); exit(1);
} }
int cplen = (int) strlen(vm_cp); int cplen = (int) strlen(vm_cp);
...@@ -78,24 +92,113 @@ int Rf_initEmbeddedR(int argc, char *argv[]) { ...@@ -78,24 +92,113 @@ int Rf_initEmbeddedR(int argc, char *argv[]) {
vm_args.options = vm_options; vm_args.options = vm_options;
vm_args.ignoreUnrecognized = JNI_TRUE; vm_args.ignoreUnrecognized = JNI_TRUE;
JNIEnv *jniEnv; jint flag = (*createJavaVMFunc)(&javaVM, (void**)
long flag = JNI_CreateJavaVM(&javaVM, (void**)
&jniEnv, &vm_args); &jniEnv, &vm_args);
if (flag == JNI_ERR) { if (flag == JNI_ERR) {
printf("Rf_initEmbeddedR: error creating VM, exiting...\n"); printf("Rf_initEmbeddedR: error creating Java VM, exiting...\n");
return 1; 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"); 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; int argLength = 0;
jobjectArray argsArray = (*jniEnv)->NewObjectArray(jniEnv, argLength, stringClass, NULL); 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; 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) { void Rf_endEmbeddedR(int fatal) {
(*javaVM)->DestroyJavaVM(javaVM); (*javaVM)->DestroyJavaVM(javaVM);
//TODO fatal //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)();
...@@ -40,7 +40,7 @@ import com.oracle.truffle.r.runtime.context.RContext.ContextKind; ...@@ -40,7 +40,7 @@ import com.oracle.truffle.r.runtime.context.RContext.ContextKind;
* symbol). * symbol).
*/ */
public final class ContextInfo implements TruffleObject { 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 ConcurrentHashMap<Integer, ContextInfo> contextInfos = new ConcurrentHashMap<>();
private static final AtomicInteger contextInfoIds = new AtomicInteger(); private static final AtomicInteger contextInfoIds = new AtomicInteger();
......
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/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/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 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. ...@@ -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/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/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/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/include/src/libintl.h,no.copyright
com.oracle.truffle.r.native/library/base/src/registration.c,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 com.oracle.truffle.r.native/library/grDevices/src/gzio.c,gnu_r_gentleman_ihaka.copyright
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment