/** * Given a packed descriptor listing methods and their type, populate the call site cache. * * <p>The format of the methods portion of the descriptor is name1;type1;name2;type2 where type1 * and type2 are a single capital letter N, F, V, or S for the four main call types. After the * method portion, the other cache sizes are provided as a packed String of char values * representing the numeric sizes. @see RuntimeCache#initOthers. * * @param descriptor The descriptor to use for populating call sites and caches */ public final void initFromDescriptor(String descriptor) { String[] pieces = descriptor.split("\uFFFF"); CallSite[] sites = new CallSite[pieces.length - 1 / 2]; // if there's no call sites, don't process it if (pieces[0].length() != 0) { for (int i = 0; i < pieces.length - 1; i += 2) { switch (pieces[i + 1].charAt(0)) { case 'N': sites[i / 2] = MethodIndex.getCallSite(pieces[i]); break; case 'F': sites[i / 2] = MethodIndex.getFunctionalCallSite(pieces[i]); break; case 'V': sites[i / 2] = MethodIndex.getVariableCallSite(pieces[i]); break; case 'S': sites[i / 2] = MethodIndex.getSuperCallSite(); break; default: throw new RuntimeException( "Unknown call type: " + pieces[i + 1] + " for method " + pieces[i]); } } this.callSites = sites; } initOthers(pieces[pieces.length - 1]); }
private static CallSite getCallSiteFor(CallType callType, MethAddr methAddr) { assert callType != null : "Calltype should never be null"; String name = methAddr.toString(); switch (callType) { case NORMAL: return MethodIndex.getCallSite(name); case FUNCTIONAL: return MethodIndex.getFunctionalCallSite(name); case VARIABLE: return MethodIndex.getVariableCallSite(name); case SUPER: return MethodIndex.getSuperCallSite(); case UNKNOWN: } return null; // fallthrough for unknown }
/** * A 'for' statement. This is implemented using iter and that is how MRI does things, but 'for's do * not have their own stack, so doing this way is mildly painful. * * @see IterNode */ public class ForNode extends IterNode { public final CallSite callAdapter = MethodIndex.getCallSite("each"); private Node iterNode; public ForNode( ISourcePosition position, Node varNode, Node bodyNode, Node iterNode, StaticScope scope) { // For nodes do not have their own scope so we pass null to indicate this. // 'For's are implemented as blocks in evaluation, but they have no scope so we // just deal with this lack of scope throughout its lifespan. We should probably // change the way this works to get rid of multiple null checks. super(position, varNode, scope, bodyNode); assert iterNode != null : "iterNode is not null"; this.iterNode = iterNode; } @Override public NodeType getNodeType() { return NodeType.FORNODE; } public Node getIterNode() { return iterNode; } /** * Accept for the visitor pattern. * * @param iVisitor the visitor */ @Override public Object accept(NodeVisitor iVisitor) { return iVisitor.visitForNode(this); } @Override public List<Node> childNodes() { return Node.createList(getVarNode(), getBodyNode(), iterNode); } @Override public IRubyObject interpret( Ruby runtime, ThreadContext context, IRubyObject self, Block aBlock) { Block block = SharedScopeBlock.newInterpretedSharedScopeClosure( context, this, context.getCurrentScope(), self); try { while (true) { try { String savedFile = context.getFile(); int savedLine = context.getLine(); IRubyObject recv = null; try { recv = iterNode.interpret(runtime, context, self, aBlock); } finally { context.setFileAndLine(savedFile, savedLine); } return callAdapter.call(context, self, recv, block); } catch (JumpException.RetryJump rj) { // do nothing, allow loop to retry } } } catch (JumpException.BreakJump bj) { return (IRubyObject) bj.getValue(); } } }