Skip to content

Commit 9880d66

Browse files
committed
[GR-10977] [GR-10799] Unify possible results of R2Foreign.
PullRequest: fastr/1610
2 parents f661064 + 402b5a1 commit 9880d66

File tree

25 files changed

+379
-104
lines changed

25 files changed

+379
-104
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,17 @@
11

2+
# 1.0 RC 5
3+
4+
Updates in interop:
5+
6+
* R code evaluated via interop never returns a Java primitive type, but always a vector
7+
* Vectors of size 1 that do not contain NA can be unboxed
8+
* Sending the READ message to an atomic R vector (array subscript in most languages) gives
9+
* Java primitive type as long as the value is not `NA`
10+
* a special value that responds to `IS_NULL` with `true`. If this value is passed back to R it behaves as `NA` again
11+
* Note that sending the READ message to a list, environment, or other heterogenous data structure never gives atomic Java type but a primitive R vector
12+
13+
# 1.0 RC 4
14+
215
# 1.0 RC 3
316

417
Added missing R builtins and C API

com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/EngineRootNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class EngineRootNode extends RootNode {
5858
private final ContextReference<RContext> contextReference;
5959

6060
@Child private EngineBodyNode bodyNode;
61-
@Child private R2Foreign r2Foreign = R2ForeignNodeGen.create();
61+
@Child private R2Foreign r2Foreign = R2Foreign.create();
6262

6363
EngineRootNode(EngineBodyNode bodyNode, RContext context, SourceSection sourceSection, MaterializedFrame executionFrame) {
6464
super(context.getLanguage());

com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ListMR.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ protected ListKeyInfoImplNode createKeyInfoNode() {
395395
private void initR2ForeignNode() {
396396
if (r2Foreign == null) {
397397
CompilerDirectives.transferToInterpreterAndInvalidate();
398-
r2Foreign = insert(R2ForeignNodeGen.create());
398+
r2Foreign = insert(R2Foreign.create());
399399
}
400400
}
401401

com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RAbstractVectorAccessFactory.java

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,14 @@
5151
import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode;
5252
import com.oracle.truffle.r.nodes.access.vector.ReplaceVectorNode;
5353
import com.oracle.truffle.r.nodes.access.vector.ReplaceVectorNodeGen;
54+
import com.oracle.truffle.r.nodes.builtin.base.IsNA;
55+
import com.oracle.truffle.r.nodes.builtin.base.IsNANodeGen;
5456
import com.oracle.truffle.r.nodes.control.RLengthNode;
5557
import com.oracle.truffle.r.runtime.RRuntime;
5658
import com.oracle.truffle.r.runtime.data.NativeDataAccess;
5759
import com.oracle.truffle.r.runtime.data.RLogical;
5860
import com.oracle.truffle.r.runtime.data.RRaw;
5961
import com.oracle.truffle.r.runtime.data.RScalar;
60-
import com.oracle.truffle.r.runtime.data.RString;
6162
import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector;
6263
import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
6364
import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
@@ -79,6 +80,9 @@ public final SourceSection getSourceSection() {
7980
}
8081
}
8182

83+
/**
84+
* Implements interop messages for all {@link RAbstractAtomicVector} subclasses.
85+
*/
8286
public final class RAbstractVectorAccessFactory implements StandardFactory {
8387

8488
abstract static class VectorReadImplNode extends InteropRootNode {
@@ -127,7 +131,7 @@ private Object read(Object receiver, Object[] positions) {
127131
Object value = extract.apply(receiver, positions, RLogical.TRUE, RLogical.TRUE);
128132
if (r2Foreign == null) {
129133
CompilerDirectives.transferToInterpreterAndInvalidate();
130-
r2Foreign = insert(R2ForeignNodeGen.create());
134+
r2Foreign = insert(R2Foreign.createNoBox());
131135
}
132136
return r2Foreign.execute(value);
133137
}
@@ -324,26 +328,23 @@ public Object execute(VirtualFrame frame) {
324328
@Override
325329
public CallTarget accessIsBoxed() {
326330
return Truffle.getRuntime().createCallTarget(new InteropRootNode() {
331+
@Child IsNA isNANode = IsNANodeGen.create();
332+
private final ConditionProfile isEmpty = ConditionProfile.createBinaryProfile();
333+
327334
@Override
328335
public Object execute(VirtualFrame frame) {
329336
RAbstractVector arg = (RAbstractVector) ForeignAccess.getReceiver(frame);
330-
return arg.getLength() == 1 && isUnBoxable(arg);
337+
if (isEmpty.profile(arg.getLength() == 0)) {
338+
return false;
339+
}
340+
Object o = arg.getDataAtAsObject(0);
341+
return arg.getLength() == 1 && !isNA(isNANode, o);
331342
}
332343
});
333344
}
334345

335-
private static boolean isUnBoxable(RAbstractVector vector) {
336-
Object o = vector.getDataAtAsObject(0);
337-
return isPrimitive(o);
338-
}
339-
340-
private static boolean isPrimitive(Object element) {
341-
if (element == null) {
342-
return false;
343-
}
344-
final Class<?> elementType = element.getClass();
345-
return elementType == String.class || elementType == Character.class || elementType == Boolean.class || elementType == Byte.class || elementType == Short.class ||
346-
elementType == Integer.class || elementType == Long.class || elementType == Float.class || elementType == Double.class;
346+
private static boolean isNA(IsNA isNANode, Object value) {
347+
return RRuntime.fromLogical((Byte) isNANode.execute(value));
347348
}
348349

349350
@Override
@@ -382,14 +383,21 @@ public Object execute(VirtualFrame frame) {
382383
@Override
383384
public CallTarget accessUnbox() {
384385
return Truffle.getRuntime().createCallTarget(new InteropRootNode() {
386+
@Child IsNA isNANode = IsNANodeGen.create();
387+
private final ConditionProfile isLogical = ConditionProfile.createBinaryProfile();
388+
385389
@Override
386390
public Object execute(VirtualFrame frame) {
387391
RAbstractVector arg = (RAbstractVector) ForeignAccess.getReceiver(frame);
388392
if (arg.getLength() == 1) {
389-
return arg.getDataAtAsObject(0);
390-
} else {
391-
throw UnsupportedMessageException.raise(Message.UNBOX);
393+
Object value = arg.getDataAtAsObject(0);
394+
if (isLogical.profile(arg instanceof RAbstractLogicalVector)) {
395+
return RLogicalMR.unboxLogical((Byte) value);
396+
} else if (!isNA(isNANode, value)) {
397+
return value;
398+
}
392399
}
400+
throw UnsupportedMessageException.raise(Message.UNBOX);
393401
}
394402
});
395403
}

com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RArgsValuesAndNamesMR.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ protected static boolean test(TruffleObject receiver) {
120120
}
121121

122122
abstract static class RArgsValuesAndNamesReadImplNode extends Node {
123-
@Child private R2Foreign r2Foreign = R2ForeignNodeGen.create();
123+
@Child private R2Foreign r2Foreign = R2Foreign.create();
124124

125125
private final ConditionProfile unknownIdentifier = ConditionProfile.createBinaryProfile();
126126

com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/REnvironmentMR.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ protected REnvironmentKeyInfoImplNode createKeyInfoNode() {
164164
private void initR2ForeignNode() {
165165
if (r2Foreign == null) {
166166
CompilerDirectives.transferToInterpreterAndInvalidate();
167-
r2Foreign = insert(R2ForeignNodeGen.create());
167+
r2Foreign = insert(R2Foreign.create());
168168
}
169169
}
170170

com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RForeignAccessFactoryImpl.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import com.oracle.truffle.r.runtime.data.RFunction;
3939
import com.oracle.truffle.r.runtime.data.RInteger;
4040
import com.oracle.truffle.r.runtime.data.RInteropScalar;
41+
import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropNA;
4142
import com.oracle.truffle.r.runtime.data.RPairList;
4243
import com.oracle.truffle.r.runtime.data.RList;
4344
import com.oracle.truffle.r.runtime.data.RLogical;
@@ -118,6 +119,8 @@ public ForeignAccess getForeignAccess(RTruffleObject obj) {
118119
return RMissingMRForeign.ACCESS;
119120
} else if (obj instanceof REmpty) {
120121
return REmptyMRForeign.ACCESS;
122+
} else if (obj instanceof RInteropNA) {
123+
return RInteropNAMRForeign.ACCESS;
121124
} else if (obj instanceof RAbstractAtomicVector) {
122125
return ForeignAccess.create(new RAbstractVectorAccessFactory(), new RAbstractVectorAccessFactory.Check());
123126
} else {

com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RFunctionMR.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ protected Object access(@SuppressWarnings("unused") RFunction receiver) {
5959
@Resolve(message = "EXECUTE")
6060
public abstract static class RFunctionExecuteNode extends Node {
6161
@Child private Foreign2R foreign2R = Foreign2RNodeGen.create();
62-
@Child private R2Foreign r2Foreign = R2ForeignNodeGen.create();
62+
@Child private R2Foreign r2Foreign = R2Foreign.create();
6363
@Child private RExplicitCallNode call = RExplicitCallNode.create();
6464

6565
protected Object access(RFunction receiver, Object[] arguments) {
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 3 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 3 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 3 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package com.oracle.truffle.r.engine.interop;
24+
25+
import com.oracle.truffle.api.interop.CanResolve;
26+
import com.oracle.truffle.api.interop.MessageResolution;
27+
import com.oracle.truffle.api.interop.Resolve;
28+
import com.oracle.truffle.api.interop.TruffleObject;
29+
import com.oracle.truffle.api.nodes.Node;
30+
import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropNA;
31+
32+
@MessageResolution(receiverType = RInteropNA.class)
33+
public class RInteropNAMR {
34+
@Resolve(message = "IS_NULL")
35+
public abstract static class RInteropNAIsNullNode extends Node {
36+
protected Object access(@SuppressWarnings("unused") RInteropNA receiver) {
37+
return true;
38+
}
39+
}
40+
41+
@CanResolve
42+
public abstract static class RInteropNACheck extends Node {
43+
protected static boolean test(TruffleObject receiver) {
44+
return receiver instanceof RInteropNA;
45+
}
46+
}
47+
}

com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RLogicalMR.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,22 @@
2323
package com.oracle.truffle.r.engine.interop;
2424

2525
import com.oracle.truffle.api.interop.CanResolve;
26+
import com.oracle.truffle.api.interop.Message;
2627
import com.oracle.truffle.api.interop.MessageResolution;
2728
import com.oracle.truffle.api.interop.Resolve;
2829
import com.oracle.truffle.api.interop.TruffleObject;
30+
import com.oracle.truffle.api.interop.UnsupportedMessageException;
2931
import com.oracle.truffle.api.nodes.Node;
32+
import com.oracle.truffle.r.runtime.RRuntime;
3033
import com.oracle.truffle.r.runtime.data.RLogical;
34+
import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
3135

3236
@MessageResolution(receiverType = RLogical.class)
3337
public class RLogicalMR {
3438
@Resolve(message = "IS_BOXED")
3539
public abstract static class RLogicalIsBoxedNode extends Node {
3640
protected Object access(@SuppressWarnings("unused") RLogical receiver) {
37-
return true;
41+
return !RRuntime.isNA(receiver.getValue());
3842
}
3943
}
4044

@@ -47,8 +51,8 @@ protected Object access(@SuppressWarnings("unused") RLogical receiver, @Suppress
4751

4852
@Resolve(message = "UNBOX")
4953
public abstract static class RLogicalUnboxNode extends Node {
50-
protected byte access(RLogical receiver) {
51-
return receiver.getValue();
54+
protected Object access(RLogical receiver) {
55+
return unboxLogical(receiver.getValue());
5256
}
5357
}
5458

@@ -58,4 +62,15 @@ protected static boolean test(TruffleObject receiver) {
5862
return receiver instanceof RLogical;
5963
}
6064
}
65+
66+
public static boolean isUnboxable(byte value) {
67+
return !RRuntime.isNA(value);
68+
}
69+
70+
public static Object unboxLogical(byte value) {
71+
if (!isUnboxable(value)) {
72+
throw UnsupportedMessageException.raise(Message.UNBOX);
73+
}
74+
return RRuntime.fromLogical(value);
75+
}
6176
}

0 commit comments

Comments
 (0)