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

rfffi: simplify factory creation

parent c00e7168
No related branches found
No related tags found
No related merge requests found
......@@ -53,7 +53,6 @@ import com.oracle.truffle.r.runtime.context.RContext.RCloseable;
import com.oracle.truffle.r.runtime.data.RFunction;
import com.oracle.truffle.r.runtime.data.RPromise;
import com.oracle.truffle.r.runtime.data.RTypedValue;
import com.oracle.truffle.r.runtime.ffi.Load_RFFIFactory;
import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
import com.oracle.truffle.r.runtime.nodes.RBaseNode;
......@@ -72,7 +71,7 @@ public final class TruffleRLanguage extends TruffleLanguage<RContext> {
*/
private static void initialize() {
try {
Load_RFFIFactory.initialize(true);
RFFIFactory.initialize();
Locale.setDefault(Locale.ROOT);
RAccuracyInfo.initialize();
} catch (Throwable t) {
......
/*
* 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
* 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;
import com.oracle.truffle.r.runtime.Utils;
/**
* Selects a particular subclass of {@link RFFIFactory}. Specification is based on system property
* {@value #FACTORY_CLASS_PROPERTY}. Current default is a JNI-based implementation.
*/
public class Load_RFFIFactory {
private static final String FACTORY_CLASS_PROPERTY = "fastr.ffi.factory.class";
private static final String DEFAULT_FACTORY_CLASS = "com.oracle.truffle.r.runtime.ffi.jni.JNI_RFFIFactory";
/**
* Singleton instance of the factory. Typically initialized at runtime but may be initialized
* during image build in an AOT VM, in which case {@code runtime} will be {@code false}.
*/
private static RFFIFactory instance;
public static RFFIFactory initialize(boolean runtime) {
if (instance == null) {
String prop = System.getProperty(FACTORY_CLASS_PROPERTY);
try {
if (prop == null) {
prop = DEFAULT_FACTORY_CLASS;
}
instance = (RFFIFactory) Class.forName(prop).newInstance();
RFFIFactory.setRFFIFactory(instance);
} catch (Exception ex) {
throw Utils.rSuicide("Failed to instantiate class: " + prop + ": " + ex);
}
}
instance.initialize(runtime);
return instance;
}
}
......@@ -74,7 +74,7 @@ import com.oracle.truffle.r.runtime.data.RList;
import com.oracle.truffle.r.runtime.data.RStringVector;
import com.oracle.truffle.r.runtime.env.REnvironment;
import com.oracle.truffle.r.runtime.ffi.DLL;
import com.oracle.truffle.r.runtime.ffi.RFFIContextStateFactory;
import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
import com.oracle.truffle.r.runtime.instrument.InstrumentationState;
import com.oracle.truffle.r.runtime.nodes.RCodeBuilder;
import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
......@@ -520,7 +520,7 @@ public final class RContext extends ExecutionContext implements TruffleObject {
state.add(State.ATTACHED);
stateDLL.initialize(this);
stateRFFI = RFFIContextStateFactory.newContextState();
stateRFFI = RFFIFactory.getInstance().newContextState();
// separate in case initialize calls getStateRFFI()!
stateRFFI.initialize(this);
......
/*
* 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
* 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;
import com.oracle.truffle.r.runtime.context.RContext;
import com.oracle.truffle.r.runtime.context.RContext.ContextState;
/**
* This is the factory-independent class referenced by {@link RContext} that manages the
* context-specific state for any given {@link RFFIFactory}. It simply forwards the calls to the
* actual factory.
*/
public class RFFIContextStateFactory {
private static RFFIFactory theFactory;
public static void registerFactory(RFFIFactory factory) {
theFactory = factory;
}
public static ContextState newContextState() {
return theFactory.newContextState();
}
}
/*
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2017, 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,24 +23,45 @@
package com.oracle.truffle.r.runtime.ffi;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.r.runtime.context.RContext;
import com.oracle.truffle.r.runtime.Utils;
import com.oracle.truffle.r.runtime.context.RContext.ContextState;
/**
* Factory class for the different possible implementations of the {@link RFFI} interface. The
* choice of factory is made by the R engine and set here by the call to {@link #setRFFIFactory}.
* Factory class for the different possible implementations of the {@link RFFI} interface.
*
* The RFFI may need to do special things in the case of multiple contexts, hence any given factory
* must support the {@link #newContextState()} method. However, since we don't know exactly which
* factory will be used, {@link RContext} references the {@link RFFIContextStateFactory} class.
* must support the {@link #newContextState()} method.
*/
public abstract class RFFIFactory {
private static final String FACTORY_CLASS_PROPERTY = "fastr.ffi.factory.class";
private static final String DEFAULT_FACTORY_CLASS = "com.oracle.truffle.r.runtime.ffi.jni.JNI_RFFIFactory";
/**
* Singleton instance of the factory.
*/
private static RFFIFactory instance;
@CompilationFinal protected static RFFI theRFFI;
public static void setRFFIFactory(RFFIFactory factory) {
RFFIContextStateFactory.registerFactory(factory);
theRFFI = factory.createRFFI();
public static RFFIFactory initialize() {
if (instance == null) {
String prop = System.getProperty(FACTORY_CLASS_PROPERTY);
try {
if (prop == null) {
prop = DEFAULT_FACTORY_CLASS;
}
instance = (RFFIFactory) Class.forName(prop).newInstance();
theRFFI = instance.createRFFI();
} catch (Exception ex) {
throw Utils.rSuicide("Failed to instantiate class: " + prop + ": " + ex);
}
}
return instance;
}
public static RFFIFactory getInstance() {
assert instance != null;
return instance;
}
public static RFFI getRFFI() {
......@@ -48,18 +69,6 @@ public abstract class RFFIFactory {
return theRFFI;
}
/**
* Initialize the factory instance. This method will be called immediately after the factory
* instance is created allowing any additional initialization that could not be done in the
* constructor.
*
* @param runtime {@code true} if the initialization is being done at runtime. An AOT system may
* call this twice, once with {@code false} whern an image is being bilt and once
* when starting up.
*/
protected void initialize(boolean runtime) {
}
/**
* Subclass implements this method to actually create the concrete {@link RFFI} instance.
*/
......
# The R FFI Implementation
# Introduction
The implementation of the [R FFI](https://cran.r-project.org/doc/manuals/r-release/R-exts.html) is contained in the `fficall` directory of
FastR interfaces to native C and Fortran code in a number of ways, for example, access to C library APIs not supported by the Java JDK, access to LaPack functions, and the `.Call`, `.Fortran`, `.C` builtins. Each of these are defined by a Java interface,e.g. `CallRFFI` for the `.Call` builtin. To facilitate experimentation and different implementations, the implementation of these interfaces is defined by a factory class, `RFFIFactory`, that is chosen at run time via the `fastr.ffi.factory.class` system property. The factory is responsible for creating an instance of the `RFFI` interface that in turn provides access to implementations of the underlying interfaces such as `CallRFFI`. This structure allows
for each of the individual interfaces to be implemented by a different mechanism. Currently the default factory class is `JNI_RFFIFactory` which uses the Java JNI system to implement the transition to native code.
# Native Implementation
The native implementation of the [R FFI](https://cran.r-project.org/doc/manuals/r-release/R-exts.html) is contained in the `fficall` directory of
the `com.oracle/truffle.r.native` project`. It's actually a bit more than that as it also contains code copied from GNU R, for example that supports graphics or is sufficiently
simple that it is neither necessary nor desirable to implement in Java. As this has evolved a better name for `fficall` would probably be `main`
for compatibility with GNU R.
......@@ -9,9 +13,8 @@ for compatibility with GNU R.
There are four sub-directories in `fficall/src`:
* `include`
* `common`
* `variable_defs`
* `jni`
* `truffle`
* `truffle_llvm`
## The `fficall/include` directory
......@@ -40,15 +43,16 @@ angle bracket form.
copied/included from GNU R. N.B. Some modified files have a `_fastr` suffix to avoid a clash with an existing file in GNU R that would match
the Makefile rule for compiling directly from the GNU R file.
## The `variable_defs` directory
The GNU R FFI defines a large number of (extern) variables the definitions of which, in GNU R, are scattered across the source files.
In FastR these are collected into one file, `variable_defs.h`. However, the actual initialization of the variables is, in general, implementation
dependent. In order to support a JNI and a non-JNI implementation, the file is stored in a separate directory.
## The `jni` directory
`jni` contains the implementation that is based on and has explicit dependencies on Java JNI. It is described in more detail [here](jni_ffi.md)
## The `truffle_llvm` directory
`truffle` contains the native side of the variant that is based on the Truffle LLVM implementation. It is described in more detail [here](truffle_llvm_ffi.md)
\ No newline at end of file
`truffle_llvm` contains the native side of the variant that is based on the Truffle LLVM implementation. It is described in more detail [here](truffle_llvm_ffi.md)
# RFFI Initialization
Not all of the individual interfaces need to be instantiated on startup. The `getXXXRFFI()` method of `RFFI` is responsible for instantiating the `XXX` interface (e.e.g `Call`).
However, the factory can choose to instantiate the interfqces eagerly if desired. The choice of factory class is made by `RFFIFactory.initialize()` which is called when the
initial `RContext` is being created by `PolyglotEngine`. Note that at this stage, very little code can be executed as the initial context has not yet been fully created and registered with `PolyglotEngine`.
In general, state maintained by the `RFFI` implementation classes is `RContext` specific and to facilitate this `RFFIFactory` defines a `newContextState` method that is called by `RContext`. Again, at the point this is called the context is not active and so any execution that requires an active context must be delayed until the `initialize` method is called on the `ContextState` instance. Typically special initialization may be required on the initialization of the initial context, such as loading native libraries, and also on the initialization of a `SHARED_PARENT_RW` context kind.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment