From d46cec840d7821171ab9064fd89b7e2a90b2c6fa Mon Sep 17 00:00:00 2001 From: Florian Angerer <florian.angerer@oracle.com> Date: Tue, 30 May 2017 14:18:48 +0200 Subject: [PATCH] Implemented deserialization of srcref attributes and conversion to source sections. --- .../r/nodes/builtin/base/GetOldClass.java | 6 + .../truffle/r/nodes/builtin/base/Parse.java | 6 +- .../oracle/truffle/r/runtime/RSerialize.java | 165 +++++++++++++++--- .../com/oracle/truffle/r/runtime/RSource.java | 10 ++ 4 files changed, 162 insertions(+), 25 deletions(-) diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetOldClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetOldClass.java index 8301704079..a0e3caa565 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetOldClass.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetOldClass.java @@ -34,6 +34,7 @@ import com.oracle.truffle.r.nodes.function.ClassHierarchyNode; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; @RBuiltin(name = "oldClass", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE) @@ -56,6 +57,11 @@ public abstract class GetOldClass extends RBuiltinNode.Arg1 { } } + @Specialization + protected Object getOldClass(@SuppressWarnings("unused") RSymbol arg) { + return RNull.instance; + } + @Specialization protected Object getOldClass(@SuppressWarnings("unused") RFunction arg) { return RNull.instance; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java index 55e01a2343..d39308b1ce 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java @@ -96,9 +96,9 @@ public abstract class Parse extends RBuiltinNode.Arg6 { @Child private CastStringNode castStringNode; @Child private CastToVectorNode castVectorNode; - @Child private SetFixedAttributeNode setSrcRefAttrNode = SetFixedAttributeNode.create("srcref"); - @Child private SetFixedAttributeNode setWholeSrcRefAttrNode = SetFixedAttributeNode.create("wholeSrcref"); - @Child private SetFixedAttributeNode setSrcFileAttrNode = SetFixedAttributeNode.create("srcfile"); + @Child private SetFixedAttributeNode setSrcRefAttrNode = SetFixedAttributeNode.create(RRuntime.R_SRCREF); + @Child private SetFixedAttributeNode setWholeSrcRefAttrNode = SetFixedAttributeNode.create(RRuntime.R_WHOLE_SRCREF); + @Child private SetFixedAttributeNode setSrcFileAttrNode = SetFixedAttributeNode.create(RRuntime.R_SRCFILE); static { Casts casts = new Casts(Parse.class); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java index 85b7cd674b..b9f432b18f 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java @@ -19,6 +19,7 @@ import java.io.OutputStream; import java.io.PrintStream; import java.lang.ref.WeakReference; import java.nio.charset.StandardCharsets; +import java.nio.file.NoSuchFileException; import java.util.ArrayList; import java.util.Arrays; import java.util.Deque; @@ -39,6 +40,8 @@ import com.oracle.truffle.api.frame.FrameSlot; import com.oracle.truffle.api.frame.FrameSlotKind; import com.oracle.truffle.api.frame.MaterializedFrame; 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.conn.RConnection; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; @@ -50,6 +53,7 @@ import com.oracle.truffle.r.runtime.data.REmpty; import com.oracle.truffle.r.runtime.data.RExpression; import com.oracle.truffle.r.runtime.data.RExternalPtr; import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.data.RIntVector; import com.oracle.truffle.r.runtime.data.RLanguage; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RMissing; @@ -80,6 +84,7 @@ import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor; import com.oracle.truffle.r.runtime.ffi.DLL; import com.oracle.truffle.r.runtime.gnur.SEXPTYPE; import com.oracle.truffle.r.runtime.nodes.RCodeBuilder; +import com.oracle.truffle.r.runtime.nodes.RSourceSectionNode; import com.oracle.truffle.r.runtime.nodes.RSyntaxCall; import com.oracle.truffle.r.runtime.nodes.RSyntaxConstant; import com.oracle.truffle.r.runtime.nodes.RSyntaxElement; @@ -580,6 +585,7 @@ public class RSerialize { RFunction func = PairlistDeserializer.processFunction(carItem, cdrItem, tagItem, currentFunctionName, packageName); if (attrItem != RNull.instance) { setAttributes(func, attrItem); + handleFunctionSrcrefAttr(func); } result = func; break; @@ -894,6 +900,7 @@ public class RSerialize { pl = (RPairList) cdr; } } + return result; } @@ -1458,15 +1465,15 @@ public class RSerialize { terminatePairList(); writeItem(RNull.instance); // hashtab DynamicObject attributes = env.getAttributes(); - if (attributes != null) { - writeAttributes(attributes); - } else { + writeAttributes(attributes, getSourceSection(obj)); + if (attributes == null) { writeItem(RNull.instance); } } } else { // flags DynamicObject attributes = null; + SourceSection ss = getSourceSection(obj); if (obj instanceof RAttributable) { RAttributable rattr = (RAttributable) obj; attributes = rattr.getAttributes(); @@ -1588,7 +1595,8 @@ public class RSerialize { /* * The objects that GnuR represents as a pairlist. To avoid stack overflow, - * these utilize manual tail recursion on the cdr of the pairlist. + * these utilize manual tail recursion on the cdr of the + * pairlist.closePairList */ case FUNSXP: @@ -1603,12 +1611,21 @@ public class RSerialize { stream.writeString(name); break; } + if (type == SEXPTYPE.FUNSXP) { + RFunction fun = (RFunction) obj; + RSyntaxFunction body = (RSyntaxFunction) fun.getRootNode(); + ss = body.getLazySourceSection(); + } tailCall = true; + // attributes written first to avoid recursion on cdr + writeAttributes(attributes, ss); if (attributes != null) { - writeAttributes(attributes); attributes = null; } + if (ss != null) { + ss = null; + } switch (type) { case FUNSXP: { @@ -1679,13 +1696,18 @@ public class RSerialize { throw RInternalError.unimplemented(type.name()); } - if (attributes != null) { - writeAttributes(attributes); - } + writeAttributes(attributes, ss); } } while (tailCall); } + private static SourceSection getSourceSection(Object obj) { + if (obj instanceof RSourceSectionNode) { + return ((RSourceSectionNode) obj).getLazySourceSection(); + } + return null; + } + private static Object getValueIgnoreActiveBinding(Frame frame, String key) { FrameDescriptor fd = frame.getFrameDescriptor(); FrameSlot slot = fd.findFrameSlot(key); @@ -1755,17 +1777,28 @@ public class RSerialize { } } - private void writeAttributes(DynamicObject attributes) throws IOException { - // have to convert to GnuR pairlist - Iterator<RAttributesLayout.RAttribute> iter = RAttributesLayout.asIterable(attributes).iterator(); - while (iter.hasNext()) { - RAttributesLayout.RAttribute attr = iter.next(); - // name is the tag of the virtual pairlist - // value is the car - // next is the cdr - writePairListEntry(attr.getName(), attr.getValue()); + private void writeAttributes(DynamicObject attributes, SourceSection ss) throws IOException { + if (attributes != null) { + // have to convert to GnuR pairlist + Iterator<RAttributesLayout.RAttribute> iter = RAttributesLayout.asIterable(attributes).iterator(); + while (iter.hasNext()) { + RAttributesLayout.RAttribute attr = iter.next(); + // name is the tag of the virtual pairlist + // value is the car + // next is the cdr + writePairListEntry(attr.getName(), attr.getValue()); + } + } + if (ss != null && ss != RSyntaxNode.LAZY_DEPARSE) { + String path = ss.getSource().getURI().getPath(); + REnvironment createSrcfile = RSrcref.createSrcfile(path); + RIntVector createLloc = RSrcref.createLloc(ss, createSrcfile); + writePairListEntry(RRuntime.R_SRCREF, createLloc); + writePairListEntry(RRuntime.R_SRCFILE, createSrcfile); + } + if (attributes != null || ss != null) { + terminatePairList(); } - terminatePairList(); } private void writePairListEntry(String name, Object value) throws IOException { @@ -2254,6 +2287,7 @@ public class RSerialize { @Override protected Void visit(RSyntaxLookup element) { +// setSrcrefs(element) state.setCarAsSymbol(element.getIdentifier()); return null; } @@ -2341,7 +2375,8 @@ public class RSerialize { REnvironment env = REnvironment.frameToEnvironment(f.getEnclosingFrame()); state.openPairList().setTag(env); serializeFunctionDefinition(state, function); - return state.closePairList(); + Object pl = state.closePairList(); + return pl; } private static void serializeFunctionDefinition(State state, RSyntaxFunction function) { @@ -2494,20 +2529,106 @@ public class RSerialize { private static RSyntaxNode processBody(Object cdr) { if (cdr instanceof RPairList) { RPairList pl = (RPairList) cdr; + RSyntaxNode body; switch (pl.getType()) { case BCODESXP: RAbstractListVector list = (RAbstractListVector) pl.cdr(); - return process(list.getDataAtAsObject(0), false); + body = process(list.getDataAtAsObject(0), false); + break; case LISTSXP: assert pl.cdr() == RNull.instance || (pl.cadr() == RNull.instance && pl.cddr() == RNull.instance); - return process(pl.car(), false); + body = process(pl.car(), false); + break; case LANGSXP: - return processCall(pl.car(), pl.cdr(), pl.getTag()); + body = processCall(pl.car(), pl.cdr(), pl.getTag()); + break; default: throw RInternalError.shouldNotReachHere("unexpected SXP type in body: " + pl.getType()); } + handleSrcrefAttr(pl, body); + return body; } return process(cdr, false); } } + + private static void handleFunctionSrcrefAttr(RFunction func) { + handleSrcrefAttr(func, (RSyntaxElement) func.getRootNode()); + } + + /** + * @param func Element carrying the {@value RRuntime#R_SRCREF} attribute. + * @param elem The syntax element to create the source section for. + */ + private static void handleSrcrefAttr(RAttributable func, RSyntaxElement elem) { + if (elem instanceof RSyntaxCall) { + handleSrcrefAttr(func, (RSyntaxCall) elem); + } else { + Object srcref = func.getAttr(RRuntime.R_SRCREF); + if (srcref instanceof RAbstractIntVector) { + handleSrcrefAttr((RAbstractIntVector) srcref, null, elem); + } + } + } + + /** + * @param func Element carrying the {@value RRuntime#R_SRCREF} attribute. + * @param elem The syntax element to create the source section for. + */ + private static void handleSrcrefAttr(RAttributable func, RSyntaxCall elem) { + Object srcref = func.getAttr(RRuntime.R_SRCREF); + if (srcref instanceof RAbstractIntVector) { + handleSrcrefAttr((RAbstractIntVector) srcref, null, elem); + } else if (srcref instanceof RList) { + try { + Object srcfile = func.getAttr(RRuntime.R_SRCFILE); + assert srcfile instanceof REnvironment; + Source source = RSource.fromFile((REnvironment) srcfile); + + RList l = (RList) srcref; + RSyntaxElement[] syntaxArguments = elem.getSyntaxArguments(); + assert syntaxArguments.length == l.getLength() - 1; + + for (int i = 0; i < l.getLength(); i++) { + Object dataAt = l.getDataAt(i); + assert dataAt instanceof RAbstractIntVector; + if (i == 0) { + handleSrcrefAttr((RAbstractIntVector) dataAt, source, elem); + } else { + handleSrcrefAttr((RAbstractIntVector) dataAt, source, syntaxArguments[i - 1]); + } + } + } catch (NoSuchFileException e) { + RError.warning(RError.SHOW_CALLER, RError.Message.GENERIC, "Missing source file: " + e.getMessage()); + } catch (IOException e) { + RError.warning(RError.SHOW_CALLER, RError.Message.GENERIC, "Cannot access source file: " + e.getMessage()); + } + } + } + + private static void handleSrcrefAttr(RAbstractIntVector srcrefVec, Source sharedSource, RSyntaxElement elem) { + + try { + Source source; + if (sharedSource != null) { + source = sharedSource; + } else { + Object srcfile = srcrefVec.getAttr(RRuntime.R_SRCFILE); + assert srcfile instanceof REnvironment; + source = RSource.fromFile((REnvironment) srcfile); + } + int startLine = srcrefVec.getDataAt(0); + int startColumn = srcrefVec.getDataAt(1); + int startIdx = source.getLineStartOffset(startLine) + startColumn; + int length = source.getLineStartOffset(srcrefVec.getDataAt(2)) + srcrefVec.getDataAt(3) - startIdx; + SourceSection createSection = source.createSection(startLine, startColumn, length); + elem.setSourceSection(createSection); + } catch (NoSuchFileException e) { + RError.warning(RError.SHOW_CALLER, RError.Message.GENERIC, "Missing source file: " + e.getMessage()); + } catch (IOException e) { + RError.warning(RError.SHOW_CALLER, RError.Message.GENERIC, "Cannot access source file: " + e.getMessage()); + } catch (IllegalArgumentException e) { + RError.warning(RError.SHOW_CALLER, RError.Message.GENERIC, "Invalid source reference: " + e.getMessage()); + } + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java index 16f3e223d1..c345c3e30c 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java @@ -30,6 +30,8 @@ import java.net.URL; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.runtime.RSrcref.SrcrefFields; +import com.oracle.truffle.r.runtime.env.REnvironment; /** * A facade for the creation of Truffle {@link Source} objects, which is complicated in R due the @@ -187,6 +189,14 @@ public class RSource { return Source.newBuilder(url).name(name).mimeType(RRuntime.R_APP_MIME).build(); } + /** + * Create an (external) source from an R srcfile ({@link RSrcref#createSrcfile(String)}). + */ + public static Source fromFile(REnvironment env) throws IOException { + String path = (String) RRuntime.r2Java(env.get(SrcrefFields.filename.name())); + return fromFileName(path, false); + } + /** * Create an unknown source with the given name. */ -- GitLab