From 1c482c4bdbc985dc529925bfd7636cceba4060d6 Mon Sep 17 00:00:00 2001 From: Miloslav Metelka <miloslav.metelka@oracle.com> Date: Thu, 9 Mar 2017 18:16:09 +0100 Subject: [PATCH] Implemented Rf_copyMatrix() and related fixes. --- .../fficall/src/jni/Rinternals.c | 112 +++++++++-- com.oracle.truffle.r.native/version.source | 2 +- .../truffle/r/nodes/builtin/base/Prod.java | 59 +++++- .../r/nodes/ffi/FFIUpCallRootNode.java | 6 + .../r/nodes/ffi/JavaUpCallsRFFIImpl.java | 186 +++++++++++++++++- .../oracle/truffle/r/nodes/ffi/MiscNodes.java | 66 +++++++ .../truffle/r/nodes/ffi/RFFIUpCallMethod.java | 3 + .../r/nodes/ffi/TracingUpCallsRFFIImpl.java | 36 ++++ .../objects/CollectGenericArgumentsNode.java | 7 +- .../truffle/r/runtime/ffi/StdUpCallsRFFI.java | 13 ++ .../truffle/r/test/ExpectedTestOutput.test | 40 ++++ .../r/test/builtins/TestBuiltin_prod.java | 12 +- 12 files changed, 520 insertions(+), 22 deletions(-) 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 9efedd0f00..7a21ecaa62 100644 --- a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c +++ b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c @@ -91,6 +91,9 @@ jmethodID logNotCharSXPWrapperMethodID; static jmethodID STRING_ELT_MethodID; static jmethodID VECTOR_ELT_MethodID; static jmethodID LENGTH_MethodID; +static jmethodID R_do_slot_MethodID; +static jmethodID R_do_slot_assign_MethodID; +static jmethodID R_MethodsNamespaceMethodID; static jmethodID Rf_asIntegerMethodID; static jmethodID Rf_asRealMethodID; static jmethodID Rf_asCharMethodID; @@ -105,6 +108,8 @@ static jmethodID TYPEOF_MethodID; static jmethodID OBJECT_MethodID; static jmethodID DUPLICATE_ATTRIB_MethodID; static jmethodID IS_S4_OBJECTMethodID; +static jmethodID SET_S4_OBJECTMethodID; +static jmethodID UNSET_S4_OBJECTMethodID; static jmethodID R_tryEvalMethodID; static jmethodID RDEBUGMethodID; static jmethodID SET_RDEBUGMethodID; @@ -114,6 +119,7 @@ static jmethodID ENCLOSMethodID; static jmethodID PRVALUEMethodID; static jmethodID R_lsInternal3MethodID; static jmethodID R_do_MAKE_CLASS_MethodID; +static jmethodID R_do_new_object_MethodID; static jmethodID PRSEENMethodID; static jmethodID PRENVMethodID; static jmethodID R_PromiseExprMethodID; @@ -171,6 +177,7 @@ void init_internals(JNIEnv *env) { Rf_classgetsMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_classgets", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 0); RprintfMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rprintf", "(Ljava/lang/Object;)V", 0); R_do_MAKE_CLASS_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_do_MAKE_CLASS", "(Ljava/lang/Object;)Ljava/lang/Object;", 0); + R_do_new_object_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_do_new_object", "(Ljava/lang/Object;)Ljava/lang/Object;", 0); R_FindNamespaceMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_FindNamespace", "(Ljava/lang/Object;)Ljava/lang/Object;", 0); R_BindingIsLockedID = checkGetMethodID(env, UpCallsRFFIClass, "R_BindingIsLocked", "(Ljava/lang/Object;Ljava/lang/Object;)I", 0); Rf_GetOption1MethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_GetOption1", "(Ljava/lang/Object;)Ljava/lang/Object;", 0); @@ -201,6 +208,9 @@ void init_internals(JNIEnv *env) { STRING_ELT_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "STRING_ELT", "(Ljava/lang/Object;I)Ljava/lang/Object;", 0); VECTOR_ELT_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "VECTOR_ELT", "(Ljava/lang/Object;I)Ljava/lang/Object;", 0); LENGTH_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "LENGTH", "(Ljava/lang/Object;)I", 0); + R_do_slot_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_do_slot", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 0); + R_do_slot_assign_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_do_slot_assign", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 0); + R_MethodsNamespaceMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_MethodsNamespace", "()Ljava/lang/Object;", 0); Rf_asIntegerMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_asInteger", "(Ljava/lang/Object;)I", 0); Rf_asRealMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_asReal", "(Ljava/lang/Object;)D", 0); Rf_asCharMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_asChar", "(Ljava/lang/Object;)Ljava/lang/Object;", 0); @@ -214,6 +224,8 @@ void init_internals(JNIEnv *env) { OBJECT_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "OBJECT", "(Ljava/lang/Object;)I", 0); DUPLICATE_ATTRIB_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "DUPLICATE_ATTRIB", "(Ljava/lang/Object;Ljava/lang/Object;)V", 0); IS_S4_OBJECTMethodID = checkGetMethodID(env, UpCallsRFFIClass, "IS_S4_OBJECT", "(Ljava/lang/Object;)I", 0); + SET_S4_OBJECTMethodID = checkGetMethodID(env, UpCallsRFFIClass, "SET_S4_OBJECT", "(Ljava/lang/Object;)V", 0); + UNSET_S4_OBJECTMethodID = checkGetMethodID(env, UpCallsRFFIClass, "UNSET_S4_OBJECT", "(Ljava/lang/Object;)V", 0); R_tryEvalMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_tryEval", "(Ljava/lang/Object;Ljava/lang/Object;Z)Ljava/lang/Object;", 0); RDEBUGMethodID = checkGetMethodID(env, UpCallsRFFIClass, "RDEBUG", "(Ljava/lang/Object;)I", 0); SET_RDEBUGMethodID = checkGetMethodID(env, UpCallsRFFIClass, "SET_RDEBUG", "(Ljava/lang/Object;I)V", 0); @@ -477,6 +489,7 @@ SEXP Rf_install(const char *name) { JNIEnv *thisenv = getEnv(); jstring string = (*thisenv)->NewStringUTF(thisenv, name); SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_installMethodID, string); + addGlobalRef(thisenv, result, 1); return checkRef(thisenv, result); } @@ -1377,10 +1390,13 @@ int IS_S4_OBJECT(SEXP x) { } void SET_S4_OBJECT(SEXP x) { - unimplemented("SET_S4_OBJECT"); + JNIEnv *env = getEnv(); + (*env)->CallVoidMethod(env, UpCallsRFFIObject, SET_S4_OBJECTMethodID, x); } + void UNSET_S4_OBJECT(SEXP x) { - unimplemented("UNSET_S4_OBJECT"); + JNIEnv *env = getEnv(); + (*env)->CallVoidMethod(env, UpCallsRFFIObject, UNSET_S4_OBJECTMethodID, x); } Rboolean R_ToplevelExec(void (*fun)(void *), void *data) { @@ -1595,11 +1611,17 @@ void R_RunWeakRefFinalizer(SEXP w) { } SEXP R_do_slot(SEXP obj, SEXP name) { - return unimplemented("R_do_slot"); + TRACE(TARGp, obj, name); + JNIEnv *thisenv = getEnv(); + SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, R_do_slot_MethodID, obj, name); + return checkRef(thisenv, result); } -SEXP R_do_slot_assign(SEXP obj, SEXP name, SEXP value) { - return unimplemented("R_do_slot_assign"); +SEXP R_do_slot_assign(SEXP obj, SEXP name, SEXP value) { // Same like R_set_slot + TRACE(TARGp, obj, name, value); + JNIEnv *thisenv = getEnv(); + SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, R_do_slot_assign_MethodID, obj, name, value); + return checkRef(thisenv, result); } int R_has_slot(SEXP obj, SEXP name) { @@ -1615,17 +1637,84 @@ SEXP R_do_MAKE_CLASS(const char *what) { SEXP R_getClassDef (const char *what) { return unimplemented("R_getClassDef"); } - + SEXP R_do_new_object(SEXP class_def) { - return unimplemented("R_do_new_object"); + JNIEnv *thisenv = getEnv(); + SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, R_do_new_object_MethodID, class_def); + return checkRef(thisenv, result); } int R_check_class_and_super(SEXP x, const char **valid, SEXP rho) { - return (int) unimplemented("R_check_class_and_super"); + int ans; + SEXP cl = PROTECT(asChar(getAttrib(x, R_ClassSymbol))); + const char *class = CHAR(cl); + for (ans = 0; ; ans++) { + if (!strlen(valid[ans])) // empty string + break; + if (!strcmp(class, valid[ans])) { + UNPROTECT(1); /* cl */ + return ans; + } + } + /* if not found directly, now search the non-virtual super classes :*/ + if(IS_S4_OBJECT(x)) { + /* now try the superclasses, i.e., try is(x, "...."); superCl := + .selectSuperClasses(getClass("....")@contains, dropVirtual=TRUE) */ + SEXP classExts, superCl, _call; + // install() results cached anyway so the following variables could be non-static if needed + static SEXP s_contains = NULL, s_selectSuperCl = NULL; + int i; + if(!s_contains) { + s_contains = install("contains"); + s_selectSuperCl = install(".selectSuperClasses"); + } + SEXP classDef = PROTECT(R_getClassDef(class)); + PROTECT(classExts = R_do_slot(classDef, s_contains)); + PROTECT(_call = lang3(s_selectSuperCl, classExts, + /* dropVirtual = */ ScalarLogical(1))); + superCl = eval(_call, rho); + UNPROTECT(3); /* _call, classExts, classDef */ + PROTECT(superCl); + for(i=0; i < LENGTH(superCl); i++) { + const char *s_class = CHAR(STRING_ELT(superCl, i)); + for (ans = 0; ; ans++) { + if (!strlen(valid[ans])) + break; + if (!strcmp(s_class, valid[ans])) { + UNPROTECT(2); /* superCl, cl */ + return ans; + } + } + } + UNPROTECT(1); /* superCl */ + } + UNPROTECT(1); /* cl */ + return -1; } int R_check_class_etc (SEXP x, const char **valid) { - return (int) unimplemented("R_check_class_etc"); + // install() results cached anyway so the following variables could be non-static if needed + static SEXP meth_classEnv = NULL; + SEXP cl = getAttrib(x, R_ClassSymbol), rho = R_GlobalEnv, pkg; + if (!meth_classEnv) + meth_classEnv = install(".classEnv"); + + pkg = getAttrib(cl, R_PackageSymbol); /* ==R== packageSlot(class(x)) */ + if (!isNull(pkg)) { /* find rho := correct class Environment */ + SEXP clEnvCall; + // FIXME: fails if 'methods' is not loaded. + PROTECT(clEnvCall = lang2(meth_classEnv, cl)); + JNIEnv *thisenv = getEnv(); + SEXP methodsNamespace = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, R_MethodsNamespaceMethodID); + rho = eval(clEnvCall, methodsNamespace); + UNPROTECT(1); + if (!isEnvironment(rho)) + error(_("could not find correct environment; please report!")); + } + PROTECT(rho); + int res = R_check_class_and_super(x, valid, rho); + UNPROTECT(1); + return res; } SEXP R_PreserveObject(SEXP x) { @@ -1648,11 +1737,12 @@ Rboolean R_compute_identical(SEXP x, SEXP y, int flags) { } void Rf_copyListMatrix(SEXP s, SEXP t, Rboolean byrow) { - JNIEnv *thisenv = getEnv(); + JNIEnv *thisenv = getEnv(); (*thisenv)->CallIntMethod(thisenv, UpCallsRFFIObject, Rf_copyListMatrixMethodID, s, t, byrow); } void Rf_copyMatrix(SEXP s, SEXP t, Rboolean byrow) { - JNIEnv *thisenv = getEnv(); + JNIEnv *thisenv = getEnv(); (*thisenv)->CallIntMethod(thisenv, UpCallsRFFIObject, Rf_copyMatrixMethodID, s, t, byrow); } + diff --git a/com.oracle.truffle.r.native/version.source b/com.oracle.truffle.r.native/version.source index 3c032078a4..d6b24041cf 100644 --- a/com.oracle.truffle.r.native/version.source +++ b/com.oracle.truffle.r.native/version.source @@ -1 +1 @@ -18 +19 diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java index 132a964889..34cd247dd9 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java @@ -15,12 +15,16 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RComplex; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RTypedValue; import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; @@ -49,12 +53,53 @@ public abstract class Prod extends RBuiltinNode { @Specialization protected Object prod(RArgsValuesAndNames args) { + int argsLen = args.getLength(); + if (argsLen == 0) { + return 1d; + } if (prodRecursive == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); prodRecursive = insert(ProdNodeGen.create()); } - // TODO: eventually handle multiple vectors properly - return prodRecursive.executeObject(args.getArgument(0)); + Object ret = prodRecursive.executeObject(args.getArgument(0)); + if (argsLen != 1) { + double prodReal; + double prodImg; + boolean complex; + if (ret instanceof RComplex) { + RComplex c = (RComplex) ret; + prodReal = c.getRealPart(); + prodImg = c.getImaginaryPart(); + complex = true; + } else { + prodReal = (Double) ret; + prodImg = 0d; + complex = false; + } + for (int i = 1; i < argsLen; i++) { + Object aProd = prodRecursive.executeObject(args.getArgument(i)); + double aProdReal; + double aProdImg; + if (aProd instanceof RComplex) { + RComplex c = (RComplex) aProd; + aProdReal = c.getRealPart(); + aProdImg = c.getImaginaryPart(); + complex = true; + } else { + aProdReal = (Double) aProd; + aProdImg = 0d; + } + if (complex) { + RComplex c = prod.op(prodReal, prodImg, aProdReal, aProdImg); + prodReal = c.getRealPart(); + prodImg = c.getImaginaryPart(); + } else { + prodReal = prod.op(prodReal, aProdReal); + } + } + ret = complex ? RComplex.valueOf(prodReal, prodImg) : prodReal; + } + return ret; } @Specialization @@ -93,4 +138,14 @@ public abstract class Prod extends RBuiltinNode { } return product; } + + @Specialization + protected double prod(RNull n) { + return 1d; + } + + @Fallback + protected Object prod(Object o) { + throw RError.error(this, RError.Message.INVALID_TYPE_ARGUMENT, ((RTypedValue) RRuntime.asAbstractVector(o)).getRType().getName()); + } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/FFIUpCallRootNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/FFIUpCallRootNode.java index e7d26f933b..475f51bdfd 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/FFIUpCallRootNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/FFIUpCallRootNode.java @@ -35,6 +35,9 @@ import com.oracle.truffle.r.nodes.ffi.ListAccessNodesFactory.CARNodeGen; import com.oracle.truffle.r.nodes.ffi.ListAccessNodesFactory.CDDRNodeGen; import com.oracle.truffle.r.nodes.ffi.ListAccessNodesFactory.CDRNodeGen; import com.oracle.truffle.r.nodes.ffi.MiscNodesFactory.LENGTHNodeGen; +import com.oracle.truffle.r.nodes.ffi.MiscNodesFactory.RDoNewObjectNodeGen; +import com.oracle.truffle.r.nodes.ffi.MiscNodesFactory.RDoSlotNodeGen; +import com.oracle.truffle.r.nodes.ffi.MiscNodesFactory.RDoSlotAssignNodeGen; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.context.RContext; @@ -91,6 +94,9 @@ public final class FFIUpCallRootNode extends RootNode { FFIUpCallRootNode.add(RFFIUpCallMethod.CADDR, CADDRNodeGen::create); FFIUpCallRootNode.add(RFFIUpCallMethod.CDDR, CDDRNodeGen::create); FFIUpCallRootNode.add(RFFIUpCallMethod.LENGTH, LENGTHNodeGen::create); + FFIUpCallRootNode.add(RFFIUpCallMethod.R_do_new_object, RDoNewObjectNodeGen::create); + FFIUpCallRootNode.add(RFFIUpCallMethod.R_do_slot, RDoSlotNodeGen::create); + FFIUpCallRootNode.add(RFFIUpCallMethod.R_do_slot_assign, RDoSlotAssignNodeGen::create); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java index 2c78c9fbb6..2bb4cee421 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java @@ -80,13 +80,20 @@ import com.oracle.truffle.r.runtime.data.RPairList; import com.oracle.truffle.r.runtime.data.RPromise; import com.oracle.truffle.r.runtime.data.RRaw; import com.oracle.truffle.r.runtime.data.RRawVector; -import com.oracle.truffle.r.runtime.data.RS4Object; import com.oracle.truffle.r.runtime.data.RSequence; import com.oracle.truffle.r.runtime.data.RShareable; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; +import com.oracle.truffle.r.runtime.data.RTypedValue; import com.oracle.truffle.r.runtime.data.RUnboundValue; +import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; +import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractListBaseVector; import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; import com.oracle.truffle.r.runtime.env.REnvironment; @@ -99,6 +106,8 @@ import com.oracle.truffle.r.runtime.nodes.DuplicationHelper; import com.oracle.truffle.r.runtime.nodes.RNode; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; import com.oracle.truffle.r.runtime.rng.RRNG; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * This class provides a simple Java-based implementation of {@link UpCallsRFFI}, where all the @@ -114,6 +123,8 @@ import com.oracle.truffle.r.runtime.rng.RRNG; */ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { + private final Map<String, Object> nameSymbolCache = new ConcurrentHashMap<>(); + // Checkstyle: stop method name check @Override @@ -197,6 +208,11 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { return RContext.getEngine().evalFunction(getClass, null, RCaller.createInvalid(null), null, clazz); } + @Override + public Object R_do_new_object(Object classDef) { + return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.R_do_new_object).call(classDef); + } + @Override public Object Rf_findVar(Object symbolArg, Object envArg) { return findVarInFrameHelper(envArg, symbolArg, true); @@ -319,7 +335,13 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { @Override public Object Rf_install(Object name) { - return RDataFactory.createSymbolInterned((String) name); + String nameStr = (String) name; + Object ret = nameSymbolCache.get(nameStr); + if (ret == null) { + ret = RDataFactory.createSymbolInterned(nameStr); + nameSymbolCache.put(nameStr, ret); + } + return ret; } @Override @@ -798,13 +820,140 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { } @Override - public void Rf_copyListMatrix(Object s, Object t, int byrow) { + public void Rf_copyListMatrix(Object t, Object s, int byrow) { throw unimplemented(); } @Override - public void Rf_copyMatrix(Object s, Object t, int byrow) { - throw unimplemented(); + public void Rf_copyMatrix(Object t, Object s, int byRow) { + int tRows = RRuntime.nrows(t); + int tCols = RRuntime.ncols(t); + final Object sav = RRuntime.asAbstractVector(s); + ContainerItemCopier c; + if (sav instanceof RAbstractContainer) { + int sLen = ((RAbstractContainer) sav).getLength(); + if (sav instanceof RAbstractIntVector) { + c = new ContainerItemCopier() { + private final RAbstractIntVector sv = (RAbstractIntVector) sav; + private final RAbstractIntVector tv = (RAbstractIntVector) t; + private final Object tvStore = tv.getInternalStore(); + + @Override + public void copy(int sIdx, int tIdx) { + tv.setDataAt(tvStore, tIdx, sv.getDataAt(sIdx)); + } + }; + } else if (sav instanceof RAbstractDoubleVector) { + c = new ContainerItemCopier() { + private final RAbstractDoubleVector sv = (RAbstractDoubleVector) sav; + private final RAbstractDoubleVector tv = (RAbstractDoubleVector) t; + private final Object tvStore = tv.getInternalStore(); + + @Override + public void copy(int sIdx, int tIdx) { + tv.setDataAt(tvStore, tIdx, sv.getDataAt(sIdx)); + } + }; + } else if (sav instanceof RAbstractLogicalVector) { + c = new ContainerItemCopier() { + private final RAbstractLogicalVector sv = (RAbstractLogicalVector) sav; + private final RAbstractLogicalVector tv = (RAbstractLogicalVector) t; + private final Object tvStore = tv.getInternalStore(); + + @Override + public void copy(int sIdx, int tIdx) { + tv.setDataAt(tvStore, tIdx, sv.getDataAt(sIdx)); + } + }; + } else if (sav instanceof RAbstractComplexVector) { + c = new ContainerItemCopier() { + private final RAbstractComplexVector sv = (RAbstractComplexVector) sav; + private final RAbstractComplexVector tv = (RAbstractComplexVector) t; + private final Object tvStore = tv.getInternalStore(); + + @Override + public void copy(int sIdx, int tIdx) { + tv.setDataAt(tvStore, tIdx, sv.getDataAt(sIdx)); + } + }; + } else if (sav instanceof RAbstractStringVector) { + c = new ContainerItemCopier() { + private final RAbstractStringVector sv = (RAbstractStringVector) sav; + private final RAbstractStringVector tv = (RAbstractStringVector) t; + private final Object tvStore = tv.getInternalStore(); + + @Override + public void copy(int sIdx, int tIdx) { + tv.setDataAt(tvStore, tIdx, sv.getDataAt(sIdx)); + } + }; + } else if (sav instanceof RAbstractRawVector) { + c = new ContainerItemCopier() { + private final RAbstractRawVector sv = (RAbstractRawVector) sav; + private final RAbstractRawVector tv = (RAbstractRawVector) t; + private final Object tvStore = tv.getInternalStore(); + + @Override + public void copy(int sIdx, int tIdx) { + tv.setRawDataAt(tvStore, tIdx, sv.getRawDataAt(sIdx)); + } + }; + } else if (sav instanceof RAbstractListBaseVector) { + c = new ContainerItemCopier() { + private final RAbstractListBaseVector sv = (RAbstractListBaseVector) sav; + private final RAbstractListBaseVector tv = (RAbstractListBaseVector) t; + private final Object tvStore = tv.getInternalStore(); + + @Override + public void copy(int sIdx, int tIdx) { + tv.setDataAt(tvStore, tIdx, sv.getDataAt(sIdx)); + } + }; + } else { + throw unimplemented(); + } + if (byRow != 0) { + int sIdx = 0; + for (int i = 0; i < tRows; i++) { + int tIdx = i; + for (int j = 0; j < tCols; j++) { + c.copy(sIdx, tIdx); + sIdx++; + if (sIdx >= sLen) { + sIdx -= sLen; + } + tIdx += tRows; + } + } + } else { // Copy by column + int tLen = ((RAbstractContainer) t).getLength(); + if (sLen >= tLen) { + for (int i = 0; i < tLen; i++) { + c.copy(i, i); + } + } else { // Recycle needed + int sIdx = 0; + for (int i = 0; i < tLen; i++) { + c.copy(sIdx, i); + if (sIdx >= sLen) { + sIdx -= sLen; + } + } + } + } + + } else { // source is non-RAbstractContainer + throw unimplemented(); + } + } + + /** + * Helper interface for {@link #Rf_copyMatrix(java.lang.Object, java.lang.Object, int)} that + * copies from source index in an (internally held) source container into target index in a + * target container. + */ + interface ContainerItemCopier { + void copy(int sIdx, int tIdx); } @Override @@ -966,7 +1115,17 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { @Override public int IS_S4_OBJECT(Object x) { - return x instanceof RS4Object ? 1 : 0; + return ((x instanceof RTypedValue) && ((RTypedValue) x).isS4()) ? 1 : 0; + } + + @Override + public void SET_S4_OBJECT(Object x) { + guaranteeInstanceOf(x, RTypedValue.class).setS4(); + } + + @Override + public void UNSET_S4_OBJECT(Object x) { + guaranteeInstanceOf(x, RTypedValue.class).unsetS4(); } @Override @@ -1264,4 +1423,19 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { return conn.isSeekable(); } + @Override + public Object R_do_slot(Object o, Object name) { + return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.R_do_slot).call(o, name); + } + + @Override + public Object R_do_slot_assign(Object o, Object name, Object value) { + return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.R_do_slot_assign).call(o, name, value); + } + + @Override + public Object R_MethodsNamespace() { + return REnvironment.getRegisteredNamespace("methods"); + } + } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/MiscNodes.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/MiscNodes.java index f3e2f0edc2..3a1ee7f7de 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/MiscNodes.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/MiscNodes.java @@ -26,8 +26,15 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.dsl.TypeSystemReference; +import com.oracle.truffle.r.nodes.access.AccessSlotNode; +import com.oracle.truffle.r.nodes.access.AccessSlotNodeGen; +import com.oracle.truffle.r.nodes.access.UpdateSlotNode; +import com.oracle.truffle.r.nodes.access.UpdateSlotNodeGen; +import com.oracle.truffle.r.nodes.objects.NewObject; +import com.oracle.truffle.r.nodes.objects.NewObjectNodeGen; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.RTypes; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.ffi.CharSXPWrapper; @@ -80,4 +87,63 @@ public final class MiscNodes { throw RError.error(RError.SHOW_CALLER2, RError.Message.LENGTH_MISAPPLIED, SEXPTYPE.gnuRTypeForObject(obj).name()); } } + + @TypeSystemReference(RTypes.class) + abstract static class RDoSlotNode extends FFIUpCallNode.Arg2 { + + @Child private AccessSlotNode accessSlotNode; + + RDoSlotNode() { + accessSlotNode = AccessSlotNodeGen.create(false); + } + + @Specialization + Object doSlot(Object o, RSymbol nameSym) { + return accessSlotNode.executeAccess(o, nameSym.getName()); + } + + @Fallback + Object doSlot(@SuppressWarnings("unused") Object o, @SuppressWarnings("unused") Object name) { + throw RError.error(RError.SHOW_CALLER2, RError.Message.INVALID_ARGUMENT_OF_TYPE, "name", SEXPTYPE.gnuRTypeForObject(name).name()); + } + + } + + @TypeSystemReference(RTypes.class) + abstract static class RDoSlotAssignNode extends FFIUpCallNode.Arg3 { + + @Child private UpdateSlotNode updateSlotNode; + + RDoSlotAssignNode() { + updateSlotNode = UpdateSlotNodeGen.create(); + } + + @Specialization + Object doSlotAssign(Object o, String name, Object value) { + return updateSlotNode.executeUpdate(o, name, value); + } + + @Fallback + Object doSlot(@SuppressWarnings("unused") Object o, Object name, @SuppressWarnings("unused") Object value) { + throw RError.error(RError.SHOW_CALLER2, RError.Message.INVALID_ARGUMENT_OF_TYPE, "name", SEXPTYPE.gnuRTypeForObject(name).name()); + } + + } + + @TypeSystemReference(RTypes.class) + abstract static class RDoNewObjectNode extends FFIUpCallNode.Arg1 { + + @Child private NewObject newObjectNode; + + RDoNewObjectNode() { + newObjectNode = NewObjectNodeGen.create(); + } + + @Specialization + Object doNewObject(Object classDef) { + return newObjectNode.execute(classDef); + } + + } + } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/RFFIUpCallMethod.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/RFFIUpCallMethod.java index 25d2f9f385..f3a19b0033 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/RFFIUpCallMethod.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/RFFIUpCallMethod.java @@ -81,6 +81,9 @@ public enum RFFIUpCallMethod { R_WriteConnection("(sint32, object) : sint32"), R_computeIdentical("(object, object, sint32) : sint32"), R_do_MAKE_CLASS("(string) : object"), + R_do_new_object("(object) : object"), + R_do_slot("(object, object) : object"), + R_do_slot_assign("(object, object, object) : object"), R_getContextCall("(object) : object"), R_getContextEnv("(object) : object"), R_getContextFun("(object) : object"), diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/TracingUpCallsRFFIImpl.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/TracingUpCallsRFFIImpl.java index b89d83cc56..9ad307eea7 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/TracingUpCallsRFFIImpl.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/TracingUpCallsRFFIImpl.java @@ -117,6 +117,12 @@ final class TracingUpCallsRFFIImpl implements UpCallsRFFI { return delegate.R_do_MAKE_CLASS(clazz); } + @Override + public Object R_do_new_object(Object classDef) { + RFFIUtils.traceUpCall("R_do_new_object", classDef); + return delegate.R_do_new_object(classDef); + } + @Override public Object Rf_findVar(Object symbolArg, Object envArg) { RFFIUtils.traceUpCall("Rf_findVar", symbolArg, envArg); @@ -579,6 +585,18 @@ final class TracingUpCallsRFFIImpl implements UpCallsRFFI { return delegate.IS_S4_OBJECT(x); } + @Override + public void SET_S4_OBJECT(Object x) { + RFFIUtils.traceUpCall("setS4Object"); + delegate.SET_S4_OBJECT(x); + } + + @Override + public void UNSET_S4_OBJECT(Object x) { + RFFIUtils.traceUpCall("unsetS4Object"); + delegate.UNSET_S4_OBJECT(x); + } + @Override public void Rprintf(Object message) { RFFIUtils.traceUpCall("Rprintf", message); @@ -789,4 +807,22 @@ final class TracingUpCallsRFFIImpl implements UpCallsRFFI { return delegate.isSeekable(x); } + @Override + public Object R_do_slot(Object o, Object name) { + RFFIUtils.traceUpCall("R_do_slot", o, name); + return delegate.R_do_slot(o, name); + } + + @Override + public Object R_do_slot_assign(Object o, Object name, Object value) { + RFFIUtils.traceUpCall("R_do_slot", o, name, value); + return delegate.R_do_slot_assign(o, name, value); + } + + @Override + public Object R_MethodsNamespace() { + RFFIUtils.traceUpCall("R_MethodsNamespace"); + return delegate.R_MethodsNamespace(); + } + } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/CollectGenericArgumentsNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/CollectGenericArgumentsNode.java index 3acb958ef9..6b57fd298b 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/CollectGenericArgumentsNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/CollectGenericArgumentsNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -39,7 +39,9 @@ import com.oracle.truffle.r.nodes.function.PromiseHelperNode; import com.oracle.truffle.r.nodes.function.PromiseHelperNode.PromiseCheckHelperNode; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.REmpty; import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RPromise; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; @@ -90,6 +92,9 @@ public abstract class CollectGenericArgumentsNode extends RBaseNode { throw new SlowPathException(); } Object value = argReads[i].execute(frame); + if (value == REmpty.instance || value == RMissing.instance) { + value = null; + } result[i] = valueMissingProfile.profile(value == null) ? "missing" : classHierarchyNodes[i].executeString(promiseHelper.checkEvaluate(frame, value)); } return RDataFactory.createStringVector(result, RDataFactory.COMPLETE_VECTOR); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/StdUpCallsRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/StdUpCallsRFFI.java index dceb6d282d..75132c6fe4 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/StdUpCallsRFFI.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/StdUpCallsRFFI.java @@ -22,6 +22,7 @@ */ package com.oracle.truffle.r.runtime.ffi; +import com.oracle.truffle.r.runtime.conn.ConnectionSupport.BaseRConnection; import com.oracle.truffle.r.runtime.data.RDoubleVector; import com.oracle.truffle.r.runtime.data.RExternalPtr; import com.oracle.truffle.r.runtime.data.RIntVector; @@ -73,6 +74,8 @@ public interface StdUpCallsRFFI { Object R_do_MAKE_CLASS(@RFFICstring Object clazz); + Object R_do_new_object(Object classDef); + /** * WARNING: argument order reversed from Rf_findVarInFrame! */ @@ -216,6 +219,10 @@ public interface StdUpCallsRFFI { int IS_S4_OBJECT(Object x); + void SET_S4_OBJECT(Object x); + + void UNSET_S4_OBJECT(Object x); + void Rprintf(@RFFICstring Object message); void GetRNGstate(); @@ -270,4 +277,10 @@ public interface StdUpCallsRFFI { boolean isSeekable(Object x); + Object R_do_slot(Object o, Object name); + + Object R_do_slot_assign(Object o, Object name, Object value); + + Object R_MethodsNamespace(); + } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test index 98500f6ccb..339c400826 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test @@ -44815,6 +44815,42 @@ age 0.00561 0.012 0.00872 0.22 1.0 0.64000 sex -1.65487 0.483 0.38527 11.74 1.0 0.00061 frailty(id, dist = 't', c 20.33 13.9 0.12000 +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#{prod('a')} +Error in prod("a") : invalid 'type' (character) of argument + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#{prod()} +[1] 1 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#{prod(2+3i,42)} +[1] 84+126i + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#{prod(2+3i,42+5i)} +[1] 69+136i + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#{prod(2+3i,c())} +[1] 2+3i + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#{prod(42,2+3i)} +[1] 84+126i + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#{prod(NULL)} +[1] 1 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#{prod(c())} +[1] 1 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#{prod(c(),c())} +[1] 1 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# #{prod(c(1+2i))} [1] 1+2i @@ -44847,6 +44883,10 @@ frailty(id, dist = 't', c 20.33 13.9 0.12000 #{prod(c(TRUE, TRUE))} [1] 1 +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#{prod(list())} +Error in prod(list()) : invalid 'type' (list) of argument + ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProdNa#Ignored.Unknown# #{prod(c(1,2,3,4,5,NA),FALSE)} [1] NA diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_prod.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_prod.java index 264a3af783..4adffd95dc 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_prod.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_prod.java @@ -4,7 +4,7 @@ * http://www.gnu.org/licenses/gpl-2.0.html * * Copyright (c) 2012-2014, Purdue University - * Copyright (c) 2013, 2016, Oracle and/or its affiliates + * Copyright (c) 2013, 2017, Oracle and/or its affiliates * * All rights reserved. */ @@ -82,6 +82,16 @@ public class TestBuiltin_prod extends TestBase { assertEval("{prod(c(1+2i,1+3i,1+45i))}"); assertEval("{prod(c(TRUE, TRUE))}"); assertEval("{prod(c(TRUE, FALSE))}"); + assertEval("{prod()}"); + assertEval("{prod(NULL)}"); + assertEval("{prod(c())}"); + assertEval("{prod(c(),c())}"); + assertEval("{prod(2+3i,c())}"); + assertEval("{prod(2+3i,42+5i)}"); + assertEval("{prod(2+3i,42)}"); + assertEval("{prod(42,2+3i)}"); + assertEval("{prod('a')}"); + assertEval("{prod(list())}"); } @Test -- GitLab