@Override public Object execute(VirtualFrame frame) { if (optimizedProfile.profile(RubyArguments.isKwOptimized(frame.getArguments()))) { Object kwarg = argumentValueProfile.profile( RubyArguments.getOptimizedKeywordArgument(frame.getArguments(), kwIndex)); if (defaultProfile.profile( kwarg instanceof OptionalKeywordArgMissingNode.OptionalKeywordArgMissing)) { return defaultValue.execute(frame); } else { return kwarg; } } else { final RubyHash hash = RubyArguments.getUserKeywordsHash(frame.getArguments(), minimum); if (defaultProfile.profile(hash == null)) { return defaultValue.execute(frame); } Object value = lookupKeywordInHash(hash); if (defaultProfile.profile(value == null)) { return defaultValue.execute(frame); } return value; } }
@ExplodeLoop private void initFrame(VirtualFrame frame, Page page) { for (FrameMapping frameMapping : mapping) { frame.setObject(frameMapping.getFrameSlot(), getColumnSlow(page, frameMapping)); } frame.setDouble(reduceNode.getSlot(), 0.0); }
@Override public Object execute(VirtualFrame frame) { final DynamicObject result; try { result = method.executeDynamicObject(frame); } catch (DoNotTaint e) { return e.getResult(); } catch (UnexpectedResultException e) { throw new UnsupportedOperationException(e); } if (result != nil()) { if (taintFromSelf) { maybeTaint((DynamicObject) RubyArguments.getSelf(frame.getArguments()), result); } // It's possible the taintFromParameter value was misconfigured by the user, but the far more // likely // scenario is that the argument at that position is a NotProvided argument, which doesn't // take up // a space in the frame. if (taintFromParameter < RubyArguments.getArgumentsCount(frame.getArguments())) { final Object argument = RubyArguments.getArgument(frame.getArguments(), taintFromParameter); if (argument instanceof DynamicObject) { final DynamicObject taintSource = (DynamicObject) argument; maybeTaint(taintSource, result); } } } return result; }
@Override public Object execute(VirtualFrame frame) { final int count = RubyArguments.getArgumentsCount(frame.getArguments()); final int effectiveIndex = count + negativeIndex; assert effectiveIndex < count; return RubyArguments.getArgument(frame.getArguments(), effectiveIndex); }
@Override public Object execute(VirtualFrame frame) { if (RubyArguments.getUserArgumentsCount(frame.getArguments()) < minimum) { defaultValueProfile.enter(); return defaultValue.execute(frame); } else { return RubyArguments.getUserArgument(frame.getArguments(), index); } }
@Override public Object execute(VirtualFrame frame) { final RubyBasicObject binding = BindingNodes.createRubyBinding( getContext().getCoreLibrary().getBindingClass(), RubyArguments.getSelf(frame.getArguments()), frame.materialize()); getContext().getCoreLibrary().getObjectClass().setConstant(this, "TOPLEVEL_BINDING", binding); return nil(); }
@Override public Object execute(VirtualFrame frame) { return ProcNodes.createRubyProc( getContext().getCoreLibrary().getProcClass(), type, sharedMethodInfo, callTargetForBlocks, callTargetForProcs, callTargetForLambdas, frame.materialize(), RubyArguments.getMethod(frame.getArguments()), RubyArguments.getSelf(frame.getArguments()), RubyArguments.getBlock(frame.getArguments())); }
@Override public Object execute(VirtualFrame frame) { if (RubyArguments.isKwOptimized(frame.getArguments())) { Object restHash = RubyArguments.getOptimizedKeywordArgument(frame.getArguments(), kwIndex); if (restHash instanceof MarkerNode.Marker) { // no rest keyword args hash passed return HashLiteralNode.create(getContext(), null, new RubyNode[0]).execute(frame); } else { return restHash; } } else { return lookupRestKeywordArgumentHash(frame); } }
@Override public void enter(Node node, VirtualFrame frame) { try { traceAssumption.check(); } catch (InvalidAssumptionException e) { traceAssumption = context.getTraceManager().getTraceAssumption(); traceFunc = context.getTraceManager().getTraceFunc(); if (traceFunc != null) { callNode = insert(Truffle.getRuntime().createDirectCallNode(traceFunc.getCallTarget())); } else { callNode = null; } } if (traceFunc != null) { if (!context.getTraceManager().isInTraceFunc()) { context.getTraceManager().setInTraceFunc(true); final Object[] args = new Object[] { event, file, line, NilPlaceholder.INSTANCE, new RubyBinding( context.getCoreLibrary().getBindingClass(), RubyArguments.getSelf(frame.getArguments()), frame.materialize()), NilPlaceholder.INSTANCE }; try { callNode.call( frame, RubyArguments.pack( traceFunc, traceFunc.getDeclarationFrame(), traceFunc.getSelfCapturedInScope(), traceFunc.getBlockCapturedInScope(), args)); } finally { context.getTraceManager().setInTraceFunc(false); } } } }
private Object lookupRestKeywordArgumentHash(VirtualFrame frame) { CompilerDirectives.transferToInterpreter(); final DynamicObject hash = RubyArguments.getUserKeywordsHash(frame.getArguments(), minimum); if (hash == null) { return Layouts.HASH.createHash( getContext().getCoreLibrary().getHashFactory(), null, null, null, 0, null, null, false); } final List<Map.Entry<Object, Object>> entries = new ArrayList<>(); outer: for (Map.Entry<Object, Object> keyValue : HashOperations.iterableKeyValues(hash)) { for (String excludedKeyword : excludedKeywords) { if (excludedKeyword.equals(keyValue.getKey().toString())) { continue outer; } } entries.add(keyValue); } return BucketsStrategy.create(getContext(), entries, Layouts.HASH.getCompareByIdentity(hash)); }
@Override public Object isDefined(VirtualFrame frame) { if (RubyArguments.getBlock(frame.getArguments()) == null) { return nil(); } else { return createString("yield"); } }
@ExplodeLoop @Override public final Object execute(VirtualFrame frame) { final Object self = RubyArguments.getSelf(frame.getArguments()); // Execute the arguments final Object[] argumentsObjects = new Object[arguments.length]; CompilerAsserts.compilationConstant(arguments.length); for (int i = 0; i < arguments.length; i++) { argumentsObjects[i] = arguments[i].execute(frame); } // Execute the block RubyProc blockObject; if (block != null) { final Object blockTempObject = block.execute(frame); if (blockTempObject instanceof RubyNilClass) { blockObject = null; } else { blockObject = (RubyProc) blockTempObject; } } else { blockObject = null; } // Check we have a method and the module is unmodified if (!guard(frame, self)) { CompilerDirectives.transferToInterpreterAndInvalidate(); lookup(frame); } // Call the method if (isSplatted) { // TODO(CS): need something better to splat the arguments array notDesignedForCompilation(); final RubyArray argumentsArray = (RubyArray) argumentsObjects[0]; return callNode.call( frame, RubyArguments.pack( superMethod, superMethod.getDeclarationFrame(), self, blockObject, argumentsArray.slowToArray())); } else { return callNode.call( frame, RubyArguments.pack( superMethod, superMethod.getDeclarationFrame(), self, blockObject, argumentsObjects)); } }
@Specialization public Object match(VirtualFrame frame, RubyString string, RubyString regexpString) { final RubyRegexp regexp = new RubyRegexp( getContext().getCoreLibrary().getRegexpClass(), regexpString.toString(), Option.DEFAULT); return regexp.match(frame.getCaller().unpack(), string.toString()); }
private boolean moduleFunctionFlag(VirtualFrame frame) { final FrameSlot moduleFunctionFlagSlot = frame.getFrameDescriptor().findFrameSlot(RubyModule.MODULE_FUNCTION_FLAG_FRAME_SLOT_ID); if (moduleFunctionFlagSlot == null) { return false; } else { Object moduleFunctionObject; try { moduleFunctionObject = frame.getObject(moduleFunctionFlagSlot); } catch (FrameSlotTypeException e) { throw new RuntimeException(e); } return (moduleFunctionObject instanceof Boolean) && (boolean) moduleFunctionObject; } }
@Override public Object execute(VirtualFrame frame) { if (index >= RubyArguments.getUserArgumentsCount(frame.getArguments())) { outOfRangeProfile.enter(); switch (missingArgumentBehaviour) { case RUNTIME_ERROR: break; case UNDEFINED: return UndefinedPlaceholder.INSTANCE; case NIL: return nil(); } } return argumentValueProfile.profile(RubyArguments.getUserArgument(frame.getArguments(), index)); }
@Override public Object execute(VirtualFrame frame) { Page page = PageArguments.get(frame); initFrame(frame, page); for (int row = 0; row < page.getRowCount(); row++) { frame.setInt(rowSlot, row); try { if (filterNode.executeBoolean(frame)) { reduceNode.execute(frame); } } catch (UnexpectedResultException e) { throw new IllegalStateException("not implemented yet: rewrite in reduce node"); } } try { return frame.getDouble(reduceNode.getSlot()); } catch (FrameSlotTypeException e) { throw new IllegalStateException("should not reach here"); } }
@Specialization public Object construct(VirtualFrame frame, RubyHash hash, Object index) { final Object value = hash.get(index); if (value == null) { if (hash.defaultBlock == null) { return NilPlaceholder.INSTANCE; } else { return hash.defaultBlock.call(frame.pack(), hash, index); } } else { return value; } }
@Override public boolean executeBoolean(VirtualFrame frame) { // TODO(CS): express this using normal nodes? // If we don't accept any arguments, there's never any need to destructure // TODO(CS): is this guaranteed by the translator anyway? if (!arity.allowsMore() && arity.getRequired() == 0 && arity.getOptional() == 0) { return false; } // If we only accept one argument, there's never any need to destructure if (!arity.allowsMore() && arity.getRequired() == 1 && arity.getOptional() == 0) { return false; } // If the caller supplied no arguments, or more than one argument, there's no need to // destructure this time if (RubyArguments.getUserArgumentsCount(frame.getArguments()) != 1) { return false; } // If the single argument is a RubyArray, destructure // TODO(CS): can we not just reply on the respondToCheck? Should experiment. if (RubyGuards.isRubyArray(RubyArguments.getUserArgument(frame.getArguments(), 0))) { return true; } // If the single argument responds to #to_ary, then destructure checkRespondProfile.enter(); return respondToCheck.executeBoolean(frame); }
@Override public Object execute(VirtualFrame frame) { final RubyClass arrayClass = getContext().getCoreLibrary().getArrayClass(); int count = RubyArguments.getUserArgumentsCount(frame.getArguments()); int endIndex = count + negativeEndIndex; if (keywordArguments) { final Object lastArgument = RubyArguments.getUserArgument( frame.getArguments(), RubyArguments.getUserArgumentsCount(frame.getArguments()) - 1); if (lastArgument instanceof RubyHash) { endIndex -= 1; } } final int length = endIndex - startIndex; if (startIndex == 0) { final Object[] arguments = RubyArguments.extractUserArguments(frame.getArguments()); return new RubyArray(arrayClass, arguments, length); } else { if (startIndex >= endIndex) { noArgumentsLeftProfile.enter(); return new RubyArray(arrayClass); } else { subsetOfArgumentsProfile.enter(); final Object[] arguments = RubyArguments.extractUserArguments(frame.getArguments()); // TODO(CS): risk here of widening types too much - always going to be Object[] - does seem // to be something that does happen return new RubyArray( arrayClass, ArrayUtils.extractRange(arguments, startIndex, endIndex), length); } } }
private boolean assertArgumentsShouldBeVisible(VirtualFrame frame) { final Object self = RubyArguments.getSelf(frame.getArguments()); assert shouldObjectBeVisible(self) : "self=" + (self == null ? "null" : self.getClass()) + "@" + getEncapsulatingSourceSection().getShortDescription(); final Object[] arguments = RubyArguments.extractUserArguments(frame.getArguments()); for (int n = 0; n < arguments.length; n++) { final Object argument = arguments[n]; assert shouldObjectBeVisible(argument) : "arg[" + n + "]=" + (argument == null ? "null" : argument.getClass() + "=" + toString(argument)) + "@" + getEncapsulatingSourceSection().getShortDescription(); } return true; }
@Override public boolean doesRespondTo(VirtualFrame frame, RubyBasicObject receiverObject) { // TODO(CS): copy-and-paste of the above - needs to be factored out MethodCacheEntry entry = lookupInCache(receiverObject.getLookupNode()); if (entry == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); final RubyBasicObject boxedCallingSelf = getContext().getCoreLibrary().box(RubyArguments.getSelf(frame.getArguments())); try { entry = new MethodCacheEntry(lookup(boxedCallingSelf, receiverObject, name), false); } catch (UseMethodMissingException e) { try { entry = new MethodCacheEntry( lookup(boxedCallingSelf, receiverObject, "method_missing"), true); } catch (UseMethodMissingException e2) { throw new RaiseException( getContext() .getCoreLibrary() .runtimeError(receiverObject.toString() + " didn't have a #method_missing")); } } if (entry.isMethodMissing()) { hasAnyMethodsMissing = true; } cache.put(receiverObject.getLookupNode(), entry); if (cache.size() > RubyContext.GENERAL_DISPATCH_SIZE_WARNING_THRESHOLD) { getContext() .getRuntime() .getWarnings() .warn( IRubyWarnings.ID.TRUFFLE, getEncapsulatingSourceSection().getSource().getName(), getEncapsulatingSourceSection().getStartLine(), "general call node cache has " + cache.size() + " entries"); } } return !entry.isMethodMissing(); }
@Override public Object execute(VirtualFrame frame) { final RubyArguments rubyArguments = frame.getArguments(RubyArguments.class); final Object[] arguments = rubyArguments.getArguments(); final RubyClass arrayClass = getContext().getCoreLibrary().getArrayClass(); if (arguments.length <= index) { return new RubyArray(arrayClass); } else if (index == 0) { return new RubyArray(arrayClass, new ObjectArrayStore(arguments)); } else { return new RubyArray( arrayClass, new ObjectArrayStore(Arrays.copyOfRange(arguments, index, arguments.length))); } }
@Override public Object execute(VirtualFrame frame) { CompilerDirectives.bailout("blocks with kwargs are not optimized yet"); final Object array = readArrayNode.executeRead(frame); final Object remainingArray = ruby( frame, "Truffle::Primitive.load_arguments_from_array_kw_helper(array, kwrest_name, binding)", "array", array, "kwrest_name", kwrestName, "binding", Layouts.BINDING.createBinding( getContext().getCoreLibrary().getBindingFactory(), frame.materialize())); writeArrayNode.executeWrite(frame, remainingArray); return nil(); }
@ExplodeLoop @Override public final Object execute(VirtualFrame frame) { Object[] argumentsObjects = new Object[arguments.length]; for (int i = 0; i < arguments.length; i++) { argumentsObjects[i] = arguments[i].execute(frame); } final RubyProc block = RubyArguments.getBlock(frame.getArguments()); if (block == null) { CompilerDirectives.transferToInterpreter(); throw new RaiseException(getContext().getCoreLibrary().noBlockToYieldTo(this)); } if (unsplat) { argumentsObjects = unsplat(argumentsObjects); } return dispatch.dispatch(frame, block, argumentsObjects); }
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); } }
public InternalMethod executeMethod(VirtualFrame frame) { final DynamicObject dummyModule = getContext().getCoreLibrary().getObjectClass(); final Visibility dummyVisibility = Visibility.PUBLIC; final DynamicObject capturedBlock; if (captureBlock) { capturedBlock = RubyArguments.getBlock(frame.getArguments()); } else { capturedBlock = null; } return new InternalMethod( sharedMethodInfo, name, dummyModule, dummyVisibility, false, null, callTarget, capturedBlock, null); }
@Specialization public Object match(VirtualFrame frame, RubyString string, RubyRegexp regexp) { return regexp.match(frame.getCaller().unpack(), string.toString()); }
protected InternalMethod getCurrentMethod(VirtualFrame frame) { return RubyArguments.getMethod(frame.getArguments()); }
@Override public Object dispatch( VirtualFrame frame, RubyBasicObject receiverObject, RubyProc blockObject, Object[] argumentsObjects) { MethodCacheEntry entry = lookupInCache(receiverObject.getLookupNode()); if (entry == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); final RubyBasicObject boxedCallingSelf = getContext().getCoreLibrary().box(RubyArguments.getSelf(frame.getArguments())); try { entry = new MethodCacheEntry(lookup(boxedCallingSelf, receiverObject, name), false); } catch (UseMethodMissingException e) { try { entry = new MethodCacheEntry( lookup(boxedCallingSelf, receiverObject, "method_missing"), true); } catch (UseMethodMissingException e2) { throw new RaiseException( getContext() .getCoreLibrary() .runtimeError(receiverObject.toString() + " didn't have a #method_missing")); } } if (entry.isMethodMissing()) { hasAnyMethodsMissing = true; } cache.put(receiverObject.getLookupNode(), entry); if (cache.size() > RubyContext.GENERAL_DISPATCH_SIZE_WARNING_THRESHOLD) { getContext() .getRuntime() .getWarnings() .warn( IRubyWarnings.ID.TRUFFLE, getEncapsulatingSourceSection().getSource().getName(), getEncapsulatingSourceSection().getStartLine(), "general call node cache has " + cache.size() + " entries"); } } final Object[] argumentsToUse; if (hasAnyMethodsMissing && entry.isMethodMissing()) { final Object[] modifiedArgumentsObjects = new Object[1 + argumentsObjects.length]; modifiedArgumentsObjects[0] = getContext().newSymbol(name); System.arraycopy(argumentsObjects, 0, modifiedArgumentsObjects, 1, argumentsObjects.length); argumentsToUse = modifiedArgumentsObjects; } else { argumentsToUse = argumentsObjects; } return callNode.call( frame, entry.getMethod().getCallTarget(), RubyArguments.pack( entry.getMethod().getDeclarationFrame(), receiverObject, blockObject, argumentsToUse)); }
@Override public Object execute(VirtualFrame frame) { frame.setObject(FormatFrameDescriptor.SOURCE_SLOT, frame.getArguments()[0]); frame.setInt(FormatFrameDescriptor.SOURCE_LENGTH_SLOT, (int) frame.getArguments()[1]); frame.setInt(FormatFrameDescriptor.SOURCE_POSITION_SLOT, 0); frame.setObject(FormatFrameDescriptor.OUTPUT_SLOT, new byte[expectedLength]); frame.setInt(FormatFrameDescriptor.OUTPUT_POSITION_SLOT, 0); frame.setInt(FormatFrameDescriptor.STRING_LENGTH_SLOT, 0); frame.setInt(FormatFrameDescriptor.STRING_CODE_RANGE_SLOT, CodeRange.CR_UNKNOWN.toInt()); frame.setBoolean(FormatFrameDescriptor.TAINT_SLOT, false); child.execute(frame); final int outputLength; try { outputLength = frame.getInt(FormatFrameDescriptor.OUTPUT_POSITION_SLOT); } catch (FrameSlotTypeException e) { throw new IllegalStateException(e); } if (outputLength > expectedLength) { CompilerDirectives.transferToInterpreterAndInvalidate(); /* * Don't over-compensate and allocate 2x or something like that for next time, as we have to copy the * byte[] at the end if it's too big to make it fit its contents. In the ideal case the byte[] is exactly * the right size. If we have to keep making it bigger in the slow-path, we can live with that. */ expectedLength = outputLength; } final byte[] output; try { output = (byte[]) frame.getObject(FormatFrameDescriptor.OUTPUT_SLOT); } catch (FrameSlotTypeException e) { throw new IllegalStateException(e); } final boolean taint; try { taint = frame.getBoolean(FormatFrameDescriptor.TAINT_SLOT); } catch (FrameSlotTypeException e) { throw new IllegalStateException(e); } final int stringLength; if (encoding == FormatEncoding.UTF_8) { try { stringLength = frame.getInt(FormatFrameDescriptor.STRING_LENGTH_SLOT); } catch (FrameSlotTypeException e) { throw new IllegalStateException(e); } } else { stringLength = outputLength; } final CodeRange stringCodeRange; try { stringCodeRange = CodeRange.fromInt(frame.getInt(FormatFrameDescriptor.STRING_CODE_RANGE_SLOT)); } catch (FrameSlotTypeException e) { throw new IllegalStateException(e); } return new BytesResult(output, outputLength, stringLength, stringCodeRange, taint, encoding); }