diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java index 1e8fa828c18417547e78c25d7639c52e43615738..bfd35372edc84a5a0a6c3e5fd96bdd7cf16a07eb 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java @@ -67,6 +67,7 @@ import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntimeASTAccess; import com.oracle.truffle.r.runtime.RSrcref; @@ -84,6 +85,7 @@ import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RLanguage; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RPairList; import com.oracle.truffle.r.runtime.data.RPromise; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java index 523b80e3b1e3fd1e07026931e2e2f47a1c1caffa..b88e5f750fc84c9ccc9c4960e8e4f529b261f2ba 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java @@ -635,18 +635,20 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { } @Override - @TruffleBoundary public long Rf_any_duplicated(Object x, int fromLast) { - RAbstractVector vec = (RAbstractVector) x; - if (vec.getLength() <= 1) { - return 0; - } else { - return DuplicationHelper.analyze(vec, null, true, fromLast != 0).getIndex(); - } + throw implementedAsNode(); + } + + @Override + public long Rf_any_duplicated3(Object x, Object incomparables, int fromLast) { + throw implementedAsNode(); } @Override public Object PRINTNAME(Object x) { + if (x == RNull.instance) { + return x; + } guaranteeInstanceOf(x, RSymbol.class); return CharSXPWrapper.create(((RSymbol) x).getName()); } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/RFFIUtils.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/RFFIUtils.java index e3adbfa00e239f67d21784e95657417e2b438713..b7a447516e4f01e10ebea2f7f0271e49cbdd53a5 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/RFFIUtils.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/RFFIUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, 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 @@ -22,22 +22,25 @@ */ package com.oracle.truffle.r.ffi.impl.common; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.file.Path; import java.util.List; import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.r.runtime.FastROptions; +import com.oracle.truffle.api.interop.ForeignAccess; +import com.oracle.truffle.api.interop.Message; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.r.runtime.RInternalError; -import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RLanguage; +import com.oracle.truffle.r.runtime.data.RObject; import com.oracle.truffle.r.runtime.data.RPairList; import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.RTypedValue; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; import com.oracle.truffle.r.runtime.ffi.RFFIContext; +import com.oracle.truffle.r.runtime.ffi.RFFILog; /** * Mostly support for tracing R FFI up/down calls. Currently tracing of the arguments to calls is @@ -49,58 +52,22 @@ import com.oracle.truffle.r.runtime.ffi.RFFIContext; * that launches RStudio.) and sets the cwd to "/", which is not writeable. */ public class RFFIUtils { - /** - * Set this to {@code true} when it is not possible to set {@link FastROptions}. - */ - private static boolean alwaysTrace; - /** - * Is set by initialization and caches whether we are tracing. - */ - @CompilationFinal public static boolean traceEnabled; - - public static boolean traceInitialized; - - /** - * Always trace to a file because stdout is problematic for embedded mode. - */ - private static final String TRACEFILE = "fastr_trace_nativecalls.log"; - private static FileOutputStream traceStream; - - /** - * Handles the initialization of the RFFI downcalls/upcall tracing implementation. - */ - public static synchronized void initializeTracing() { - if (!traceInitialized) { - traceInitialized = true; - traceEnabled = alwaysTrace || FastROptions.TraceNativeCalls.getBooleanValue(); - if (traceEnabled) { - if (traceStream == null) { - initTraceStream(); - } - } - } - } - private static void initTraceStream() { - Path tracePath = Utils.getLogPath(TRACEFILE); - try { - traceStream = new FileOutputStream(tracePath.toString()); - } catch (IOException ex) { - System.err.println(ex.getMessage()); - System.exit(1); - } - } + private static Node isPointerNode; + private static Node asPointerNode; private enum CallMode { - UP("U"), - UP_RETURN("UR"), - DOWN("D"), - DOWN_RETURN("DR"); + UP("U", true), + UP_RETURN("UR", false), + DOWN("D", false), + DOWN_RETURN("DR", true); private final String printName; + private final boolean logNativeMirror; - CallMode(String printName) { + CallMode(String printName, boolean logNativeMirror) { this.printName = printName; + this.logNativeMirror = logNativeMirror; } } @@ -125,11 +92,11 @@ public class RFFIUtils { } public static boolean traceEnabled() { - return traceEnabled; + return RFFILog.traceEnabled(); } private static void traceCall(CallMode mode, String name, int depthValue, Object... args) { - if (traceEnabled) { + if (traceEnabled()) { StringBuilder sb = new StringBuilder(); sb.append("CallRFFI["); sb.append(mode.printName); @@ -138,21 +105,13 @@ public class RFFIUtils { sb.append(']'); sb.append(name); sb.append('('); - printArgs(sb, args); + printArgs(mode, sb, args); sb.append(')'); - sb.append(" [ctx:").append(System.identityHashCode(RContext.getInstance())); - sb.append(",thread:").append(Thread.currentThread().getId()).append(']'); - try { - traceStream.write(sb.toString().getBytes()); - traceStream.write('\n'); - traceStream.flush(); - } catch (IOException ex) { - // ignore - } + RFFILog.write(sb.toString()); } } - private static void printArgs(StringBuilder sb, Object[] args) { + private static void printArgs(CallMode mode, StringBuilder sb, Object[] args) { boolean first = true; for (Object arg : args) { if (first) { @@ -160,14 +119,38 @@ public class RFFIUtils { } else { sb.append(", "); } - sb.append(arg == null ? "" : arg.getClass().getSimpleName()); - if (arg instanceof RSymbol) { - RSymbol symbol = (RSymbol) arg; - sb.append("(\"" + symbol.getName() + "\")"); + if (arg == null) { + sb.append("null"); + continue; + } + sb.append(arg.getClass().getSimpleName()).append('(').append(arg.hashCode()); + if (arg instanceof TruffleObject && ForeignAccess.sendIsPointer(getIsPointerNode(), (TruffleObject) arg)) { + try { + sb.append(";ptr:").append(String.valueOf(ForeignAccess.sendAsPointer(getAsPointerNode(), (TruffleObject) arg))); + } catch (UnsupportedMessageException e) { + throw RInternalError.shouldNotReachHere(); + } + } else if (arg instanceof RSymbol) { + sb.append(';').append("\"" + arg.toString() + "\""); + } else if (arg instanceof RAbstractVector) { + RAbstractVector vec = (RAbstractVector) arg; + if (vec.getLength() == 0) { + sb.append(";empty"); + } else { + sb.append(";len:" + vec.getLength() + ";data:"); + for (int i = 0; i < Math.min(3, vec.getLength()); i++) { + String str = ((RAbstractVector) arg).getDataAtAsObject(0).toString(); + str = str.length() > 30 ? str.substring(0, 27) + "..." : str; + sb.append(',').append(str); + } + } } - if (!(arg instanceof RTypedValue)) { - sb.append("(" + arg + ")"); + // Note: it makes sense to include native mirrors only once they have been create + // already + if (mode.logNativeMirror && arg instanceof RObject) { + sb.append(";" + ((RObject) arg).getNativeMirror()); } + sb.append(')'); } } @@ -179,6 +162,10 @@ public class RFFIUtils { static RuntimeException unimplemented(String message) { CompilerDirectives.transferToInterpreter(); + if (traceEnabled()) { + RFFILog.printf("Error: unimplemented %s", message); + RFFILog.printStackTrace(); + } throw RInternalError.unimplemented(message); } @@ -196,15 +183,44 @@ public class RFFIUtils { public static <T> T guaranteeInstanceOf(Object x, Class<T> clazz) { if (x == null) { CompilerDirectives.transferToInterpreter(); + if (traceEnabled()) { + RFFILog.printf("Error: unexpected type: null instead of " + clazz.getSimpleName()); + RFFILog.printStackTrace(); + } unimplemented("unexpected type: null instead of " + clazz.getSimpleName()); } else if (!clazz.isInstance(x)) { CompilerDirectives.transferToInterpreter(); + if (traceEnabled()) { + RFFILog.printf("Error: unexpected type: %s is %s instead of %s", x, x.getClass().getSimpleName(), clazz.getSimpleName()); + RFFILog.printStackTrace(); + } unimplemented("unexpected type: " + x + " is " + x.getClass().getSimpleName() + " instead of " + clazz.getSimpleName()); } return clazz.cast(x); } + public static void logException(Throwable ex) { + if (traceEnabled()) { + RFFILog.printf("Error: %s, Message: %s", ex.getClass().getSimpleName(), ex.getMessage()); + RFFILog.printStackTrace(); + } + } + private static RFFIContext getContext() { return RContext.getInstance().getRFFI(); } + + private static Node getIsPointerNode() { + if (isPointerNode == null) { + isPointerNode = Message.IS_POINTER.createNode(); + } + return isPointerNode; + } + + private static Node getAsPointerNode() { + if (asPointerNode == null) { + asPointerNode = Message.AS_POINTER.createNode(); + } + return asPointerNode; + } } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Call.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Call.java index 27448accd62d39405390e1353a3fe5ea079a1d5f..0ee3d5ff4c0e359055f2cf25f3a87d09b82f046e 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Call.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Call.java @@ -53,12 +53,13 @@ import com.oracle.truffle.r.runtime.ffi.CallRFFI; import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle; import com.oracle.truffle.r.runtime.ffi.NativeCallInfo; import com.oracle.truffle.r.runtime.ffi.RFFIFactory; +import com.oracle.truffle.r.runtime.ffi.RFFILog; import com.oracle.truffle.r.runtime.ffi.RFFIVariables; final class TruffleLLVM_Call implements CallRFFI { TruffleLLVM_Call() { - RFFIUtils.initializeTracing(); + RFFILog.initializeTracing(); } static final class ContextStateImpl implements RContext.ContextState { diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Context.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Context.java index b83771cec9b0c6885632d2bcc28f76b31f7ccfa7..b002c4884753b040aa1f819f1f955610cafbc587 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Context.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Context.java @@ -61,6 +61,7 @@ import com.oracle.truffle.r.runtime.ffi.NativeFunction; import com.oracle.truffle.r.runtime.ffi.PCRERFFI; import com.oracle.truffle.r.runtime.ffi.REmbedRFFI; import com.oracle.truffle.r.runtime.ffi.RFFIContext; +import com.oracle.truffle.r.runtime.ffi.RFFILog; import com.oracle.truffle.r.runtime.ffi.RFFIVariables; import com.oracle.truffle.r.runtime.ffi.StatsRFFI; import com.oracle.truffle.r.runtime.ffi.ToolsRFFI; @@ -286,7 +287,7 @@ final class TruffleNFI_Context extends RFFIContext { @Override public ContextState initialize(RContext context) { - RFFIUtils.initializeTracing(); + RFFILog.initializeTracing(); initializeLock(); if (traceEnabled()) { traceDownCall("initialize"); @@ -368,13 +369,13 @@ final class TruffleNFI_Context extends RFFIContext { UnsafeAdapter.UNSAFE.freeMemory(ptr); } transientAllocations.clear(); + RuntimeException lastUpCallEx = getLastUpCallException(); + setLastUpCallException(null); if (hasAccessLock) { releaseLock(); } - RuntimeException lastUpCallEx = getLastUpCallException(); if (lastUpCallEx != null) { CompilerDirectives.transferToInterpreter(); - setLastUpCallException(null); throw lastUpCallEx; } } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceNodes.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceNodes.java index bc51d6d45c3eb4590ec0f85ec40df30d74dd49af..b3007b211c50f7552ebd8bfab8cf3bd583b09458 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceNodes.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceNodes.java @@ -51,6 +51,7 @@ import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RPairList; import com.oracle.truffle.r.runtime.data.RShareable; import com.oracle.truffle.r.runtime.data.RStringVector; +import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.RTypedValue; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; @@ -75,7 +76,7 @@ public final class CoerceNodes { for (int i = 0; i < v.getLength(); i++) { Object element = v.getDataAtAsObject(i); adjustSharing(v, element); - RPairList cur = RDataFactory.createPairList(element, RNull.instance, names != null ? names.getDataAt(i) : RNull.instance, gnurType); + RPairList cur = RDataFactory.createPairList(element, RNull.instance, names != null ? RDataFactory.createSymbol(names.getDataAt(i)) : RNull.instance, gnurType); if (prev == null) { assert head == null; diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/DuplicateNodes.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/DuplicateNodes.java index 4eab0d8673373a401ed93d7e7091d7ae122d7e62..ff0dbb981c6475531d933cf9613037766f642b0b 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/DuplicateNodes.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/DuplicateNodes.java @@ -23,14 +23,21 @@ package com.oracle.truffle.r.ffi.impl.nodes; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +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.profiles.ConditionProfile; import com.oracle.truffle.r.ffi.impl.nodes.DuplicateNodesFactory.DuplicateNodeGen; +import com.oracle.truffle.r.ffi.impl.nodes.DuplicateNodesFactory.RfAnyDuplicated3NodeGen; +import com.oracle.truffle.r.ffi.impl.nodes.DuplicateNodesFactory.RfAnyDuplicatedNodeGen; import com.oracle.truffle.r.runtime.data.RExternalPtr; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RSequence; import com.oracle.truffle.r.runtime.data.RShareable; import com.oracle.truffle.r.runtime.data.RSymbol; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; import com.oracle.truffle.r.runtime.env.REnvironment; +import com.oracle.truffle.r.runtime.nodes.DuplicationHelper; public final class DuplicateNodes { @@ -58,6 +65,11 @@ public final class DuplicateNodes { return val; } + @Fallback + public Object doOther(Object x, Object y) { + throw unsupportedTypes("Rf_duplicate", x, y); + } + protected static boolean isReusableForDuplicate(Object o) { return o == RNull.instance || o instanceof REnvironment || o instanceof RSymbol; } @@ -67,4 +79,45 @@ public final class DuplicateNodes { } } + public abstract static class RfAnyDuplicated extends FFIUpCallNode.Arg2 { + @Specialization + public int doDuplicate(RAbstractVector vec, int fromLast, + @Cached("createBinaryProfile()") ConditionProfile isEmptyProfile) { + if (isEmptyProfile.profile(vec.getLength() <= 1)) { + return 0; + } else { + return DuplicationHelper.analyze(vec, null, true, fromLast != 0).getIndex(); + } + } + + @Fallback + public Object doOthers(Object vec, Object fromLast) { + throw unsupportedTypes("Rf_any_duplicated", vec, fromLast); + } + + public static RfAnyDuplicated create() { + return RfAnyDuplicatedNodeGen.create(); + } + } + + public abstract static class RfAnyDuplicated3 extends FFIUpCallNode.Arg3 { + @Specialization + public int doDuplicate(RAbstractVector vec, RAbstractVector incomparables, int fromLast, + @Cached("createBinaryProfile()") ConditionProfile isEmptyProfile) { + if (isEmptyProfile.profile(vec.getLength() <= 1)) { + return 0; + } else { + return DuplicationHelper.analyze(vec, incomparables, true, fromLast != 0).getIndex(); + } + } + + @Fallback + public Object doOthers(Object vec, Object incomparables, Object fromLast) { + throw unsupportedTypes("Rf_any_duplicated3", vec, incomparables, fromLast); + } + + public static RfAnyDuplicated3 create() { + return RfAnyDuplicated3NodeGen.create(); + } + } } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/FFIUpCallNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/FFIUpCallNode.java index 5df825b06b78e80c37dfb663f2f3b2c4c311a156..4a86d30d42e81a4811fdde6e7983a6328b67e30b 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/FFIUpCallNode.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/FFIUpCallNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, 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 @@ -22,11 +22,26 @@ */ package com.oracle.truffle.r.ffi.impl.nodes; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.Utils; public abstract class FFIUpCallNode extends Node { protected abstract int numArgs(); + @TruffleBoundary + protected final RError unsupportedTypes(String name, Object... args) { + assert args.length > 0; + StringBuilder sb = new StringBuilder(args.length * 15); + sb.append("wrong argument types provided to Rf_duplicated: ").append(Utils.getTypeName(args[0])); + for (int i = 1; i < args.length; i++) { + sb.append(',').append(Utils.getTypeName(args[i])); + } + throw RError.error(RError.NO_CALLER, Message.GENERIC, sb); + } + public abstract static class Arg0 extends FFIUpCallNode { public abstract Object executeObject(); diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java index a576084b4f92e967c536c75f70d17c849d4f3745..c74c97380988dc47a87c715faa2f94fa57be56f2 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java @@ -34,9 +34,11 @@ import com.oracle.truffle.r.ffi.impl.nodes.CoerceNodes.CoerceVectorNode; import com.oracle.truffle.r.ffi.impl.nodes.CoerceNodes.VectorToPairListNode; import com.oracle.truffle.r.ffi.impl.nodes.DoMakeClassNode; import com.oracle.truffle.r.ffi.impl.nodes.DuplicateNodes; -import com.oracle.truffle.r.ffi.impl.nodes.GetClassDefNode; +import com.oracle.truffle.r.ffi.impl.nodes.DuplicateNodes.RfAnyDuplicated; +import com.oracle.truffle.r.ffi.impl.nodes.DuplicateNodes.RfAnyDuplicated3; import com.oracle.truffle.r.ffi.impl.nodes.EnvNodes.LockBindingNode; import com.oracle.truffle.r.ffi.impl.nodes.EnvNodes.UnlockBindingNode; +import com.oracle.truffle.r.ffi.impl.nodes.GetClassDefNode; import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodes.CAARNode; import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodes.CAD4RNode; import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodes.CADDDRNode; @@ -206,8 +208,12 @@ public interface StdUpCallsRFFI { @RFFIUpCallNode(DuplicateNodes.DuplicateNode.class) Object Rf_duplicate(Object x, int deep); + @RFFIUpCallNode(RfAnyDuplicated.class) long Rf_any_duplicated(Object x, int fromLast); + @RFFIUpCallNode(RfAnyDuplicated3.class) + long Rf_any_duplicated3(Object x, Object incomparables, int fromLast); + Object PRINTNAME(Object x); @RFFIUpCallNode(TAG.class) diff --git a/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java b/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java index 9934ccd6fa5f9fc8635efa871925625a5a3ee37f..d6948785437e6e3db76afb80f900b81c31973ebd 100644 --- a/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java +++ b/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java @@ -300,7 +300,7 @@ public final class FFIProcessor extends AbstractProcessor { w.append(" public Object execute(VirtualFrame frame) {\n"); w.append(" List<Object> arguments = ForeignAccess.getArguments(frame);\n"); w.append(" assert arguments.size() == " + params.size() + " : \"wrong number of arguments passed to " + name + "\";\n"); - w.append(" if (RFFIUtils.traceEnabled) {\n"); + w.append(" if (RFFIUtils.traceEnabled()) {\n"); w.append(" RFFIUtils.traceUpCall(\"" + name + "\", arguments);\n"); w.append(" }\n"); w.append(" RFFIContext ctx = RContext.getInstance().getStateRFFI();\n"); @@ -328,8 +328,9 @@ public final class FFIProcessor extends AbstractProcessor { } else { w.append(";\n"); } - w.append(" } catch (Exception ex) {\n"); + w.append(" } catch (Throwable ex) {\n"); w.append(" CompilerDirectives.transferToInterpreter();\n"); + w.append(" RFFIUtils.logException(ex);\n"); w.append(" handleExceptionNode.execute(ex);\n"); if (returnKind.isPrimitive()) { w.append(" resultRObj = Integer.valueOf(-1);\n"); @@ -339,11 +340,17 @@ public final class FFIProcessor extends AbstractProcessor { w.append(" }\n"); w.append(" ctx.afterUpcall(" + canRunGc + ");\n"); if (returnKind == TypeKind.VOID) { + w.append(" if (RFFIUtils.traceEnabled()) {\n"); + w.append(" RFFIUtils.traceUpCallReturn(\"" + name + "\", null);\n"); + w.append(" }\n"); w.append(" return 0; // void return type\n"); } else { if (!returnKind.isPrimitive() && m.getAnnotationsByType(RFFICpointer.class).length == 0) { w.append(" ctx.registerReferenceUsedInNative(resultRObj); \n"); } + w.append(" if (RFFIUtils.traceEnabled()) {\n"); + w.append(" RFFIUtils.traceUpCallReturn(\"" + name + "\", resultRObj);\n"); + w.append(" }\n"); w.append(" return resultRObj;\n"); } w.append(" }\n"); diff --git a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h index 1a6bc2c49b7a21559098ea7126a3d1a70ec9c902..e60dcbfe7fe9af0207c983535a0907aca7533757 100644 --- a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h +++ b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h @@ -57,6 +57,7 @@ typedef SEXP (*call_Rf_duplicate)(SEXP x, int v); typedef SEXP (*call_Rf_shallow_duplicate)(SEXP x); typedef SEXP (*call_Rf_coerceVector)(SEXP x, SEXPTYPE mode); typedef R_xlen_t (*call_Rf_any_duplicated)(SEXP x, Rboolean from_last); +typedef R_xlen_t (*call_Rf_any_duplicated3)(SEXP x, SEXP y, Rboolean from_last); typedef SEXP (*call_Rf_duplicated)(SEXP x, Rboolean y); typedef SEXP (*call_Rf_applyClosure)(SEXP x, SEXP y, SEXP z, SEXP a, SEXP b); typedef int (*call_Rf_copyMostAttrib)(SEXP x, SEXP y); diff --git a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcallsindex.h b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcallsindex.h index 8c6c12994411ddc5c7c0fa7a6e43e5ce5c922238..1dc742abd6f75f1fc437844b34bf8872c4e2dd37 100644 --- a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcallsindex.h +++ b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcallsindex.h @@ -104,98 +104,99 @@ #define Rf_allocMatrix_x 99 #define Rf_allocVector_x 100 #define Rf_any_duplicated_x 101 -#define Rf_asChar_x 102 -#define Rf_asCharacterFactor_x 103 -#define Rf_asInteger_x 104 -#define Rf_asLogical_x 105 -#define Rf_asReal_x 106 -#define Rf_classgets_x 107 -#define Rf_coerceVector_x 108 -#define Rf_cons_x 109 -#define Rf_copyListMatrix_x 110 -#define Rf_copyMatrix_x 111 -#define Rf_copyMostAttrib_x 112 -#define Rf_dchisq_x 113 -#define Rf_defineVar_x 114 -#define Rf_dnchisq_x 115 -#define Rf_dunif_x 116 -#define Rf_duplicate_x 117 -#define Rf_error_x 118 -#define Rf_errorcall_x 119 -#define Rf_eval_x 120 -#define Rf_findFun_x 121 -#define Rf_findVar_x 122 -#define Rf_findVarInFrame_x 123 -#define Rf_findVarInFrame3_x 124 -#define Rf_getAttrib_x 125 -#define Rf_gsetVar_x 126 -#define Rf_inherits_x 127 -#define Rf_install_x 128 -#define Rf_installChar_x 129 -#define Rf_isNull_x 130 -#define Rf_isString_x 131 -#define Rf_lengthgets_x 132 -#define Rf_match_x 133 -#define Rf_mkCharLenCE_x 134 -#define Rf_namesgets_x 135 -#define Rf_ncols_x 136 -#define Rf_nrows_x 137 -#define Rf_pchisq_x 138 -#define Rf_pnchisq_x 139 -#define Rf_protect_x 140 -#define Rf_punif_x 141 -#define Rf_qchisq_x 142 -#define Rf_qnchisq_x 143 -#define Rf_qunif_x 144 -#define Rf_rchisq_x 145 -#define Rf_rnchisq_x 146 -#define Rf_runif_x 147 -#define Rf_setAttrib_x 148 -#define Rf_str2type_x 149 -#define Rf_unprotect_x 150 -#define Rf_unprotect_ptr_x 151 -#define Rf_warning_x 152 -#define Rf_warningcall_x 153 -#define Rprintf_x 154 -#define SETCAD4R_x 155 -#define SETCADDDR_x 156 -#define SETCADDR_x 157 -#define SETCADR_x 158 -#define SETCAR_x 159 -#define SETCDR_x 160 -#define SET_BODY_x 161 -#define SET_CLOENV_x 162 -#define SET_FORMALS_x 163 -#define SET_NAMED_FASTR_x 164 -#define SET_RDEBUG_x 165 -#define SET_RSTEP_x 166 -#define SET_S4_OBJECT_x 167 -#define SET_STRING_ELT_x 168 -#define SET_SYMVALUE_x 169 -#define SET_TAG_x 170 -#define SET_TYPEOF_FASTR_x 171 -#define SET_VECTOR_ELT_x 172 -#define STRING_ELT_x 173 -#define SYMVALUE_x 174 -#define TAG_x 175 -#define TYPEOF_x 176 -#define UNSET_S4_OBJECT_x 177 -#define VECTOR_ELT_x 178 -#define forceSymbols_x 179 -#define getCCallable_x 180 -#define getConnectionClassString_x 181 -#define getEmbeddingDLLInfo_x 182 -#define getOpenModeString_x 183 -#define getSummaryDescription_x 184 -#define isSeekable_x 185 -#define octsize_x 186 -#define registerCCallable_x 187 -#define registerRoutines_x 188 -#define restoreHandlerStacks_x 189 -#define setDotSymbolValues_x 190 -#define unif_rand_x 191 -#define useDynamicSymbols_x 192 +#define Rf_any_duplicated3_x 102 +#define Rf_asChar_x 103 +#define Rf_asCharacterFactor_x 104 +#define Rf_asInteger_x 105 +#define Rf_asLogical_x 106 +#define Rf_asReal_x 107 +#define Rf_classgets_x 108 +#define Rf_coerceVector_x 109 +#define Rf_cons_x 110 +#define Rf_copyListMatrix_x 111 +#define Rf_copyMatrix_x 112 +#define Rf_copyMostAttrib_x 113 +#define Rf_dchisq_x 114 +#define Rf_defineVar_x 115 +#define Rf_dnchisq_x 116 +#define Rf_dunif_x 117 +#define Rf_duplicate_x 118 +#define Rf_error_x 119 +#define Rf_errorcall_x 120 +#define Rf_eval_x 121 +#define Rf_findFun_x 122 +#define Rf_findVar_x 123 +#define Rf_findVarInFrame_x 124 +#define Rf_findVarInFrame3_x 125 +#define Rf_getAttrib_x 126 +#define Rf_gsetVar_x 127 +#define Rf_inherits_x 128 +#define Rf_install_x 129 +#define Rf_installChar_x 130 +#define Rf_isNull_x 131 +#define Rf_isString_x 132 +#define Rf_lengthgets_x 133 +#define Rf_match_x 134 +#define Rf_mkCharLenCE_x 135 +#define Rf_namesgets_x 136 +#define Rf_ncols_x 137 +#define Rf_nrows_x 138 +#define Rf_pchisq_x 139 +#define Rf_pnchisq_x 140 +#define Rf_protect_x 141 +#define Rf_punif_x 142 +#define Rf_qchisq_x 143 +#define Rf_qnchisq_x 144 +#define Rf_qunif_x 145 +#define Rf_rchisq_x 146 +#define Rf_rnchisq_x 147 +#define Rf_runif_x 148 +#define Rf_setAttrib_x 149 +#define Rf_str2type_x 150 +#define Rf_unprotect_x 151 +#define Rf_unprotect_ptr_x 152 +#define Rf_warning_x 153 +#define Rf_warningcall_x 154 +#define Rprintf_x 155 +#define SETCAD4R_x 156 +#define SETCADDDR_x 157 +#define SETCADDR_x 158 +#define SETCADR_x 159 +#define SETCAR_x 160 +#define SETCDR_x 161 +#define SET_BODY_x 162 +#define SET_CLOENV_x 163 +#define SET_FORMALS_x 164 +#define SET_NAMED_FASTR_x 165 +#define SET_RDEBUG_x 166 +#define SET_RSTEP_x 167 +#define SET_S4_OBJECT_x 168 +#define SET_STRING_ELT_x 169 +#define SET_SYMVALUE_x 170 +#define SET_TAG_x 171 +#define SET_TYPEOF_FASTR_x 172 +#define SET_VECTOR_ELT_x 173 +#define STRING_ELT_x 174 +#define SYMVALUE_x 175 +#define TAG_x 176 +#define TYPEOF_x 177 +#define UNSET_S4_OBJECT_x 178 +#define VECTOR_ELT_x 179 +#define forceSymbols_x 180 +#define getCCallable_x 181 +#define getConnectionClassString_x 182 +#define getEmbeddingDLLInfo_x 183 +#define getOpenModeString_x 184 +#define getSummaryDescription_x 185 +#define isSeekable_x 186 +#define octsize_x 187 +#define registerCCallable_x 188 +#define registerRoutines_x 189 +#define restoreHandlerStacks_x 190 +#define setDotSymbolValues_x 191 +#define unif_rand_x 192 +#define useDynamicSymbols_x 193 -#define UPCALLS_TABLE_SIZE 193 +#define UPCALLS_TABLE_SIZE 194 #endif // RFFI_UPCALLSINDEX_H diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h b/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h index 82bf7b8f64b6c1c2a002a7b769f31f757865f43d..5edea4d43b092503fe7a9dfaf848b6c120a247ac 100644 --- a/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h +++ b/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h @@ -68,6 +68,7 @@ #define UNIMPLEMENTED unimplemented(__FUNCTION__) +#define NO_FASTR_REDEFINE #include <rffiutils.h> // these two functions are here just to handle casting void* to void function pointers... @@ -448,6 +449,13 @@ R_xlen_t Rf_any_duplicated(SEXP x, Rboolean from_last) { return result; } +R_xlen_t Rf_any_duplicated3(SEXP x, SEXP incomp, Rboolean from_last) { + TRACE0(); + R_xlen_t result = (R_xlen_t) ((call_Rf_any_duplicated3) callbacks[Rf_any_duplicated3_x])(x, incomp, from_last); + checkExitCall(); + return result; +} + SEXP Rf_duplicated(SEXP x, Rboolean y) { TRACE0(); unimplemented("Rf_duplicated"); @@ -1245,7 +1253,7 @@ void DUPLICATE_ATTRIB(SEXP to, SEXP from) { R_len_t R_BadLongVector(SEXP x, const char *y, int z) { TRACE0(); unimplemented("R_BadLongVector"); - return (R_len_t) 0; + // "no return" function } int IS_S4_OBJECT(SEXP x) { diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_llvm/Rinternals.c b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/Rinternals.c index 4b3d916edd833c9728fb25cc0f26c8ca8b575202..f6dcf567ef2f622bf0878352af1478402c523c3e 100644 --- a/com.oracle.truffle.r.native/fficall/src/truffle_llvm/Rinternals.c +++ b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/Rinternals.c @@ -21,6 +21,7 @@ * questions. */ +#define NO_FASTR_REDEFINE #include <Rinterface.h> #include <rffiutils.h> #include <Rinternals_common.h> diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rinternals.c b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rinternals.c index 39b2d0b9ab6b6ca0cba775cd6826c9cc08494fd5..cf8ea6aa96ee13995af6de6c2c38acf878dc80cd 100644 --- a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rinternals.c +++ b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rinternals.c @@ -20,6 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +#define NO_FASTR_REDEFINE #include <Rinterface.h> #include <rffiutils.h> #include <Rinternals_common.h> diff --git a/com.oracle.truffle.r.native/version.source b/com.oracle.truffle.r.native/version.source index fb1e7bc86996a80d4a16529b990adda1d3434c92..e1617e842ad9a038ec2d8332c6084300a43cb09d 100644 --- a/com.oracle.truffle.r.native/version.source +++ b/com.oracle.truffle.r.native/version.source @@ -1 +1 @@ -54 +57 diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java index 17a34fa9a8e7f6e74783757d6f91afa58d25a9f7..601f97464f58dc91e5b9ab586645b47b7795b1ac 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java @@ -72,7 +72,6 @@ import com.oracle.truffle.r.nodes.builtin.base.infix.BreakBuiltinNodeGen; import com.oracle.truffle.r.nodes.builtin.base.infix.ForBuiltin; import com.oracle.truffle.r.nodes.builtin.base.infix.ForBuiltinNodeGen; import com.oracle.truffle.r.nodes.builtin.base.infix.FunctionBuiltin; -import com.oracle.truffle.r.nodes.builtin.base.infix.FunctionBuiltinNodeGen; import com.oracle.truffle.r.nodes.builtin.base.infix.IfBuiltin; import com.oracle.truffle.r.nodes.builtin.base.infix.IfBuiltinNodeGen; import com.oracle.truffle.r.nodes.builtin.base.infix.NextBuiltin; @@ -798,7 +797,7 @@ public class BasePackage extends RBuiltinPackage { add(BraceBuiltin.class, BraceBuiltinNodeGen::create); add(BreakBuiltin.class, BreakBuiltinNodeGen::create); add(ForBuiltin.class, ForBuiltinNodeGen::create); - add(FunctionBuiltin.class, FunctionBuiltinNodeGen::create); + add(FunctionBuiltin.class, FunctionBuiltin::create); add(IfBuiltin.class, IfBuiltinNodeGen::create); add(NextBuiltin.class, NextBuiltinNodeGen::create); add(ParenBuiltin.class, ParenBuiltin::new, ParenBuiltin::special); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Call.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Call.java index da1db2993a9274581f31f7907d66ba41b21d9680..c60c75338c8c594cd5a1a4aab0abf79b5fba1ed9 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Call.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Call.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, 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 @@ -33,6 +33,8 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.nodes.RASTUtils; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.nodes.builtin.base.infix.FunctionBuiltin; +import com.oracle.truffle.r.nodes.function.FunctionExpressionNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RError.Message; @@ -79,32 +81,15 @@ public abstract class Call extends RBuiltinNode.Arg2 { @TruffleBoundary public static RLanguage makeCall(TruffleRLanguage language, RSyntaxNode target, Object[] arguments, ArgumentsSignature signature) { assert arguments.length == signature.getLength(); - if (target instanceof RSyntaxLookup && "function".equals(((RSyntaxLookup) target).getIdentifier())) { - return makeFunction(language, arguments); + if (target instanceof RSyntaxLookup && "function".equals(((RSyntaxLookup) target).getIdentifier()) && arguments.length == 2) { + // this optimization is not strictly necessary, `function` builtin is functional too. + FunctionExpressionNode function = FunctionBuiltin.createFunctionExpressionNode(language, arguments[0], arguments[1]); + return RDataFactory.createLanguage(Closure.createLanguageClosure(function.asRNode())); } else { return makeCall0(target, arguments, signature); } } - private static RLanguage makeFunction(TruffleRLanguage language, Object[] arguments) { - CompilerAsserts.neverPartOfCompilation(); - Object body = arguments.length <= 1 ? RNull.instance : arguments[1]; - Object argList = arguments.length == 0 ? RNull.instance : arguments[0]; - ArrayList<RCodeBuilder.Argument<RSyntaxNode>> finalArgs = new ArrayList<>(); - while (argList != RNull.instance) { - if (!(argList instanceof RPairList)) { - throw RError.error(RError.SHOW_CALLER, Message.BAD_FUNCTION_EXPR); - } - RPairList pl = (RPairList) argList; - String name = ((RSymbol) pl.getTag()).getName(); - RSyntaxNode value = RASTUtils.createNodeForValue(pl.car()).asRSyntaxNode(); - finalArgs.add(RCodeBuilder.argument(RSyntaxNode.LAZY_DEPARSE, name, value)); - argList = pl.cdr(); - } - RSyntaxNode function = RContext.getASTBuilder().function(language, RSyntaxNode.LAZY_DEPARSE, finalArgs, RASTUtils.createNodeForValue(body).asRSyntaxNode(), null); - return RDataFactory.createLanguage(Closure.createLanguageClosure(function.asRNode())); - } - @TruffleBoundary private static RLanguage makeCall0(RSyntaxNode target, Object[] arguments, ArgumentsSignature signature) { RSyntaxNode[] args = new RSyntaxNode[arguments.length]; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/FunctionBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/FunctionBuiltin.java index 3909ffbb92edc496f1e07f724252dcc77cd3df50..4f885fac2fe13fa5909fa370a48596f4509b096d 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/FunctionBuiltin.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/FunctionBuiltin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, 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 @@ -22,23 +22,78 @@ */ package com.oracle.truffle.r.nodes.builtin.base.infix; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean; +import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX; import static com.oracle.truffle.r.runtime.builtins.RBehavior.READS_FRAME; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; +import java.util.ArrayList; +import java.util.List; + +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +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.MaterializedFrame; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.r.nodes.RASTUtils; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.nodes.function.FunctionExpressionNode; +import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode; +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.builtins.RBuiltin; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.context.TruffleRLanguage; +import com.oracle.truffle.r.runtime.data.Closure; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RExpression; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RPairList; +import com.oracle.truffle.r.runtime.data.RPromise; +import com.oracle.truffle.r.runtime.data.RSymbol; +import com.oracle.truffle.r.runtime.nodes.RCodeBuilder; +import com.oracle.truffle.r.runtime.nodes.RCodeBuilder.Argument; +import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; -@RBuiltin(name = "function", kind = PRIMITIVE, parameterNames = {"x"}, behavior = READS_FRAME) -public abstract class FunctionBuiltin extends RBuiltinNode.Arg1 { +@RBuiltin(name = "function", kind = PRIMITIVE, nonEvalArgs = 1, parameterNames = {"args", "body"}, behavior = COMPLEX) +public final class FunctionBuiltin extends RBuiltinNode.Arg2 { static { Casts.noCasts(FunctionBuiltin.class); } - @Specialization - protected Object doIt(@SuppressWarnings("unused") Object x) { - throw RInternalError.unimplemented(); + @Child private CreateAndExecuteFunctionExpr createFunNode; + + @Override + public Object execute(VirtualFrame frame, Object args, Object body) { + if (createFunNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + createFunNode = insert(new CreateAndExecuteFunctionExpr()); + } + return createFunNode.execute(frame.materialize(), getRLanguage(), args, body); + } + + public static FunctionBuiltin create() { + return new FunctionBuiltin(); + } + + protected static final class CreateAndExecuteFunctionExpr extends TruffleBoundaryNode { + @Child private FunctionExpressionNode funExprNode; + + @TruffleBoundary + public Object execute(MaterializedFrame frame, TruffleRLanguage language, Object args, Object body) { + funExprNode = insert(createFunctionExpressionNode(getRLanguage(), args, body)); + return funExprNode.execute(frame); + } + } + + public static FunctionExpressionNode createFunctionExpressionNode(TruffleRLanguage language, Object args, Object body) { + List<Argument<RSyntaxNode>> finalArgs = RContext.getASTBuilder().getFunctionExprArgs(args); + return (FunctionExpressionNode) RContext.getASTBuilder().function(language, RSyntaxNode.LAZY_DEPARSE, finalArgs, RASTUtils.createNodeForValue(body).asRSyntaxNode(), null); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java index f970469231a641cd2190c2595ec57870aded683d..b682b1268a7c728e81af732e330ffea1e96c43bc 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java @@ -22,8 +22,10 @@ */ package com.oracle.truffle.r.nodes; +import java.util.ArrayList; import java.util.List; +import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.FrameDescriptor; @@ -53,12 +55,17 @@ import com.oracle.truffle.r.nodes.function.signature.MissingNode; import com.oracle.truffle.r.nodes.function.signature.QuoteNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.FastROptions; +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.builtins.FastPathFactory; import com.oracle.truffle.r.runtime.context.TruffleRLanguage; import com.oracle.truffle.r.runtime.data.REmpty; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RPairList; import com.oracle.truffle.r.runtime.data.RShareable; +import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor; import com.oracle.truffle.r.runtime.nodes.EvaluatedArgumentsVisitor; import com.oracle.truffle.r.runtime.nodes.RCodeBuilder; @@ -190,6 +197,27 @@ public final class RASTBuilder implements RCodeBuilder<RSyntaxNode> { return FunctionExpressionNode.create(source, callTarget); } + @Override + public ArrayList<Argument<RSyntaxNode>> getFunctionExprArgs(Object args) { + CompilerAsserts.neverPartOfCompilation(); + if (!(args instanceof RPairList || args == RNull.instance)) { + throw RError.error(RError.SHOW_CALLER, Message.INVALID_FORMAL_ARG_LIST, "function"); + } + ArrayList<Argument<RSyntaxNode>> finalArgs = new ArrayList<>(); + Object argList = args; + while (argList != RNull.instance) { + if (!(argList instanceof RPairList)) { + throw RError.error(RError.SHOW_CALLER, Message.INVALID_FORMAL_ARG_LIST, "function"); + } + RPairList pl = (RPairList) argList; + String name = ((RSymbol) pl.getTag()).getName(); + RSyntaxNode value = RASTUtils.createNodeForValue(pl.car()).asRSyntaxNode(); + finalArgs.add(RCodeBuilder.argument(RSyntaxNode.LAZY_DEPARSE, name, value)); + argList = pl.cdr(); + } + return finalArgs; + } + @Override public RootCallTarget rootFunction(TruffleRLanguage language, SourceSection source, List<Argument<RSyntaxNode>> params, RSyntaxNode body, String name) { // Parse argument list diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java index 7bef648d8b4e38b0ad54d4f1de55b92c1c9b929b..0b5398bfaacc456437a3fac92200f5b5920f1502 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java @@ -28,6 +28,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.interop.TruffleObject; @@ -35,6 +36,7 @@ import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RAttributable; import com.oracle.truffle.r.runtime.data.RAttributesLayout; @@ -67,6 +69,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector; import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle; import com.oracle.truffle.r.runtime.interop.TruffleObjectConverter; +import com.oracle.truffle.r.runtime.nodes.RCodeBuilder; +import com.oracle.truffle.r.runtime.nodes.RCodeBuilder.Argument; import com.oracle.truffle.r.runtime.nodes.RSyntaxCall; import com.oracle.truffle.r.runtime.nodes.RSyntaxConstant; import com.oracle.truffle.r.runtime.nodes.RSyntaxElement; @@ -521,6 +525,9 @@ public class RDeparse { RSyntaxElement[] args = call.getSyntaxArguments(); if (lhs instanceof RSyntaxLookup) { String symbol = ((RSyntaxLookup) lhs).getIdentifier(); + if ("function".equals(symbol)) { + return visitFunctionFunction(args); + } RDeparse.Func func = RDeparse.getFunc(symbol); if (func != null) { PPInfo info = func.info; @@ -675,10 +682,34 @@ public class RDeparse { @Override protected Void visit(RSyntaxFunction function) { + return visitFunctionExpr(function.getSyntaxSignature(), function.getSyntaxArgumentDefaults(), function.getSyntaxBody()); + } + + private Void visitFunctionExpr(ArgumentsSignature signature, RSyntaxElement[] argsDefaults, RSyntaxElement body) { append("function("); - appendArgs(function.getSyntaxSignature(), function.getSyntaxArgumentDefaults(), 0, true); + appendArgs(signature, argsDefaults, 0, true); append(") "); - appendFunctionBody(function.getSyntaxBody()); + appendFunctionBody(body); + return null; + } + + private Void visitFunctionFunction(RSyntaxElement[] args) { + if (args.length > 0 && !(args[0] instanceof RSyntaxConstant)) { + throw RError.error(RError.SHOW_CALLER2, Message.BAD_FUNCTION_EXPR); + } + Object funArgsValue = args.length > 0 ? ((RSyntaxConstant) args[0]).getValue() : RNull.instance; + List<Argument<RSyntaxNode>> syntaxArgs = RContext.getASTBuilder().getFunctionExprArgs(funArgsValue); + String[] names = new String[syntaxArgs.size()]; + RSyntaxNode[] values = new RSyntaxNode[syntaxArgs.size()]; + for (int i = 0; i < syntaxArgs.size(); i++) { + names[i] = syntaxArgs.get(i).name; + values[i] = syntaxArgs.get(i).value; + } + Object body = args.length <= 1 ? RNull.instance : args[1]; + if (!(body instanceof RSyntaxElement)) { + body = RContext.getASTBuilder().constant(RSyntaxNode.SOURCE_UNAVAILABLE, body); + } + visitFunctionExpr(ArgumentsSignature.get(names), values, (RSyntaxElement) body); return null; } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java index a0282f634ed69c6694626fa30b24124e1f69c376..9c04e55fe45ece31a5d914e6c135a75f40f65b4d 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java @@ -944,6 +944,7 @@ public final class RError extends RuntimeException implements TruffleException { VERSION_N_NOT_SUPPORTED("version %d not supported"), ATOMIC_VECTOR_ARGUMENTS_ONLY("atomic vector arguments only"), MUST_BE_COMPLEX_MATRIX("'%s' must be a complex matrix"), + INVALID_FORMAL_ARG_LIST("invalid formal argument list for \"%s\""), SINGULAR_BACKSOLVE("singular matrix in 'backsolve'. First zero in diagonal [%d]"); public final String message; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java index 9f542e9f7a5d049ba41de0dc0aee624b31949749..aad7079a8101d62d73865029366576cf63a7a6ac 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java @@ -37,6 +37,7 @@ import java.util.function.Function; import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleRuntime; @@ -57,6 +58,7 @@ import com.oracle.truffle.r.runtime.data.RLanguage; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RPairList; import com.oracle.truffle.r.runtime.data.RStringVector; +import com.oracle.truffle.r.runtime.data.RTypedValue; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor.MultiSlotData; import com.oracle.truffle.r.runtime.ffi.BaseRFFI; @@ -678,6 +680,21 @@ public final class Utils { return String.format(format, objects); } + /** + * Makes the best effort to create end user understandable String representation of the type of + * the parameter. When the parameter is null, returns "null". + */ + public static String getTypeName(Object value) { + // Typically part of error reporting. The whole error reporting should be behind TB. + CompilerAsserts.neverPartOfCompilation(); + if (value == null) { + return "null"; + } else if (value instanceof RTypedValue) { + return ((RTypedValue) value).getRType().getName(); + } + return value.getClass().getSimpleName(); + } + private static boolean isWriteableDirectory(String path) { File f = new File(path); return f.exists() && f.isDirectory() && f.canWrite(); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java index 09b82c05c43a5a1e6f9dbf57cceae1b0c579f59b..7bddf458f755527ef10cc2b606b752dd732bdae9 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java @@ -42,6 +42,7 @@ import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.ffi.RFFILog; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; import sun.misc.Unsafe; @@ -125,7 +126,7 @@ public final class NativeDataAccess { private Object nativeWrapper; NativeMirror() { - this.id = counter.incrementAndGet(); + this.id = counter.addAndGet(2); } /** @@ -179,9 +180,16 @@ public final class NativeDataAccess { assert (dataAddress = 0xbadbad) != 0; } } + + @Override + public String toString() { + return "mirror:" + dataAddress; + } } - private static final AtomicLong counter = new AtomicLong(0xdef000000000000L); + // The counter is initialized to invalid address and incremented by 2 to always get invalid + // address value + private static final AtomicLong counter = new AtomicLong(0xdef000000000001L); private static final ConcurrentHashMap<Long, WeakReference<RObject>> nativeMirrors = new ConcurrentHashMap<>(); private static final ConcurrentHashMap<Long, RuntimeException> nativeMirrorInfo = new ConcurrentHashMap<>(); @@ -235,6 +243,9 @@ public final class NativeDataAccess { if (TRACE_MIRROR_ALLOCATION_SITES) { registerAllocationSite(arg, newMirror); } + if (RFFILog.traceEnabled()) { + RFFILog.printf("NativeMirror:" + newMirror.id + "->" + obj.getClass().getSimpleName() + ',' + obj.hashCode()); + } return newMirror; } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RArgsValuesAndNames.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RArgsValuesAndNames.java index fee0ee0e9f4f3d1ec84ad3b192ca03f0bdf94f8d..f0182160856b72173b12e5dd533ec35f7ad2f186 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RArgsValuesAndNames.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RArgsValuesAndNames.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, 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 @@ -108,7 +108,7 @@ public final class RArgsValuesAndNames extends RObject implements RTypedValue { assert signature.getLength() == getLength(); for (int i = 0; i < getLength(); i++) { String name = signature.getName(i); - RPairList cur = RDataFactory.createPairList(getArgument(i), RNull.instance, name != null ? name : RNull.instance, SEXPTYPE.DOTSXP); + RPairList cur = RDataFactory.createPairList(getArgument(i), RNull.instance, name != null ? RDataFactory.createSymbol(name) : RNull.instance, SEXPTYPE.DOTSXP); if (head == null) { head = cur; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExternalPtr.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExternalPtr.java index fa03686af947f9cc3137ef97fbcb97ac4f14b686..5112b663132a02c31723cd5da68c103149ac51bf 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExternalPtr.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExternalPtr.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, 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 @@ -56,6 +56,7 @@ public final class RExternalPtr extends RAttributeStorage implements RTypedValue } public SymbolHandle getAddr() { + // TODO: can be null? Callers do dereference the return value. return handle; } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java index 8ba6f70a6a9a78a99fd0fcf5609becef434cf1af..b729095f5df82ea0face701e2c98ccf540b0eb45 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java @@ -45,7 +45,13 @@ import com.oracle.truffle.r.runtime.gnur.SEXPTYPE; * {@code null} is never allowed as a value for the tag, car or cdr, only the type. */ public final class RPairList extends RSharingAttributeStorage implements RAbstractContainer, Iterable<RPairList> { + /** + * Data of the current pair list cell. + */ private Object car = RNull.instance; + /** + * Link to the next {@link RPairList} cell or {@link RNull} if last. + */ private Object cdr = RNull.instance; /** * Externally, i.e., when serialized, this is either a SYMSXP ({@link RSymbol}) or an @@ -336,9 +342,7 @@ public final class RPairList extends RSharingAttributeStorage implements RAbstra int i = 0; while (true) { data[i] = Utils.toString(pl.tag); - if (pl.tag == RRuntime.STRING_NA) { - complete = false; - } + complete &= data[i] != RRuntime.STRING_NA; if (isNull(pl.cdr)) { break; } @@ -353,7 +357,7 @@ public final class RPairList extends RSharingAttributeStorage implements RAbstra Object p = this; for (int i = 0; i < newNames.getLength() && !isNull(p); i++) { RPairList pList = (RPairList) p; - pList.tag = newNames.getDataAt(i); + pList.tag = RDataFactory.createSymbol(newNames.getDataAt(i)); p = pList.cdr; } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFILog.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFILog.java new file mode 100644 index 0000000000000000000000000000000000000000..5f736dec33c52d126a9bf8c02000b22fc0846d4d --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFILog.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2018, 2018, 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.runtime.ffi; + +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Path; + +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.r.runtime.FastROptions; +import com.oracle.truffle.r.runtime.Utils; +import com.oracle.truffle.r.runtime.context.RContext; + +public class RFFILog { + /** + * Set this to {@code true} when it is not possible to set {@link FastROptions}. + */ + private static boolean alwaysTrace; + /** + * Is set by initialization and caches whether we are tracing. + */ + @CompilationFinal public static boolean traceEnabled; + + public static boolean traceInitialized; + + /** + * Always trace to a file because stdout is problematic for embedded mode. + */ + private static final String TRACEFILE = "fastr_trace_nativecalls.log"; + private static PrintWriter traceStream; + + /** + * Handles the initialization of the RFFI downcalls/upcall tracing implementation. + */ + public static synchronized void initializeTracing() { + if (!traceInitialized) { + traceInitialized = true; + traceEnabled = alwaysTrace || FastROptions.TraceNativeCalls.getBooleanValue(); + if (traceEnabled) { + if (traceStream == null) { + initTraceStream(); + } + } + } + } + + public static boolean traceEnabled() { + return traceEnabled; + } + + public static synchronized void write(String value) { + assert traceEnabled : "check traceEnabled() before calling RFFILog.write"; + traceStream.write(value); + traceStream.append(" [ctx:").append("" + System.identityHashCode(RContext.getInstance())); + traceStream.append(",thread:").append("" + Thread.currentThread().getId()).append(']'); + traceStream.write('\n'); + traceStream.flush(); + } + + public static synchronized void printf(String fmt, Object... args) { + assert traceEnabled : "check traceEnabled() before calling RFFILog.printf"; + traceStream.printf(fmt, args); + traceStream.write('\n'); + traceStream.flush(); + } + + public static synchronized void printStackTrace() { + assert traceEnabled : "check traceEnabled() before calling RFFILog.printStackTrace"; + new RuntimeException().printStackTrace(traceStream); + } + + private static void initTraceStream() { + Path tracePath = Utils.getLogPath(TRACEFILE); + try { + traceStream = new PrintWriter(tracePath.toString()); + } catch (IOException ex) { + System.err.println(ex.getMessage()); + System.exit(1); + } + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RCodeBuilder.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RCodeBuilder.java index 1071ca6c130f8dd37f1e075776b94f0b84a391ef..9d4415f7ab1c90c91c4132c59618c156184b9ade 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RCodeBuilder.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RCodeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, 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 @@ -32,6 +32,7 @@ import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.context.TruffleRLanguage; +import com.oracle.truffle.r.runtime.data.RNull; /** * Implementers of this interface can be used to generate a representation of an R closure. @@ -120,6 +121,13 @@ public interface RCodeBuilder<T> { */ RootCallTarget rootFunction(TruffleRLanguage language, SourceSection source, List<Argument<T>> arguments, T body, String name); + /** + * Given a {@link com.oracle.truffle.r.runtime.data.RPairList} or {@link RNull}, this method + * creates a corresponding list of named arguments with default values if any, like if passed to + * the `function` expression. + */ + List<Argument<RSyntaxNode>> getFunctionExprArgs(Object args); + void setContext(CodeBuilderContext context); CodeBuilderContext getContext(); 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 1a21c8090a5a601bfb60f3d7df41906514cd2d50..440ac65414ad32b7126fb05f6e1781f0e148f82b 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 @@ -5917,10 +5917,6 @@ foo() #call('function') function() NULL -##com.oracle.truffle.r.test.builtins.TestBuiltin_ascall.testAsCall#Output.IgnoreWhitespace# -#call('function', 'a') -Error: badly formed function expression - ##com.oracle.truffle.r.test.builtins.TestBuiltin_ascall.testAsCall#Output.IgnoreWhitespace# #call('function', pairlist(a=1)) function(a = 1) NULL @@ -5949,6 +5945,13 @@ pairlist(a = )() #e <- substitute(a$b(c)); as.call(lapply(e, function(x) x)) a$b(c) +##com.oracle.truffle.r.test.builtins.TestBuiltin_ascall.testAsCall#Output.IgnoreWhitespace# +#invisible(call('function', 'a')) + +##com.oracle.truffle.r.test.builtins.TestBuiltin_ascall.testAsCall#Output.IgnoreWhitespace# +#length(call('function', 'a')) +[1] 2 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_ascall.testAsCall# #typeof(as.call(list(substitute(graphics::par)))) [1] "language" @@ -28261,6 +28264,21 @@ Error: atomic vector arguments only #argv <- structure(list(pv = 0.200965994008331, digits = 3), .Names = c('pv', 'digits'));do.call('format.pval', argv) [1] "0.201" +##com.oracle.truffle.r.test.builtins.TestBuiltin_function.testFunctionFunction# +#do.call('function', list(as.pairlist(list(x=4)), expression(x + 1)[[1]])) +function (x = 4) +x + 1 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_function.testFunctionFunction#Output.IgnoreErrorContext# +#eval(call('function', 1, expression(x + 1)[[1]])) +Error in eval(call("function", 1, expression(x + 1)[[1]])) : + invalid formal argument list for "function" + +##com.oracle.truffle.r.test.builtins.TestBuiltin_function.testFunctionFunction# +#eval(call('function', as.pairlist(list(x=4)), expression(x + 1)[[1]])) +function (x = 4) +x + 1 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_g.testg1#Output.IgnoreErrorContext# #argv <- list(1);g(argv[[1]]); Error in g(argv[[1]]) : could not find function "g" diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_ascall.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_ascall.java index 7b5523963748615dc4b7c21994975f8f3acf90f4..bc6fff85e3d6fb0157283ba3669227307ad25d7d 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_ascall.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_ascall.java @@ -4,7 +4,7 @@ * http://www.gnu.org/licenses/gpl-2.0.html * * Copyright (c) 2012-2014, Purdue University - * Copyright (c) 2013, 2017, Oracle and/or its affiliates + * Copyright (c) 2013, 2018, Oracle and/or its affiliates * * All rights reserved. */ @@ -68,7 +68,9 @@ public class TestBuiltin_ascall extends TestBase { assertEval(Output.IgnoreWhitespace, "e <- expression(function(a) b); as.call(list(e[[1]][[1]]))"); assertEval("e <- expression(function(a) b); as.call(list(e[[1]][[2]]))"); assertEval("call('foo')"); - assertEval(Output.IgnoreWhitespace, "call('function', 'a')"); + // Note: call('function', 'a') should not cause the exception, it should be the printing + assertEval(Output.IgnoreWhitespace, "invisible(call('function', 'a'))"); + assertEval(Output.IgnoreWhitespace, "length(call('function', 'a'))"); assertEval(Output.IgnoreWhitespace, "call('function', pairlist(a=1))"); assertEval(Output.IgnoreWhitespace, "call('function', pairlist(a=1), 3)"); assertEval(Output.IgnoreWhitespace, "call('function', pairlist(a=1), 5,3)"); diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_function.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_function.java new file mode 100644 index 0000000000000000000000000000000000000000..eac9c3629d63f0921183400c3ad3b3ba025206dc --- /dev/null +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_function.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014, 2018, 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.test.builtins; + +import org.junit.Test; + +import com.oracle.truffle.r.test.TestBase; + +// Checkstyle: stop line length check +public class TestBuiltin_function extends TestBase { + @Test + public void testFunctionFunction() { + assertEval(Output.IgnoreErrorContext, "eval(call('function', 1, expression(x + 1)[[1]]))"); + assertEval("eval(call('function', as.pairlist(list(x=4)), expression(x + 1)[[1]]))"); + assertEval("do.call('function', list(as.pairlist(list(x=4)), expression(x + 1)[[1]]))"); + } +} diff --git a/mx.fastr/mx_fastr_edinclude.py b/mx.fastr/mx_fastr_edinclude.py index 0032c54979c0af20778ea657a9375c0eb1fdea47..40d357e92ea0c54e58b544ea598780ae36d2c79a 100644 --- a/mx.fastr/mx_fastr_edinclude.py +++ b/mx.fastr/mx_fastr_edinclude.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2018, 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 @@ -74,6 +74,14 @@ use_internals_end = '''#endif ''' +set_typeof_rewrite = '''#ifdef FASTR +SEXP SET_TYPEOF_FASTR(SEXP x, int v); +#ifndef NO_FASTR_REDEFINE +#define SET_TYPEOF(X,Y) X=SET_TYPEOF_FASTR(X,Y) +#endif +#endif +''' + def ed_r_internals(gnu_dir): r_internals_h = join(gnu_dir, 'Rinternals.h') with open(r_internals_h) as f: @@ -105,6 +113,9 @@ def ed_r_internals(gnu_dir): rewrite_var(f, var, line) else: f.write(line) + elif 'SET_TYPEOF' in line and '(SEXP' in line: + f.write(line) + f.write(set_typeof_rewrite) else: f.write(line)