Skip to content

Commit

Permalink
Rf_allocSExp supports CLOSXP
Browse files Browse the repository at this point in the history
  • Loading branch information
steve-s committed Jan 15, 2021
1 parent de00e69 commit 544b572
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 37 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,10 @@ Bug fixes:

* `switch` builtin handles arguments properly (#171)

Added missing R builtins and C APIs:

* `Rf_allocSExp` supports `CLOSXP`

# 21.0.0

Bug fixes:
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
Expand Down Expand Up @@ -49,7 +49,12 @@ public final class FFITestsCodeGen extends CodeGenBase {
private static final String FUN_PREFIX = "api_";
private static final HashSet<String> IGNORE_FUNS = new HashSet<>(
Arrays.asList("Rf_cospi", "Rf_sinpi", "Rf_tanpi", "R_forceAndCall", "Rf_duplicate", "R_ToplevelExec", "R_CleanUp", "R_ParseVector", "octsize", "R_NewHashedEnv", "Rf_ScalarComplex",
"Rf_ScalarRaw", "Rf_allocList", "Rf_allocSExp", "DispatchPRIMFUN", "COMPLEX_ELT"));
"Rf_ScalarRaw", "Rf_allocList", "DispatchPRIMFUN", "COMPLEX_ELT", "match5" /*
* match5
* is
* not
* public
*/));

