Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package org.jruby.ir; 
  
 
 public class IRBuilder19 extends IRBuilder {
     public IRBuilder19(IRManager manager) {
         super(manager);
     }
     
     @Override
     public boolean is1_9() {
         return true;
     }    
 
     @Override
     protected Operand buildVersionSpecificNodes(Node nodeIRScope s) {
         switch (node.getNodeType()) {
             case return buildEncoding((EncodingNode)nodes);
             case return buildMultipleAsgn19((MultipleAsgn19Nodenodes);
             case return buildLambda((LambdaNode)nodes);
             defaultthrow new NotCompilableException("Unknown node encountered in builder: " + node.getClass());
         }
     }
 
     @Override
     protected LocalVariable getBlockArgVariable(IRScope sString nameint depth) {
         IRClosure cl = (IRClosure)s;
         if (cl.isForLoopBody()) {
             return cl.getLocalVariable(namedepth);
         } else {
             throw new NotCompilableException("Cannot ask for block-arg variable in 1.9 mode");
         }
     }
 
     @Override
     public void buildVersionSpecificBlockArgsAssignment(Node nodeIRScope sOperand argsArrayint argIndexboolean isMasgnRootboolean isClosureArgboolean isSplat) {
         IRClosure cl = (IRClosure)s;
         if (!cl.isForLoopBody())
             throw new NotCompilableException("Should not have come here for block args assignment in 1.9 mode: " + node);
 
         // Argh!  For-loop bodies and regular iterators are different in terms of block-args!
         switch (node.getNodeType()) {
             case : {
                 ListNode sourceArray = ((MultipleAsgn19Nodenode).getPre();
                 int i = 0; 
                 for (Node ansourceArray.childNodes()) {
                     // Use 1.8 mode version for this
                     buildBlockArgsAssignment(ansnullifalsefalsefalse);
                     i++;
                 }
                break;
            }
            default
                throw new NotCompilableException("Can't build assignment node: " + node);
        }
    }
    protected LocalVariable getArgVariable(IRScope sString nameint depth) {
        // For non-loops, this name will override any name that exists in outer scopes
        return s.isForLoopBody() ? s.getLocalVariable(namedepth) : s.getNewLocalVariable(name, 0);
    }
    private void addArgReceiveInstr(IRScope sVariable vint argIndexboolean postint numPreReqdint numPostRead) {
        if (posts.addInstr(new ReceivePostReqdArgInstr(vargIndexnumPreReqdnumPostRead));
        else s.addInstr(new ReceivePreReqdArgInstr(vargIndex));
    }
    public void receiveRequiredArg(Node nodeIRScope sint argIndexboolean postint numPreReqdint numPostRead) {
        switch (node.getNodeType()) {
            case : {
                ArgumentNode a = (ArgumentNode)node;
                String argName = a.getName();
                if (s instanceof IRMethod) ((IRMethod)s).addArgDesc("req"argName);
                addArgReceiveInstr(ss.getNewLocalVariable(argName, 0), argIndexpostnumPreReqdnumPostRead);
                break;
            }
            case : {
                MultipleAsgn19Node childNode = (MultipleAsgn19Nodenode;
                Variable v = s.getNewTemporaryVariable();
                addArgReceiveInstr(svargIndexpostnumPreReqdnumPostRead);
                if (s instanceof IRMethod) ((IRMethod)s).addArgDesc("rest""");
                s.addInstr(new ToAryInstr(vv.getFalse()));
                buildMultipleAsgn19Assignment(childNodesvnull);
                break;
            }
            defaultthrow new NotCompilableException("Can't build assignment node: " + node);
        }
    }
    private void receiveClosureArg(BlockArgNode blockVarNodeIRScope s) {
        Variable blockVar = null;
        if (blockVarNode != null) {
            String blockArgName = blockVarNode.getName();
            blockVar = s.getNewLocalVariable(blockArgName, 0);
            if (s instanceof IRMethod) ((IRMethod)s).addArgDesc("block"blockArgName);
            s.addInstr(new ReceiveClosureInstr(blockVar));
        }
        // SSS FIXME: This instruction is only needed if there is an yield instr somewhere!
        // In addition, store the block argument in an implicit block variable
        Variable implicitBlockArg = s.getImplicitBlockArg();
        if (blockVar == nulls.addInstr(new ReceiveClosureInstr(implicitBlockArg));
        else s.addInstr(new CopyInstr(implicitBlockArgblockVar));
    }
    public void receiveArgs(final ArgsNode argsNodeIRScope s) {
        final int numPreReqd = argsNode.getPreCount();
        final int numPostReqd = argsNode.getPostCount();
        final int required = argsNode.getRequiredArgsCount(); // numPreReqd + numPostReqd
        int opt = argsNode.getOptionalArgsCount();
        int rest = argsNode.getRestArg();
        s.getStaticScope().setArities(requiredoptrest);
        // For closures, we don't need the check arity call
        if (s instanceof IRMethod) {
            // FIXME: Expensive to do this explicitly?  But, two advantages:
            // (a) on inlining, we'll be able to get rid of these checks in almost every case.
            // (b) compiler to bytecode will anyway generate this and this is explicit.
            // For now, we are going explicit instruction route.  But later, perhaps can make this implicit in the method setup preamble?  
            s.addInstr(new CheckArityInstr(requiredoptrest));
        }
        // Other args begin at index 0
        int argIndex = 0;
        // Pre(-opt and rest) required args
        ListNode preArgs = argsNode.getPre();
        for (int i = 0; i < numPreReqdi++, argIndex++) {
            receiveRequiredArg(preArgs.get(i), sargIndexfalse, -1, -1);
        }
        // Fixup opt/rest
        opt = opt > 0 ? opt : 0;
        rest = rest > -1 ? 1 : 0;
        // Now for opt args
        if (opt > 0) {
            ListNode optArgs = argsNode.getOptArgs();
            for (int j = 0; j < optj++, argIndex++) {
                // Jump to 'l' if this arg is not null.  If null, fall through and build the default value!
                Label l = s.getNewLabel();
                OptArgNode n = (OptArgNode)optArgs.get(j);
                String argName = n.getName();
                Variable av = s.getNewLocalVariable(argName, 0);
                if (s instanceof IRMethod) ((IRMethod)s).addArgDesc("opt"argName);
                // You need at least required+j+1 incoming args for this opt arg to get an arg at all
                s.addInstr(new ReceiveOptArgInstr19(avargIndexrequired+j+1));
                s.addInstr(BNEInstr.create(av.l)); // if 'av' is not undefined, go to default
                build(n.getValue(), s);
                s.addInstr(new LabelInstr(l));
            }
        }
        // Rest arg
        if (rest > 0) {
            // Consider: def foo(*); .. ; end
            // For this code, there is no argument name available from the ruby code.
            // So, we generate an implicit arg name
            String argName = argsNode.getRestArgNode().getName();
            if (s instanceof IRMethod) ((IRMethod)s).addArgDesc("rest"argName == null ? "" : argName);
            argName = (argName == null || argName.equals("")) ? "%_arg_array" : argName;
            // You need at least required+opt+1 incoming args for the rest arg to get any args at all
            // If it is going to get something, then it should ignore required+opt args from the beginning
            // because they have been accounted for already.
            s.addInstr(new ReceiveRestArgInstr19(s.getNewLocalVariable(argName, 0), argIndexrequiredopt));
            argIndex++;
        }
        // Post(-opt and rest) required args
        ListNode postArgs = argsNode.getPost();
        for (int i = 0; i < numPostReqdi++) {
            receiveRequiredArg(postArgs.get(i), sitruenumPreReqdnumPostReqd);
        }
        // Now, receive the block arg 
        // -- for methods, we always receive it (implicitly, if the block arg is not explicit)
        // -- for closures, only if it is explicitly present
        BlockArgNode blockArg = argsNode.getBlock();
        if ((s instanceof IRMethod) || (blockArg != null)) receiveClosureArg(blockArgs);
    }
    @Override
    public void receiveBlockArgs(final IterNode nodeIRScope s) {
        Node args = node.getVarNode();
        if (args instanceof ArgsNode) { // regular blocks
            ((IRClosure)s).setParameterList(RuntimeHelpers.encodeParameterList((ArgsNode)args).split(";"));
            receiveArgs((ArgsNode)argss);
        } else  { 
            // for loops -- reuse code in IRBuilder:buildBlockArgsAssignment
            buildBlockArgsAssignment(argssnull, 0, falsefalsefalse);
        }
    }
    @Override
    public void receiveBlockClosureArg(Node nodeIRScope s) {
        // Nothing to do here.  iterNode.blockVarNode is not valid in 1.9 mode
    }
    @Override
    public void receiveMethodArgs(final ArgsNode argsNodeIRScope s) {
        receiveArgs(argsNodes);
    }
    protected void receiveArg(IRScope sVariable vOperand argsArrayint argIndexboolean isSplat) {
        // We are in a nested receive situation -- when we are not at the root of a masgn tree
        // Ex: We are trying to receive (b,c) in this example: "|a, (b,c), d| = ..."
    }
    // This method is called to build arguments
    public void buildArgsMasgn(Node nodeIRScope sOperand argsArrayboolean isMasgnRootint preArgsCountint postArgsCountint indexboolean isSplat) {
        Variable v;
        switch (node.getNodeType()) {
            case : {
                DAsgnNode dynamicAsgn = (DAsgnNodenode;
                v = getArgVariable(sdynamicAsgn.getName(), dynamicAsgn.getDepth());
                if (isSplats.addInstr(new RestArgMultipleAsgnInstr(vargsArraypreArgsCountpostArgsCountindex));
                else s.addInstr(new ReqdArgMultipleAsgnInstr(vargsArraypreArgsCountpostArgsCountindex));
                break;
            }
            case : {
                LocalAsgnNode localVariable = (LocalAsgnNodenode;
                v = getArgVariable(slocalVariable.getName(), localVariable.getDepth());
                if (isSplats.addInstr(new RestArgMultipleAsgnInstr(vargsArraypreArgsCountpostArgsCountindex));
                else s.addInstr(new ReqdArgMultipleAsgnInstr(vargsArraypreArgsCountpostArgsCountindex));
                break;
            }
            case : {
                Variable oldArgs = null;
                MultipleAsgn19Node childNode = (MultipleAsgn19Nodenode;
                if (!isMasgnRoot) {
                    v = s.getNewTemporaryVariable();
                    if (isSplats.addInstr(new RestArgMultipleAsgnInstr(vargsArraypreArgsCountpostArgsCountindex));
                    else s.addInstr(new ReqdArgMultipleAsgnInstr(vargsArraypreArgsCountpostArgsCountindex));
                    s.addInstr(new ToAryInstr(vv.getFalse()));
                    argsArray = v;
                }
                // Build
                buildMultipleAsgn19Assignment(childNodesargsArraynull);
                break;
            }
            default:
                throw new NotCompilableException("Shouldn't get here: " + node);
        }
    }
    // SSS: This method is called both for regular multiple assignment as well as argument passing
    //
    // Ex: a,b,*c=v  is a regular assignment and in this case, the "values" operand will be non-null
    // Ex: { |a,b,*c| ..} is the argument passing case
    public void buildMultipleAsgn19Assignment(final MultipleAsgn19Node multipleAsgnNodeIRScope sOperand argsArrayOperand values) {
        final ListNode masgnPre = multipleAsgnNode.getPre();
        // Build assignments for specific named arguments
        int i = 0; 
        if (masgnPre != null) {
            for (Node anmasgnPre.childNodes()) {
                if (values == null) {
                    buildArgsMasgn(ansargsArrayfalse, -1, -1, ifalse);
                } else {
                    Variable rhsVal = s.getNewTemporaryVariable();
                    s.addInstr(new ReqdArgMultipleAsgnInstr(rhsValvaluesi));
                    buildAssignment(ansrhsVal);
                }
                i++;
            }
        }
        // Build an assignment for a splat, if any, with the rest of the operands!
        Node restNode = multipleAsgnNode.getRest();
        int postArgsCount = multipleAsgnNode.getPostCount();
        if (restNode != null) {
            if (restNode instanceof StarNode) {
                // do nothing
            } else if (values == null) {
                buildArgsMasgn(restNodesargsArrayfalseipostArgsCount, 0, true); // rest of the argument array!
            } else {
                Variable rhsVal = s.getNewTemporaryVariable();
                s.addInstr(new RestArgMultipleAsgnInstr(rhsValvaluesipostArgsCount, 0));
                buildAssignment(restNodesrhsVal); // rest of the argument array!
            }
        }
        // Build assignments for rest of the operands
        final ListNode masgnPost = multipleAsgnNode.getPost();
        if (masgnPost != null) {
            int j = 0;
            for (Node anmasgnPost.childNodes()) {
                if (values == null) {
                    buildArgsMasgn(ansargsArrayfalseipostArgsCountjfalse);
                } else {
                    Variable rhsVal = s.getNewTemporaryVariable();
                    s.addInstr(new ReqdArgMultipleAsgnInstr(rhsValvaluesipostArgsCountj));  // Fetch from the end
                    buildAssignment(ansrhsVal);
                }
                j++;
            }
        }
    }
    // Non-arg masgn (actually a nested masgn)
    @Override
    public void buildVersionSpecificAssignment(Node nodeIRScope sVariable v) {
        switch (node.getNodeType()) {
        case : {
            s.addInstr(new ToAryInstr(vv.getFalse()));
            buildMultipleAsgn19Assignment((MultipleAsgn19Node)nodesnullv);
            break;
        }
        default
            throw new NotCompilableException("Can't build assignment node: " + node);
        }
    }
    @Override
    public Operand buildArgsPush(final ArgsPushNode nodeIRScope s) {
        Operand v1 = build(node.getFirstNode(), s);
        Operand v2 = build(node.getSecondNode(), s);
        return new CompoundArray(v1v2true);
    }
    public Operand buildEncoding(EncodingNode nodeIRScope s) {
        Variable ret = s.getNewTemporaryVariable();
        s.addInstr(new GetEncodingInstr(retnode.getEncoding()));
        return ret;
    }
    public Operand buildLambda(LambdaNode nodeIRScope s) {
        IRClosure closure = new IRClosure(sfalsenode.getPosition().getStartLine(), node.getScope(), Arity.procArityOf(node.getArgs()), node.getArgumentType(), true);
        s.addClosure(closure);
        // Create a new nested builder to ensure this gets its own IR builder state 
        // like the ensure block stack
        IRBuilder closureBuilder = createIRBuilder(is1_9());
        // Receive self
        closure.addInstr(new ReceiveSelfInstr(getSelf(closure)));
        // args
        closureBuilder.receiveBlockArgs(nodeclosure);
        closureBuilder.receiveBlockClosureArg(node.getBlockVarNode(), closure);
        Operand closureRetVal = node.getBody() == null ? .getNil() : closureBuilder.build(node.getBody(), closure);
        // can be U_NIL if the node is an if node with returns in both branches.
        if (closureRetVal != closure.addInstr(new ClosureReturnInstr(closureRetVal));
        Variable lambda = s.getNewTemporaryVariable();
        s.addInstr(new BuildLambdaInstr(lambdaclosurenode.getPosition()));
        return lambda;
    }
    @Override
    public Operand buildYield(YieldNode nodeIRScope s) {
        boolean unwrap = true;
        Node argNode = node.getArgsNode();
        // Get rid of one level of array wrapping
        if (argNode != null && (argNode instanceof ArrayNode) && ((ArrayNode)argNode).size() == 1) {
            argNode = ((ArrayNode)argNode).getLast();
            unwrap = false;
        }
        Variable ret = s.getNewTemporaryVariable();
        s.addInstr(new YieldInstr(rets.getImplicitBlockArg(), build(argNodes), unwrap));
        return ret;
    }
    // Non-arg masgn
    public Operand buildMultipleAsgn19(MultipleAsgn19Node multipleAsgnNodeIRScope s) {
        Operand  values = build(multipleAsgnNode.getValueNode(), s);
        Variable ret = getValueInTemporaryVariable(svalues);
        s.addInstr(new ToAryInstr(retret.getFalse()));
        buildMultipleAsgn19Assignment(multipleAsgnNodesnullret);
        return ret;
    }
    // 1.9 specific defined? logic  
    @Override
        switch (node.getNodeType()) {
            case :
            case : {
                return new StringLiteral("expression");
            }
            case : {
                return new StringLiteral("assignment");
            }
            case : {
                return new StringLiteral("local-variable");
            }
            case : {
                return buildDefinitionCheck(snew BackrefIsMatchDataInstr(s.getNewTemporaryVariable()), "global-variable");
            }
            case :
            case : {
                Operand v = super.buildVersionSpecificGetDefinitionIR(nodes);
                Label doneLabel = s.getNewLabel();
                Variable tmpVar = getValueInTemporaryVariable(sv);
                s.addInstr(BNEInstr.create(tmpVar.getNil(), doneLabel));
                s.addInstr(new CopyInstr(tmpVarnew StringLiteral("expression")));
                s.addInstr(new LabelInstr(doneLabel));
                return tmpVar;
            }
            case : {
                Operand v = buildGetDefinitionBase(((NotNode)node).getConditionNode(), s);
                Label doneLabel = s.getNewLabel();
                Variable tmpVar = getValueInTemporaryVariable(sv);
                s.addInstr(BEQInstr.create(tmpVar.getNil(), doneLabel));
                s.addInstr(new CopyInstr(tmpVarnew StringLiteral("method")));
                s.addInstr(new LabelInstr(doneLabel));
                return tmpVar;
            }
            case : {
            // SSS FIXME: Is there a reason to do this all with low-level IR?
            // Can't this all be folded into a Java method that would be part
            // of the runtime library, which then can be used by buildDefinitionCheck method above?
            // This runtime library would be used both by the interpreter & the compiled code!
                /* -------------------------------------------------------------------------------------
                 * We have to generate IR for this:
                 *    v = backref; (!(v instanceof RubyMatchData) || v.group(n).nil?) ? nil : "global-variable"
                 *
                 * which happens to be identical to: (where nthRef implicitly fetches backref again!)
                 *    v = backref; (!(v instanceof RubyMatchData) || nthRef(n).nil?) ? nil : "global-variable"
                 *
                 * I am using the second form since it let us encode it in fewer IR instructions.
                 * But, note that this second form is not as clean as the first one plus it fetches backref twice!
                 * ------------------------------------------------------------------------------------- */
                int n = ((NthRefNodenode).getMatchNumber();
                Label undefLabel = s.getNewLabel();
                Variable tmpVar = s.getNewTemporaryVariable();
                s.addInstr(new BackrefIsMatchDataInstr(tmpVar));
                s.addInstr(BEQInstr.create(tmpVar.getFalse(), undefLabel));
                // SSS FIXME: 
                // - Can/should I use BEQInstr(new NthRef(n), manager.getNil(), undefLabel)? instead of .nil? & compare with flag?
                // - Or, even create a new IsNilInstr and NotNilInstr to represent optimized scenarios where
                //   the nil? method is not monkey-patched?
                // This matters because if String.nil? is monkey-patched, the two sequences can behave differently.
                s.addInstr(CallInstr.create(tmpVarnew MethAddr("nil?"), new NthRef(n), null));
                s.addInstr(BEQInstr.create(tmpVar.getTrue(), undefLabel));
                return buildDefnCheckIfThenPaths(sundefLabelnew StringLiteral("global-variable"));
            }
            default: {
                return buildGenericGetDefinitionIR(nodes);
            }
        }
    }
New to GrepCode? Check out our FAQ X