From b587e7da580dbfb170af09014f93ac531a600b6a Mon Sep 17 00:00:00 2001 From: Mick Jordan <mick.jordan@oracle.com> Date: Wed, 1 Feb 2017 10:04:41 -0800 Subject: [PATCH] rfffi: simplify factory creation --- .../truffle/r/engine/TruffleRLanguage.java | 3 +- .../r/runtime/ffi/Load_RFFIFactory.java | 57 ------------------- .../truffle/r/runtime/context/RContext.java | 4 +- .../runtime/ffi/RFFIContextStateFactory.java | 43 -------------- .../truffle/r/runtime/ffi/RFFIFactory.java | 51 ++++++++++------- documentation/dev/ffi.md | 24 ++++---- 6 files changed, 47 insertions(+), 135 deletions(-) delete mode 100644 com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/Load_RFFIFactory.java delete mode 100644 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContextStateFactory.java diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java index 8b6d249024..aee4e3ae22 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java @@ -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) { diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/Load_RFFIFactory.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/Load_RFFIFactory.java deleted file mode 100644 index 5450aec0a2..0000000000 --- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/Load_RFFIFactory.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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; - } -} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java index 96aa10c847..22e721f0d7 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java @@ -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); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContextStateFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContextStateFactory.java deleted file mode 100644 index 934ad58e5e..0000000000 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContextStateFactory.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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(); - } -} 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 fa98950004..35fdd63dac 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 @@ -1,5 +1,5 @@ /* - * 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. */ diff --git a/documentation/dev/ffi.md b/documentation/dev/ffi.md index 96c15ef183..1ebb04860b 100644 --- a/documentation/dev/ffi.md +++ b/documentation/dev/ffi.md @@ -1,7 +1,11 @@ # 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. -- GitLab