public static void main(String[] args) {
new FFITestsCodeGen().run(args);
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2021, 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
Expand All @@ -22,6 +22,16 @@
*/
package com.oracle.truffle.r.ffi.impl.common;

import static com.oracle.truffle.r.ffi.impl.common.RFFIUtils.guarantee;
import static com.oracle.truffle.r.ffi.impl.common.RFFIUtils.guaranteeInstanceOf;
import static com.oracle.truffle.r.ffi.impl.common.RFFIUtils.unimplemented;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.function.Function;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.frame.Frame;
Expand Down Expand Up @@ -117,16 +127,6 @@
import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
import com.oracle.truffle.r.runtime.rng.RRNG;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.function.Function;

import static com.oracle.truffle.r.ffi.impl.common.RFFIUtils.guarantee;
import static com.oracle.truffle.r.ffi.impl.common.RFFIUtils.guaranteeInstanceOf;
import static com.oracle.truffle.r.ffi.impl.common.RFFIUtils.unimplemented;

/**
* This class provides a simple Java-based implementation of {@link UpCallsRFFI}, where all the
* argument values are standard Java types, i.e. no special types used by Truffle NFI or Truffle
Expand Down Expand Up @@ -477,6 +477,8 @@ public Object Rf_allocSExp(int mode) {
return RDataFactory.createPairList(RNull.instance, RNull.instance);
case LANGSXP:
return RDataFactory.createPairList(1, type);
case CLOSXP:
return RDataFactory.createFunction("<unknown-from-Rf_allocSExp>", "RFFI", null, null, REnvironment.globalEnv().getFrame());
default:
throw unimplemented("unexpected SEXPTYPE " + type);
}
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2021, 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
Expand Down Expand Up @@ -31,6 +31,7 @@
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.NodeUtil;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.r.nodes.access.AccessArgumentNode;
import com.oracle.truffle.r.nodes.access.ConstantNode;
Expand Down Expand Up @@ -310,7 +311,12 @@ public static Object createFormals(RFunction fun) {
if (fun.isBuiltin()) {
return RNull.instance;
}
FunctionDefinitionNode fdNode = (FunctionDefinitionNode) fun.getTarget().getRootNode();
RootNode root = fun.getRootNode();
assert root == null || root instanceof FunctionDefinitionNode;
if (!(root instanceof FunctionDefinitionNode)) {
return RNull.instance;
}
FunctionDefinitionNode fdNode = (FunctionDefinitionNode) root;
FormalArguments formalArgs = fdNode.getFormalArguments();
Object succ = RNull.instance;
for (int i = formalArgs.getSignature().getLength() - 1; i >= 0; i--) {
Expand All @@ -325,7 +331,7 @@ public static Object createFormals(RFunction fun) {
@TruffleBoundary
public static void modifyFunction(RFunction fun, Object newBody, Object newFormals, MaterializedFrame newEnv) {
RootCallTarget target = fun.getTarget();
FunctionDefinitionNode root = (FunctionDefinitionNode) target.getRootNode();
FunctionDefinitionNode root = target != null ? (FunctionDefinitionNode) target.getRootNode() : null;

SaveArgumentsNode saveArguments;
FormalArguments formals;
Expand Down Expand Up @@ -377,16 +383,17 @@ public static void modifyFunction(RFunction fun, Object newBody, Object newForma
access.setFormals(formals);
}

RSyntaxNode bodyNode = root.getBody();
RSyntaxNode bodyNode = root != null ? root.getBody() : null;
if (newBody != null) {
bodyNode = RASTUtils.createSyntaxNodeForRValue(newBody);
}

String name = root != null ? root.getName() : "<unknown-from-SET_BODY>";
FrameDescriptor descriptor = new FrameDescriptor();
FrameSlotChangeMonitor.initializeFunctionFrameDescriptor("<SET_BODY/SET_FORMALS/SET_CLOENV>", descriptor);
FrameSlotChangeMonitor.initializeEnclosingFrame(descriptor, newEnv);
FunctionDefinitionNode rootNode = FunctionDefinitionNode.create(RContext.getInstance().getLanguage(), RSyntaxNode.LAZY_DEPARSE, descriptor, null, saveArguments, bodyNode, formals,
root.getName(), null);
name, null);
RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode);
fun.reassignTarget(callTarget);
fun.reassignEnclosingFrame(newEnv);
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2021, 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
Expand Down Expand Up @@ -44,10 +44,10 @@
import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor;
import com.oracle.truffle.r.runtime.context.RContext;
import com.oracle.truffle.r.runtime.data.RFunctionFactory.CachedExplicitCallNodeGen;
import com.oracle.truffle.r.runtime.data.RSharingAttributeStorage.Shareable;
import com.oracle.truffle.r.runtime.interop.Foreign2R;
import com.oracle.truffle.r.runtime.interop.R2Foreign;
import com.oracle.truffle.r.runtime.interop.R2ForeignNodeGen;
import com.oracle.truffle.r.runtime.data.RSharingAttributeStorage.Shareable;

/**
* An instance of {@link RFunction} represents a function defined in R. The properties of a function
Expand Down Expand Up @@ -78,7 +78,7 @@ public final class RFunction extends RSharingAttributeStorage implements Shareab
this.target = target;
this.builtin = builtin;
this.name = name;
if (!isBuiltin() && name != NO_NAME) {
if (!isBuiltin() && name != NO_NAME && target != null) {
// If we have a name, propagate it to the rootnode
RContext.getRRuntimeASTAccess().setFunctionName(getRootNode(), name);
}
Expand Down Expand Up @@ -139,7 +139,7 @@ public RootCallTarget getTarget() {
}

public RootNode getRootNode() {
return target.getRootNode();
return target != null ? target.getRootNode() : null;
}

public MaterializedFrame getEnclosingFrame() {
Expand Down
@@ -1,4 +1,4 @@
# Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2021, 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
Expand Down Expand Up @@ -57,6 +57,7 @@ api.Rf_errorcall <- function(...) .Call(C_api_Rf_errorcall, ...)
api.Rf_allocVector <- function(...) .Call(C_api_Rf_allocVector, ...)
api.Rf_allocArray <- function(...) .Call(C_api_Rf_allocArray, ...)
api.Rf_allocMatrix <- function(...) .Call(C_api_Rf_allocMatrix, ...)
api.Rf_allocSExp <- function(...) .Call(C_api_Rf_allocSExp, ...)
api.Rf_nrows <- function(...) .Call(C_api_Rf_nrows, ...)
api.Rf_ncols <- function(...) .Call(C_api_Rf_ncols, ...)
api.LENGTH <- function(...) .Call(C_api_LENGTH, ...)
Expand Down Expand Up @@ -288,7 +289,6 @@ api.Rf_namesgets <- function(...) .Call(C_api_Rf_namesgets, ...)
api.Rf_copyMostAttrib <- function(...) .Call(C_api_Rf_copyMostAttrib, ...)
api.Rf_VectorToPairList <- function(...) .Call(C_api_Rf_VectorToPairList, ...)
api.Rf_asCharacterFactor <- function(...) .Call(C_api_Rf_asCharacterFactor, ...)
api.Rf_match <- function(...) .Call(C_api_Rf_match, ...)
api.Rf_NonNullStringMatch <- function(...) .Call(C_api_Rf_NonNullStringMatch, ...)
api.R_has_slot <- function(...) .Call(C_api_R_has_slot, ...)
api.Rf_PrintValue <- function(...) .Call(C_api_Rf_PrintValue, ...)
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
Expand Down Expand Up @@ -62,6 +62,7 @@ CALLDEF(api_Rf_errorcall, 2),
CALLDEF(api_Rf_allocVector, 2),
CALLDEF(api_Rf_allocArray, 2),
CALLDEF(api_Rf_allocMatrix, 3),
CALLDEF(api_Rf_allocSExp, 1),
CALLDEF(api_Rf_nrows, 1),
CALLDEF(api_Rf_ncols, 1),
CALLDEF(api_LENGTH, 1),
Expand Down Expand Up @@ -293,7 +294,6 @@ CALLDEF(api_Rf_namesgets, 2),
CALLDEF(api_Rf_copyMostAttrib, 2),
CALLDEF(api_Rf_VectorToPairList, 1),
CALLDEF(api_Rf_asCharacterFactor, 1),
CALLDEF(api_Rf_match, 3),
CALLDEF(api_Rf_NonNullStringMatch, 2),
CALLDEF(api_R_has_slot, 2),
CALLDEF(api_Rf_PrintValue, 1),
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
Expand Down Expand Up @@ -189,6 +189,10 @@ SEXP api_Rf_allocMatrix(SEXP mode, SEXP nrow, SEXP ncol) {
return Rf_allocMatrix(INTEGER_VALUE(mode), INTEGER_VALUE(nrow), INTEGER_VALUE(ncol));
}

SEXP api_Rf_allocSExp(SEXP type) {
return Rf_allocSExp(INTEGER_VALUE(type));
}

SEXP api_Rf_nrows(SEXP x) {
return ScalarInteger(Rf_nrows(x));
}
Expand Down Expand Up @@ -1145,10 +1149,6 @@ SEXP api_Rf_asCharacterFactor(SEXP x) {
return Rf_asCharacterFactor(x);
}

SEXP api_Rf_match(SEXP itables, SEXP ix, SEXP nmatch) {
return Rf_match(itables, ix, INTEGER_VALUE(nmatch));
}

SEXP api_Rf_NonNullStringMatch(SEXP s, SEXP t) {
return ScalarLogical(Rf_NonNullStringMatch(s, t));
}
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
Expand Down Expand Up @@ -34,6 +34,8 @@
#include <R_ext/Connections.h>
#include <Rmath.h>

SEXP api_OBJECT(SEXP x);

SEXP api_Rf_ScalarInteger(SEXP value);

SEXP api_Rf_ScalarLogical(SEXP value);
Expand Down Expand Up @@ -102,6 +104,8 @@ SEXP api_Rf_allocArray(SEXP mode, SEXP dimsObj);

SEXP api_Rf_allocMatrix(SEXP mode, SEXP nrow, SEXP ncol);

SEXP api_Rf_allocSExp(SEXP type);

SEXP api_Rf_nrows(SEXP x);

SEXP api_Rf_ncols(SEXP x);
Expand Down Expand Up @@ -564,8 +568,6 @@ SEXP api_Rf_VectorToPairList(SEXP x);

SEXP api_Rf_asCharacterFactor(SEXP x);

SEXP api_Rf_match(SEXP itables, SEXP ix, SEXP nmatch);

SEXP api_Rf_NonNullStringMatch(SEXP s, SEXP t);

SEXP api_R_has_slot(SEXP container, SEXP name);
Expand All @@ -578,5 +580,3 @@ SEXP api_Rf_isObject(SEXP x);

SEXP api_R_MakeActiveBinding(SEXP sym, SEXP fun, SEXP env);

SEXP api_OBJECT(SEXP x);

@@ -1,4 +1,4 @@
# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2019, 2021, 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
Expand Down Expand Up @@ -41,6 +41,27 @@ ignore <- function(...) {}

library(testrffi)


# ---------------------------------------------------------------------------------------
# Rf_allocSExp

assertTrue(is.environment(api.Rf_allocSExp(4))) # ENVSXP
assertTrue(is.pairlist(api.Rf_allocSExp(2))) # LISTSXP
assertTrue(is.function(api.Rf_allocSExp(3))) # CLOSXP
assertTrue(is.language(api.Rf_allocSExp(6))) # LANGSXP

# combined with SET_BODY, SET_FORMALS, SET_CLOENV
q <- 42
f2 <- function(a,b=2) a+b+q

f <- api.Rf_allocSExp(3)
# assertEquals("closure", typeof(f))
api.SET_BODY(f, api.BODY(f2))
api.SET_FORMALS(f, api.FORMALS(f2))
api.SET_CLOENV(f, api.CLOENV(f2))
assertEquals(42, f(-2))


# ---------------------------------------------------------------------------------------
# SET_ATTRIB

Expand Down

0 comments on commit 544b572

Please sign in to comment.