From 4c5a43e2d5ef0dcf98eb098c7beeafb4725f0778 Mon Sep 17 00:00:00 2001
From: stepan <stepan.sindelar@oracle.com>
Date: Fri, 21 Jul 2017 12:41:47 +0200
Subject: [PATCH] Implement RFFI inlined length for REnvironment + tests

---
 .../truffle/r/ffi/impl/nodes/MiscNodes.java   | 11 ++++++++++
 .../fficall/src/common/inlined_fastr.c        | 20 +++++++++----------
 com.oracle.truffle.r.native/version.source    |  2 +-
 .../packages/testrffi/testrffi/R/testrffi.R   |  4 ++++
 .../packages/testrffi/testrffi/src/init.c     |  1 +
 .../packages/testrffi/testrffi/src/testrffi.c |  4 ++++
 .../packages/testrffi/testrffi/src/testrffi.h |  2 ++
 .../testrffi/testrffi/tests/simpleTests.R     | 17 ++++++++++++++++
 8 files changed, 50 insertions(+), 11 deletions(-)

diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MiscNodes.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MiscNodes.java
index 802b9db6f9..edcb77b445 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MiscNodes.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MiscNodes.java
@@ -23,9 +23,11 @@
 package com.oracle.truffle.r.ffi.impl.nodes;
 
 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.Specialization;
 import com.oracle.truffle.api.dsl.TypeSystemReference;
+import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.access.AccessSlotNode;
 import com.oracle.truffle.r.nodes.access.AccessSlotNodeGen;
 import com.oracle.truffle.r.nodes.access.UpdateSlotNode;
@@ -38,6 +40,7 @@ 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.env.REnvironment;
 import com.oracle.truffle.r.runtime.ffi.CharSXPWrapper;
 import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
 
@@ -82,6 +85,14 @@ public final class MiscNodes {
             return obj.getLength();
         }
 
+        @Specialization
+        protected int length(REnvironment env,
+                        @Cached("createClassProfile()") ValueProfile frameAccessProfile) {
+            // May seem wasteful of resources, but simple env.getFrame().getDescriptor().getSize()
+            // is not correct!
+            return env.ls(true, null, false).getLength();
+        }
+
         @Specialization
         protected int length(RArgsValuesAndNames obj) {
             return obj.getLength();
diff --git a/com.oracle.truffle.r.native/fficall/src/common/inlined_fastr.c b/com.oracle.truffle.r.native/fficall/src/common/inlined_fastr.c
index 48cab27362..4d6ac072c5 100644
--- a/com.oracle.truffle.r.native/fficall/src/common/inlined_fastr.c
+++ b/com.oracle.truffle.r.native/fficall/src/common/inlined_fastr.c
@@ -35,7 +35,7 @@ INLINE_FUN R_len_t length(SEXP s)
     int i;
     switch (TYPEOF(s)) {
     case NILSXP:
-	return 0;
+        return 0;
     case LGLSXP:
     case INTSXP:
     case REALSXP:
@@ -46,13 +46,14 @@ INLINE_FUN R_len_t length(SEXP s)
     case EXPRSXP:
     case RAWSXP:
     case DOTSXP:
-	return LENGTH(s);
+    case ENVSXP:
     case LISTSXP:
     case LANGSXP:
-    case ENVSXP:
-	return Rf_envlength(s);
+        // Note: all these types should have specialization in MiscNodes$LENGTHNode
+        return LENGTH(s);
     default:
-	return 1;
+        // e.g. SYMSXP (symbol), CLOSXP (closure)
+        return 1;
     }
 }
 
