@Specialization( guards = { "!copyAllAttributes || target != source", "containsMetadata(source, attrSourceProfiles)" }) public RAbstractVector copySameLength( RAbstractVector target, RAbstractVector source, // @Cached("create()") CopyOfRegAttributesNode copyOfReg, // @Cached("createDim()") RemoveAttributeNode removeDim, // @Cached("createDimNames()") RemoveAttributeNode removeDimNames, // @Cached("create()") InitAttributesNode initAttributes, // @Cached("createNames()") PutAttributeNode putNames, // @Cached("createDim()") PutAttributeNode putDim, // @Cached("createBinaryProfile()") ConditionProfile noDimensions, // @Cached("createBinaryProfile()") ConditionProfile hasNamesSource, // @Cached("createBinaryProfile()") ConditionProfile hasDimNames) { RVector result = target.materialize(); if (copyAllAttributes) { copyOfReg.execute(source, result); } int[] newDimensions = source.getDimensions(); if (noDimensions.profile(newDimensions == null)) { RAttributes attributes = result.getAttributes(); if (attributes != null) { removeDim.execute(attributes); removeDimNames.execute(attributes); result.setInternalDimNames(null); } result.setInternalDimensions(null); RStringVector vecNames = source.getNames(attrSourceProfiles); if (hasNamesSource.profile(vecNames != null)) { putNames.execute(initAttributes.execute(result), vecNames); result.setInternalNames(vecNames); return result; } return result; } putDim.execute( initAttributes.execute(result), RDataFactory.createIntVector(newDimensions, RDataFactory.COMPLETE_VECTOR)); result.setInternalDimensions(newDimensions); RList newDimNames = source.getDimNames(attrSourceProfiles); if (hasDimNames.profile(newDimNames != null)) { result.getAttributes().put(RRuntime.DIMNAMES_ATTR_KEY, newDimNames); newDimNames.elementNamePrefix = RRuntime.DIMNAMES_LIST_ELEMENT_NAME_PREFIX; result.setInternalDimNames(newDimNames); return result; } return result; }
@ExplodeLoop public boolean getContainsNA(PositionProfile[] profiles) { if (positionsCheck.length == 1) { return containsNAProfile.profile(profiles[0].containsNA); } else { boolean containsNA = false; for (int i = 0; i < positionsCheck.length; i++) { containsNA |= profiles[i].containsNA; } return containsNAProfile.profile(containsNA); } }
private Object tryConvertToHash( VirtualFrame frame, final int argumentCount, final Object lastArgument) { if (respondsToToHashProfile.profile(respondToToHash(frame, lastArgument))) { final Object converted = callToHash(frame, lastArgument); if (convertedIsHashProfile.profile(RubyGuards.isRubyHash(converted))) { RubyArguments.setArgument(frame, argumentCount - 1, converted); return converted; } } return null; }
private static final class WriteSuperFrameVariableConditionalNode extends WriteSuperFrameVariableNode { @Child private ResolvedWriteSuperFrameVariableNode writeNode; @Child private WriteSuperFrameVariableNode nextNode; @Child private RNode rhs; private final ValueProfile enclosingFrameProfile = ValueProfile.createClassProfile(); private final ConditionProfile hasValueProfile = ConditionProfile.createBinaryProfile(); private final ConditionProfile nullSuperFrameProfile = ConditionProfile.createBinaryProfile(); WriteSuperFrameVariableConditionalNode( ResolvedWriteSuperFrameVariableNode writeNode, WriteSuperFrameVariableNode nextNode, RNode rhs) { this.writeNode = writeNode; this.nextNode = nextNode; this.rhs = rhs; } @Override public Object getName() { return writeNode.getName(); } @Override public RNode getRhs() { return rhs; } @Override public void execute(VirtualFrame frame, Object value, MaterializedFrame enclosingFrame) { MaterializedFrame profiledEnclosingFrame = enclosingFrameProfile.profile(enclosingFrame); if (hasValueProfile.profile(writeNode.getFrameSlotNode().hasValue(profiledEnclosingFrame))) { writeNode.execute(frame, value, profiledEnclosingFrame); } else { MaterializedFrame superFrame = RArguments.getEnclosingFrame(profiledEnclosingFrame); if (nullSuperFrameProfile.profile(superFrame == null)) { // Might be the case if "{ x <<- 42 }": This is in globalEnv! superFrame = REnvironment.globalEnv().getFrame(); } nextNode.execute(frame, value, superFrame); } } @Override public void execute(VirtualFrame frame, Object value) { assert RArguments.getEnclosingFrame(frame) != null; execute(frame, value, RArguments.getEnclosingFrame(frame)); } }
@Override public void execute(VirtualFrame frame, Object value, MaterializedFrame enclosingFrame) { MaterializedFrame profiledEnclosingFrame = enclosingFrameProfile.profile(enclosingFrame); if (hasValueProfile.profile(writeNode.getFrameSlotNode().hasValue(profiledEnclosingFrame))) { writeNode.execute(frame, value, profiledEnclosingFrame); } else { MaterializedFrame superFrame = RArguments.getEnclosingFrame(profiledEnclosingFrame); if (nullSuperFrameProfile.profile(superFrame == null)) { // Might be the case if "{ x <<- 42 }": This is in globalEnv! superFrame = REnvironment.globalEnv().getFrame(); } nextNode.execute(frame, value, superFrame); } }
@Specialization(guards = {"!copyAllAttributes || target != source", "containsMetadata(source)"}) protected RAbstractVector copySameLength( RAbstractVector target, RAbstractVector source, // @Cached("create()") CopyOfRegAttributesNode copyOfReg, // @Cached("createDim()") RemoveFixedAttributeNode removeDim, // @Cached("createDimNames()") RemoveFixedAttributeNode removeDimNames, // @Cached("create()") InitAttributesNode initAttributes, // @Cached("createNames()") SetFixedAttributeNode putNames, // @Cached("createDim()") SetFixedAttributeNode putDim, // @Cached("createDimNames()") SetFixedAttributeNode putDimNames, // @Cached("createBinaryProfile()") ConditionProfile noDimensions, // @Cached("createBinaryProfile()") ConditionProfile hasNamesSource, // @Cached("createBinaryProfile()") ConditionProfile hasDimNames, @Cached("create()") GetDimAttributeNode getDimsNode) { RVector<?> result = target.materialize(); if (copyAllAttributes) { copyOfReg.execute(source, result); } int[] newDimensions = getDimsNode.getDimensions(source); if (noDimensions.profile(newDimensions == null)) { DynamicObject attributes = result.getAttributes(); if (attributes != null) { removeDim.execute(attributes); removeDimNames.execute(attributes); } RStringVector vecNames = getNamesNode.getNames(source); if (hasNamesSource.profile(vecNames != null)) { putNames.execute(initAttributes.execute(result), vecNames); return result; } return result; } putDim.execute( initAttributes.execute(result), RDataFactory.createIntVector(newDimensions, RDataFactory.COMPLETE_VECTOR)); RList newDimNames = getDimNamesNode.getDimNames(source); if (hasDimNames.profile(newDimNames != null)) { putDimNames.execute(result.getAttributes(), newDimNames); newDimNames.elementNamePrefix = RRuntime.DIMNAMES_LIST_ELEMENT_NAME_PREFIX; return result; } return result; }
@Specialization(guards = {"each > 1", "hasNames(x)"}) protected RAbstractVector repEachNames( RAbstractVector x, RAbstractIntVector times, int lengthOut, int each, @Cached("create()") InitAttributesNode initAttributes, @Cached("createNames()") SetFixedAttributeNode putNames) { if (times.getLength() > 1) { errorBranch.enter(); throw invalidTimes(); } RAbstractVector input = handleEach(x, each); RStringVector names = (RStringVector) handleEach(getNames.getNames(x), each); RVector<?> r; if (lengthOutOrTimes.profile(!RRuntime.isNA(lengthOut))) { names = (RStringVector) handleLengthOut(names, lengthOut, false); r = handleLengthOut(input, lengthOut, false); } else { names = (RStringVector) handleTimes(names, times, false); r = handleTimes(input, times, false); } putNames.execute(initAttributes.execute(r), names); return r; }
private Object lookupRestKeywordArgumentHash(VirtualFrame frame) { final Object hash = readUserKeywordsHashNode.execute(frame); if (noHash.profile(hash == null)) { return Layouts.HASH.createHash( coreLibrary().getHashFactory(), null, 0, null, null, null, null, false); } CompilerDirectives.bailout("Ruby keyword arguments aren't optimized"); final DynamicObject hashObject = (DynamicObject) hash; final List<Map.Entry<Object, Object>> entries = new ArrayList<>(); outer: for (Map.Entry<Object, Object> keyValue : HashOperations.iterableKeyValues(hashObject)) { if (!RubyGuards.isRubySymbol(keyValue.getKey())) { continue; } for (String excludedKeyword : excludedKeywords) { if (excludedKeyword.equals(keyValue.getKey().toString())) { continue outer; } } entries.add(keyValue); } return BucketsStrategy.create( getContext(), entries, Layouts.HASH.getCompareByIdentity(hashObject)); }
@Override public Object execute(VirtualFrame frame) { final int argumentCount = RubyArguments.getArgumentsCount(frame); if (notEnoughArgumentsProfile.profile(argumentCount <= minArgumentCount)) { return null; } final Object lastArgument = RubyArguments.getArgument(frame, argumentCount - 1); if (lastArgumentIsHashProfile.profile(RubyGuards.isRubyHash(lastArgument))) { return lastArgument; } return tryConvertToHash(frame, argumentCount, lastArgument); }
public class AdvanceSourcePositionNode extends FormatNode { private final boolean toEnd; private final ConditionProfile rangeProfile = ConditionProfile.createBinaryProfile(); public AdvanceSourcePositionNode(RubyContext context, boolean toEnd) { super(context); this.toEnd = toEnd; } @Override public Object execute(VirtualFrame frame) { if (toEnd) { setSourcePosition(frame, getSourceLength(frame)); } else { final int position = getSourcePosition(frame); if (rangeProfile.profile(position + 1 > getSourceLength(frame))) { throw new OutsideOfStringException(); } setSourcePosition(frame, getSourcePosition(frame) + 1); } return null; } }
/** Replicate the vector a given number of times. */ private RVector<?> handleTimes( RAbstractVector x, RAbstractIntVector times, boolean copyIfSameSize) { if (oneTimeGiven.profile(times.getLength() == 1)) { // only one times value is given final int howManyTimes = times.getDataAt(0); if (howManyTimes < 0) { errorBranch.enter(); throw invalidTimes(); } if (replicateOnce.profile(howManyTimes == 1)) { return (RVector<?>) (copyIfSameSize ? x.copy() : x); } else { return x.copyResized(x.getLength() * howManyTimes, false); } } else { // times is a vector with several elements if (x.getLength() != times.getLength()) { errorBranch.enter(); invalidTimes(); } // iterate once over the times vector to determine result vector size int resultLength = 0; for (int i = 0; i < times.getLength(); i++) { int t = times.getDataAt(i); if (t < 0) { errorBranch.enter(); throw invalidTimes(); } resultLength += t; } // create and populate result vector RVector<?> r = x.createEmptySameType(resultLength, x.isComplete()); int wp = 0; // write pointer for (int i = 0; i < x.getLength(); i++) { for (int j = 0; j < times.getDataAt(i); ++j, ++wp) { r.transferElementSameType(wp, x, i); } } return r; } }
@NodeChild(value = "lexicalParentModule", type = RubyNode.class) public abstract class DefineModuleNode extends RubyNode { private final String name; @Child LookupForExistingModuleNode lookupForExistingModuleNode; private final ConditionProfile needToDefineProfile = ConditionProfile.createBinaryProfile(); private final BranchProfile errorProfile = BranchProfile.create(); public DefineModuleNode(RubyContext context, SourceSection sourceSection, String name) { super(context, sourceSection); this.name = name; } @Specialization(guards = "isRubyModule(lexicalParentModule)") public Object defineModule(VirtualFrame frame, DynamicObject lexicalParentModule) { final RubyConstant constant = lookupForExistingModule(frame, name, lexicalParentModule); final DynamicObject definingModule; if (needToDefineProfile.profile(constant == null)) { definingModule = ModuleNodes.createModule( getContext(), coreLibrary().getModuleClass(), lexicalParentModule, name, this); } else { final Object constantValue = constant.getValue(); if (!RubyGuards.isRubyModule(constantValue) || RubyGuards.isRubyClass(constantValue)) { errorProfile.enter(); throw new RaiseException(coreExceptions().typeErrorIsNotA(name, "module", this)); } definingModule = (DynamicObject) constantValue; } return definingModule; } @Specialization(guards = "!isRubyModule(lexicalParentObject)") public Object defineModuleWrongParent(VirtualFrame frame, Object lexicalParentObject) { throw new RaiseException(coreExceptions().typeErrorIsNotA(lexicalParentObject, "module", this)); } private RubyConstant lookupForExistingModule( VirtualFrame frame, String name, DynamicObject lexicalParent) { if (lookupForExistingModuleNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); lookupForExistingModuleNode = insert(LookupForExistingModuleNodeGen.create(null, null)); } return lookupForExistingModuleNode.executeLookupForExistingModule(frame, name, lexicalParent); } }
public class ReadKeywordRestArgumentNode extends RubyNode { private final String[] excludedKeywords; @Child private ReadUserKeywordsHashNode readUserKeywordsHashNode; private final ConditionProfile noHash = ConditionProfile.createBinaryProfile(); public ReadKeywordRestArgumentNode( RubyContext context, SourceSection sourceSection, int minimum, String[] excludedKeywords) { super(context, sourceSection); this.excludedKeywords = excludedKeywords; readUserKeywordsHashNode = new ReadUserKeywordsHashNode(context, sourceSection, minimum); } @Override public Object execute(VirtualFrame frame) { return lookupRestKeywordArgumentHash(frame); } private Object lookupRestKeywordArgumentHash(VirtualFrame frame) { final Object hash = readUserKeywordsHashNode.execute(frame); if (noHash.profile(hash == null)) { return Layouts.HASH.createHash( coreLibrary().getHashFactory(), null, 0, null, null, null, null, false); } CompilerDirectives.bailout("Ruby keyword arguments aren't optimized"); final DynamicObject hashObject = (DynamicObject) hash; final List<Map.Entry<Object, Object>> entries = new ArrayList<>(); outer: for (Map.Entry<Object, Object> keyValue : HashOperations.iterableKeyValues(hashObject)) { if (!RubyGuards.isRubySymbol(keyValue.getKey())) { continue; } for (String excludedKeyword : excludedKeywords) { if (excludedKeyword.equals(keyValue.getKey().toString())) { continue outer; } } entries.add(keyValue); } return BucketsStrategy.create( getContext(), entries, Layouts.HASH.getCompareByIdentity(hashObject)); } }
@Specialization(guards = {"each <= 1", "!hasNames(x)"}) protected RAbstractVector repNoEachNoNames( RAbstractVector x, RAbstractIntVector times, int lengthOut, @SuppressWarnings("unused") int each) { if (lengthOutOrTimes.profile(!RRuntime.isNA(lengthOut))) { return handleLengthOut(x, lengthOut, true); } else { return handleTimes(x, times, true); } }
@Specialization(guards = {"each > 1", "!hasNames(x)"}) protected RAbstractVector repEachNoNames( RAbstractVector x, RAbstractIntVector times, int lengthOut, int each) { if (times.getLength() > 1) { errorBranch.enter(); throw invalidTimes(); } RAbstractVector input = handleEach(x, each); if (lengthOutOrTimes.profile(!RRuntime.isNA(lengthOut))) { return handleLengthOut(input, lengthOut, false); } else { return handleTimes(input, times, false); } }
@Specialization(guards = "strategy.matches(array)", limit = "ARRAY_STRATEGIES") public boolean ensureCapacity( DynamicObject array, int requiredCapacity, @Cached("of(array)") ArrayStrategy strategy, @Cached("createCountingProfile()") ConditionProfile extendProfile) { final ArrayMirror mirror = strategy.newMirror(array); if (extendProfile.profile(mirror.getLength() < requiredCapacity)) { final int capacity = ArrayUtils.capacity(getContext(), mirror.getLength(), requiredCapacity); Layouts.ARRAY.setStore(array, mirror.copyArrayAndMirror(capacity).getArray()); return true; } else { return false; } }
@Override public Object execute(VirtualFrame frame) { if (toEnd) { setSourcePosition(frame, getSourceLength(frame)); } else { final int position = getSourcePosition(frame); if (rangeProfile.profile(position + 1 > getSourceLength(frame))) { throw new OutsideOfStringException(); } setSourcePosition(frame, getSourcePosition(frame) + 1); } return null; }
@Specialization protected Object getDimNames(RAbstractContainer container) { controlVisibility(); RList names; if (container instanceof RDataFrame) { dataframeProfile.enter(); names = ((RDataFrame) container).getVector().getDimNames(); } else if (container instanceof RFactor) { factorProfile.enter(); names = ((RFactor) container).getVector().getDimNames(); } else { otherProfile.enter(); names = container.getDimNames(attrProfiles); } return nullProfile.profile(names == null) ? RNull.instance : names; }
@Specialization( guards = {"x.getLength() == 1", "times.getLength() == 1", "each <= 1", "!hasNames(x)"}) protected RAbstractVector repNoEachNoNamesSimple( RAbstractDoubleVector x, RAbstractIntVector times, int lengthOut, @SuppressWarnings("unused") int each) { int t = times.getDataAt(0); if (t < 0) { errorBranch.enter(); throw invalidTimes(); } int length = lengthOutOrTimes.profile(!RRuntime.isNA(lengthOut)) ? lengthOut : t; double[] data = new double[length]; Arrays.fill(data, x.getDataAt(0)); return RDataFactory.createDoubleVector(data, !RRuntime.isNA(x.getDataAt(0))); }
@Specialization(guards = {"each <= 1", "hasNames(x)"}) protected RAbstractVector repNoEachNames( RAbstractVector x, RAbstractIntVector times, int lengthOut, @SuppressWarnings("unused") int each, @Cached("create()") InitAttributesNode initAttributes, @Cached("createNames()") SetFixedAttributeNode putNames) { RStringVector names; RVector<?> r; if (lengthOutOrTimes.profile(!RRuntime.isNA(lengthOut))) { names = (RStringVector) handleLengthOut(getNames.getNames(x), lengthOut, true); r = handleLengthOut(x, lengthOut, true); } else { names = (RStringVector) handleTimes(getNames.getNames(x), times, true); r = handleTimes(x, times, true); } putNames.execute(initAttributes.execute(r), names); return r; }
private void checkSlotAssign(VirtualFrame frame, Object object, String name, Object value) { // TODO: optimize using a mechanism similar to overrides? if (checkSlotAssignFunction == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); checkSlotAssignFunction = (RFunction) checkAtAssignmentFind.execute(frame); checkAtAssignmentCall = insert(CallRFunctionNode.create(checkSlotAssignFunction.getTarget())); assert objClassHierarchy == null && valClassHierarchy == null; objClassHierarchy = insert(ClassHierarchyNodeGen.create(true, false)); valClassHierarchy = insert(ClassHierarchyNodeGen.create(true, false)); } RStringVector objClass = objClassHierarchy.execute(object); RStringVector valClass = objClassHierarchy.execute(value); RFunction currentFunction = (RFunction) checkAtAssignmentFind.execute(frame); if (cached.profile(currentFunction == checkSlotAssignFunction)) { // TODO: technically, someone could override checkAtAssignment function and access the // caller, but it's rather unlikely checkAtAssignmentCall.execute( frame, checkSlotAssignFunction, RCaller.create(frame, getOriginalCall()), null, new Object[] {objClass, name, valClass}, SIGNATURE, checkSlotAssignFunction.getEnclosingFrame(), null); } else { // slow path RContext.getEngine() .evalFunction( currentFunction, frame.materialize(), RCaller.create(frame, getOriginalCall()), null, objClass, name, valClass); } }
@Specialization(guards = "isRubyModule(lexicalParentModule)") public Object defineModule(VirtualFrame frame, DynamicObject lexicalParentModule) { final RubyConstant constant = lookupForExistingModule(frame, name, lexicalParentModule); final DynamicObject definingModule; if (needToDefineProfile.profile(constant == null)) { definingModule = ModuleNodes.createModule( getContext(), coreLibrary().getModuleClass(), lexicalParentModule, name, this); } else { final Object constantValue = constant.getValue(); if (!RubyGuards.isRubyModule(constantValue) || RubyGuards.isRubyClass(constantValue)) { errorProfile.enter(); throw new RaiseException(coreExceptions().typeErrorIsNotA(name, "module", this)); } definingModule = (DynamicObject) constantValue; } return definingModule; }
@RBuiltin( name = "dimnames", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = INTERNAL_GENERIC) public abstract class DimNames extends RBuiltinNode { private final RAttributeProfiles attrProfiles = RAttributeProfiles.create(); private final ConditionProfile nullProfile = ConditionProfile.createBinaryProfile(); private final BranchProfile dataframeProfile = BranchProfile.create(); private final BranchProfile factorProfile = BranchProfile.create(); private final BranchProfile otherProfile = BranchProfile.create(); @Specialization protected RNull getDimNames(@SuppressWarnings("unused") RNull operand) { controlVisibility(); return RNull.instance; } @Specialization protected Object getDimNames(RAbstractContainer container) { controlVisibility(); RList names; if (container instanceof RDataFrame) { dataframeProfile.enter(); names = ((RDataFrame) container).getVector().getDimNames(); } else if (container instanceof RFactor) { factorProfile.enter(); names = ((RFactor) container).getVector().getDimNames(); } else { otherProfile.enter(); names = container.getDimNames(attrProfiles); } return nullProfile.profile(names == null) ? RNull.instance : names; } }
final class PositionsCheckNode extends Node { @Children private final PositionCheckNode[] positionsCheck; private final ElementAccessMode mode; private final BranchProfile errorBranch = BranchProfile.create(); private final VectorLengthProfile selectedPositionsCountProfile = VectorLengthProfile.create(); private final VectorLengthProfile maxOutOfBoundsProfile = VectorLengthProfile.create(); private final ConditionProfile containsNAProfile = ConditionProfile.createBinaryProfile(); private final BranchProfile unsupportedProfile = BranchProfile.create(); private final boolean replace; private final int positionsLength; PositionsCheckNode( ElementAccessMode mode, RType containerType, Object[] positions, boolean exact, boolean replace, boolean recursive) { this.mode = mode; this.replace = replace; this.positionsCheck = new PositionCheckNode[positions.length]; for (int i = 0; i < positions.length; i++) { positionsCheck[i] = PositionCheckNode.createNode( mode, containerType, positions[i], i, positions.length, exact, replace, recursive); } this.positionsLength = positions.length; } public PositionCheckNode getPositionCheckAt(int index) { return positionsCheck[index]; } @ExplodeLoop public boolean isSupported(Object[] positions) { if (positionsCheck.length != positions.length) { unsupportedProfile.enter(); return false; } for (int i = 0; i < positionsCheck.length; i++) { if (!positionsCheck[i].isSupported(positions[i])) { unsupportedProfile.enter(); return false; } } return true; } public int getDimensions() { return positionsCheck.length; } public boolean isSingleDimension() { return positionsCheck.length == 1; } public boolean isMultiDimension() { return positionsCheck.length > 1; } @ExplodeLoop public PositionProfile[] executeCheck( RAbstractContainer vector, int[] vectorDimensions, int vectorLength, Object[] positions) { assert isSupported(positions); verifyDimensions(vectorDimensions); PositionProfile[] statistics = new PositionProfile[positionsLength]; for (int i = 0; i < positionsLength; i++) { Object position = positions[i]; PositionProfile profile = new PositionProfile(); positions[i] = positionsCheck[i].execute(profile, vector, vectorDimensions, vectorLength, position); statistics[i] = profile; } return statistics; } @TruffleBoundary private void print() { System.out.println(positionsCheck.length); } private void verifyDimensions(int[] vectorDimensions) { if (vectorDimensions == null) { if (isMultiDimension()) { errorBranch.enter(); throw dimensionsError(); } } else { if (getDimensions() > vectorDimensions.length || getDimensions() < vectorDimensions.length) { errorBranch.enter(); throw dimensionsError(); } } } private RError dimensionsError() { if (replace) { if (mode.isSubset()) { if (getDimensions() == 2) { return RError.error(this, RError.Message.INCORRECT_SUBSCRIPTS_MATRIX); } else { return RError.error(this, RError.Message.INCORRECT_SUBSCRIPTS); } } else { return RError.error(this, RError.Message.IMPROPER_SUBSCRIPT); } } else { return RError.error(this, RError.Message.INCORRECT_DIMENSIONS); } } @ExplodeLoop public int getSelectedPositionsCount(PositionProfile[] profiles) { if (positionsCheck.length == 1) { return selectedPositionsCountProfile.profile(profiles[0].selectedPositionsCount); } else { int newSize = 1; for (int i = 0; i < positionsCheck.length; i++) { newSize *= profiles[i].selectedPositionsCount; } return selectedPositionsCountProfile.profile(newSize); } } public int getCachedSelectedPositionsCount() { return selectedPositionsCountProfile.getCachedLength(); } @ExplodeLoop public boolean getContainsNA(PositionProfile[] profiles) { if (positionsCheck.length == 1) { return containsNAProfile.profile(profiles[0].containsNA); } else { boolean containsNA = false; for (int i = 0; i < positionsCheck.length; i++) { containsNA |= profiles[i].containsNA; } return containsNAProfile.profile(containsNA); } } @ExplodeLoop public int getMaxOutOfBounds(PositionProfile[] replacementStatistics) { if (positionsCheck.length == 1) { return maxOutOfBoundsProfile.profile(replacementStatistics[0].maxOutOfBoundsIndex); } else { // impossible to be relevant as position check will throw an error in this case. return 0; } } public boolean isMissing() { return positionsCheck.length == 1 && // (positionsCheck[0].getPositionClass() == RMissing.class || positionsCheck[0].getPositionClass() == REmpty.class || // positionsCheck[0].getPositionClass() == RSymbol.class); } final class PositionProfile { int selectedPositionsCount; int maxOutOfBoundsIndex; boolean containsNA; } }
/** * The {@code rep} builtin works as follows. * * <ol> * <li>If {@code each} is greater than one, all elements of {@code x} are first replicated {@code * each} times. * <li>If {@code length.out} is given, the result of the first step is truncated or extended as * required. In this case, {@code times} is ignored. * <li>If {@code length.out} is not given, {@code times} is regarded: * <ul> * <li>If {@code times} is a one-element vector, the result of the first step is replicated * {@code times} times. * <li>If {@code times} is a vector longer than one, and {@code each} is greater than one, * an error is issued. * <li>If {@code times} is a vector longer than one, and {@code each} is one, and {@code * times} is as long as {@code x}, each element of {@code x} is given the number of * times indicated by the value at the same index of {@code times}. If {@code times} has * a different length, an error is issued. * </ul> * </ol> */ @RBuiltin( name = "rep", kind = PRIMITIVE, parameterNames = {"x", "times", "length.out", "each"}, dispatch = INTERNAL_GENERIC, behavior = PURE) public abstract class Repeat extends RBuiltinNode { protected abstract Object execute( RAbstractVector x, RAbstractIntVector times, int lengthOut, int each); private final ConditionProfile lengthOutOrTimes = ConditionProfile.createBinaryProfile(); private final BranchProfile errorBranch = BranchProfile.create(); private final ConditionProfile oneTimeGiven = ConditionProfile.createBinaryProfile(); private final ConditionProfile replicateOnce = ConditionProfile.createBinaryProfile(); @Child private GetNamesAttributeNode getNames = GetNamesAttributeNode.create(); @Override public Object[] getDefaultParameterValues() { return new Object[] {RMissing.instance, 1, RRuntime.INT_NA, 1}; } private String argType(Object arg) { return ((RTypedValue) arg).getRType().getName(); } @Override protected void createCasts(CastBuilder casts) { Function<Object, Object> argType = this::argType; casts.arg("x").mustBe(abstractVectorValue(), RError.Message.ATTEMPT_TO_REPLICATE, argType); casts .arg("times") .defaultError(RError.Message.INVALID_ARGUMENT, "times") .mustNotBeNull() .asIntegerVector(); casts .arg("length.out") .mustNotBeNull() .asIntegerVector() .shouldBe(size(1).or(size(0)), RError.Message.FIRST_ELEMENT_USED, "length.out") .findFirst(RRuntime.INT_NA, RError.Message.FIRST_ELEMENT_USED, "length.out") .mustBe(intNA().or(gte(0))); casts .arg("each") .asIntegerVector() .shouldBe(size(1).or(size(0)), RError.Message.FIRST_ELEMENT_USED, "each") .findFirst(1, RError.Message.FIRST_ELEMENT_USED, "each") .notNA(1) .mustBe(gte(0)); } protected boolean hasNames(RAbstractVector x) { return getNames.getNames(x) != null; } private RError invalidTimes() { throw RError.error(this, RError.Message.INVALID_ARGUMENT, "times"); } @Specialization( guards = {"x.getLength() == 1", "times.getLength() == 1", "each <= 1", "!hasNames(x)"}) protected RAbstractVector repNoEachNoNamesSimple( RAbstractDoubleVector x, RAbstractIntVector times, int lengthOut, @SuppressWarnings("unused") int each) { int t = times.getDataAt(0); if (t < 0) { errorBranch.enter(); throw invalidTimes(); } int length = lengthOutOrTimes.profile(!RRuntime.isNA(lengthOut)) ? lengthOut : t; double[] data = new double[length]; Arrays.fill(data, x.getDataAt(0)); return RDataFactory.createDoubleVector(data, !RRuntime.isNA(x.getDataAt(0))); } @Specialization(guards = {"each > 1", "!hasNames(x)"}) protected RAbstractVector repEachNoNames( RAbstractVector x, RAbstractIntVector times, int lengthOut, int each) { if (times.getLength() > 1) { errorBranch.enter(); throw invalidTimes(); } RAbstractVector input = handleEach(x, each); if (lengthOutOrTimes.profile(!RRuntime.isNA(lengthOut))) { return handleLengthOut(input, lengthOut, false); } else { return handleTimes(input, times, false); } } @Specialization(guards = {"each <= 1", "!hasNames(x)"}) protected RAbstractVector repNoEachNoNames( RAbstractVector x, RAbstractIntVector times, int lengthOut, @SuppressWarnings("unused") int each) { if (lengthOutOrTimes.profile(!RRuntime.isNA(lengthOut))) { return handleLengthOut(x, lengthOut, true); } else { return handleTimes(x, times, true); } } @Specialization(guards = {"each > 1", "hasNames(x)"}) protected RAbstractVector repEachNames( RAbstractVector x, RAbstractIntVector times, int lengthOut, int each, @Cached("create()") InitAttributesNode initAttributes, @Cached("createNames()") SetFixedAttributeNode putNames) { if (times.getLength() > 1) { errorBranch.enter(); throw invalidTimes(); } RAbstractVector input = handleEach(x, each); RStringVector names = (RStringVector) handleEach(getNames.getNames(x), each); RVector<?> r; if (lengthOutOrTimes.profile(!RRuntime.isNA(lengthOut))) { names = (RStringVector) handleLengthOut(names, lengthOut, false); r = handleLengthOut(input, lengthOut, false); } else { names = (RStringVector) handleTimes(names, times, false); r = handleTimes(input, times, false); } putNames.execute(initAttributes.execute(r), names); return r; } @Specialization(guards = {"each <= 1", "hasNames(x)"}) protected RAbstractVector repNoEachNames( RAbstractVector x, RAbstractIntVector times, int lengthOut, @SuppressWarnings("unused") int each, @Cached("create()") InitAttributesNode initAttributes, @Cached("createNames()") SetFixedAttributeNode putNames) { RStringVector names; RVector<?> r; if (lengthOutOrTimes.profile(!RRuntime.isNA(lengthOut))) { names = (RStringVector) handleLengthOut(getNames.getNames(x), lengthOut, true); r = handleLengthOut(x, lengthOut, true); } else { names = (RStringVector) handleTimes(getNames.getNames(x), times, true); r = handleTimes(x, times, true); } putNames.execute(initAttributes.execute(r), names); return r; } /** Prepare the input vector by replicating its elements. */ private static RVector<?> handleEach(RAbstractVector x, int each) { RVector<?> r = x.createEmptySameType(x.getLength() * each, x.isComplete()); for (int i = 0; i < x.getLength(); i++) { for (int j = i * each; j < (i + 1) * each; j++) { r.transferElementSameType(j, x, i); } } return r; } /** Extend or truncate the vector to a specified length. */ private static RVector<?> handleLengthOut( RAbstractVector x, int lengthOut, boolean copyIfSameSize) { if (x.getLength() == lengthOut) { return (RVector<?>) (copyIfSameSize ? x.copy() : x); } return x.copyResized(lengthOut, false); } /** Replicate the vector a given number of times. */ private RVector<?> handleTimes( RAbstractVector x, RAbstractIntVector times, boolean copyIfSameSize) { if (oneTimeGiven.profile(times.getLength() == 1)) { // only one times value is given final int howManyTimes = times.getDataAt(0); if (howManyTimes < 0) { errorBranch.enter(); throw invalidTimes(); } if (replicateOnce.profile(howManyTimes == 1)) { return (RVector<?>) (copyIfSameSize ? x.copy() : x); } else { return x.copyResized(x.getLength() * howManyTimes, false); } } else { // times is a vector with several elements if (x.getLength() != times.getLength()) { errorBranch.enter(); invalidTimes(); } // iterate once over the times vector to determine result vector size int resultLength = 0; for (int i = 0; i < times.getLength(); i++) { int t = times.getDataAt(i); if (t < 0) { errorBranch.enter(); throw invalidTimes(); } resultLength += t; } // create and populate result vector RVector<?> r = x.createEmptySameType(resultLength, x.isComplete()); int wp = 0; // write pointer for (int i = 0; i < x.getLength(); i++) { for (int j = 0; j < times.getDataAt(i); ++j, ++wp) { r.transferElementSameType(wp, x, i); } } return r; } } }
@RBuiltin( name = "@<-", kind = PRIMITIVE, parameterNames = {"", "", "value"}, nonEvalArgs = 1, behavior = COMPLEX) public abstract class UpdateSlot extends RBuiltinNode { private static final ArgumentsSignature SIGNATURE = ArgumentsSignature.get("cl", "name", "valueClass"); @CompilationFinal private RFunction checkSlotAssignFunction; @Child private ClassHierarchyNode objClassHierarchy; @Child private ClassHierarchyNode valClassHierarchy; @Child private UpdateSlotNode updateSlotNode = com.oracle.truffle.r.nodes.access.UpdateSlotNodeGen.create(null, null, null); @Child private ReadVariableNode checkAtAssignmentFind = ReadVariableNode.createFunctionLookup(RSyntaxNode.INTERNAL, "checkAtAssignment"); @Child private CallRFunctionNode checkAtAssignmentCall; private final ConditionProfile cached = ConditionProfile.createBinaryProfile(); @Override protected void createCasts(CastBuilder casts) { casts.arg(0).allowNull().asAttributable(true, true, true); } protected String getName(Object nameObj) { assert nameObj instanceof RPromise; Object rep = ((RPromise) nameObj).getRep(); if (rep instanceof WrapArgumentNode) { rep = ((WrapArgumentNode) rep).getOperand(); } if (rep instanceof ConstantNode) { Object val = ((ConstantNode) rep).getValue(); if (val instanceof String) { return (String) val; } if (val instanceof RSymbol) { return ((RSymbol) val).getName(); } } else if (rep instanceof ReadVariableNode) { return ((ReadVariableNode) rep).getIdentifier(); } else if (rep instanceof RCallNode) { throw RError.error(this, RError.Message.SLOT_INVALID_TYPE, "language"); } // TODO: this is not quite correct, but I wonder if we even reach here (can also be // augmented on demand) throw RError.error(this, RError.Message.SLOT_INVALID_TYPE, nameObj.getClass().toString()); } private void checkSlotAssign(VirtualFrame frame, Object object, String name, Object value) { // TODO: optimize using a mechanism similar to overrides? if (checkSlotAssignFunction == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); checkSlotAssignFunction = (RFunction) checkAtAssignmentFind.execute(frame); checkAtAssignmentCall = insert(CallRFunctionNode.create(checkSlotAssignFunction.getTarget())); assert objClassHierarchy == null && valClassHierarchy == null; objClassHierarchy = insert(ClassHierarchyNodeGen.create(true, false)); valClassHierarchy = insert(ClassHierarchyNodeGen.create(true, false)); } RStringVector objClass = objClassHierarchy.execute(object); RStringVector valClass = objClassHierarchy.execute(value); RFunction currentFunction = (RFunction) checkAtAssignmentFind.execute(frame); if (cached.profile(currentFunction == checkSlotAssignFunction)) { // TODO: technically, someone could override checkAtAssignment function and access the // caller, but it's rather unlikely checkAtAssignmentCall.execute( frame, checkSlotAssignFunction, RCaller.create(frame, getOriginalCall()), null, new Object[] {objClass, name, valClass}, SIGNATURE, checkSlotAssignFunction.getEnclosingFrame(), null); } else { // slow path RContext.getEngine() .evalFunction( currentFunction, frame.materialize(), RCaller.create(frame, getOriginalCall()), null, objClass, name, valClass); } } /* * Motivation for cached version is that in the operator form (foo@bar<-baz), the name is an * interned string which allows us to avoid longer lookup */ @Specialization(guards = "sameName(nameObj, nameObjCached)") protected Object updateSlotCached( VirtualFrame frame, Object object, @SuppressWarnings("unused") Object nameObj, Object value, @SuppressWarnings("unused") @Cached("nameObj") Object nameObjCached, @Cached("getName(nameObjCached)") String name) { checkSlotAssign(frame, object, name, value); return updateSlotNode.executeUpdate(object, name, value); } @Specialization(contains = "updateSlotCached") protected Object updateSlot(VirtualFrame frame, Object object, Object nameObj, Object value) { String name = getName(nameObj); checkSlotAssign(frame, object, name, value); return updateSlotNode.executeUpdate(object, name, value); } protected boolean sameName(Object nameObj, Object nameObjCached) { assert nameObj instanceof RPromise; assert nameObjCached instanceof RPromise; return ((RPromise) nameObj).getRep() == ((RPromise) nameObjCached).getRep(); } }
public class ReadUserKeywordsHashNode extends RubyNode { private final int minArgumentCount; @Child private DoesRespondDispatchHeadNode respondToToHashNode; @Child private CallDispatchHeadNode callToHashNode; private final ConditionProfile notEnoughArgumentsProfile = ConditionProfile.createBinaryProfile(); private final ConditionProfile lastArgumentIsHashProfile = ConditionProfile.createBinaryProfile(); private final ConditionProfile respondsToToHashProfile = ConditionProfile.createBinaryProfile(); private final ConditionProfile convertedIsHashProfile = ConditionProfile.createBinaryProfile(); public ReadUserKeywordsHashNode(int minArgumentCount) { this.minArgumentCount = minArgumentCount; } @Override public Object execute(VirtualFrame frame) { final int argumentCount = RubyArguments.getArgumentsCount(frame); if (notEnoughArgumentsProfile.profile(argumentCount <= minArgumentCount)) { return null; } final Object lastArgument = RubyArguments.getArgument(frame, argumentCount - 1); if (lastArgumentIsHashProfile.profile(RubyGuards.isRubyHash(lastArgument))) { return lastArgument; } return tryConvertToHash(frame, argumentCount, lastArgument); } private Object tryConvertToHash( VirtualFrame frame, final int argumentCount, final Object lastArgument) { if (respondsToToHashProfile.profile(respondToToHash(frame, lastArgument))) { final Object converted = callToHash(frame, lastArgument); if (convertedIsHashProfile.profile(RubyGuards.isRubyHash(converted))) { RubyArguments.setArgument(frame, argumentCount - 1, converted); return converted; } } return null; } private boolean respondToToHash(VirtualFrame frame, final Object lastArgument) { if (respondToToHashNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); respondToToHashNode = insert(new DoesRespondDispatchHeadNode(getContext(), false)); } return respondToToHashNode.doesRespondTo(frame, "to_hash", lastArgument); } private Object callToHash(VirtualFrame frame, final Object lastArgument) { if (callToHashNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); callToHashNode = insert(CallDispatchHeadNode.createMethodCall()); } return callToHashNode.call(frame, lastArgument, "to_hash"); } }