From 97b865480e1edc6189ca3785d8e1d67873e4e597 Mon Sep 17 00:00:00 2001 From: Lukas Stadler <lukas.stadler@oracle.com> Date: Wed, 15 Nov 2017 16:56:29 +0100 Subject: [PATCH] restructure extract/replace nodes and convert to VectorAccess --- .../r/nodes/builtin/base/GetFunctions.java | 3 +- .../vector/CachedExtractVectorNode.java | 91 +--- .../vector/CachedReplaceVectorNode.java | 313 ++++---------- .../nodes/access/vector/CachedVectorNode.java | 27 -- .../access/vector/ExtractS4ObjectNode.java | 61 --- .../access/vector/ExtractVectorNode.java | 103 ++++- .../access/vector/ReplaceS4ObjectNode.java | 53 --- .../access/vector/ReplaceVectorNode.java | 265 ++++++++---- .../access/vector/WriteIndexedVectorNode.java | 390 ++++++------------ .../oracle/truffle/r/nodes/objects/AsS4.java | 2 +- .../r/nodes/objects/GetS4DataSlot.java | 18 +- .../oracle/truffle/r/runtime/RRuntime.java | 4 + 12 files changed, 518 insertions(+), 812 deletions(-) delete mode 100644 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractS4ObjectNode.java delete mode 100644 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceS4ObjectNode.java diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java index c1c66e7f6d..972ed1ade4 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java @@ -51,7 +51,6 @@ import com.oracle.truffle.r.nodes.function.RCallerHelper; import com.oracle.truffle.r.nodes.function.call.CallRFunctionCachedNode; import com.oracle.truffle.r.nodes.function.call.CallRFunctionCachedNodeGen; import com.oracle.truffle.r.nodes.objects.GetS4DataSlot; -import com.oracle.truffle.r.nodes.objects.GetS4DataSlotNodeGen; import com.oracle.truffle.r.nodes.unary.CastNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RCaller; @@ -146,7 +145,7 @@ public class GetFunctions { public static final class S4ToEnvNode extends CastNode { - @Child private GetS4DataSlot getS4Data = GetS4DataSlotNodeGen.create(RType.Environment); + @Child private GetS4DataSlot getS4Data = GetS4DataSlot.create(RType.Environment); @Override public Object execute(Object obj) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java index 903947939f..4ab4126616 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java @@ -39,10 +39,8 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNa import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode; -import com.oracle.truffle.r.nodes.function.PromiseHelperNode; import com.oracle.truffle.r.nodes.profile.AlwaysOnBranchProfile; import com.oracle.truffle.r.nodes.profile.VectorLengthProfile; -import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.context.RContext; @@ -52,8 +50,6 @@ import com.oracle.truffle.r.runtime.data.RLanguage; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RLogical; import com.oracle.truffle.r.runtime.data.RNull; -import com.oracle.truffle.r.runtime.data.RPromise; -import com.oracle.truffle.r.runtime.data.RS4Object; import com.oracle.truffle.r.runtime.data.RString; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RTypedValue; @@ -61,7 +57,6 @@ import com.oracle.truffle.r.runtime.data.RVector; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; -import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.nodes.RBaseNode; final class CachedExtractVectorNode extends CachedVectorNode { @@ -69,7 +64,7 @@ final class CachedExtractVectorNode extends CachedVectorNode { private static final boolean DEFAULT_EXACT = true; private static final boolean DEFAULT_DROP_DIMENSION = true; - private final Class<? extends RTypedValue> targetClass; + private final Class<? extends RAbstractContainer> targetClass; private final Class<? extends RTypedValue> exactClass; private final Class<? extends RTypedValue> dropDimensionsClass; private final boolean exact; @@ -90,10 +85,7 @@ final class CachedExtractVectorNode extends CachedVectorNode { @Child private ExtractDimNamesNode extractDimNames; - @Child private ExtractS4ObjectNode extractS4ObjectNode; - private final ConditionProfile resultHasDimensions = ConditionProfile.createBinaryProfile(); - private final ConditionProfile promiseInEnvironment = ConditionProfile.createBinaryProfile(); /** * Profile if any metadata was applied at any point in time. This is useful extract primitive @@ -101,8 +93,9 @@ final class CachedExtractVectorNode extends CachedVectorNode { */ private final AlwaysOnBranchProfile metadataApplied = AlwaysOnBranchProfile.create(); - CachedExtractVectorNode(ElementAccessMode mode, RTypedValue vector, Object[] positions, RTypedValue exact, RTypedValue dropDimensions, boolean recursive) { + CachedExtractVectorNode(ElementAccessMode mode, RAbstractContainer vector, Object[] positions, RTypedValue exact, RTypedValue dropDimensions, boolean recursive) { super(mode, vector, positions, recursive); + assert vectorType != RType.Null && vectorType != RType.Environment; this.targetClass = vector.getClass(); this.exactClass = exact.getClass(); this.dropDimensionsClass = dropDimensions.getClass(); @@ -112,9 +105,7 @@ final class CachedExtractVectorNode extends CachedVectorNode { this.exact = logicalAsBoolean(exact, DEFAULT_EXACT); this.dropDimensions = logicalAsBoolean(dropDimensions, DEFAULT_DROP_DIMENSION); this.positionsCheckNode = new PositionsCheckNode(mode, vectorType, convertedPositions, this.exact, false, recursive); - if (error == null && vectorType != RType.Null && vectorType != RType.Environment && vectorType != RType.S4Object) { - this.writeVectorNode = WriteIndexedVectorNode.create(vectorType, convertedPositions.length, true, false, false, false); - } + this.writeVectorNode = WriteIndexedVectorNode.create(vectorType, convertedPositions.length, true, false, false); } public boolean isSupported(Object target, Object[] positions, Object exactValue, Object dropDimensionsValue) { @@ -130,36 +121,10 @@ final class CachedExtractVectorNode extends CachedVectorNode { private final ConditionProfile extractedLengthGTZeroProfile = ConditionProfile.createBinaryProfile(); private final ConditionProfile oneDimensionProfile = ConditionProfile.createBinaryProfile(); - public Object apply(Object originalVector, Object[] originalPositions, PositionProfile[] originalProfiles, Object originalExact, Object originalDropDimensions) { - if (error != null) { - CompilerDirectives.transferToInterpreter(); - error.run(); - } + public Object apply(RAbstractContainer originalVector, Object[] originalPositions, PositionProfile[] originalProfiles, Object originalExact, Object originalDropDimensions) { final Object[] positions = filterPositions(originalPositions); - assert isSupported(originalVector, positions, originalExact, originalDropDimensions); - - final RTypedValue castVector = targetClass.cast(originalVector); - final RAbstractContainer vector; - switch (vectorType) { - case Null: - return RNull.instance; - case Environment: - /* - * TODO (chumer) the environment case cannot be applied to the default extract - * method as it does not implement RAbstractContainer. This should be harmonized - * later. - */ - return doEnvironment((REnvironment) castVector, positions); - case S4Object: - return doS4Object((RS4Object) castVector, positions); - case Integer: - vector = (RAbstractContainer) castVector; - break; - default: - vector = (RAbstractContainer) castVector; - break; - } + RAbstractContainer vector = targetClass.cast(originalVector); int vectorLength = vectorLengthProfile.profile(vector.getLength()); @@ -178,11 +143,8 @@ final class CachedExtractVectorNode extends CachedVectorNode { } int extractedVectorLength = positionsCheckNode.getSelectedPositionsCount(positionProfiles); - final RVector<?> extractedVector; + RVector<?> extractedVector; switch (vectorType) { - case Expression: - extractedVector = RType.Expression.create(extractedVectorLength, false); - break; case Language: case PairList: extractedVector = RType.List.create(extractedVectorLength, false); @@ -194,9 +156,7 @@ final class CachedExtractVectorNode extends CachedVectorNode { if (mode.isSubset()) { if (extractedLengthGTZeroProfile.profile(extractedVectorLength > 0)) { - writeVectorNode.enableValueNACheck(vector); - writeVectorNode.apply(extractedVector, extractedVectorLength, positions, vector, vectorLength, dimensions); - extractedVector.setComplete(writeVectorNode.neverSeenNAInValue()); + writeVectorNode.execute(extractedVector, positions, vector, dimensions); RBaseNode.reportWork(this, extractedVectorLength); } if (oneDimensionProfile.profile(numberOfDimensions == 1)) { @@ -216,15 +176,13 @@ final class CachedExtractVectorNode extends CachedVectorNode { } switch (vectorType) { - case Expression: - return extractedVector; case Language: return materializeLanguage(extractedVector); default: return trySubsetPrimitive(extractedVector); } } else { - writeVectorNode.apply(extractedVector, extractedVectorLength, positions, vector, vectorLength, dimensions); + writeVectorNode.execute(extractedVector, positions, vector, dimensions); RBaseNode.reportWork(this, 1); assert extractedVectorLength == 1; return extractedVector.getDataAtAsObject(0); @@ -242,7 +200,7 @@ final class CachedExtractVectorNode extends CachedVectorNode { } private Object trySubsetPrimitive(RAbstractVector extractedVector) { - if (!metadataApplied.isVisited() && positionsCheckNode.getCachedSelectedPositionsCount() == 1 && !isList()) { + if (!metadataApplied.isVisited() && positionsCheckNode.getCachedSelectedPositionsCount() == 1 && vectorType != RType.List && vectorType != RType.Expression) { /* * If the selected count was always 1 and no metadata was ever set we can just extract * the primitive value from the vector. This branch has to fold to a constant because we @@ -256,31 +214,6 @@ final class CachedExtractVectorNode extends CachedVectorNode { return extractedVector; } - @TruffleBoundary - private Object doEnvironment(REnvironment env, Object[] positions) { - if (mode.isSubset()) { - throw error(RError.Message.OBJECT_NOT_SUBSETTABLE, RType.Environment.getName()); - } - - String positionString = tryCastSingleString(positionsCheckNode, positions); - if (positionString != null) { - Object obj = env.get(positionString); - if (promiseInEnvironment.profile(obj instanceof RPromise)) { - obj = PromiseHelperNode.evaluateSlowPath((RPromise) obj); - } - return obj == null ? RNull.instance : obj; - } - throw error(RError.Message.WRONG_ARGS_SUBSET_ENV); - } - - private Object doS4Object(RS4Object object, Object[] positions) { - if (extractS4ObjectNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - extractS4ObjectNode = insert(new ExtractS4ObjectNode(mode, exact, dropDimensions)); - } - return extractS4ObjectNode.execute(object, positions); - } - private boolean isMissingSingleDimension() { return numberOfDimensions == 1 && positionsCheckNode.isMissing(); } @@ -298,10 +231,6 @@ final class CachedExtractVectorNode extends CachedVectorNode { return extractDimNames.extract(dimensionIndex, vector, pos, profile); } - private boolean isList() { - return vectorType == RType.List; - } - private final ConditionProfile dimNamesNull = ConditionProfile.createBinaryProfile(); private final ValueProfile foundDimNamesProfile = ValueProfile.createClassProfile(); private final ConditionProfile selectPositionsProfile = ConditionProfile.createBinaryProfile(); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java index 40e456bf6c..43e9de314e 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java @@ -34,7 +34,6 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; -import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.profiles.ValueProfile; @@ -49,15 +48,11 @@ import com.oracle.truffle.r.nodes.unary.CastNode; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RType; -import com.oracle.truffle.r.runtime.context.RContext; -import com.oracle.truffle.r.runtime.data.RAttributesLayout; import com.oracle.truffle.r.runtime.data.RDataFactory; -import com.oracle.truffle.r.runtime.data.RLanguage; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RNull; -import com.oracle.truffle.r.runtime.data.RPairList; -import com.oracle.truffle.r.runtime.data.RS4Object; +import com.oracle.truffle.r.runtime.data.RScalarList; import com.oracle.truffle.r.runtime.data.RScalarVector; import com.oracle.truffle.r.runtime.data.RShareable; import com.oracle.truffle.r.runtime.data.RStringVector; @@ -66,27 +61,22 @@ import com.oracle.truffle.r.runtime.data.RVector; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; -import com.oracle.truffle.r.runtime.env.REnvironment; -import com.oracle.truffle.r.runtime.env.REnvironment.PutException; import com.oracle.truffle.r.runtime.nodes.RBaseNode; final class CachedReplaceVectorNode extends CachedVectorNode { private static final Object DELETE_MARKER = new Object(); - private final Class<?> vectorClass; + private final Class<? extends RAbstractVector> vectorClass; private final Class<?> valueClass; private final VectorLengthProfile targetLengthProfile = VectorLengthProfile.create(); private final VectorLengthProfile valueLengthProfile = VectorLengthProfile.create(); private final BranchProfile warningBranch = BranchProfile.create(); - private final ConditionProfile valueIsNA = ConditionProfile.createBinaryProfile(); private final BranchProfile resizeProfile = BranchProfile.create(); - private final ConditionProfile rlanguageAttributesProfile = ConditionProfile.createBinaryProfile(); private final ConditionProfile valueLengthOneProfile = ConditionProfile.createBinaryProfile(); private final ConditionProfile emptyReplacementProfile = ConditionProfile.createBinaryProfile(); - private final ConditionProfile completeVectorProfile = ConditionProfile.createBinaryProfile(); private final ValueProfile vectorTypeProfile = ValueProfile.createClassProfile(); @@ -103,9 +93,13 @@ final class CachedReplaceVectorNode extends CachedVectorNode { @Child private DeleteElementsNode deleteElementsNode; @Child private SetNamesAttributeNode setNamesNode; - CachedReplaceVectorNode(ElementAccessMode mode, RTypedValue vector, Object[] positions, Class<?> valueClass, RType valueType, boolean updatePositionNames, boolean recursive, - boolean ignoreRecursive, boolean isValueGt1) { + // if this is non-null, the node needs to throw the error whenever it is executed + @CompilationFinal protected Runnable error; + + CachedReplaceVectorNode(ElementAccessMode mode, RAbstractVector vector, Object[] positions, Class<?> valueClass, RType valueType, boolean updatePositionNames, boolean recursive, + boolean isValueGt1) { super(mode, vector, positions, recursive); + assert vectorType.isVector(); if (numberOfDimensions == 1 && positions[0] instanceof String || positions[0] instanceof RAbstractStringVector) { this.updatePositionNames = updatePositionNames; @@ -117,17 +111,48 @@ final class CachedReplaceVectorNode extends CachedVectorNode { this.valueClass = valueClass; this.valueType = valueType; this.isValueGt1 = isValueGt1; - this.castType = resolveCastVectorType(); - verifyCastType(this.castType); - this.castVectorNode = createCastVectorNode(); + + // determine the target cast type + if (vectorType == RType.List && mode.isSubscript()) { + if (valueType.isNull() && numberOfDimensions > 1) { + this.castType = null; + } else { + this.castType = vectorType; + } + } else if (valueType.isVector()) { + if (vectorType.isAtomic() && valueType.isAtomic() && (vectorType == RType.Raw ^ valueType == RType.Raw)) { + // mixing with raw with other atomic types is not allowed + this.castType = null; + } else { + this.castType = RType.maxPrecedence(valueType, vectorType); + } + } else if (valueType.isNull()) { + if (mode.isSubscript() && numberOfDimensions > 1) { + this.castType = null; + } else { + this.castType = vectorType; + } + } else { + this.castType = null; + } + + if (castType == null) { + Message message = (mode.isSubset() || vectorType != RType.List) ? RError.Message.SUBASSIGN_TYPE_FIX : RError.Message.SUBSCRIPT_TYPES; + error = () -> { + throw error(message, valueType.getName(), vectorType.getName(), false); + }; + } + + if (castType != vectorType && castType != null) { + // All casts except list casts preserve dimension names. + this.castVectorNode = castType == RType.List ? CastListNodeGen.create(true, false, true) : CastTypeNode.createCast(castType, true, true, true, false); + } this.deleteElementsNode = isDeleteElements() ? new DeleteElementsNode() : null; Object[] convertedPositions = filterPositions(positions); this.positionsCheckNode = new PositionsCheckNode(mode, vectorType, convertedPositions, true, true, recursive); - if (vectorType == RType.S4Object) { - replaceS4ObjectNode = new ReplaceS4ObjectNode(mode, ignoreRecursive); - } else if (castType != null && !castType.isNull()) { - this.writeVectorNode = WriteIndexedVectorNode.create(castType, convertedPositions.length, false, true, mode.isSubscript() && !isDeleteElements(), true); + if (castType != null && !castType.isNull()) { + this.writeVectorNode = WriteIndexedVectorNode.create(castType, convertedPositions.length, false, true, true); } } @@ -135,50 +160,41 @@ final class CachedReplaceVectorNode extends CachedVectorNode { return (values instanceof RAbstractContainer) && ((RAbstractContainer) values).getLength() > 1; } - public boolean isSupported(Object target, Object[] positions, Object values) { + public boolean isSupported(RAbstractVector target, Object[] positions, Object values) { if (vectorClass == target.getClass() && values.getClass() == valueClass) { return positionsCheckNode.isSupported(positions) && isValueLengthGreaterThanOne(values) == isValueGt1; } return false; } - public Object apply(Object originalVector, Object[] originalPositions, Object originalValues) { + public Object apply(RAbstractVector originalVector, Object[] originalPositions, Object originalValues) { if (error != null) { CompilerDirectives.transferToInterpreter(); error.run(); } - final Object[] positions = filterPositions(originalPositions); + Object[] positions = filterPositions(originalPositions); assert isSupported(originalVector, positions, originalValues); - Object castVector = vectorClass.cast(originalVector); + RAbstractVector vector = vectorClass.cast(originalVector); Object castValue = valueClass.cast(originalValues); - if (vectorType == RType.Environment) { - return doEnvironment((REnvironment) castVector, positions, castValue); - } else if (vectorType == RType.S4Object) { - return doS4Object((RS4Object) castVector, positions, castValue); - } - - Object value; + RAbstractContainer value; if (valueType == RType.Null) { - if (vectorType == RType.Null) { - // we cast Null to Logical, but in the end it will fold and return Null - value = RType.Logical.getEmpty(); - } else if (castType == RType.List) { + if (castType == RType.List) { value = RDataFactory.createList(new Object[]{DELETE_MARKER}); } else { value = castType.getEmpty(); } } else { - value = castValue; + if ((castType == RType.List || castType == RType.Expression) && mode.isSubscript() && !isDeleteElements() && !(castValue instanceof RScalarVector)) { + // wrap into a list when + value = RScalarList.valueOf(castValue); + } else { + value = (RAbstractContainer) castValue; + } } - int appliedValueLength; - if (value instanceof RAbstractContainer) { - appliedValueLength = valueLengthProfile.profile(((RAbstractContainer) value).getLength()); - } else { - appliedValueLength = 1; - } + int appliedValueLength = valueLengthProfile.profile(value.getLength()); int valueLength; if (this.numberOfDimensions > 1 && isDeleteElements()) { @@ -187,39 +203,6 @@ final class CachedReplaceVectorNode extends CachedVectorNode { valueLength = appliedValueLength; } - if (vectorType == RType.Null) { - if (valueLength == 0) { - return RNull.instance; - } - } - - /* - * Unfortunately special behavior for some RTypes are necessary. We should aim for getting - * rid of them as much as possible in the future. N.B.: because of this 'unwrapping' any - * return should call wrapResult(vector, repType) to do the reverse where necessary. - */ - RAbstractVector vector; - RLanguage.RepType repType = RLanguage.RepType.UNKNOWN; - switch (vectorType) { - case Null: - vector = castType.getEmpty(); - break; - case PairList: - vector = ((RPairList) castVector).toRList(); - break; - case Language: - repType = RContext.getRRuntimeASTAccess().getRepType((RLanguage) castVector); - vector = RContext.getRRuntimeASTAccess().asList((RLanguage) castVector); - DynamicObject attrs = ((RLanguage) castVector).getAttributes(); - if (rlanguageAttributesProfile.profile(attrs != null && !attrs.isEmpty())) { - vector.initAttributes(RAttributesLayout.copy(attrs)); - } - break; - default: - vector = (RAbstractVector) castVector; - break; - } - int vectorLength = targetLengthProfile.profile(vector.getLength()); int[] vectorDimensions; if (numberOfDimensions == 1) { @@ -238,29 +221,30 @@ final class CachedReplaceVectorNode extends CachedVectorNode { int replacementLength = positionsCheckNode.getSelectedPositionsCount(positionProfiles); if (emptyReplacementProfile.profile(replacementLength == 0)) { - /* Nothing to modify */ - if (vectorType == RType.Language || vectorType == RType.Expression) { - return originalVector; - } else { - return vector.materialize(); - } + // Nothing to modify + return vector; } if (valueLengthOneProfile.profile(valueLength != 1)) { verifyValueLength(positionProfiles, valueLength); } - - if (!isList() && value instanceof RAbstractVector) { - value = ((RAbstractVector) value).castSafe(castType, valueIsNA, false); + if (vector instanceof RShareable) { + RShareable shareable = (RShareable) vector; + // TODO find out if we need to copy always in the recursive case + if (recursive || sharedConditionProfile.execute(shareable.isShared()) || valueEqualsVectorProfile.profile(vector == value)) { + shareable = (RShareable) vector.copy(); + vector = (RAbstractVector) shareable; + assert shareable.isTemporary(); + } } - - vector = share(vector, value); + vector = sharedClassProfile.profile(vector); + CompilerAsserts.partialEvaluationConstant(vector.getClass()); int maxOutOfBounds = positionsCheckNode.getMaxOutOfBounds(positionProfiles); if (maxOutOfBounds > vectorLength) { resizeProfile.enter(); if (isDeleteElements() && mode.isSubscript()) { - return wrapResult(vector, repType); + return vector; } vector = resizeVector(vector, maxOutOfBounds); } else { @@ -297,17 +281,7 @@ final class CachedReplaceVectorNode extends CachedVectorNode { } } - if (value instanceof RAbstractContainer) { - writeVectorNode.enableValueNACheck((RAbstractContainer) value); - } - - writeVectorNode.apply(vector, vectorLength, positions, value, appliedValueLength, vectorDimensions); - boolean complete = vector.isComplete(); - if (completeVectorProfile.profile(complete)) { - if (!writeVectorNode.neverSeenNAInValue()) { - vector.setComplete(false); - } - } + writeVectorNode.execute(vector, positions, value, vectorDimensions); RBaseNode.reportWork(this, replacementLength); @@ -320,48 +294,7 @@ final class CachedReplaceVectorNode extends CachedVectorNode { updateVectorWithPositionNames(vector, positions); } - return wrapResult(vector, repType); - } - - private Object wrapResult(RAbstractVector vector, RLanguage.RepType repType) { - switch (vectorType) { - case Language: - return RContext.getRRuntimeASTAccess().createLanguageFromList((RList) vector, repType); - default: - return vector; - } - } - - private void verifyCastType(RType compatibleType) { - if (error == null && compatibleType == null && (vectorType.isNull() || vectorType.isVector())) { - Message message; - if (mode.isSubset()) { - message = RError.Message.SUBASSIGN_TYPE_FIX; - } else { - if (vectorType == RType.List) { - message = RError.Message.SUBSCRIPT_TYPES; - } else { - message = RError.Message.SUBASSIGN_TYPE_FIX; - } - } - error = () -> { - throw error(message, valueType.getName(), vectorType.getName(), false); - }; - } - } - - private CastNode createCastVectorNode() { - if (castType == vectorType || castType == null || castType == RType.Null) { - return null; - } - /* - * All casts except list casts preserve dimension names. - */ - if (castType == RType.List) { - return CastListNodeGen.create(true, false, true); - } else { - return CastTypeNode.createCast(castType, true, true, true, false); - } + return vector; } private boolean isDeleteElements() { @@ -372,54 +305,6 @@ final class CachedReplaceVectorNode extends CachedVectorNode { return castType == RType.List; } - private RType resolveCastVectorType() { - final RType vector; - // convert type for list like values - switch (this.vectorType) { - case Language: - case Expression: - case PairList: - vector = RType.List; - break; - case Environment: - vector = RType.List; - break; - default: - vector = this.vectorType; - break; - } - - RType value = this.valueType; - - if (vector == RType.List && mode.isSubscript()) { - if (value.isNull() && numberOfDimensions > 1) { - return null; - } else { - return vector; - } - } else if (vector.isVector() && value.isVector()) { - if (vector != value) { - if (vector == RType.List || value == RType.List) { - return RType.List; - } - if (vector == RType.Raw || value == RType.Raw) { - return null; - } - } - return RType.maxPrecedence(value, vector); - } else if (vector.isNull() || value.isNull()) { - if (!value.isNull()) { - return (mode == ElementAccessMode.FIELD_SUBSCRIPT || (mode == ElementAccessMode.SUBSCRIPT && isValueGt1)) ? RType.List : value; - } - if (mode.isSubscript() && numberOfDimensions > 1) { - return null; - } - return vector; - } else { - return null; - } - } - private void verifyValueLength(PositionProfile[] positionProfiles, int valueLength) { if (mode.isSubscript()) { if (!isList()) { @@ -469,34 +354,6 @@ final class CachedReplaceVectorNode extends CachedVectorNode { } } - private Object doEnvironment(REnvironment env, Object[] positions, Object originalValues) { - if (mode.isSubset()) { - throw error(RError.Message.OBJECT_NOT_SUBSETTABLE, RType.Environment.getName()); - } - - String positionString = tryCastSingleString(positionsCheckNode, positions); - if (positionString == null) { - throw error(RError.Message.WRONG_ARGS_SUBSET_ENV); - } - - try { - Object value = originalValues; - if (value instanceof RScalarVector) { - value = ((RScalarVector) value).getDataAtAsObject(0); - } - env.put(positionString, value); - } catch (PutException ex) { - throw error(ex); - } - return env; - } - - @Child private ReplaceS4ObjectNode replaceS4ObjectNode; - - private Object doS4Object(RS4Object obj, Object[] positions, Object originalValues) { - return replaceS4ObjectNode.execute(obj, positions, originalValues); - } - @NodeInfo(cost = NONE) public abstract static class ValueProfileNode extends Node { @@ -520,28 +377,6 @@ final class CachedReplaceVectorNode extends CachedVectorNode { private final ConditionProfile valueEqualsVectorProfile = ConditionProfile.createBinaryProfile(); - /* - * TODO (chumer) share code between {@link #share(RAbstractVector)} and {@link - * #copyValueOnAssignment(RAbstractContainer)} - */ - private RAbstractVector share(RAbstractVector vector, Object value) { - RAbstractVector returnVector = vector; - if (returnVector instanceof RShareable) { - RShareable shareable = (RShareable) returnVector; - // TODO find out if we need to copy always in the recursive case - if (recursive || sharedConditionProfile.execute(shareable.isShared()) || valueEqualsVectorProfile.profile(vector == value)) { - shareable = (RShareable) returnVector.copy(); - returnVector = (RAbstractVector) shareable; - assert shareable.isTemporary(); - } - } - returnVector = sharedClassProfile.profile(returnVector); - - CompilerAsserts.partialEvaluationConstant(returnVector.getClass()); - - return returnVector; - } - // TODO (chumer) this is way to complicated at the moment // not yet worth compiling. we should introduce some nodes for this @TruffleBoundary diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedVectorNode.java index 595c1452ef..d934635642 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedVectorNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedVectorNode.java @@ -22,9 +22,7 @@ */ package com.oracle.truffle.r.nodes.access.vector; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode; -import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RMissing; @@ -56,9 +54,6 @@ abstract class CachedVectorNode extends RBaseNode { protected final int numberOfDimensions; private final int filteredPositionsLength; - // if this is non-null, the node needs to throw the error whenever it is executed - @CompilationFinal protected Runnable error; - @Child private GetDimAttributeNode getDimNode = GetDimAttributeNode.create(); CachedVectorNode(ElementAccessMode mode, RTypedValue vector, Object[] positions, boolean recursive) { @@ -71,11 +66,6 @@ abstract class CachedVectorNode extends RBaseNode { } else { this.numberOfDimensions = filteredPositionsLength; } - if (!isSubsetable(vectorType)) { - error = () -> { - throw error(RError.Message.OBJECT_NOT_SUBSETTABLE, vectorType.getName()); - }; - } } private static int initializeFilteredPositionsCount(Object[] positions) { @@ -136,23 +126,6 @@ abstract class CachedVectorNode extends RBaseNode { } } - private static boolean isSubsetable(RType type) { - if (type.isVector()) { - return true; - } - switch (type) { - case Null: - case Language: - case PairList: - case Environment: - case Expression: - case S4Object: - return true; - default: - return false; - } - } - protected final int[] loadVectorDimensions(RAbstractContainer vector) { // N.B. (stepan) this method used to be instance method and have special handling for // RDataFrame, which was removed and any test case, which would require this special diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractS4ObjectNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractS4ObjectNode.java deleted file mode 100644 index 70df313158..0000000000 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractS4ObjectNode.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2017, 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.nodes.access.vector; - -import static com.oracle.truffle.r.runtime.RError.Message.OP_NOT_DEFINED_FOR_S4_CLASS; - -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.r.nodes.objects.GetS4DataSlot; -import com.oracle.truffle.r.nodes.objects.GetS4DataSlotNodeGen; -import com.oracle.truffle.r.runtime.RError; -import com.oracle.truffle.r.runtime.RType; -import com.oracle.truffle.r.runtime.data.RDataFactory; -import com.oracle.truffle.r.runtime.data.RNull; -import com.oracle.truffle.r.runtime.data.RS4Object; -import com.oracle.truffle.r.runtime.data.RTypedValue; -import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; - -public class ExtractS4ObjectNode extends Node { - @Child private GetS4DataSlot getS4DataSlotNode = GetS4DataSlotNodeGen.create(RType.Environment); - @Child private ExtractVectorNode extract; - private final boolean exact; - private final boolean dropDimensions; - - public ExtractS4ObjectNode(ElementAccessMode accessMode, boolean exact, boolean dropDimensions) { - this.extract = ExtractVectorNode.create(accessMode, true); - this.exact = exact; - this.dropDimensions = dropDimensions; - } - - public Object execute(RS4Object obj, Object[] positions) { - RTypedValue dataSlot = getS4DataSlotNode.executeObject(obj); - if (dataSlot == RNull.instance) { - throw RError.error(RError.SHOW_CALLER, OP_NOT_DEFINED_FOR_S4_CLASS, "$"); - } - return extract.execute(dataSlot, positions, createLogical(exact), createLogical(dropDimensions)); - } - - private static RAbstractLogicalVector createLogical(boolean b) { - return RDataFactory.createLogicalVectorFromScalar(b); - } -} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java index c3c7bcbd35..54338db024 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java @@ -23,8 +23,10 @@ package com.oracle.truffle.r.nodes.access.vector; 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.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.interop.ForeignAccess; @@ -34,20 +36,31 @@ import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.interop.java.JavaInterop; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.ValueProfile; +import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNodeGen.ExtractSingleNameNodeGen; import com.oracle.truffle.r.nodes.binary.BoxPrimitiveNode; +import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef; +import com.oracle.truffle.r.nodes.function.PromiseHelperNode.PromiseCheckHelperNode; +import com.oracle.truffle.r.nodes.objects.GetS4DataSlot; import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode; import com.oracle.truffle.r.nodes.unary.CastStringNode; import com.oracle.truffle.r.nodes.unary.FirstStringNode; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RLogical; import com.oracle.truffle.r.runtime.data.RMissing; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RS4Object; import com.oracle.truffle.r.runtime.data.RTypedValue; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator; +import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.interop.Foreign2R; import com.oracle.truffle.r.runtime.interop.ForeignArray2R; import com.oracle.truffle.r.runtime.interop.ForeignArray2R.ForeignArrayData; @@ -58,7 +71,7 @@ public abstract class ExtractVectorNode extends RBaseNode { protected static final int CACHE_LIMIT = 5; - private final ElementAccessMode mode; + protected final ElementAccessMode mode; private final boolean recursive; private final boolean ignoreRecursive; @@ -124,23 +137,92 @@ public abstract class ExtractVectorNode extends RBaseNode { } @Specialization(limit = "CACHE_LIMIT", guards = {"!isForeignObject(vector)", "cached != null", "cached.isSupported(vector, positions, exact, dropDimensions)"}) - protected Object doExtractDefaultCached(Object vector, Object[] positions, Object exact, Object dropDimensions, // + protected Object doExtractDefaultCached(RAbstractContainer vector, Object[] positions, Object exact, Object dropDimensions, // @Cached("createDefaultCache(getThis(), vector, positions, exact, dropDimensions)") CachedExtractVectorNode cached) { assert !isRecursiveSubscript(vector, positions); return cached.apply(vector, positions, null, exact, dropDimensions); } - protected static CachedExtractVectorNode createDefaultCache(ExtractVectorNode node, Object vector, Object[] positions, Object exact, Object dropDimensions) { - return new CachedExtractVectorNode(node.getMode(), (RTypedValue) vector, positions, (RTypedValue) exact, (RTypedValue) dropDimensions, node.recursive); + protected static CachedExtractVectorNode createDefaultCache(ExtractVectorNode node, RAbstractContainer vector, Object[] positions, Object exact, Object dropDimensions) { + assert !(vector instanceof REnvironment); + return new CachedExtractVectorNode(node.getMode(), vector, positions, (RTypedValue) exact, (RTypedValue) dropDimensions, node.recursive); } - @Specialization(replaces = "doExtractDefaultCached", guards = "!isForeignObject(vector)") + @Specialization(replaces = "doExtractDefaultCached", guards = {"!isForeignObject(vector)"}) @TruffleBoundary - protected Object doExtractDefaultGeneric(Object vector, Object[] positions, Object exact, Object dropDimensions, // + protected Object doExtractDefaultGeneric(RAbstractContainer vector, Object[] positions, Object exact, Object dropDimensions, // @Cached("new(createDefaultCache(getThis(), vector, positions, exact, dropDimensions))") GenericVectorExtractNode generic) { return generic.get(this, vector, positions, exact, dropDimensions).apply(vector, positions, null, exact, dropDimensions); } + @Specialization + protected Object doExtractEnvironment(REnvironment env, Object[] positions, @SuppressWarnings("unused") Object exact, @SuppressWarnings("unused") Object dropDimensions, + @Cached("createExtractName()") ExtractSingleName extractName, + @Cached("new()") PromiseCheckHelperNode promiseHelper) { + if (mode.isSubset()) { + throw error(RError.Message.OBJECT_NOT_SUBSETTABLE, RType.Environment.getName()); + } + String name = positions.length == 1 ? extractName.execute(positions[0]) : null; + if (name != null) { + Object obj = env.get(name); + return obj == null ? RNull.instance : promiseHelper.checkEvaluate(null, obj); + } + throw error(RError.Message.WRONG_ARGS_SUBSET_ENV); + } + + @Specialization + protected Object doExtractS4Object(RS4Object obj, Object[] positions, Object exact, Object dropDimensions, + @Cached("createEnvironment()") GetS4DataSlot getS4DataSlotNode, + @Cached("create(mode, True)") ExtractVectorNode recursiveExtract) { + RTypedValue dataSlot = getS4DataSlotNode.executeObject(obj); + if (dataSlot == RNull.instance) { + throw RError.error(RError.SHOW_CALLER, RError.Message.OP_NOT_DEFINED_FOR_S4_CLASS, "$"); + } + return recursiveExtract.execute(dataSlot, positions, exact, dropDimensions); + } + + abstract static class ExtractSingleName extends Node { + + public abstract String execute(Object value); + + public static ExtractSingleName createExtractName() { + return ExtractSingleNameNodeGen.create(); + } + + @Specialization + protected static String extract(String value) { + return value; + } + + @Specialization(guards = "access.supports(value)") + protected static String extractCached(RAbstractStringVector value, + @Cached("value.access()") VectorAccess access) { + try (RandomIterator iter = access.randomAccess(value)) { + if (access.getLength(iter) == 1) { + return access.getString(iter, 0); + } + } + return null; + } + + @Specialization(replaces = "extractCached") + @TruffleBoundary + protected static String extractGeneric(RAbstractStringVector value) { + return extractCached(value, value.slowPathAccess()); + } + + @Fallback + protected static String extractFallback(@SuppressWarnings("unused") Object value) { + return null; + } + } + + @SuppressWarnings("unused") + @Specialization + protected Object doExtractRNull(RNull vector, Object[] positions, Object exact, Object dropDimensions) { + return RNull.instance; + } + // TODO hack until Truffle-DSL supports this. protected ExtractVectorNode getThis() { return this; @@ -154,7 +236,7 @@ public abstract class ExtractVectorNode extends RBaseNode { this.cached = insert(cachedOperation); } - public CachedExtractVectorNode get(ExtractVectorNode node, Object vector, Object[] positions, Object exact, Object dropDimensions) { + public CachedExtractVectorNode get(ExtractVectorNode node, RAbstractContainer vector, Object[] positions, Object exact, Object dropDimensions) { CompilerAsserts.neverPartOfCompilation(); if (!cached.isSupported(vector, positions, exact, dropDimensions)) { cached = cached.replace(createDefaultCache(node, vector, positions, exact, dropDimensions)); @@ -251,4 +333,11 @@ public abstract class ExtractVectorNode extends RBaseNode { private static TruffleObject toJavaClass(TruffleObject obj) { return JavaInterop.toJavaClass(obj); } + + @SuppressWarnings("unused") + @Fallback + protected Object access(Object object, Object[] positions, Object exact, Object dropDimensions) { + CompilerDirectives.transferToInterpreter(); + throw error(RError.Message.OBJECT_NOT_SUBSETTABLE, Predef.typeName().apply(object)); + } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceS4ObjectNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceS4ObjectNode.java deleted file mode 100644 index afc04f304e..0000000000 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceS4ObjectNode.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2017, 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.nodes.access.vector; - -import static com.oracle.truffle.r.runtime.RError.Message.NO_METHOD_ASSIGNING_SUBSET_S4; - -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.r.nodes.objects.GetS4DataSlot; -import com.oracle.truffle.r.nodes.objects.GetS4DataSlotNodeGen; -import com.oracle.truffle.r.runtime.RError; -import com.oracle.truffle.r.runtime.RType; -import com.oracle.truffle.r.runtime.data.RNull; -import com.oracle.truffle.r.runtime.data.RS4Object; -import com.oracle.truffle.r.runtime.data.RTypedValue; - -public class ReplaceS4ObjectNode extends Node { - @Child private GetS4DataSlot getS4DataSlotNode = GetS4DataSlotNodeGen.create(RType.Environment); - @Child private ReplaceVectorNode replaceVectorNode; - - public ReplaceS4ObjectNode(ElementAccessMode mode, boolean ignoreRecursive) { - replaceVectorNode = ReplaceVectorNode.create(mode, ignoreRecursive); - } - - public Object execute(RS4Object obj, Object[] positions, Object values) { - RTypedValue dataSlot = getS4DataSlotNode.executeObject(obj); - if (dataSlot == RNull.instance) { - throw RError.error(RError.SHOW_CALLER, NO_METHOD_ASSIGNING_SUBSET_S4); - } - // No need to update the data slot, the value is env and they have reference semantics. - replaceVectorNode.execute(dataSlot, positions, values); - return obj; - } -} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java index f295281ded..9d78ec1485 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java @@ -23,31 +23,49 @@ package com.oracle.truffle.r.nodes.access.vector; 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.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.interop.ForeignAccess; import com.oracle.truffle.api.interop.InteropException; import com.oracle.truffle.api.interop.KeyInfo; -import com.oracle.truffle.api.interop.Message; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.interop.java.JavaInterop; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.object.DynamicObject; +import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode.ExtractSingleName; import com.oracle.truffle.r.nodes.binary.BoxPrimitiveNode; +import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef; +import com.oracle.truffle.r.nodes.objects.GetS4DataSlot; import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode; import com.oracle.truffle.r.nodes.unary.CastStringNode; import com.oracle.truffle.r.nodes.unary.FirstStringNode; import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RAttributesLayout; +import com.oracle.truffle.r.runtime.data.RLanguage; +import com.oracle.truffle.r.runtime.data.RLanguage.RepType; +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.RS4Object; +import com.oracle.truffle.r.runtime.data.RScalarVector; import com.oracle.truffle.r.runtime.data.RTypedValue; +import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.env.REnvironment; +import com.oracle.truffle.r.runtime.env.REnvironment.PutException; import com.oracle.truffle.r.runtime.interop.R2Foreign; -import com.oracle.truffle.r.runtime.interop.R2ForeignNodeGen; import com.oracle.truffle.r.runtime.nodes.RBaseNode; /** @@ -58,9 +76,9 @@ public abstract class ReplaceVectorNode extends RBaseNode { protected static final int CACHE_LIMIT = 5; - private final ElementAccessMode mode; + protected final ElementAccessMode mode; private final boolean recursive; - private final boolean ignoreRecursive; + protected final boolean ignoreRecursive; @Child private BoxPrimitiveNode boxVector = BoxPrimitiveNode.create(); @Child private BoxPrimitiveNode boxValue = BoxPrimitiveNode.create(); @@ -81,23 +99,177 @@ public abstract class ReplaceVectorNode extends RBaseNode { return ReplaceVectorNodeGen.create(mode, false, ignoreRecursive); } - static ReplaceVectorNode createRecursive(ElementAccessMode mode) { + protected static ReplaceVectorNode createRecursive(ElementAccessMode mode) { return ReplaceVectorNodeGen.create(mode, true, false); } - protected Node createForeignWrite(Object[] positions) { - if (positions.length != 1) { - throw error(RError.Message.GENERIC, "Invalid number positions for foreign access."); + private boolean isRecursiveSubscript(Object vector, Object[] positions) { + return !recursive && !ignoreRecursive && mode.isSubscript() && vector instanceof RAbstractListVector && positions.length == 1; + } + + protected RecursiveReplaceSubscriptNode createRecursiveCache(Object vector, Object[] positions) { + if (isRecursiveSubscript(vector, positions)) { + return RecursiveReplaceSubscriptNode.create((RAbstractListVector) vector, positions[0]); } - return Message.WRITE.createNode(); + return null; } - protected FirstStringNode createFirstString() { - return FirstStringNode.createWithError(RError.Message.GENERIC, "Cannot corce position to character for foreign access."); + @Specialization(limit = "CACHE_LIMIT", guards = {"!isForeignObject(vector)", "cached != null", "cached.isSupported(vector, positions)"}) + protected Object doRecursive(RAbstractListVector vector, Object[] positions, Object value, // + @Cached("createRecursiveCache(vector, positions)") RecursiveReplaceSubscriptNode cached) { + return cached.apply(vector, positions, value); + } + + protected CachedReplaceVectorNode createDefaultCached(RAbstractVector vector, Object[] positions, Object value) { + if (vector instanceof RAbstractListVector && isRecursiveSubscript(vector, positions)) { + return null; + } + return new CachedReplaceVectorNode(mode, vector, positions, value.getClass(), RRuntime.isForeignObject(value) ? RType.TruffleObject : ((RTypedValue) value).getRType(), true, + recursive, CachedReplaceVectorNode.isValueLengthGreaterThanOne(value)); + } + + @Specialization(limit = "CACHE_LIMIT", guards = {"!isForeignObject(vector)", "cached != null", "cached.isSupported(vector, positions, value)"}) + protected Object doReplaceCached(RAbstractVector vector, Object[] positions, Object value, // + @Cached("createDefaultCached(vector, positions, value)") CachedReplaceVectorNode cached) { + assert !isRecursiveSubscript(vector, positions); + return cached.apply(vector, positions, value); + } + + @Specialization + @TruffleBoundary + protected Object doReplaceEnvironment(REnvironment env, Object[] positions, Object value, + @Cached("createExtractName()") ExtractSingleName extractName) { + if (mode.isSubset()) { + throw error(RError.Message.OBJECT_NOT_SUBSETTABLE, RType.Environment.getName()); + } + String name = positions.length == 1 ? extractName.execute(positions[0]) : null; + if (name != null) { + try { + env.put(name, value instanceof RScalarVector ? ((RScalarVector) value).getDataAtAsObject(0) : value); + } catch (PutException ex) { + throw error(ex); + } + } + return env; + } + + @Specialization + @TruffleBoundary + protected Object doReplaceS4Object(RS4Object obj, Object[] positions, Object value, + @Cached("createEnvironment()") GetS4DataSlot getS4DataSlotNode, + @Cached("create(mode, ignoreRecursive)") ReplaceVectorNode recursiveReplace) { + RTypedValue dataSlot = getS4DataSlotNode.executeObject(obj); + if (dataSlot == RNull.instance) { + throw RError.error(RError.SHOW_CALLER, RError.Message.NO_METHOD_ASSIGNING_SUBSET_S4); + } + // No need to update the data slot, the value is env and they have reference semantics. + recursiveReplace.execute(dataSlot, positions, value); + return obj; + } + + protected ReplaceVectorNode createForContainerTypes() { + return ReplaceVectorNodeGen.create(mode, false, false); + } + + @Specialization + protected Object doReplacementNull(@SuppressWarnings("unused") RNull vector, Object[] positions, Object value, + @Cached("createForContainerTypes()") ReplaceVectorNode replace) { + /* + * Replacing inside a variable containing NULL is quite inconsistent, we try to emulate the + * behavior as good as possible. + */ + if (value == RNull.instance) { + return RNull.instance; + } + RType type; + switch (mode) { + case FIELD_SUBSCRIPT: + type = RType.List; + break; + case SUBSCRIPT: + if (value instanceof RAbstractAtomicVector && ((RAbstractAtomicVector) value).getLength() == 1) { + type = ((RAbstractAtomicVector) value).getRType(); + } else { + type = RType.List; + } + break; + case SUBSET: + if (value instanceof RAbstractAtomicVector) { + if (((RAbstractAtomicVector) value).getLength() == 0) { + return RNull.instance; + } else { + type = ((RAbstractAtomicVector) value).getRType(); + } + } else { + type = RType.List; + } + break; + default: + throw RInternalError.shouldNotReachHere(); + } + return replace.execute(type.getEmpty(), positions, value); + } + + @Specialization + @TruffleBoundary + protected Object doReplacementLanguage(RLanguage vector, Object[] positions, Object value, + @Cached("createForContainerTypes()") ReplaceVectorNode replace) { + RepType repType = RContext.getRRuntimeASTAccess().getRepType(vector); + RList result = RContext.getRRuntimeASTAccess().asList(vector); + DynamicObject attrs = vector.getAttributes(); + if (attrs != null && !attrs.isEmpty()) { + result.initAttributes(RAttributesLayout.copy(attrs)); + } + result = (RList) replace.execute(result, positions, value); + return RContext.getRRuntimeASTAccess().createLanguageFromList(result, repType); + } + + @Specialization + @TruffleBoundary + protected Object doReplacementPairList(RPairList vector, Object[] positions, Object value, + @Cached("createForContainerTypes()") ReplaceVectorNode replace) { + return replace.execute(vector.toRList(), positions, value); + } + + protected static GenericVectorReplaceNode createGeneric() { + return new GenericVectorReplaceNode(); + } + + @Specialization(replaces = "doReplaceCached", guards = "!isForeignObject(vector)") + @TruffleBoundary + protected Object doReplaceDefaultGeneric(RAbstractVector vector, Object[] positions, Object value, // + @Cached("createGeneric()") GenericVectorReplaceNode generic) { + if (vector instanceof RAbstractListVector && isRecursiveSubscript(vector, positions)) { + return generic.getRecursive(this, vector, positions).apply(vector, positions, value); + } else { + return generic.get(this, vector, positions, value).apply(vector, positions, value); + } + } + + protected static final class GenericVectorReplaceNode extends TruffleBoundaryNode { + + @Child private RecursiveReplaceSubscriptNode cachedRecursive; + @Child private CachedReplaceVectorNode cached; + + private RecursiveReplaceSubscriptNode getRecursive(ReplaceVectorNode node, Object vector, Object[] positions) { + CompilerAsserts.neverPartOfCompilation(); + if (cachedRecursive == null || !cachedRecursive.isSupported(vector, positions)) { + cachedRecursive = insert(node.createRecursiveCache(vector, positions)); + } + return cachedRecursive; + } + + private CachedReplaceVectorNode get(ReplaceVectorNode node, RAbstractVector vector, Object[] positions, Object value) { + CompilerAsserts.neverPartOfCompilation(); + if (cached == null || !cached.isSupported(vector, positions, value)) { + cached = insert(node.createDefaultCached(vector, positions, value)); + } + return cached; + } } - protected R2Foreign createR2Foreign() { - return R2ForeignNodeGen.create(); + protected FirstStringNode createFirstString() { + return FirstStringNode.createWithError(RError.Message.GENERIC, "Cannot corce position to character for foreign access."); } @Specialization(guards = {"isForeignObject(object)", "positions.length == cachedLength"}) @@ -109,7 +281,7 @@ public abstract class ReplaceVectorNode extends RBaseNode { @SuppressWarnings("unused") @Cached("positions.length") int cachedLength, @Cached("create()") CastStringNode castNode, @Cached("createFirstString()") FirstStringNode firstString, - @Cached("createR2Foreign()") R2Foreign r2Foreign) { + @Cached("create()") R2Foreign r2Foreign) { Object writtenValue = value; try { TruffleObject result = object; @@ -163,65 +335,10 @@ public abstract class ReplaceVectorNode extends RBaseNode { return JavaInterop.toJavaClass(obj); } - @Specialization(limit = "CACHE_LIMIT", guards = {"cached != null", "cached.isSupported(vector, positions)"}) - protected Object doRecursive(RAbstractListVector vector, Object[] positions, Object value, // - @Cached("createRecursiveCache(vector, positions)") RecursiveReplaceSubscriptNode cached) { - return cached.apply(vector, positions, value); - } - - protected RecursiveReplaceSubscriptNode createRecursiveCache(Object vector, Object[] positions) { - if (isRecursiveSubscript(vector, positions)) { - return RecursiveReplaceSubscriptNode.create((RAbstractListVector) vector, positions[0]); - } - return null; - } - - private boolean isRecursiveSubscript(Object vector, Object[] positions) { - return !recursive && !ignoreRecursive && mode.isSubscript() && vector instanceof RAbstractListVector && positions.length == 1; - } - - @Specialization(limit = "CACHE_LIMIT", guards = {"cached != null", "cached.isSupported(vector, positions, value)"}) - protected Object doReplaceCached(Object vector, Object[] positions, Object value, // - @Cached("createDefaultCached(getThis(), vector, positions, value)") CachedReplaceVectorNode cached) { - assert !isRecursiveSubscript(vector, positions); - return cached.apply(vector, positions, value); - } - - protected static CachedReplaceVectorNode createDefaultCached(ReplaceVectorNode node, Object vector, Object[] positions, Object value) { - return new CachedReplaceVectorNode(node.mode, (RTypedValue) vector, positions, value.getClass(), RRuntime.isForeignObject(value) ? RType.TruffleObject : ((RTypedValue) value).getRType(), true, - node.recursive, node.ignoreRecursive, CachedReplaceVectorNode.isValueLengthGreaterThanOne(value)); - } - - public ElementAccessMode getMode() { - return mode; - } - - @Specialization(replaces = "doReplaceCached") - @TruffleBoundary - protected Object doReplaceDefaultGeneric(Object vector, Object[] positions, Object value, // - @Cached("new(createDefaultCached(getThis(), vector, positions, value))") GenericVectorReplaceNode generic) { - return generic.get(this, vector, positions, value).apply(vector, positions, value); - } - - // TODO hack until Truffle-DSL supports this. - protected ReplaceVectorNode getThis() { - return this; - } - - protected static final class GenericVectorReplaceNode extends TruffleBoundaryNode { - - @Child private CachedReplaceVectorNode cached; - - public GenericVectorReplaceNode(CachedReplaceVectorNode cachedOperation) { - this.cached = insert(cachedOperation); - } - - private CachedReplaceVectorNode get(ReplaceVectorNode node, Object vector, Object[] positions, Object value) { - CompilerAsserts.neverPartOfCompilation(); - if (!cached.isSupported(vector, positions, value)) { - cached = cached.replace(createDefaultCached(node, vector, positions, value)); - } - return cached; - } + @SuppressWarnings("unused") + @Fallback + protected Object access(Object object, Object[] positions, Object value) { + CompilerDirectives.transferToInterpreter(); + throw error(RError.Message.OBJECT_NOT_SUBSETTABLE, Predef.typeName().apply(object)); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/WriteIndexedVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/WriteIndexedVectorNode.java index aecab8b403..28666c2bfe 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/WriteIndexedVectorNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/WriteIndexedVectorNode.java @@ -22,6 +22,7 @@ */ package com.oracle.truffle.r.nodes.access.vector; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.Node; @@ -35,33 +36,84 @@ import com.oracle.truffle.r.nodes.function.opt.UpdateShareableChildValueNode; import com.oracle.truffle.r.nodes.profile.AlwaysOnBranchProfile; import com.oracle.truffle.r.nodes.profile.IntValueProfile; import com.oracle.truffle.r.nodes.profile.VectorLengthProfile; -import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.Utils; -import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RIntSequence; import com.oracle.truffle.r.runtime.data.RMissing; -import com.oracle.truffle.r.runtime.data.RNull; -import com.oracle.truffle.r.runtime.data.RScalarVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; -import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractListBaseVector; import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator; import com.oracle.truffle.r.runtime.ops.na.NACheck; +abstract class WriteIndexedVectorNode extends Node { + + private final RType vectorType; + private final int totalDimensions; + private final int dimensionIndex; + private final boolean positionAppliesToRight; + private final boolean skipNA; + private final boolean isReplace; + + private final ConditionProfile completeVectorProfile = ConditionProfile.createBinaryProfile(); + + protected WriteIndexedVectorNode(RType vectorType, int totalDimensions, int dimensionIndex, boolean positionAppliesToRight, boolean skipNA, boolean isReplace) { + this.vectorType = vectorType; + this.totalDimensions = totalDimensions; + this.dimensionIndex = dimensionIndex; + this.positionAppliesToRight = positionAppliesToRight; + this.skipNA = skipNA; + this.isReplace = isReplace; + } + + public static WriteIndexedVectorNode create(RType vectorType, int totalDimensions, boolean positionAppliesToValue, boolean skipNA, boolean isReplace) { + return WriteIndexedVectorNodeGen.create(vectorType, totalDimensions, totalDimensions - 1, positionAppliesToValue, skipNA, isReplace); + } + + protected abstract void execute(RAbstractVector left, Object[] positions, RAbstractContainer right, int[] positionTargetDimensions); + + protected WriteIndexedVectorAccessNode createWrite() { + return WriteIndexedVectorAccessNodeGen.create(vectorType, totalDimensions, dimensionIndex, positionAppliesToRight, skipNA, isReplace); + } + + @Specialization(guards = {"leftAccess.supports(left)", "rightAccess.supports(right)"}) + protected void write(RAbstractVector left, Object[] positions, RAbstractContainer right, int[] positionTargetDimensions, + @Cached("left.access()") VectorAccess leftAccess, + @Cached("right.access()") VectorAccess rightAccess, + @Cached("createWrite()") WriteIndexedVectorAccessNode write) { + try (RandomIterator leftIter = leftAccess.randomAccess(left); RandomIterator rightIter = rightAccess.randomAccess(right)) { + write.apply(leftIter, leftAccess, positions, rightIter, rightAccess, right, positionTargetDimensions); + + if (completeVectorProfile.profile(left.isComplete())) { + if (!(leftAccess.na.neverSeenNA() && rightAccess.na.neverSeenNA())) { + left.setComplete(false); + } + } + } + } + + @Specialization(replaces = "write") + @TruffleBoundary + protected void writeGeneric(RAbstractVector left, Object[] positions, RAbstractContainer right, int[] positionTargetDimensions, + @Cached("createWrite()") WriteIndexedVectorAccessNode write) { + VectorAccess leftAccess = left.slowPathAccess(); + VectorAccess rightAccess = right.slowPathAccess(); + try (RandomIterator leftIter = leftAccess.randomAccess(left); RandomIterator rightIter = rightAccess.randomAccess(right)) { + write.apply(leftIter, leftAccess, positions, rightIter, rightAccess, right, positionTargetDimensions); + } + } +} + /** * Primitive indexed N-dimensional vector write node. It can be used for vector replaces and * extracts. The only difference is that replace indexes the left vector and extract indexes the * right vector. The index direction is indicated with the boolean flag * {@link #positionsApplyToRight}. */ -abstract class WriteIndexedVectorNode extends Node { +abstract class WriteIndexedVectorAccessNode extends Node { private final int dimensionIndex; private final int totalDimensions; @@ -84,57 +136,39 @@ abstract class WriteIndexedVectorNode extends Node { private final NACheck positionNACheck = NACheck.create(); private final ConditionProfile resetIndexProfile = ConditionProfile.createBinaryProfile(); - @Child private WriteIndexedScalarNode<RAbstractVector, Object> scalarNode; - @Child private WriteIndexedVectorNode innerVectorNode; + @Child private WriteIndexedVectorAccessNode innerVectorNode; + + @Child private UpdateShareableChildValueNode updateStateOfListElement; + @Child private ShareObjectNode shareObjectNode; - @SuppressWarnings("unchecked") - protected WriteIndexedVectorNode(RType vectorType, int totalDimensions, int dimensionIndex, boolean positionAppliesToRight, boolean skipNA, boolean setListElementAsObject, boolean isReplace) { - this.scalarNode = (WriteIndexedScalarNode<RAbstractVector, Object>) createIndexedAction(vectorType, setListElementAsObject, isReplace); + private final boolean isReplace; + private final RType vectorType; + + protected WriteIndexedVectorAccessNode(RType vectorType, int totalDimensions, int dimensionIndex, boolean positionAppliesToRight, boolean skipNA, boolean isReplace) { + this.vectorType = vectorType; this.dimensionIndex = dimensionIndex; this.totalDimensions = totalDimensions; this.positionsApplyToRight = positionAppliesToRight; this.skipNA = skipNA; + this.isReplace = isReplace; if (dimensionIndex > 0) { - innerVectorNode = WriteIndexedVectorNodeGen.create(vectorType, totalDimensions, dimensionIndex - 1, positionAppliesToRight, skipNA, setListElementAsObject, isReplace); - } - } - - public static WriteIndexedVectorNode create(RType vectorType, int totalDimensions, boolean positionAppliesToValue, boolean skipNA, boolean setListElementAsObject, boolean isReplace) { - return WriteIndexedVectorNodeGen.create(vectorType, totalDimensions, totalDimensions - 1, positionAppliesToValue, skipNA, setListElementAsObject, isReplace); - } - - public NACheck getValueNACheck() { - return scalarNode.valueNACheck; - } - - public void enableValueNACheck(RAbstractContainer vector) { - getValueNACheck().enable(vector); - if (innerVectorNode != null) { - innerVectorNode.enableValueNACheck(vector); + innerVectorNode = WriteIndexedVectorAccessNodeGen.create(vectorType, totalDimensions, dimensionIndex - 1, positionAppliesToRight, skipNA, isReplace); } - } - - public boolean neverSeenNAInValue() { - if (getValueNACheck().neverSeenNA()) { - if (innerVectorNode == null || innerVectorNode.neverSeenNAInValue()) { - return true; + if (vectorType == RType.List || vectorType == RType.Expression) { + if (!isReplace) { + updateStateOfListElement = UpdateShareableChildValueNode.create(); + } else { + shareObjectNode = ShareObjectNode.create(); } } - return false; } - public final void apply(RAbstractVector left, int leftLength, - Object[] positions, Object right, int rightLength, int[] positionTargetDimensions) { - assert left.getLength() == leftLength; + public void apply(RandomIterator leftIter, VectorAccess leftAccess, Object[] positions, RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, + int[] positionTargetDimensions) { assert totalDimensions == positions.length : "totalDimensions must be constant per vector write node"; - Object leftStore = left.getInternalStore(); - Object rightStore = null; - if (right instanceof RAbstractContainer) { - RAbstractContainer rightContainer = (RAbstractContainer) right; - assert rightContainer.getLength() == rightLength; - rightStore = rightContainer.getInternalStore(); - } + int leftLength = leftAccess.getLength(leftIter); + int rightLength = rightAccess.getLength(rightIter); int initialPositionOffset; if (positionsApplyToRight) { @@ -151,17 +185,17 @@ abstract class WriteIndexedVectorNode extends Node { firstTargetDimension = dimensionValueProfile.profile(positionTargetDimensions[dimensionIndex]); } - applyImpl(left, leftStore, 0, leftLength, positionTargetDimensions, firstTargetDimension, + applyImpl(leftIter, leftAccess, 0, leftLength, positionTargetDimensions, firstTargetDimension, positions, initialPositionOffset, - right, rightStore, 0, rightLength, false); + rightIter, rightAccess, right, 0, rightLength, false); } private final ConditionProfile positionMatchesTargetDimensionsProfile = ConditionProfile.createBinaryProfile(); private int applyImpl(// - RAbstractVector left, Object leftStore, int leftBase, int leftLength, Object targetDimensions, int targetDimension, + RandomIterator leftIter, VectorAccess leftAccess, int leftBase, int leftLength, Object targetDimensions, int targetDimension, Object[] positions, int positionOffset, - Object right, Object rightStore, int rightBase, int rightLength, boolean parentNA) { + RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int rightBase, int rightLength, boolean parentNA) { Object position = positionClassProfile.profile(positions[dimensionIndex]); @@ -172,9 +206,9 @@ abstract class WriteIndexedVectorNode extends Node { } else { newPositionOffset = positionOffsetProfile.profile(positionOffset / targetDimension); } - return execute(left, leftStore, leftBase, leftLength, targetDimensions, targetDimension, + return execute(leftIter, leftAccess, leftBase, leftLength, targetDimensions, targetDimension, positions, position, newPositionOffset, positionLength, - right, rightStore, rightBase, rightLength, parentNA); + rightIter, rightAccess, right, rightBase, rightLength, parentNA); } private int getPositionLength(Object position) { @@ -185,30 +219,30 @@ abstract class WriteIndexedVectorNode extends Node { } } - protected abstract int execute(RAbstractVector left, Object leftStore, int storeBase, int storeLength, Object targetDimensions, int targetDimension, + protected abstract int execute(RandomIterator leftIter, VectorAccess leftAccess, int storeBase, int storeLength, Object targetDimensions, int targetDimension, Object[] positions, Object position, int positionOffset, int positionLength, - Object right, Object rightStore, int valueBase, int valueLength, boolean parentNA); + RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int valueBase, int valueLength, boolean parentNA); @Specialization - protected int doMissing(RAbstractVector left, Object leftStore, int leftBase, int leftLength, Object targetDimensions, int targetDimension, + protected int doMissing(RandomIterator leftIter, VectorAccess leftAccess, int leftBase, int leftLength, Object targetDimensions, int targetDimension, Object[] positions, @SuppressWarnings("unused") RMissing position, int positionOffset, @SuppressWarnings("unused") int positionLength, - RAbstractContainer right, Object rightStore, int rightBase, int rightLength, boolean parentNA, + RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int rightBase, int rightLength, boolean parentNA, @Cached("createCountingProfile()") LoopConditionProfile profile) { int rightIndex = rightBase; profile.profileCounted(targetDimension); for (int positionValue = 0; profile.inject(positionValue < targetDimension); positionValue += 1) { rightIndex = applyInner(// - left, leftStore, leftBase, leftLength, targetDimensions, + leftIter, leftAccess, leftBase, leftLength, targetDimensions, positions, positionOffset, positionValue, - right, rightStore, rightLength, rightIndex, parentNA); + rightIter, rightAccess, right, rightLength, rightIndex, parentNA); } return rightIndex; } @Specialization - protected int doLogicalPosition(RAbstractVector left, Object leftStore, int leftBase, int leftLength, Object targetDimensions, int targetDimension, + protected int doLogicalPosition(RandomIterator leftIter, VectorAccess leftAccess, int leftBase, int leftLength, Object targetDimensions, int targetDimension, Object[] positions, RAbstractLogicalVector position, int positionOffset, int positionLength, - Object right, Object rightStore, int rightBase, int rightLength, boolean parentNA, + RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int rightBase, int rightLength, boolean parentNA, @Cached("create()") BranchProfile wasTrue, @Cached("create()") AlwaysOnBranchProfile outOfBounds, @Cached("createCountingProfile()") LoopConditionProfile profile, @@ -235,9 +269,9 @@ abstract class WriteIndexedVectorNode extends Node { isNA = true; } rightIndex = applyInner(// - left, leftStore, leftBase, leftLength, targetDimensions, + leftIter, leftAccess, leftBase, leftLength, targetDimensions, positions, positionOffset, i, - right, rightStore, rightLength, rightIndex, isNA || parentNA); + rightIter, rightAccess, right, rightLength, rightIndex, isNA || parentNA); } positionIndex = Utils.incMod(positionIndex, positionLength, incModProfile); } @@ -251,9 +285,9 @@ abstract class WriteIndexedVectorNode extends Node { * @throws SlowPathException */ @Specialization(rewriteOn = SlowPathException.class) - protected int doIntegerSequencePosition(RAbstractVector left, Object leftStore, int leftBase, int leftLength, Object targetDimensions, @SuppressWarnings("unused") int targetDimension, + protected int doIntegerSequencePosition(RandomIterator leftIter, VectorAccess leftAccess, int leftBase, int leftLength, Object targetDimensions, @SuppressWarnings("unused") int targetDimension, Object[] positions, RIntSequence position, int positionOffset, int positionLength, - Object right, Object rightStore, int rightBase, int rightLength, boolean parentNA, + RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int rightBase, int rightLength, boolean parentNA, @Cached("create()") IntValueProfile startProfile, @Cached("create()") IntValueProfile strideProfile, @Cached("createBinaryProfile()") ConditionProfile conditionProfile, @@ -272,27 +306,22 @@ abstract class WriteIndexedVectorNode extends Node { profile.profileCounted(positionLength); for (int positionValue = start; profile.inject(ascending ? positionValue < end : positionValue > end); positionValue += stride) { rightIndex = applyInner(// - left, leftStore, leftBase, leftLength, targetDimensions, + leftIter, leftAccess, leftBase, leftLength, targetDimensions, positions, positionOffset, positionValue, - right, rightStore, rightLength, rightIndex, parentNA); + rightIter, rightAccess, right, rightLength, rightIndex, parentNA); } return rightIndex; } /** * Integer vectors iterate over the number of positions because we assume that the number of - * positions in an integer vector is significantly lower than the number of elements in the - * store. This might not be always true and could benefit from more investigation. - */ - /** - * Integer vectors iterate over the number of positions because we assume that the number of - * positions in an integer vector is significantly lower than the number of elements in the - * store. This might not be always true and could benefit from more investigation. + * positions in an integer vector is significantly lower than the number of elements. This might + * not be always true and could benefit from more investigation. */ @Specialization(replaces = "doIntegerSequencePosition") - protected int doIntegerPosition(RAbstractVector left, Object leftStore, int leftBase, int leftLength, Object targetDimensions, @SuppressWarnings("unused") int targetDimension, + protected int doIntegerPosition(RandomIterator leftIter, VectorAccess leftAccess, int leftBase, int leftLength, Object targetDimensions, @SuppressWarnings("unused") int targetDimension, Object[] positions, RAbstractIntVector position, int positionOffset, int positionLength, - Object right, Object rightStore, int rightBase, int rightLength, boolean parentNA, + RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int rightBase, int rightLength, boolean parentNA, @Cached("createCountingProfile()") LoopConditionProfile lengthProfile) { positionNACheck.enable(position); int rightIndex = rightBase; @@ -307,17 +336,17 @@ abstract class WriteIndexedVectorNode extends Node { } } rightIndex = applyInner(// - left, leftStore, leftBase, leftLength, targetDimensions, + leftIter, leftAccess, leftBase, leftLength, targetDimensions, positions, positionOffset, positionValue - 1, - right, rightStore, rightLength, rightIndex, isNA || parentNA); + rightIter, rightAccess, right, rightLength, rightIndex, isNA || parentNA); } return rightIndex; } private int applyInner(// - RAbstractVector left, Object leftStore, int leftBase, int leftLength, Object targetDimensions, + RandomIterator leftIter, VectorAccess leftAccess, int leftBase, int leftLength, Object targetDimensions, Object[] positions, int positionOffset, int positionValue, - Object right, Object rightStore, int rightLength, int actionIndex, boolean isNA) { + RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int rightLength, int actionIndex, boolean isNA) { int newTargetIndex = leftBase + positionValue * positionOffset; if (dimensionIndex == 0) { // for-loops leaf for innermost dimension @@ -334,9 +363,15 @@ abstract class WriteIndexedVectorNode extends Node { } if (isNA) { - scalarNode.applyNA(left, leftStore, actionLeftIndex); + leftAccess.setNA(leftIter, actionLeftIndex); + leftAccess.na.seenNA(); } else { - scalarNode.apply(left, leftStore, actionLeftIndex, right, rightStore, actionRightIndex); + if (vectorType == RType.List || vectorType == RType.Expression) { + setListElement(leftIter, leftAccess, rightIter, rightAccess, right, actionLeftIndex, actionRightIndex); + } else { + leftAccess.setFromSameType(leftIter, actionLeftIndex, rightAccess, rightIter, actionRightIndex); + } + rightAccess.isNA(rightIter, actionRightIndex); } if (resetIndexProfile.profile((actionIndex + 1) == (positionsApplyToRight ? leftLength : rightLength))) { @@ -347,189 +382,24 @@ abstract class WriteIndexedVectorNode extends Node { // generate another for-loop for other dimensions int nextTargetDimension = innerVectorNode.dimensionValueProfile.profile(((int[]) targetDimensions)[innerVectorNode.dimensionIndex]); return innerVectorNode.applyImpl(// - left, leftStore, newTargetIndex, leftLength, targetDimensions, nextTargetDimension, + leftIter, leftAccess, newTargetIndex, leftLength, targetDimensions, nextTargetDimension, positions, positionOffset, - right, rightStore, actionIndex, rightLength, isNA); - } - } - - private static WriteIndexedScalarNode<? extends RAbstractVector, ? extends Object> createIndexedAction(RType type, boolean setListElementAsObject, boolean isReplace) { - switch (type) { - case Logical: - return new WriteLogicalAction(); - case Integer: - return new WriteIntegerAction(); - case Double: - return new WriteDoubleAction(); - case Complex: - return new WriteComplexAction(); - case Character: - return new WriteCharacterAction(); - case Raw: - return new WriteRawAction(); - case Language: - case Expression: - case PairList: - case List: - return new WriteListAction(setListElementAsObject, isReplace); - default: - throw RInternalError.shouldNotReachHere("WriteIndexedScalarNode for " + type); - } - } - - private abstract static class WriteIndexedScalarNode<A extends RAbstractVector, V extends Object> extends Node { - - final NACheck valueNACheck = NACheck.create(); - - abstract void apply(A leftAccess, Object leftStore, int leftIndex, V rightAccess, Object rightStore, int rightIndex); - - abstract void applyNA(A leftAccess, Object leftStore, int leftIndex); - - } - - private static final class WriteLogicalAction extends WriteIndexedScalarNode<RAbstractLogicalVector, RAbstractLogicalVector> { - - @Override - void apply(RAbstractLogicalVector leftAccess, Object leftStore, int leftIndex, RAbstractLogicalVector rightAccess, Object rightStore, int rightIndex) { - byte value = rightAccess.getDataAt(rightStore, rightIndex); - leftAccess.setDataAt(leftStore, leftIndex, value); - valueNACheck.check(value); - } - - @Override - void applyNA(RAbstractLogicalVector leftAccess, Object leftStore, int leftIndex) { - leftAccess.setDataAt(leftStore, leftIndex, RRuntime.LOGICAL_NA); - valueNACheck.seenNA(); - } - } - - private static final class WriteIntegerAction extends WriteIndexedScalarNode<RAbstractIntVector, RAbstractIntVector> { - - @Override - void apply(RAbstractIntVector leftAccess, Object leftStore, int leftIndex, RAbstractIntVector rightAccess, Object rightStore, int rightIndex) { - int value = rightAccess.getDataAt(rightStore, rightIndex); - leftAccess.setDataAt(leftStore, leftIndex, value); - valueNACheck.check(value); - } - - @Override - void applyNA(RAbstractIntVector leftAccess, Object leftStore, int leftIndex) { - leftAccess.setDataAt(leftStore, leftIndex, RRuntime.INT_NA); - valueNACheck.seenNA(); - } - } - - private static final class WriteDoubleAction extends WriteIndexedScalarNode<RAbstractDoubleVector, RAbstractDoubleVector> { - - @Override - void apply(RAbstractDoubleVector leftAccess, Object leftStore, int leftIndex, RAbstractDoubleVector rightAccess, Object rightStore, int rightIndex) { - double value = rightAccess.getDataAt(rightStore, rightIndex); - leftAccess.setDataAt(leftStore, leftIndex, value); - valueNACheck.check(value); - } - - @Override - void applyNA(RAbstractDoubleVector leftAccess, Object leftStore, int leftIndex) { - leftAccess.setDataAt(leftStore, leftIndex, RRuntime.DOUBLE_NA); - valueNACheck.seenNA(); - } - } - - private static final class WriteComplexAction extends WriteIndexedScalarNode<RAbstractComplexVector, RAbstractComplexVector> { - - @Override - void apply(RAbstractComplexVector leftAccess, Object leftStore, int leftIndex, RAbstractComplexVector rightAccess, Object rightStore, int rightIndex) { - RComplex value = rightAccess.getDataAt(rightStore, rightIndex); - leftAccess.setDataAt(leftStore, leftIndex, value); - valueNACheck.check(value); - } - - @Override - void applyNA(RAbstractComplexVector leftAccess, Object leftStore, int leftIndex) { - leftAccess.setDataAt(leftStore, leftIndex, RComplex.createNA()); - valueNACheck.seenNA(); + rightIter, rightAccess, right, actionIndex, rightLength, isNA); } } - private static final class WriteCharacterAction extends WriteIndexedScalarNode<RAbstractStringVector, RAbstractStringVector> { - - @Override - void apply(RAbstractStringVector leftAccess, Object leftStore, int leftIndex, RAbstractStringVector rightAccess, Object rightStore, int rightIndex) { - String value = rightAccess.getDataAt(rightStore, rightIndex); - leftAccess.setDataAt(leftStore, leftIndex, value); - valueNACheck.check(value); - } - - @Override - void applyNA(RAbstractStringVector leftAccess, Object leftStore, int leftIndex) { - leftAccess.setDataAt(leftStore, leftIndex, RRuntime.STRING_NA); - valueNACheck.seenNA(); - } - } - - private static final class WriteRawAction extends WriteIndexedScalarNode<RAbstractRawVector, RAbstractRawVector> { - - @Override - void apply(RAbstractRawVector leftAccess, Object leftStore, int leftIndex, RAbstractRawVector rightAccess, Object rightStore, int rightIndex) { - byte value = rightAccess.getRawDataAt(rightStore, rightIndex); - leftAccess.setRawDataAt(leftStore, leftIndex, value); - valueNACheck.check(value); - } - - @Override - void applyNA(RAbstractRawVector leftAccess, Object leftStore, int leftIndex) { - // nothing to do - } - } - - private static final class WriteListAction extends WriteIndexedScalarNode<RAbstractListBaseVector, Object> { - - private final boolean setListElementAsObject; - private final boolean isReplace; - @Child private UpdateShareableChildValueNode updateStateOfListElement; - @Child private ShareObjectNode shareObjectNode; - - WriteListAction(boolean setListElementAsObject, boolean isReplace) { - this.setListElementAsObject = setListElementAsObject; - this.isReplace = isReplace; - if (!isReplace) { - updateStateOfListElement = UpdateShareableChildValueNode.create(); - } else { - shareObjectNode = ShareObjectNode.create(); + private void setListElement(RandomIterator leftIter, VectorAccess leftAccess, RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int leftIndex, int rightIndex) { + Object rightValue = rightAccess.getListElement(rightIter, rightIndex); + if (isReplace) { + // we are replacing within the same list + if (leftAccess.getListElement(leftIter, leftIndex) != rightValue) { + shareObjectNode.execute(rightValue); } + } else { + // we are writing into a list data that are being read from possibly another list + updateStateOfListElement.execute(right, rightValue); } - @Override - void apply(RAbstractListBaseVector leftAccess, Object leftStore, int leftIndex, Object rightAccess, Object rightStore, int rightIndex) { - Object rightValue; - if (setListElementAsObject) { - rightValue = rightAccess; - // unbox scalar vectors - if (rightValue instanceof RScalarVector) { - rightValue = ((RScalarVector) rightValue).getDataAtAsObject(rightStore, 0); - } - } else { - rightValue = ((RAbstractContainer) rightAccess).getDataAtAsObject(rightStore, rightIndex); - } - - if (isReplace) { - // we are replacing within the same list - if (leftAccess.getDataAtAsObject(leftStore, leftIndex) != rightValue) { - shareObjectNode.execute(rightValue); - } - } else { - // we are writing into a list data that are being read from possibly another list - updateStateOfListElement.execute(rightAccess, rightValue); - } - - leftAccess.setDataAt(leftStore, leftIndex, rightValue); - valueNACheck.checkListElement(rightValue); - } - - @Override - void applyNA(RAbstractListBaseVector leftAccess, Object leftStore, int leftIndex) { - leftAccess.setDataAt(leftStore, leftIndex, RNull.instance); - valueNACheck.seenNA(); - } + leftAccess.setListElement(leftIter, leftIndex, rightValue); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/AsS4.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/AsS4.java index dd6ba6f6a1..2d5361356d 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/AsS4.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/AsS4.java @@ -54,7 +54,7 @@ public abstract class AsS4 extends Node { if (complete != 0) { if (getS4DataSlot == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - getS4DataSlot = insert(GetS4DataSlotNodeGen.create(RType.Any)); + getS4DataSlot = insert(GetS4DataSlot.create(RType.Any)); } RTypedValue value = getS4DataSlot.executeObject(obj); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetS4DataSlot.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetS4DataSlot.java index 6d2ca9ae16..37827a9f33 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetS4DataSlot.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetS4DataSlot.java @@ -13,7 +13,6 @@ package com.oracle.truffle.r.nodes.objects; import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.profiles.BranchProfile; @@ -32,9 +31,7 @@ import com.oracle.truffle.r.runtime.data.RShareable; import com.oracle.truffle.r.runtime.data.RTypedValue; // transcribed from src/main/attrib.c -public abstract class GetS4DataSlot extends Node { - - public abstract RTypedValue executeObject(RAttributable attObj); +public final class GetS4DataSlot extends Node { @Child private GetFixedAttributeNode s3ClassAttrAccess; @Child private RemoveFixedAttributeNode s3ClassAttrRemove; @@ -48,12 +45,19 @@ public abstract class GetS4DataSlot extends Node { private final RType type; - protected GetS4DataSlot(RType type) { + private GetS4DataSlot(RType type) { this.type = type; } - @Specialization - protected RTypedValue doNewObject(RAttributable attrObj) { + public static GetS4DataSlot create(RType type) { + return new GetS4DataSlot(type); + } + + public static GetS4DataSlot createEnvironment() { + return new GetS4DataSlot(RType.Environment); + } + + public RTypedValue executeObject(RAttributable attrObj) { RAttributable obj = attrObj; Object value = null; if (!(obj instanceof RS4Object) || type == RType.S4Object) { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java index ddba79ddb2..267fdbba3c 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java @@ -68,6 +68,10 @@ public class RRuntime { //@formatter:on + // used in DSL expressions: + public static final boolean True = true; + public static final boolean False = false; + public static final String R_APP_MIME = "application/x-r"; public static final String R_TEXT_MIME = "text/x-r"; -- GitLab