@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 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)); }