@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 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)); }
private Object methodMissing( RubyBasicObject self, RubySymbol name, Object[] args, RubyProc block) { throw new RaiseException( getContext().getCoreLibrary().nameErrorNoMethod(name.toString(), self.toString())); }