diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/CPar.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/CPar.java index e65a91bc85710dc9bb27a9044b76e5f14e37f013..524eeb912a1a86689b13e6dc427156186d67d920 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/CPar.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/CPar.java @@ -32,6 +32,7 @@ import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RNull; public final class CPar extends RExternalBuiltinNode { static { @@ -65,6 +66,10 @@ public final class CPar extends RExternalBuiltinNode { } private static Object getParam(String name, GridDevice device) { + if (name == null) { + // TODO: a hot-fix to enable package tests (e.g. cluster) + return RNull.instance; + } switch (name) { case "din": return RDataFactory.createDoubleVector(new double[]{device.getWidth(), device.getHeight()}, RDataFactory.COMPLETE_VECTOR); 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 1858fc85e7cd08ff94bb904ee071ba437500ade9..0414f5f032cd4daf66d45d49b72ada1b39c15dc0 100644 --- a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c +++ b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c @@ -407,7 +407,7 @@ SEXP Rf_getAttrib(SEXP vec, SEXP name) { SEXP Rf_setAttrib(SEXP vec, SEXP name, SEXP val) { TRACE(TARGppp, vec,name, val); JNIEnv *thisenv = getEnv(); - updateNativeArrays(thisenv); + updateNativeArray(thisenv, val); (*thisenv)->CallVoidMethod(thisenv, UpCallsRFFIObject, Rf_setAttribMethodID, vec, name, val); return val; } diff --git a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c index 9df3ebbeafedac00a00faa15d25b1209a8d7bf49..e0de22345a3be9875d731bc5f6e6320912570f6d 100644 --- a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c +++ b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c @@ -233,30 +233,30 @@ void updateNativeArrays(JNIEnv *env) { } -static void *findNativeArray(JNIEnv *env, SEXP x) { +static NativeArrayElem *findNativeArray(JNIEnv *env, SEXP x) { if (nativeArrayTableLastIndex < nativeArrayTableHwm) { - NativeArrayElem cv = nativeArrayTable[nativeArrayTableLastIndex]; - if (cv.obj != NULL && (cv.obj == x || fast_IsSameObject(cv.obj, x))) { - void *data = cv.data; + NativeArrayElem *cv = &nativeArrayTable[nativeArrayTableLastIndex]; + if (cv->obj != NULL && (cv->obj == x || fast_IsSameObject(cv->obj, x))) { + void *data = cv->data; #if TRACE_NATIVE_ARRAYS fprintf(traceFile, "findNativeArray(%p): found %p (cached)\n", x, data); #endif - return data; + return cv; } } int i; assert(isValidJNIRef(env, x)); for (i = 0; i < nativeArrayTableHwm; i++) { - NativeArrayElem cv = nativeArrayTable[i]; - if (cv.obj != NULL) { - assert(isValidJNIRef(env, cv.obj)); - if (fast_IsSameObject(cv.obj, x)) { + NativeArrayElem *cv = &nativeArrayTable[i]; + if (cv->obj != NULL) { + assert(isValidJNIRef(env, cv->obj)); + if (fast_IsSameObject(cv->obj, x)) { nativeArrayTableLastIndex = i; - void *data = cv.data; + void *data = cv->data; #if TRACE_NATIVE_ARRAYS fprintf(traceFile, "findNativeArray(%p): found %p\n", x, data); #endif - return data; + return cv; } } } @@ -266,6 +266,19 @@ static void *findNativeArray(JNIEnv *env, SEXP x) { return NULL; } +void updateNativeArray(JNIEnv *env, SEXP x) { + NativeArrayElem *cv = findNativeArray(env, x); + void *data = NULL; + if (cv != NULL) { + data = cv->data; + } + + if (data != NULL) { + int len = (*env)->GetArrayLength(env, cv->jArray); + (*env)->SetByteArrayRegion(env, cv->jArray, 0, len, data); + } +} + static void addNativeArray(JNIEnv *env, SEXP x, SEXPTYPE type, void *jArray, void *data) { #if TRACE_NATIVE_ARRAYS fprintf(traceFile, "addNativeArray(x=%p, t=%p, ix=%d)\n", x, data, nativeArrayTableHwm); @@ -290,10 +303,14 @@ static void addNativeArray(JNIEnv *env, SEXP x, SEXPTYPE type, void *jArray, voi } void *getNativeArray(JNIEnv *thisenv, SEXP x, SEXPTYPE type) { - void *data = findNativeArray(thisenv, x); - jboolean isCopy; + NativeArrayElem *cv = findNativeArray(thisenv, x); + void *data = NULL; + if (cv != NULL) { + data = cv->data; + } if (data == NULL) { jarray jArray; + jboolean isCopy; switch (type) { case INTSXP: { jintArray intArray = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, INTEGER_MethodID, x); @@ -354,7 +371,7 @@ void *getNativeArray(JNIEnv *thisenv, SEXP x, SEXPTYPE type) { static void releaseNativeArray(JNIEnv *env, int i) { NativeArrayElem cv = nativeArrayTable[i]; #if TRACE_NATIVE_ARRAYS - fprintf(traceFile, "releaseNativeArray(x=%p, ix=%d, freedata=%d)\n", cv.obj, i, freedata); + fprintf(traceFile, "releaseNativeArray(x=%p, ix=%d)\n", cv.obj, i); #endif if (cv.obj != NULL) { assert(isValidJNIRef(env, cv.obj)); diff --git a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h index 91bd2d985dbb01555cf035768c4fbae852351c25..c0942f8f76a82dbeb747c37ed98db599b7c8f5bf 100644 --- a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h +++ b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h @@ -76,6 +76,8 @@ void invalidateNativeArray(JNIEnv *env, SEXP oldObj); // Should be called before up calling to arbitrary code, e.g. Rf_eval, // to copy back the arrays into their Java counterparts void updateNativeArrays(JNIEnv *env); +// Copies back the array to the Java counterpart +void updateNativeArray(JNIEnv *env, SEXP obj); SEXP addGlobalRef(JNIEnv *env, SEXP obj, int permanent); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Colon.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Colon.java index 90e3aa33b9021ae0ec2cd1bc318904288d560934..3e6b6ea49cde5bb42d72cbf8b726136758172c66 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Colon.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Colon.java @@ -25,12 +25,10 @@ package com.oracle.truffle.r.nodes.builtin.base; 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.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeCost; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.profiles.ConditionProfile; @@ -51,6 +49,7 @@ import com.oracle.truffle.r.runtime.data.RSequence; 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.RAbstractStringVector; +import com.oracle.truffle.r.runtime.nodes.RBaseNode; import com.oracle.truffle.r.runtime.nodes.RNode; import com.oracle.truffle.r.runtime.ops.na.NACheck; @@ -93,7 +92,7 @@ public abstract class Colon extends RBuiltinNode.Arg2 { } @NodeInfo(cost = NodeCost.NONE) - abstract static class ColonInternal extends Node { + abstract static class ColonInternal extends RBaseNode { private final NACheck leftNA = NACheck.create(); private final NACheck rightNA = NACheck.create(); @@ -102,8 +101,7 @@ public abstract class Colon extends RBuiltinNode.Arg2 { private void naCheck(boolean na) { if (na) { - CompilerDirectives.transferToInterpreter(); - throw RError.error(this, RError.Message.NA_OR_NAN); + error(RError.Message.NA_OR_NAN); } } @@ -116,6 +114,7 @@ public abstract class Colon extends RBuiltinNode.Arg2 { leftNA.enable(left); rightNA.enable(right); naCheck(leftNA.check(left) || rightNA.check(right)); + checkVecLength(left, right); return RDataFactory.createAscendingRange(left, right); } @@ -124,14 +123,38 @@ public abstract class Colon extends RBuiltinNode.Arg2 { leftNA.enable(left); rightNA.enable(right); naCheck(leftNA.check(left) || rightNA.check(right)); + checkVecLength(left, right); return RDataFactory.createDescendingRange(left, right); } - @Specialization(guards = "asDouble(left) <= right") + protected static boolean isNaN(double x) { + return Double.isNaN(x); + } + + @SuppressWarnings("unused") + @Specialization(guards = "isNaN(right)") + protected RSequence colonRightNaN(int left, double right) { + throw error(Message.NA_OR_NAN); + } + + @SuppressWarnings("unused") + @Specialization(guards = "isNaN(left)") + protected RSequence colonLeftNaN(double left, int right) { + throw error(Message.NA_OR_NAN); + } + + @SuppressWarnings("unused") + @Specialization(guards = "isNaN(left) || isNaN(right)") + protected RSequence colonLeftOrRightNaN(double left, double right) { + throw error(Message.NA_OR_NAN); + } + + @Specialization(guards = {"!isNaN(left)", "asDouble(left) <= right"}) protected RSequence colonAscending(int left, double right, @Cached("createBinaryProfile()") ConditionProfile isDouble) { leftNA.enable(left); naCheck(leftNA.check(left) || RRuntime.isNAorNaN(right)); + checkVecLength(left, right); if (isDouble.profile(right > Integer.MAX_VALUE)) { return RDataFactory.createAscendingRange(left, right); } else { @@ -139,11 +162,12 @@ public abstract class Colon extends RBuiltinNode.Arg2 { } } - @Specialization(guards = "asDouble(left) > right") + @Specialization(guards = {"!isNaN(left)", "asDouble(left) > right"}) protected RSequence colonDescending(int left, double right, @Cached("createBinaryProfile()") ConditionProfile isDouble) { leftNA.enable(left); naCheck(leftNA.check(left) || RRuntime.isNAorNaN(right)); + checkVecLength(left, right); if (isDouble.profile(right <= Integer.MIN_VALUE)) { return RDataFactory.createDescendingRange(left, right); } else { @@ -151,31 +175,42 @@ public abstract class Colon extends RBuiltinNode.Arg2 { } } - @Specialization(guards = "left <= asDouble(right)") + @Specialization(guards = {"!isNaN(left)", "left <= asDouble(right)"}) protected RDoubleSequence colonAscending(double left, int right) { rightNA.enable(right); naCheck(RRuntime.isNAorNaN(left) || rightNA.check(right)); + checkVecLength(left, right); return RDataFactory.createAscendingRange(left, right); } - @Specialization(guards = "left > asDouble(right)") + @Specialization(guards = {"!isNaN(left)", "left > asDouble(right)"}) protected RDoubleSequence colonDescending(double left, int right) { rightNA.enable(right); naCheck(RRuntime.isNAorNaN(left) || rightNA.check(right)); + checkVecLength(left, right); return RDataFactory.createDescendingRange(left, right); } - @Specialization(guards = "left <= right") + @Specialization(guards = {"!isNaN(left)", "!isNaN(right)", "left <= right"}) protected RDoubleSequence colonAscending(double left, double right) { naCheck(RRuntime.isNAorNaN(left) || RRuntime.isNAorNaN(right)); + checkVecLength(left, right); return RDataFactory.createAscendingRange(left, right); } - @Specialization(guards = "left > right") + @Specialization(guards = {"!isNaN(left)", "!isNaN(right)", "left > right"}) protected RDoubleSequence colonDescending(double left, double right) { naCheck(RRuntime.isNAorNaN(left) || RRuntime.isNAorNaN(right)); + checkVecLength(left, right); return RDataFactory.createDescendingRange(left, right); } + + private void checkVecLength(double from, double to) { + double r = Math.abs(to - from); + if (r >= Integer.MAX_VALUE) { + throw error(RError.Message.TOO_LONG_VECTOR); + } + } } @NodeInfo(cost = NodeCost.NONE) diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatC.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatC.java index bab1c075934a48b4b486a6b16ec598ad46f3743f..59d2ff208bffeeb5c493687e37792b771ea3e4f9 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatC.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatC.java @@ -160,9 +160,11 @@ public abstract class FormatC extends RBuiltinNode.Arg7 { } /* if(do_fg) for(i..) */ } else { String form = "%" + flag + width + "." + dig + format; + String form2 = "%" + width + "s"; for (int i = 0; i < x.getLength(); i++) { String str = String.format(form, x.getDataAtAsObject(i)); - result[i] = ("g".equals(format) || "f".equals(format)) ? trimZero(str) : str; + str = ("g".equals(format) || "f".equals(format)) ? trimZero(str) : str; + result[i] = String.format(form2, str); } } } else { @@ -173,13 +175,21 @@ public abstract class FormatC extends RBuiltinNode.Arg7 { } private static String trimZero(String str) { - int i = str.length(); + int e = str.indexOf('e'); + int i = e < 0 ? str.length() : e; while (i > 0 && str.charAt(i - 1) == '0') { i--; } if (i > 0 && str.charAt(i - 1) == '.') { i--; - return str.substring(0, i); + String s = str.substring(0, i); + if (e < 0) { + return s; + } else { + StringBuilder sb = new StringBuilder(s); + sb.append(str.substring(e)); + return sb.toString(); + } } if (i == str.length()) { return str; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java index d128c387dc169ba7cfa2d328ed306a3a136d7214..afaa35a46f4ee13c6dd42ce27f0755e5700d3660 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java @@ -105,7 +105,11 @@ public abstract class Paste extends RBuiltinNode.Arg3 { int length = lengthProfile.profile(values.getLength()); if (hasNonNullElements(values, length)) { String[] result = pasteListElements(frame, values, sep, length); - return RDataFactory.createStringVector(result, RDataFactory.COMPLETE_VECTOR); + if (result == ONE_EMPTY_STRING) { + return RDataFactory.createEmptyStringVector(); + } else { + return RDataFactory.createStringVector(result, RDataFactory.COMPLETE_VECTOR); + } } else { return RDataFactory.createEmptyStringVector(); } @@ -136,13 +140,21 @@ public abstract class Paste extends RBuiltinNode.Arg3 { private String[] pasteListElements(VirtualFrame frame, RAbstractListVector values, String sep, int length) { String[][] converted = new String[length][]; int maxLength = 1; + int emptyCnt = 0; for (int i = 0; i < length; i++) { Object element = values.getDataAt(i); String[] array = castCharacterVector(frame, element).materialize().getDataWithoutCopying(); maxLength = Math.max(maxLength, array.length); - converted[i] = array.length == 0 ? ONE_EMPTY_STRING : array; + if (array.length == 0) { + converted[i] = ONE_EMPTY_STRING; + emptyCnt++; + } else { + converted[i] = array; + } } - if (length == 1) { + if (emptyCnt == length) { + return ONE_EMPTY_STRING; + } else if (length == 1) { return converted[0]; } else { return prepareResult(sep, length, converted, maxLength); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Signif.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Signif.java index 1ef56ebc6b17357b39cb72c0b879006c7038d680..1bf082778ce46bdd4ea5ab5aab2ef9e5434c9d59 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Signif.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Signif.java @@ -137,7 +137,7 @@ public abstract class Signif extends RBuiltinNode.Arg2 { @TruffleBoundary private static double bigIntegerSignif(int digits, double val) { - BigDecimal bigDecimalVal = new BigDecimal(val, new MathContext(digits, RoundingMode.HALF_UP)); + BigDecimal bigDecimalVal = new BigDecimal(val, new MathContext(digits, RoundingMode.HALF_EVEN)); return bigDecimalVal.doubleValue(); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java index db4fa2a7fa41ad40cb1ac8117e331075c79ba5be..abad492f9edd0a6c2fb3d83f0a84797ae82fcc5d 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java @@ -30,6 +30,7 @@ import com.oracle.truffle.r.nodes.attributes.InitAttributesNode; import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode; +import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.profile.VectorLengthProfile; import com.oracle.truffle.r.runtime.RError.Message; @@ -37,6 +38,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RVector; import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; @@ -62,6 +64,7 @@ public abstract class Transpose extends RBuiltinNode.Arg1 { @Child private SetFixedAttributeNode putDimensions = SetFixedAttributeNode.createDim(); @Child private SetFixedAttributeNode putDimNames = SetFixedAttributeNode.createDimNames(); @Child private GetDimNamesAttributeNode getDimNamesNode = GetDimNamesAttributeNode.create(); + @Child private GetNamesAttributeNode getAxisNamesNode = GetNamesAttributeNode.create(); @Child private GetDimAttributeNode getDimNode; static { @@ -113,7 +116,9 @@ public abstract class Transpose extends RBuiltinNode.Arg1 { if (dimNames != null) { hasDimNamesProfile.enter(); assert dimNames.getLength() == 2; - RList newDimNames = RDataFactory.createList(new Object[]{dimNames.getDataAt(1), dimNames.getDataAt(0)}); + RStringVector axisNames = getAxisNamesNode.getNames(dimNames); + RStringVector transAxisNames = axisNames == null ? null : RDataFactory.createStringVector(new String[]{axisNames.getDataAt(1), axisNames.getDataAt(0)}, true); + RList newDimNames = RDataFactory.createList(new Object[]{dimNames.getDataAt(1), dimNames.getDataAt(0)}, transAxisNames); putDimNames.execute(r.getAttributes(), newDimNames); } return r; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java index 681396be29706924bf7f3d910b6a638a3f6e7ae8..6383859deaab3e59577068cda6b109e6c62c2447 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java @@ -36,6 +36,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode; +import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetNamesAttributeNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.builtin.base.Lapply.LapplyInternalNode; @@ -57,6 +58,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RVector; import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; @@ -94,7 +96,9 @@ public abstract class VApply extends RBuiltinNode.Arg4 { @Child private CastLogicalNode castLogical; @Child private CastStringNode castString; @Child private SetDimAttributeNode setDimNode; - @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create(); + @Child private GetNamesAttributeNode getColNamesNode = GetNamesAttributeNode.create(); + @Child private GetNamesAttributeNode getRowNamesNode = GetNamesAttributeNode.create(); + @Child private SetDimNamesAttributeNode setDimNamesNode = SetDimNamesAttributeNode.create(); @Child private SetNamesAttributeNode setNamesNode = SetNamesAttributeNode.create(); @Child private CastToVectorNode castToVector = CastToVectorNode.create(); @@ -204,11 +208,30 @@ public abstract class VApply extends RBuiltinNode.Arg4 { setDimNode = insert(SetDimAttributeNode.create()); } setDimNode.setDimensions(result, new int[]{funValueVecLen, applyResult.length}); - } - // TODO: handle names in case of matrices - if (useNamesProfile.profile(useNames)) { - RStringVector names = getNamesNode.getNames(vecMat); + if (useNamesProfile.profile(useNames)) { + // the names from the input vector are used as the column names in the result + RStringVector names = getColNamesNode.getNames(vecMat); + RStringVector colNames = null; + if (names != null) { + colNames = names; + } else if (vecMat instanceof RStringVector) { + colNames = (RStringVector) vecMat.copy(); + } + Object rowNames = RNull.instance; + if (!applyResultZeroLength) { + // take the names from the first input vector and use it as the row names in the + // result + Object firstVec = applyResult[0]; + Object rn = getRowNamesNode.getNames(firstVec); + rowNames = rn == null ? RNull.instance : rn; + } + if (colNames != null) { + setDimNamesNode.setDimNames(result, RDataFactory.createList(new Object[]{rowNames, colNames})); + } + } + } else if (useNamesProfile.profile(useNames)) { + RStringVector names = getColNamesNode.getNames(vecMat); RStringVector newNames = null; if (names != null) { newNames = names; @@ -219,6 +242,8 @@ public abstract class VApply extends RBuiltinNode.Arg4 { setNamesNode.setNames(result, newNames); } } + + // TODO: handle names in case of matrices return result; } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/FortranAndCFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/FortranAndCFunctions.java index 72a31dc4aee921dbd699201441ba380916047251..da358853e981db282353cb67d3377fb806b1a6de 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/FortranAndCFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/FortranAndCFunctions.java @@ -22,8 +22,11 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.profiles.BranchProfile; +import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetNamesAttributeNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; +import com.oracle.truffle.r.nodes.builtin.base.foreign.FortranAndCFunctionsFactory.FortranResultNamesSetterNodeGen; import com.oracle.truffle.r.nodes.builtin.base.foreign.LookupAdapter.ExtractNativeCallInfoNode; import com.oracle.truffle.r.nodes.builtin.base.foreign.LookupAdapterFactory.ExtractNativeCallInfoNodeGen; import com.oracle.truffle.r.runtime.ArgumentsSignature; @@ -31,6 +34,7 @@ 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.RAttributable; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RMissing; @@ -44,6 +48,7 @@ import com.oracle.truffle.r.runtime.ffi.CRFFI; import com.oracle.truffle.r.runtime.ffi.DLL; import com.oracle.truffle.r.runtime.ffi.NativeCallInfo; import com.oracle.truffle.r.runtime.ffi.RFFIFactory; +import com.oracle.truffle.r.runtime.nodes.RBaseNode; /** * {@code .C} and {@code .Fortran} functions, which share a common signature. @@ -251,6 +256,8 @@ public class FortranAndCFunctions { Casts.noCasts(Fortran.class); } + @Child private FortranResultNamesSetter resNamesSetter = FortranResultNamesSetterNodeGen.create(); + @Override @TruffleBoundary public RExternalBuiltinNode lookupBuiltin(RList symbol) { @@ -277,7 +284,7 @@ public class FortranAndCFunctions { protected Object doExternal(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, byte naok, byte dup, Object rPackage, RMissing encoding, @Cached("symbol") RList cached, @Cached("lookupBuiltin(symbol)") RExternalBuiltinNode builtin) { - return builtin.call(frame, args); + return resNamesSetter.execute(builtin.call(frame, args), args); } @Specialization(guards = "lookupBuiltin(symbol) == null") @@ -306,6 +313,40 @@ public class FortranAndCFunctions { } } + public abstract static class FortranResultNamesSetter extends RBaseNode { + + public abstract Object execute(Object result, RArgsValuesAndNames argNames); + + @Specialization + public Object handleArgNames(RAttributable result, RArgsValuesAndNames argValNames, + @Cached("create()") SetNamesAttributeNode namesSetter, + @Cached("create()") BranchProfile namesProfile) { + ArgumentsSignature sig = argValNames.getSignature(); + if (sig.getNonNullCount() > 0) { + namesProfile.enter(); + String[] argNames = sig.getNames(); + String[] names = new String[sig.getLength()]; + for (int i = 0; i < sig.getLength(); i++) { + String argName = argNames[i]; + if (argName == null) { + names[i] = ""; + } else { + names[i] = argName; + } + } + namesSetter.execute(result, RDataFactory.createStringVector(names, true)); + } + + return result; + } + + @Fallback + public Object handleOthers(@SuppressWarnings("unused") Object result, @SuppressWarnings("unused") RArgsValuesAndNames argNames) { + // do nothing + return result; + } + } + @RBuiltin(name = ".C", kind = PRIMITIVE, parameterNames = {".NAME", "...", "NAOK", "DUP", "PACKAGE", "ENCODING"}, behavior = COMPLEX) public abstract static class DotC extends CRFFIAdapter { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/SpecialsUtils.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/SpecialsUtils.java index 987dc95344f9af694fe34fb37f26f66050602580..a9860a5d31058644a95bb67c8852cc60f0deb05c 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/SpecialsUtils.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/SpecialsUtils.java @@ -30,6 +30,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeCost; import com.oracle.truffle.api.nodes.NodeInfo; +import com.oracle.truffle.r.nodes.attributes.HasAttributesNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode; import com.oracle.truffle.r.nodes.builtin.base.infix.SpecialsUtilsFactory.ConvertIndexNodeGen; @@ -207,15 +208,17 @@ class SpecialsUtils { return value; } - @Specialization(guards = {"value.getLength() == 1", "hierarchyNode.execute(value) == null"}) + @Specialization(guards = {"value.getLength() == 1", "hierarchyNode.execute(value) == null", "hasAttrsNode.execute(value)"}) protected static int convertIntVector(RIntVector value, - @Cached("create()") @SuppressWarnings("unused") ClassHierarchyNode hierarchyNode) { + @Cached("create()") @SuppressWarnings("unused") ClassHierarchyNode hierarchyNode, + @Cached("create()") @SuppressWarnings("unused") HasAttributesNode hasAttrsNode) { return value.getDataAt(0); } - @Specialization(guards = {"value.getLength() == 1", "hierarchyNode.execute(value) == null"}) + @Specialization(guards = {"value.getLength() == 1", "hierarchyNode.execute(value) == null", "hasAttrsNode.execute(value)"}) protected static double convertDoubleVector(RDoubleVector value, - @Cached("create()") @SuppressWarnings("unused") ClassHierarchyNode hierarchyNode) { + @Cached("create()") @SuppressWarnings("unused") ClassHierarchyNode hierarchyNode, + @Cached("create()") @SuppressWarnings("unused") HasAttributesNode hasAttrsNode) { return value.getDataAt(0); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java index d3ebedd8fe3c597764ce73f4e78956df9d057640..aa7010c1a8e29ee96d0416b873ad6af6a0236ae4 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java @@ -12,6 +12,8 @@ package com.oracle.truffle.r.nodes.builtin.base.printer; import java.io.IOException; +import java.math.BigDecimal; +import java.math.MathContext; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.r.runtime.RRuntime; @@ -489,9 +491,9 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect str.append((char) ('0' + (log10 / 10))); str.append((char) ('0' + (log10 % 10))); } else { /* e == 0 */ - // round towards next digit instead of truncating - x += DECIMAL_VALUES[-d - 1 + DECIMAL_SHIFT][5]; - + double intx = Math.floor(x); + double pow10 = DECIMAL_WEIGHTS[d + DECIMAL_SHIFT]; + x = intx + Math.rint((x - intx) * pow10) / pow10; int log10 = x == 0 ? 0 : Math.max((int) Math.log10(x), 0); int blanks = w // target width - (negated ? 1 : 0) // "-" @@ -505,13 +507,19 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect if (negated) { str.append('-'); } - for (int i = log10; i >= 0; i--) { - x = appendDigit(x, i, str); + String xs = String.format("%." + d + "f", x); + for (int i = 0; i <= log10; i++) { + str.append(xs.charAt(i)); } if (d > 0) { str.append(cdec); for (int i = 1; i <= d; i++) { - x = appendDigit(x, -i, str); + int j = i + log10 + 1; + if (j < xs.length()) { + str.append(xs.charAt(j)); + } else { + str.append('0'); + } } } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrintParameters.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrintParameters.java index 45a9a4724b7fe11f0944cb97c36d72174976e2a8..728f9e8e90004906b1b31a1852b1732e8efe3190 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrintParameters.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrintParameters.java @@ -11,8 +11,6 @@ */ package com.oracle.truffle.r.nodes.builtin.base.printer; -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; //Transcribed from GnuR, src/include/Print.h @@ -23,8 +21,6 @@ import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RNull; public final class PrintParameters { - @CompilationFinal private static int DefaultDigits = -1; - private int width; private int naWidth; private int naWidthNoquote; @@ -45,11 +41,7 @@ public final class PrintParameters { private boolean suppressIndexLabels; public static int getDefaultDigits() { - if (DefaultDigits == -1) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - DefaultDigits = RRuntime.asInteger(RContext.getInstance().stateROptions.getValue("digits")); - } - return DefaultDigits; + return RRuntime.asInteger(RContext.getInstance().stateROptions.getValue("digits")); } public PrintParameters() { diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/castsTests/CastBuilderTest.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/castsTests/CastBuilderTest.java index 1ae687272d0a714a1bcd32daf5b71b7d34606d71..74dfcb6ba5359f03e683a9ea2558f47f4b517c92 100644 --- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/castsTests/CastBuilderTest.java +++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/castsTests/CastBuilderTest.java @@ -65,6 +65,7 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.shouldBe; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.squareMatrix; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.rawValue; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -78,6 +79,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import com.oracle.truffle.api.vm.PolyglotEngine.Language; import com.oracle.truffle.r.nodes.builtin.CastBuilder; import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef; import com.oracle.truffle.r.nodes.builtin.casts.fluent.InitialPhaseBuilder; @@ -92,6 +94,7 @@ import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.builtins.RBehavior; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.builtins.RBuiltinKind; +import com.oracle.truffle.r.runtime.context.TruffleRLanguage; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RDoubleVector; import com.oracle.truffle.r.runtime.data.RFunction; @@ -106,6 +109,7 @@ 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; import com.oracle.truffle.r.runtime.env.REnvironment.NewEnv; +import com.oracle.truffle.r.test.generate.FastRSession; /** * Tests the cast pipelines and also that the samples generation process matches the intended @@ -125,7 +129,10 @@ public class CastBuilderTest { private CastNode castNode; private PreinitialPhaseBuilder arg; + private static FastRSession fastRSession; + static { + fastRSession = FastRSession.create(); CastNode.testingMode(); } @@ -887,12 +894,23 @@ public class CastBuilderTest { testPipeline(); } + @Test + public void testIntOrRawPassing() { + arg.mustNotBeNull().mustBe(integerValue().or(rawValue())); + assertCastPreserves(1); + assertCastPreserves(RDataFactory.createIntVector(new int[]{1, 2}, true)); + assertCastPreserves(RDataFactory.createRaw((byte) 2)); + assertCastPreserves(RDataFactory.createRawVector(new byte[]{1, 2})); + assertCastFail(RNull.instance); + assertCastFail("abc"); + } + /** * Casts given object using the configured pipeline in {@link #arg}. */ private Object cast(Object a) { CastNode.clearLastWarning(); - NodeHandle<CastNode> argCastNodeHandle = TestUtilities.createHandle(getCastNode(), (node, args) -> node.doCast(args[0])); + NodeHandle<CastNode> argCastNodeHandle = TestUtilities.createHandle(getCastNode(), (node, args) -> node.doCast(args[0]), fastRSession.getContext().getLanguage()); return argCastNodeHandle.call(a); } diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/TestUtilities.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/TestUtilities.java index 8e376cf64bbe3e43a351374b045eeccc677c3649..17af249bd3ec7505813672ff1eca0f11d8cfc6e2 100644 --- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/TestUtilities.java +++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/TestUtilities.java @@ -35,6 +35,7 @@ import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.ReturnException; +import com.oracle.truffle.r.runtime.context.TruffleRLanguage; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RNull; @@ -170,6 +171,10 @@ public class TestUtilities { return new NodeHandle<>(Truffle.getRuntime().createCallTarget(new TestRoot<>(node, invoke))); } + public static <T extends Node> NodeHandle<T> createHandle(T node, NodeAdapter<T> invoke, TruffleRLanguage language) { + return new NodeHandle<>(Truffle.getRuntime().createCallTarget(new TestRoot<>(node, invoke, language))); + } + public interface NodeAdapter<T extends Node> { Object invoke(T node, Object... args); @@ -204,7 +209,11 @@ public class TestUtilities { @Child private T node; TestRoot(T node, NodeAdapter<T> invoke) { - super(TruffleRLanguageImpl.getCurrentLanguage()); + this(node, invoke, TruffleRLanguageImpl.getCurrentLanguage()); + } + + TestRoot(T node, NodeAdapter<T> invoke, TruffleRLanguage language) { + super(language); this.node = node; this.invoke = invoke; } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java index 11d21398eea17528bccbe66516ea56d603fcd9d3..cccb20e1576e02a78889ca6a505f5de09275aabc 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java @@ -93,6 +93,8 @@ final class CachedReplaceVectorNode extends CachedVectorNode { private final RType castType; private final boolean updatePositionNames; + private final boolean isValueGt1; + @Child private WriteIndexedVectorNode writeVectorNode; @Child private PositionsCheckNode positionsCheckNode; @Child private CastNode castVectorNode; @@ -100,7 +102,7 @@ final class CachedReplaceVectorNode extends CachedVectorNode { @Child private DeleteElementsNode deleteElementsNode; @Child private SetNamesAttributeNode setNamesNode; - CachedReplaceVectorNode(ElementAccessMode mode, RTypedValue vector, Object[] positions, Class<?> valueClass, RType valueType, boolean updatePositionNames, boolean recursive) { + CachedReplaceVectorNode(ElementAccessMode mode, RTypedValue vector, Object[] positions, Class<?> valueClass, RType valueType, boolean updatePositionNames, boolean recursive, boolean isValueGt1) { super(mode, vector, positions, recursive); if (numberOfDimensions == 1 && positions[0] instanceof String || positions[0] instanceof RAbstractStringVector) { @@ -112,6 +114,7 @@ final class CachedReplaceVectorNode extends CachedVectorNode { this.vectorClass = vector.getClass(); this.valueClass = valueClass; this.valueType = valueType; + this.isValueGt1 = isValueGt1; this.castType = resolveCastVectorType(); verifyCastType(this.castType); this.castVectorNode = createCastVectorNode(); @@ -124,9 +127,13 @@ final class CachedReplaceVectorNode extends CachedVectorNode { } } + public static boolean isValueLengthGreaterThanOne(Object values) { + return (values instanceof RAbstractContainer) && ((RAbstractContainer) values).getLength() > 1; + } + public boolean isSupported(Object target, Object[] positions, Object values) { if (vectorClass == target.getClass() && values.getClass() == valueClass) { - return positionsCheckNode.isSupported(positions); + return positionsCheckNode.isSupported(positions) && isValueLengthGreaterThanOne(values) == isValueGt1; } return false; } @@ -394,7 +401,7 @@ final class CachedReplaceVectorNode extends CachedVectorNode { return RType.maxPrecedence(value, vector); } else if (vector.isNull() || value.isNull()) { if (!value.isNull()) { - return (mode == ElementAccessMode.FIELD_SUBSCRIPT) ? RType.List : value; + return (mode == ElementAccessMode.FIELD_SUBSCRIPT || (mode == ElementAccessMode.SUBSCRIPT && isValueGt1)) ? RType.List : value; } if (mode.isSubscript() && numberOfDimensions > 1) { return null; @@ -562,7 +569,7 @@ final class CachedReplaceVectorNode extends CachedVectorNode { } if (copyPositionNames == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - copyPositionNames = insert(new CachedReplaceVectorNode(mode, names, positions, positionNames.getClass(), positionNames.getRType(), false, recursive)); + copyPositionNames = insert(new CachedReplaceVectorNode(mode, names, positions, positionNames.getClass(), positionNames.getRType(), false, recursive, positionNames.getLength() > 1)); } assert copyPositionNames.isSupported(names, positions, positionNames); RAbstractStringVector newNames = (RAbstractStringVector) copyPositionNames.apply(names, positions, positionNames); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java index 574f7f314cfd6b4f65c91fb6ec1eb0124a3ca073..ed182a5496d8539394c85901ec2339461133dba0 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java @@ -44,6 +44,7 @@ import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RTypedValue; +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.RAbstractListVector; @@ -187,7 +188,7 @@ public abstract class ReplaceVectorNode extends RBaseNode { protected static CachedReplaceVectorNode createDefaultCached(ReplaceVectorNode node, Object vector, Object[] positions, Object value) { return new CachedReplaceVectorNode(node.mode, (RTypedValue) vector, positions, value.getClass(), RRuntime.isForeignObject(value) ? RType.TruffleObject : ((RTypedValue) value).getRType(), true, - node.recursive); + node.recursive, CachedReplaceVectorNode.isValueLengthGreaterThanOne(value)); } public ElementAccessMode getMode() { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/HasAttributesNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/HasAttributesNode.java new file mode 100644 index 0000000000000000000000000000000000000000..a544ed3f278df0d6eaf62a15947fe7ec67e2f792 --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/HasAttributesNode.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 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 + * 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.nodes.attributes; + +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.object.DynamicObject; +import com.oracle.truffle.api.profiles.ConditionProfile; +import com.oracle.truffle.api.profiles.ValueProfile; +import com.oracle.truffle.r.runtime.data.RAttributable; +import com.oracle.truffle.r.runtime.data.RAttributeStorage; +import com.oracle.truffle.r.runtime.nodes.RBaseNode; + +public abstract class HasAttributesNode extends RBaseNode { + + public abstract boolean execute(Object attrs); + + public static HasAttributesNode create() { + return HasAttributesNodeGen.create(); + } + + @Specialization + protected boolean handleAttributable(RAttributable x, + @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile, + @Cached("createClassProfile()") ValueProfile xTypeProfile) { + + DynamicObject attributes; + if (attrStorageProfile.profile(x instanceof RAttributeStorage)) { + attributes = ((RAttributeStorage) x).getAttributes(); + } else { + attributes = xTypeProfile.profile(x).getAttributes(); + } + + return attributes != null; + } + + @Fallback + protected boolean handleOthers(@SuppressWarnings("unused") Object x) { + return false; + } + +} 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 829d3bfebe2c171fb20927bb0645d789cb039a06..fed424a0076766d9532b3acf99d78fd3069e910a 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 @@ -21970,6 +21970,13 @@ NULL A 1 3 B 2 4 +##com.oracle.truffle.r.test.builtins.TestBuiltin_dimnamesassign.testDimnamesElementAssign# +#{ x<-matrix(12,3,4); dimnames(x)[[2]]<-c('a','b','c','d'); x } + a b c d +[1,] 12 12 12 12 +[2,] 12 12 12 12 +[3,] 12 12 12 12 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_dimnamesassign.testdimnamesassign1# #argv <- list(structure(c(300, 3000, 400, 4000), .Dim = c(2L, 2L, 1L), .Dimnames = list(c('happy', 'sad'), NULL, '')), value = list(c('happy', 'sad'), NULL, ''));`dimnames<-`(argv[[1]],argv[[2]]); , , @@ -22593,7 +22600,7 @@ NULL ##com.oracle.truffle.r.test.builtins.TestBuiltin_dqr.testdqrqty# -#.Fortran(.F_dqrqty, 1, 1L, 1L, 1, 1, 1L, 1) +#.Fortran(.F_dqrqty, 1, 1L, 1L, 1, 1, 1L, qty=1) [[1]] [1] 1 @@ -22612,7 +22619,7 @@ NULL [[6]] [1] 1 -[[7]] +$qty [1] 1 @@ -24905,6 +24912,16 @@ character(0) [21] "1967" "1968" "1968" "1968" "1968" "1968" "1969" "1969" "1969" "1970" [31] "1970" "1970" "1970" "1970" "1971" "1971" "1971" "1972" "1972" +##com.oracle.truffle.r.test.builtins.TestBuiltin_formatC.testformatC15# +#.Internal(formatC(1e-15, "double", 1L, 6L, "g", "", 12)) +[1] "1e-15" + +##com.oracle.truffle.r.test.builtins.TestBuiltin_formatC.testformatC15# +#y <- structure(c(2, 14.1776856316985), .Dim = c(2L, 1L), .Dimnames = list(c("m.ship.expon.", "objective"), " ")); formatC(y, digits = 6) + +m.ship.expon. " 2" +objective "14.1777" + ##com.oracle.truffle.r.test.builtins.TestBuiltin_formatC.testformatC2#Ignored.ImplementationError# #argv <- list(1, 'double', 8, 5, 'g', '-', 13); .Internal(formatC(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]])) [1] "1 " @@ -43870,6 +43887,10 @@ character(0) #{ paste(1:2, 1:3, FALSE, collapse=NULL) } [1] "1 1 FALSE" "2 2 FALSE" "1 3 FALSE" +##com.oracle.truffle.r.test.builtins.TestBuiltin_paste.testPaste# +#{ paste(NULL, list(), sep = "=") } +character(0) + ##com.oracle.truffle.r.test.builtins.TestBuiltin_paste.testPaste# #{ paste(character(0),31415) } [1] " 31415" @@ -63981,6 +64002,14 @@ Error in signif(42.1234, character()) : [,1] [,2] [1,] 40 42 +##com.oracle.truffle.r.test.builtins.TestBuiltin_signif.testSignif# +#{ signif(8.125, 3) } +[1] 8.12 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_signif.testSignif# +#{ signif(8.175, 3) } +[1] 8.18 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_signif.testSignif# #{ signif(c(42.1234, 7.1234), 1) } [1] 40 7 @@ -69324,6 +69353,13 @@ integer(0) [,1] [,2] [,3] [,4] [1,] 01 02 03 04 +##com.oracle.truffle.r.test.builtins.TestBuiltin_t.testTranspose# +#t(matrix(1:6, 3, 2, dimnames=list(x=c("x1","x2","x3"),y=c("y1","y2")))) + x +y x1 x2 x3 + y1 1 2 3 + y2 4 5 6 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_t.testTranspose# #t(new.env()) Error in t.default(new.env()) : argument is not a matrix @@ -73360,6 +73396,14 @@ Error in match.fun(FUN) : '42' is not a function, character or symbol Error in vapply(quote(a), function(x) quote(b), quote(a)) : 'FUN.VALUE' must be a vector +##com.oracle.truffle.r.test.builtins.TestBuiltin_vapply.testVapplyNames# +#{ a <- vapply(list(a=1:20,b=1:20), function (x) x, FUN.VALUE=1:20); attributes(a); a[1:5] } +[1] 1 2 3 4 5 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_vapply.testVapplyNames# +#{ b <- list(a=structure(c(1:3), names=c('x','y')),b=structure(c(1:3), names=c('x2','y2','z2'))); a <- vapply(b, function (x) x, FUN.VALUE=1:3); attributes(a); a[1:5] } +[1] 1 2 3 1 2 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_vector.testVectorConstructor# #{ vector("numeric", c(7, 42)) } Error in vector("numeric", c(7, 42)) : invalid 'length' argument @@ -88198,6 +88242,14 @@ NULL #{ (0-5):(0-9) } [1] -5 -6 -7 -8 -9 +##com.oracle.truffle.r.test.library.base.TestSimpleSequences.testSequenceConstruction# +#{ (0/0):(0/0) } +Error in (0/0):(0/0) : NA/NaN argument + +##com.oracle.truffle.r.test.library.base.TestSimpleSequences.testSequenceConstruction# +#{ (0/0):1L } +Error in (0/0):1L : NA/NaN argument + ##com.oracle.truffle.r.test.library.base.TestSimpleSequences.testSequenceConstruction# #{ (1:3):(1:3) } [1] 1 @@ -88213,6 +88265,34 @@ Warning messages: Warning message: In (1:3):3 : numerical expression has 3 elements: only the first used +##com.oracle.truffle.r.test.library.base.TestSimpleSequences.testSequenceConstruction# +#{ -Inf:0 } +Error in -Inf:0 : result would be too long a vector + +##com.oracle.truffle.r.test.library.base.TestSimpleSequences.testSequenceConstruction# +#{ -Inf:0L } +Error in -Inf:0L : result would be too long a vector + +##com.oracle.truffle.r.test.library.base.TestSimpleSequences.testSequenceConstruction# +#{ -Inf:Inf } +Error in -Inf:Inf : result would be too long a vector + +##com.oracle.truffle.r.test.library.base.TestSimpleSequences.testSequenceConstruction# +#{ 0:-Inf } +Error in 0:-Inf : result would be too long a vector + +##com.oracle.truffle.r.test.library.base.TestSimpleSequences.testSequenceConstruction# +#{ 0:Inf } +Error in 0:Inf : result would be too long a vector + +##com.oracle.truffle.r.test.library.base.TestSimpleSequences.testSequenceConstruction# +#{ 0L:-Inf } +Error in 0L:-Inf : result would be too long a vector + +##com.oracle.truffle.r.test.library.base.TestSimpleSequences.testSequenceConstruction# +#{ 0L:Inf } +Error in 0L:Inf : result would be too long a vector + ##com.oracle.truffle.r.test.library.base.TestSimpleSequences.testSequenceConstruction# #{ 1.1:3.1 } [1] 1.1 2.1 3.1 @@ -88260,6 +88340,10 @@ Error in 1:NA : NA/NaN argument #{ 1L:(0-10) } [1] 1 0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 +##com.oracle.truffle.r.test.library.base.TestSimpleSequences.testSequenceConstruction# +#{ 1L:(0/0) } +Error in 1L:(0/0) : NA/NaN argument + ##com.oracle.truffle.r.test.library.base.TestSimpleSequences.testSequenceConstruction# #{ 3.1:1 } [1] 3.1 2.1 1.1 diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_dimnamesassign.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_dimnamesassign.java index f592d11f570e6158b74a8d0baa19023e79463866..38c358a69d3f396ccfdde6201cc6ac9a0ebdf000 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_dimnamesassign.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_dimnamesassign.java @@ -4,7 +4,7 @@ * http://www.gnu.org/licenses/gpl-2.0.html * * Copyright (c) 2014, Purdue University - * Copyright (c) 2014, 2016, Oracle and/or its affiliates + * Copyright (c) 2014, 2017, Oracle and/or its affiliates * * All rights reserved. */ @@ -96,4 +96,10 @@ public class TestBuiltin_dimnamesassign extends TestBase { public void testDimnamesAssign() { assertEval("{ x<-data.frame(c(1,2),c(3,4)); dimnames(x) <- list(c(\"A\", \"B\"), c(\"C\", \"D\")); x }"); } + + @Test + public void testDimnamesElementAssign() { + assertEval("{ x<-matrix(12,3,4); dimnames(x)[[2]]<-c('a','b','c','d'); x }"); + } + } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_dqr.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_dqr.java index 52ea765150439641f423f22685c404be835fa265..20fbc5bba758da0032fc387b4528b797258e17af 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_dqr.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_dqr.java @@ -41,7 +41,7 @@ public class TestBuiltin_dqr extends TestBase { @Test public void testdqrqty() { - assertEval(".Fortran(.F_dqrqty, 1, 1L, 1L, 1, 1, 1L, 1)"); + assertEval(".Fortran(.F_dqrqty, 1, 1L, 1L, 1, 1, 1L, qty=1)"); } @Test diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_formatC.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_formatC.java index 23276863358730e81aaf2c0afdfbdc7958683694..1561f3af525bd440117f11f77950f755c7d0cad9 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_formatC.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_formatC.java @@ -97,4 +97,11 @@ public class TestBuiltin_formatC extends TestBase { assertEval(Ignored.ReferenceError, "argv <- list(structure(c(1962.25, 1962.5, 1962.75, 1963, 1963.25, 1963.5, 1963.75, 1964, 1964.25, 1964.5, 1964.75, 1965, 1965.25, 1965.5, 1965.75, 1966, 1966.25, 1966.5, 1966.75, 1967, 1967.25, 1967.5, 1967.75, 1968, 1968.25, 1968.5, 1968.75, 1969, 1969.25, 1969.5, 1969.75, 1970, 1970.25, 1970.5, 1970.75, 1971, 1971.25, 1971.5, 1971.75), .Tsp = c(1962.25, 1971.75, 4), class = 'ts'), 'double', 1, 4L, 'g', '', c(12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L, 12L)); .Internal(formatC(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]]))"); } + + @Test + public void testformatC15() { + assertEval(".Internal(formatC(1e-15, \"double\", 1L, 6L, \"g\", \"\", 12))"); + assertEval("y <- structure(c(2, 14.1776856316985), .Dim = c(2L, 1L), .Dimnames = list(c(\"m.ship.expon.\", \"objective\"), \" \")); formatC(y, digits = 6)"); + } + } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_paste.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_paste.java index 15183cd6f32c514481cd5d217b543b0ca0f95b49..d132fb4543837fdb1a9e3780fe62cf6172a86b2c 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_paste.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_paste.java @@ -80,6 +80,7 @@ public class TestBuiltin_paste extends TestBase { assertEval("{ paste(1:2, 1:3, FALSE, collapse=NULL) }"); assertEval("{ paste(sep=\"\") }"); assertEval("{ paste(1:2, 1:3, FALSE, collapse=\"-\", sep=\"+\") }"); + assertEval("{ paste(NULL, list(), sep = \"=\") }"); } @Test diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_signif.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_signif.java index 70108c51e81a1fb5c6fe5c2ea21c00c3362e4906..69ae9275e75aff15c5422f9aab77dc8bd2f15432 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_signif.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_signif.java @@ -26,6 +26,8 @@ public class TestBuiltin_signif extends TestBase { @Test public void testSignif() { + assertEval("{ signif(8.175, 3) }"); + assertEval("{ signif(8.125, 3) }"); assertEval("{ signif(0.555, 2) }"); assertEval("{ signif(0.5549, 2) }"); assertEval("{ signif(0.5551, 2) }"); diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_t.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_t.java index 693cde32eb6e252583908b569377a1a8b142a8c2..b4640e1d0567158ad6dba2e8ccfc5be46df9f85a 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_t.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_t.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. */ @@ -46,5 +46,6 @@ public class TestBuiltin_t extends TestBase { assertEval("t(1)"); assertEval("t(TRUE)"); assertEval("t(as.raw(c(1,2,3,4)))"); + assertEval("t(matrix(1:6, 3, 2, dimnames=list(x=c(\"x1\",\"x2\",\"x3\"),y=c(\"y1\",\"y2\"))))"); } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_vapply.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_vapply.java index 931015c40709bdd2df477a7f1e4382553d67ffda..c171773a5fce99766a9cde7e06727872a7d4e1a1 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_vapply.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_vapply.java @@ -53,4 +53,10 @@ public class TestBuiltin_vapply extends TestBase { assertEval("{ m <- matrix(c(1,2,3,4,5,6),2) ; apply(m,1,sum) }"); assertEval("{ m <- matrix(c(1,2,3,4,5,6),2) ; apply(m,2,sum) }"); } + + @Test + public void testVapplyNames() { + assertEval("{ a <- vapply(list(a=1:20,b=1:20), function (x) x, FUN.VALUE=1:20); attributes(a); a[1:5] }"); + assertEval("{ b <- list(a=structure(c(1:3), names=c('x','y')),b=structure(c(1:3), names=c('x2','y2','z2'))); a <- vapply(b, function (x) x, FUN.VALUE=1:3); attributes(a); a[1:5] }"); + } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java index 4770f9db91ca6638f2420d9d40ecc05c4d39e5fc..a7e587dc0f6b8f43d74dd648b94a61612aac4375 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java @@ -147,6 +147,10 @@ public final class FastRSession implements RSession { decoder.onUnmappableCharacter(CodingErrorAction.IGNORE); } + public RContext getContext() { + return mainContext; + } + private String readLine() { /* * We cannot use an InputStreamReader because it buffers characters internally, whereas diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleSequences.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleSequences.java index dc4f1bdb0eade007de69ea3e2e28451cddeddc05..dda6158cb7604e1193f49c88d630f0b26fed4900 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleSequences.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleSequences.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -53,6 +53,16 @@ public class TestSimpleSequences extends TestBase { assertEval("{ 1:(1:3) }"); assertEval("{ (1:3):3 }"); assertEval("{ (1:3):(1:3) }"); + assertEval("{ 0L:Inf }"); + assertEval("{ 0L:-Inf }"); + assertEval("{ -Inf:0L }"); + assertEval("{ -Inf:Inf }"); + assertEval("{ 0:Inf }"); + assertEval("{ 0:-Inf }"); + assertEval("{ -Inf:0 }"); + assertEval("{ 1L:(0/0) }"); + assertEval("{ (0/0):1L }"); + assertEval("{ (0/0):(0/0) }"); } @Test