@@ -61,7 +62,7 @@ INLINE_FUN R_xlen_t xlength(SEXP s)
     int i;
     switch (TYPEOF(s)) {
     case NILSXP:
-	return 0;
+        return 0;
     case LGLSXP:
     case INTSXP:
     case REALSXP:
@@ -72,13 +73,12 @@ INLINE_FUN R_xlen_t xlength(SEXP s)
     case EXPRSXP:
     case RAWSXP:
     case DOTSXP:
-	return XLENGTH(s);
+    case ENVSXP:
     case LISTSXP:
     case LANGSXP:
-    case ENVSXP:
-	return Rf_envlength(s);
+        return XLENGTH(s);
     default:
-	return 1;
+        return 1;
     }
 }
 
diff --git a/com.oracle.truffle.r.native/version.source b/com.oracle.truffle.r.native/version.source
index 64bb6b746d..f5c89552bd 100644
--- a/com.oracle.truffle.r.native/version.source
+++ b/com.oracle.truffle.r.native/version.source
@@ -1 +1 @@
-30
+32
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R
index b10b83725e..a5783eb3aa 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R
@@ -153,6 +153,10 @@ rffi.LENGTH <- function(x) {
 	.Call("test_LENGTH", x)
 }
 
+rffi.inlined_length <- function(x) {
+    .Call("test_inlined_length", x)
+}
+
 rffi.coerceVector <- function(x, mode) {
 	.Call("test_coerceVector", x, mode)
 }
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/init.c b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/init.c
index ca91702c5e..e47d7a69e8 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/init.c
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/init.c
@@ -71,6 +71,7 @@ static const R_CallMethodDef CallEntries[] = {
         CALLDEF(test_CAR, 1),
         CALLDEF(test_CDR, 1),
         CALLDEF(test_LENGTH, 1),
+        CALLDEF(test_inlined_length, 1),
         CALLDEF(test_coerceVector, 2),
         CALLDEF(test_ATTRIB, 1),
         CALLDEF(test_stringNA, 0),
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c
index 28ab2aed24..0721954ee0 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c
@@ -318,6 +318,10 @@ SEXP test_LENGTH(SEXP x) {
 	return ScalarInteger(LENGTH(x));
 }
 
+SEXP test_inlined_length(SEXP x) {
+    return ScalarInteger(length(x));
+}
+
 SEXP test_coerceVector(SEXP x, SEXP mode) {
     int intMode = INTEGER_VALUE(mode);
     return Rf_coerceVector(x, intMode);
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.h b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.h
index 981df927da..3570fbd380 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.h
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.h
@@ -86,6 +86,8 @@ extern SEXP test_CDR(SEXP x);
 
 extern SEXP test_LENGTH(SEXP x);
 
+extern SEXP test_inlined_length(SEXP x);
+
 extern SEXP test_coerceVector(SEXP x, SEXP mode);
 
 extern SEXP test_ATTRIB(SEXP);
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/tests/simpleTests.R b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/tests/simpleTests.R
index b378a50ecf..8d8dceb5b0 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/tests/simpleTests.R
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/tests/simpleTests.R
@@ -42,3 +42,20 @@ bar <- function() rffi.captureDotsWithSingleElement(parent.frame())
 promiseInfo <- foo(tmp)
 stopifnot('some_unique_name' %in% ls(promiseInfo[[2]]))
 eval(promiseInfo[[1]], promiseInfo[[2]])
+
+# legth tests
+env <- new.env(); env$a <- 42; env$b <- 44;
+rffi.inlined_length(env)
+rffi.inlined_length(c(1,2,3))
+rffi.inlined_length(list(a = 1, b = 42))
+rffi.inlined_length(as.pairlist(c(1,2,3,4,5)))
+expr <- expression(x + y, 3)
+rffi.inlined_length(expr)
+rffi.inlined_length(expr[[1]])
+
+# fails in FastR because DotCall class cannot recognize that the RArgsValuesAndNames
+# are not meant to be extracted into individual arguments, but instead send as is 
+# to the native function as SEXP
+#
+# foo <-function(...) rffi.inlined_length(get('...'))
+# foo(a = 1, b = 2, c = 3, d = 42)
-- 
GitLab