diff --git a/com.oracle.truffle.r.native/fficall/Makefile b/com.oracle.truffle.r.native/fficall/Makefile index d703990b4fcac05314bb58a934cc567f10c57e2e..4c9863072da00ac2157f2bbc5d53ae8a6ea45353 100644 --- a/com.oracle.truffle.r.native/fficall/Makefile +++ b/com.oracle.truffle.r.native/fficall/Makefile @@ -45,7 +45,7 @@ BLAS_TARGET := $(FASTR_LIB_DIR)/libRblas$(DYLIB_EXT) all: $(C_LIB) $(C_LIB): objs - $(DYLIB_LD) $(DYLIB_LDFLAGS) -o $(C_LIB) $(wildcard lib/*.o) -L $(GNUR_HOME)/lib -lRblas $(VERSION_FLAGS) + $(DYLIB_LD) $(DYLIB_LDFLAGS) -o $(C_LIB) $(wildcard lib/*.o) -L $(GNUR_HOME)/lib -lRblas -lpcre $(VERSION_FLAGS) ifeq ($(OS_NAME),Darwin) install_name_tool -change libRblas.dylib $(BLAS_TARGET) $(C_LIB) endif diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c index 14227cbd329b3acd95354e84d88609a379ecbaee..60b308a8eb17d20f7b073d8de8186e86d40fb6ed 100644 --- a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c +++ b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c @@ -252,24 +252,6 @@ SEXP Rf_ScalarReal(double value) { return checkRef(thisenv, result); } -// JNR calls to PCRE do not work properly (via JNR) without these wrappers - -char *pcre_maketables(); -void *pcre_compile(char * pattern, int options, char ** errorMessage, int *errOffset, char * tables); -int pcre_exec(void * code, void *extra, char* subject, int subjectLength, int startOffset, int options, int *ovector, int ovecSize); - -char *fastr_pcre_maketables() { - return pcre_maketables(); -} - -void *fastr_pcre_compile(char * pattern, int options, char ** errorMessage, int *errOffset, char * tables) { - return pcre_compile(pattern, options, errorMessage, errOffset, tables); -} - -int fastr_pcre_exec(void * code, void *extra, char* subject, int subjectLength, int startOffset, int options, int *ovector, int ovecSize) { - return pcre_exec(code, extra, subject, subjectLength, startOffset, options, ovector, ovecSize); -} - SEXP Rf_ScalarString(SEXP value) { TRACE(TARGp, value); JNIEnv *thisenv = getEnv(); diff --git a/com.oracle.truffle.r.native/fficall/src/jni/pcre_fastr.c b/com.oracle.truffle.r.native/fficall/src/jni/pcre_fastr.c new file mode 100644 index 0000000000000000000000000000000000000000..643b48c555b7ca4aeb58c4b1304d44b7c27f0ec7 --- /dev/null +++ b/com.oracle.truffle.r.native/fficall/src/jni/pcre_fastr.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016, 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. + */ + +#include <rffiutils.h> + +char *pcre_maketables(); +void *pcre_compile(char * pattern, int options, char ** errorMessage, int *errOffset, char * tables); +int pcre_exec(void * code, void *extra, char* subject, int subjectLength, int startOffset, int options, int *ovector, int ovecSize); + +jclass JNI_PCRE_ResultClass; +jmethodID ResultClassConstructorID; + +void init_pcre(JNIEnv *env) { + JNI_PCRE_ResultClass = checkFindClass(env, "com/oracle/truffle/r/runtime/ffi/PCRERFFI$Result"); + ResultClassConstructorID = checkGetMethodID(env, JNI_PCRE_ResultClass, "<init>", "(JLjava/lang/String;I)V", 0); +} + +JNIEXPORT jlong JNICALL +Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1PCRE_nativeMaketables(JNIEnv *env, jclass c) { + return (jlong) pcre_maketables(); +} + +JNIEXPORT jobject JNICALL +Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1PCRE_nativeCompile(JNIEnv *env, jclass c, jstring pattern, jint options, jlong tables) { + const char *patternChars = (*env)->GetStringUTFChars(env, pattern, NULL); + char *errorMessage; + int errOffset; + void *pcre_result = pcre_compile(patternChars, options, &errorMessage, &errOffset, (char*) tables); + jstring stringErrorMessage = NULL; + if (pcre_result == NULL) { + stringErrorMessage = (*env)->NewStringUTF(env, errorMessage); + } + jobject result = (*env)->NewObject(env, JNI_PCRE_ResultClass, ResultClassConstructorID, pcre_result, stringErrorMessage, errOffset); + return result; +} + +JNIEXPORT jint JNICALL +Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1PCRE_nativeExec(JNIEnv *env, jclass c,jlong code, jlong extra, jstring subject, + jint startOffset, jint options, jintArray ovector, jint ovectorLen) { + const char *subjectChars = (*env)->GetStringUTFChars(env, subject, NULL); + int subjectLength = (*env)->GetStringUTFLength(env, subject); + int* ovectorElems = (*env)->GetIntArrayElements(env, ovector, NULL); + + int rc = pcre_exec(code, extra, subjectChars, subjectLength, startOffset, options, + ovectorElems, ovectorLen); + (*env)->ReleaseIntArrayElements(env, ovector, ovectorElems, 0); + (*env)->ReleaseStringUTFChars(env, subject, subjectChars); + return rc; +} diff --git a/com.oracle.truffle.r.native/fficall/src/jni/rfficall.c b/com.oracle.truffle.r.native/fficall/src/jni/rfficall.c index a8d153d4a0c39265d82c94e63c739c61e1c7a777..5b2b3df96d7e0c3c143477af788392db4c908f87 100644 --- a/com.oracle.truffle.r.native/fficall/src/jni/rfficall.c +++ b/com.oracle.truffle.r.native/fficall/src/jni/rfficall.c @@ -35,6 +35,7 @@ Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_initialize(JNIEnv *env, init_rmath(env); init_random(env); init_parse(env); + init_pcre(env); } JNIEXPORT void JNICALL diff --git a/com.oracle.truffle.r.native/gnur/Makefile.libs b/com.oracle.truffle.r.native/gnur/Makefile.libs index 13841dcc2b47ed3aeb80dc589d1f0422f010b9de..33309794eb330ec0f29a9998c0d1de0d340391f6 100644 --- a/com.oracle.truffle.r.native/gnur/Makefile.libs +++ b/com.oracle.truffle.r.native/gnur/Makefile.libs @@ -33,8 +33,11 @@ endif BLAS_TARGET := $(FASTR_LIB_DIR)/libRblas$(DYLIB_EXT) LAPACK_TARGET := $(FASTR_LIB_DIR)/libRlapack$(DYLIB_EXT) +# at a minimum we need to know where libpcre is located, +# to keep the Java side simpler, we copy it to $(FASTR_LIB_DIR) +PCRE_TARGET := $(FASTR_LIB_DIR)/libpcre$(DYLIB_EXT) -all: $(FASTR_LIB_DIR) $(BLAS_TARGET) $(LAPACK_TARGET) +all: $(FASTR_LIB_DIR) $(BLAS_TARGET) $(LAPACK_TARGET) $(PCRE_TARGET) $(FASTR_LIB_DIR): mkdir -p $(FASTR_LIB_DIR) @@ -51,7 +54,10 @@ ifeq ($(OS_NAME),Darwin) install_name_tool -id $(LAPACK_TARGET) $(LAPACK_TARGET) endif +$(PCRE_TARGET): + cp $(shell mx findpcre) $(PCRE_TARGET) + clean: - rm -f $(BLAS_TARGET) $(LAPACK_TARGET) + rm -f $(BLAS_TARGET) $(LAPACK_TARGET) $(PCRE_TARGET) diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNI_PCRE.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNI_PCRE.java new file mode 100644 index 0000000000000000000000000000000000000000..724511b8636c4efd849f5a05d6d264987fa538a8 --- /dev/null +++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNI_PCRE.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015, 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.jnr; + +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.ffi.LibPaths; +import com.oracle.truffle.r.runtime.ffi.PCRERFFI; + +public class JNI_PCRE implements PCRERFFI { + JNI_PCRE() { + System.load(LibPaths.getBuiltinLibPath("pcre")); + } + + @Override + public long maketables() { + return nativeMaketables(); + } + + @Override + public Result compile(String pattern, int options, long tables) { + return nativeCompile(pattern, options, tables); + } + + @Override + public Result study(long code, int options) { + throw RInternalError.unimplemented("pcre_study"); + } + + @Override + public int exec(long code, long extra, String subject, int offset, int options, int[] ovector) { + return nativeExec(code, extra, subject, offset, options, ovector, ovector.length); + } + + private static native long nativeMaketables(); + + private static native Result nativeCompile(String pattern, int options, long tables); + + private static native int nativeExec(long code, long extra, String subject, int offset, + int options, int[] ovector, int ovectorLen); + +} diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_PCRE.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_PCRE.java deleted file mode 100644 index 13cae21398ccdcf4a69361c7bad7119f33d8eea3..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_PCRE.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2015, 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.jnr; - -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.r.runtime.RInternalError; -import com.oracle.truffle.r.runtime.ffi.LibPaths; -import com.oracle.truffle.r.runtime.ffi.PCRERFFI; - -import jnr.ffi.LibraryLoader; -import jnr.ffi.annotations.In; -import jnr.ffi.annotations.Out; - -/** - * PCRE support using JNR. - */ -// Checkstyle: stop method name -public class JNR_PCRE implements PCRERFFI { - public interface PCRE { - long fastr_pcre_maketables(); - - long fastr_pcre_compile(byte[] pattern, int options, @Out byte[] errorMessage, @Out int[] errOffset, long tables); - - int fastr_pcre_exec(long code, long extra, @In byte[] subject, int subjectLength, int startOffset, int options, @Out int[] ovector, int ovecSize); - } - - private static class PCREProvider { - private static PCRE pcre; - - @TruffleBoundary - private static PCRE createAndLoadLib() { - return LibraryLoader.create(PCRE.class).library(LibPaths.getBuiltinLibPath("R")).library("pcre").load(); - } - - static PCRE pcre() { - if (pcre == null) { - pcre = createAndLoadLib(); - } - return pcre; - } - } - - private static PCRE pcre() { - return PCREProvider.pcre(); - } - - @Override - public long maketables() { - return pcre().fastr_pcre_maketables(); - } - - @Override - public Result compile(String pattern, int options, long tables) { - int[] errOffset = new int[1]; - byte[] errorMessage = new byte[512]; - long result = pcre().fastr_pcre_compile(pattern.getBytes(), options, errorMessage, errOffset, tables); - if (result == 0) { - return new Result(result, new String(errorMessage), errOffset[0]); - } else { - return new Result(result, null, 0); - } - } - - @Override - public int exec(long code, long extra, String subject, int offset, int options, int[] ovector) { - return pcre().fastr_pcre_exec(code, extra, subject.getBytes(), subject.length(), offset, options, ovector, ovector.length); - } - - @Override - public Result study(long code, int options) { - throw RInternalError.unimplemented("pcre_study"); - } -} 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 168618a998bd8e666fe27f37136eaf78372965a4..c8ccd6c7e830abbe84fcb31613226979a83c4895 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 @@ -195,7 +195,7 @@ public class JNR_RFFIFactory extends RFFIFactory implements RFFI { @Override public PCRERFFI getPCRERFFI() { if (pcreRFFI == null) { - pcreRFFI = new JNR_PCRE(); + pcreRFFI = new JNI_PCRE(); } return pcreRFFI; } diff --git a/mx.fastr/mx_fastr.py b/mx.fastr/mx_fastr.py index dd65727a8202fb78c7388cd8e15755401064208c..12ae6ffb3c3849945c13e595eae48c16e36c6d5a 100644 --- a/mx.fastr/mx_fastr.py +++ b/mx.fastr/mx_fastr.py @@ -26,6 +26,7 @@ from argparse import ArgumentParser import mx import mx_gate import mx_fastr_pkgs +import mx_find_pcre import os ''' @@ -516,6 +517,7 @@ _commands = { 'installpkgs' : [installpkgs, '[options]'], 'installcran' : [installpkgs, '[options]'], 'r-cp' : [r_classpath, '[options]'], + 'findpcre' : [mx_find_pcre.findpcre, '[]'], } mx.update_commands(_fastr_suite, _commands) diff --git a/mx.fastr/mx_find_pcre.py b/mx.fastr/mx_find_pcre.py new file mode 100644 index 0000000000000000000000000000000000000000..7ec98e155c2ddb443c3f08ddaeb1c60cbf2a1fcc --- /dev/null +++ b/mx.fastr/mx_find_pcre.py @@ -0,0 +1,43 @@ +# +# Copyright (c) 2016, 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. +# +import os +import platform +import mx + +def findpcre(args): + ''' + GNU R is built using GNUR_LDFLAGS_OVERRIDE to specify the location of necessary external libraries, + but this isn't captured anywhere, so we re-analyze here + ''' + if not os.environ.has_key('GNUR_LDFLAGS_OVERRIDE'): + mx.abort('GNUR_LDFLAGS_OVERRIDE is not set') + parts = os.environ['GNUR_LDFLAGS_OVERRIDE'].split(' ') + ext = '.dylib' if platform.system() == 'Darwin' else '.so' + name = 'libpcre' + ext + for part in parts: + path = part.lstrip('-I') + for f in os.listdir(path): + if name == f: + mx.log(os.path.join(path, f)) + return 0 + mx.abort(name + ' not found')