From fc208bbb4bc242b565552f80afa63497ce570b8f Mon Sep 17 00:00:00 2001 From: Florian Angerer <florian.angerer@oracle.com> Date: Mon, 25 Sep 2017 18:06:04 +0200 Subject: [PATCH] Implemented recursive materialization for FFI arguments. --- .../foreign/CallAndExternalFunctions.java | 2 +- .../r/runtime/data/nodes/MaterializeNode.java | 106 +++++++++++++++++- 2 files changed, 101 insertions(+), 7 deletions(-) diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java index 647e0140bb..b6cedaff81 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java @@ -224,7 +224,7 @@ public class CallAndExternalFunctions { public abstract static class DotCall extends LookupAdapter { @Child CallRFFI.InvokeCallNode callRFFINode = RFFIFactory.getCallRFFI().createInvokeCallNode(); - @Child MaterializeNode materializeNode = MaterializeNode.create(); + @Child MaterializeNode materializeNode = MaterializeNode.create(true); static { Casts.noCasts(DotCall.class); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/MaterializeNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/MaterializeNode.java index 67f641bca4..0378a2abac 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/MaterializeNode.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/MaterializeNode.java @@ -22,28 +22,100 @@ */ package com.oracle.truffle.r.runtime.data.nodes; +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.nodes.attributes.HasAttributesNode; +import com.oracle.truffle.r.nodes.attributes.IterableAttributeNode; +import com.oracle.truffle.r.nodes.attributes.SetAttributeNode; +import com.oracle.truffle.r.runtime.data.RAttributable; +import com.oracle.truffle.r.runtime.data.RAttributesLayout.RAttribute; +import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; public abstract class MaterializeNode extends Node { protected static final int LIMIT = 10; + @Child private HasAttributesNode hasAttributes; + @Child private IterableAttributeNode attributesIt; + @Child private SetAttributeNode setAttributeNode; + + @Child private MaterializeNode recursive; + @Child private MaterializeNode recursiveAttr; + + private final boolean deep; + + protected MaterializeNode(boolean deep) { + this.deep = deep; + if (deep) { + CompilerAsserts.neverPartOfCompilation(); + hasAttributes = insert(HasAttributesNode.create()); + } + } + public abstract Object execute(VirtualFrame frame, Object arg); + @Specialization + protected RList doList(VirtualFrame frame, RList vec) { + RList materialized = materializeContents(frame, vec); + materializeAttributes(frame, materialized); + return materialized; + } + + private RList materializeContents(VirtualFrame frame, RList list) { + boolean changed = false; + RList materializedContents = null; + for (int i = 0; i < list.getLength(); i++) { + if (recursive == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + recursive = insert(MaterializeNode.create(deep)); + } + Object element = list.getDataAt(i); + Object materializedElem = recursive.execute(frame, element); + if (materializedElem != element) { + materializedContents = (RList) list.copy(); + changed = true; + } + if (changed && materializedElem != element) { + materializedContents.setDataAt(i, materializedElem); + } + } + if (changed) { + return materializedContents; + } + return list; + } + @Specialization(limit = "LIMIT", guards = {"vec.getClass() == cachedClass"}) - protected RAbstractContainer doAbstractContainerCached(RAbstractContainer vec, + protected RAttributable doAbstractContainerCached(VirtualFrame frame, RAttributable vec, @SuppressWarnings("unused") @Cached("vec.getClass()") Class<?> cachedClass) { - return vec.materialize(); + if (vec instanceof RList) { + return doList(frame, (RList) vec); + } else if (vec instanceof RAbstractContainer) { + RAbstractContainer materialized = ((RAbstractContainer) vec).materialize(); + materializeAttributes(frame, materialized); + return materialized; + } + materializeAttributes(frame, vec); + return vec; } @Specialization(replaces = "doAbstractContainerCached") - protected RAbstractContainer doAbstractContainer(RAbstractContainer vec) { - return vec.materialize(); + protected RAttributable doAbstractContainer(VirtualFrame frame, RAttributable vec) { + if (vec instanceof RList) { + return doList(frame, (RList) vec); + } else if (vec instanceof RAbstractContainer) { + RAbstractContainer materialized = ((RAbstractContainer) vec).materialize(); + materializeAttributes(frame, materialized); + return materialized; + } + materializeAttributes(frame, vec); + return vec; } @Fallback @@ -51,8 +123,30 @@ public abstract class MaterializeNode extends Node { return o; } - public static MaterializeNode create() { - return MaterializeNodeGen.create(); + private void materializeAttributes(VirtualFrame frame, RAttributable materialized) { + // TODO we could further optimize by first checking for fixed/special attributes + if (deep && hasAttributes.execute(materialized)) { + if (attributesIt == null) { + assert recursiveAttr == null; + CompilerDirectives.transferToInterpreterAndInvalidate(); + attributesIt = insert(IterableAttributeNode.create()); + recursiveAttr = insert(MaterializeNode.create(deep)); + } + for (RAttribute attr : attributesIt.execute(materialized)) { + Object materializedAttr = recursiveAttr.execute(frame, attr.getValue()); + if (materializedAttr != attr.getValue()) { + if (setAttributeNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + setAttributeNode = insert(SetAttributeNode.create()); + } + setAttributeNode.execute(materialized, attr.getName(), materializedAttr); + } + } + } + } + + public static MaterializeNode create(boolean deep) { + return MaterializeNodeGen.create(deep); } } -- GitLab