Examples of IRScope


Examples of org.jruby.ir.IRScope

    }

    public static IRubyObject INTERPRET_METHOD(ThreadContext context, InterpretedIRMethod irMethod,
        IRubyObject self, String name, IRubyObject[] args, Block block, Block.Type blockType, boolean isTraceable) {
        Ruby       runtime   = context.runtime;
        IRScope    scope     = irMethod.getIRMethod();
        RubyModule implClass = irMethod.getImplementationClass();
        Visibility viz       = irMethod.getVisibility();
        boolean syntheticMethod = name == null || name.equals("");

        try {
            if (!syntheticMethod) ThreadContext.pushBacktrace(context, name, scope.getFileName(), context.getLine());
            if (isTraceable) methodPreTrace(runtime, context, name, implClass);
            return interpret(context, self, scope, viz, implClass, args, block, blockType);
        } finally {
            if (isTraceable) {
                try {methodPostTrace(runtime, context, name, implClass);}
View Full Code Here

Examples of org.jruby.ir.IRScope

        } else {
            // SSS FIXME: The code below is not entirely correct.  We have to process 'yi.getYieldArg()' similar
            // to how InterpretedIRBlockBody (1.8 and 1.9 modes) processes it.  We may need a special instruction
            // that takes care of aligning the stars and bringing good fortune to arg yielder and arg receiver.

            IRScope callerScope   = getInlineHostScope();
            boolean needSpecialProcessing = (blockArityValue != -1) && (blockArityValue != 1);
            Variable yieldArgArray = callerScope.getNewTemporaryVariable();
            yieldBB.addInstr(new ToAryInstr(yieldArgArray, yieldInstrArg, callerScope.getManager().getTrue()));
            this.yieldArg = yieldArgArray;
        }

        this.yieldResult = yi.getResult();
    }
View Full Code Here

Examples of org.jruby.ir.IRScope

    }

    public void inlineMethod(IRScope scope, RubyModule implClass, int classToken, BasicBlock callBB, CallBase call) {
        // Temporarily turn off inlining of recursive methods
        // Conservative turning off for inlining of a method in a closure nested within the same method
        IRScope hostScope = cfg.getScope();
        if (hostScope.getNearestMethod() == scope) return;

/*
        System.out.println("host cfg   :" + cfg.toStringGraph());
        System.out.println("host instrs:" + cfg.toStringInstrs());
        System.out.println("source cfg   :" + scope.getCFG().toStringGraph());
        System.out.println("source instrs:" + scope.getCFG().toStringInstrs());
*/

        // Host method data init
        InlinerInfo ii = new InlinerInfo(call, cfg);
        Label splitBBLabel = hostScope.getNewLabel();
        BasicBlock splitBB;

        // Inlinee method data init
        CFG methodCFG = scope.getCFG();
        BasicBlock mEntry = methodCFG.getEntryBB();
        BasicBlock mExit = methodCFG.getExitBB();
        List<BasicBlock> methodBBs = new ArrayList<BasicBlock>();
        for (BasicBlock b: methodCFG.getBasicBlocks()) methodBBs.add(b);

        // Check if we are inlining a recursive method
        if (hostScope.getNearestMethod() == scope) {
            // 1. clone self
            // SSS: FIXME: We need a clone-graph api method in cfg and graph
            CFG selfClone = cloneSelf(ii);

            // 2. add callee bbs and their edges
            // SSS: FIXME: We need a swallow-graph api method in cfg and graph
            for (BasicBlock b : selfClone.getBasicBlocks()) {
                cfg.addBasicBlock(b);
                for (Edge<BasicBlock> e : selfClone.getOutgoingEdges(b)) {
                    cfg.addEdge(b, e.getDestination().getData(), e.getType());
                }
            }
        } else {
            // 2. clone callee and add it to the host cfg
            for (BasicBlock b : methodCFG.getBasicBlocks()) {
                if (b != mEntry && b != mExit) {
                    cfg.addBasicBlock(b.cloneForInlinedMethod(ii));
                }
            }
            for (BasicBlock x : methodCFG.getBasicBlocks()) {
                if (x != mEntry && x != mExit) {
                    BasicBlock rx = ii.getRenamedBB(x);
                    for (Edge<BasicBlock> e : methodCFG.getOutgoingEdges(x)) {
                        BasicBlock b = e.getDestination().getData();
                        if (b != mExit) cfg.addEdge(rx, ii.getRenamedBB(b), e.getType());
                    }
                }
            }
        }

        // 3. split callsite bb, move outbound edges from callsite bb to split bb, and unhook call bb
        splitBB = callBB.splitAtInstruction(call, splitBBLabel, false);
        cfg.addBasicBlock(splitBB);
        for (Edge<BasicBlock> e : cfg.getOutgoingEdges(callBB)) {
            cfg.addEdge(splitBB, e.getDestination().getData(), e.getType());
        }
        cfg.removeAllOutgoingEdgesForBB(callBB);

        // 4a. Hook up entry edges
        assert methodCFG.outDegree(mEntry) == 2: "Entry BB of inlinee method does not have outdegree 2: " + methodCFG.toStringGraph();
        for (Edge<BasicBlock> e : methodCFG.getOutgoingEdges(mEntry)) {
            BasicBlock destination = e.getDestination().getData();
            if (destination != mExit) {
                BasicBlock dstBB = ii.getRenamedBB(destination);
                if (!ii.canMapArgsStatically()) {
                    dstBB.addInstr(new ToAryInstr((Variable)ii.getArgs(), new Array(call.getCallArgs()), cfg.getScope().getManager().getTrue()));
                }
                cfg.addEdge(callBB, dstBB, CFG.EdgeType.FALL_THROUGH);
            }
        }

        // 4b. Hook up exit edges
        for (Edge<BasicBlock> e : methodCFG.getIncomingEdges(mExit)) {
            BasicBlock source = e.getSource().getData();
            if (source != mEntry) {
                BasicBlock clonedSource = ii.getRenamedBB(source);
                if (e.getType() == EdgeType.EXCEPTION) {
                    // e._src has an explicit throw that returns from the callee
                    // after inlining, if the caller instruction has a rescuer, then the
                    // throw has to be captured by the rescuer as well.
                    BasicBlock rescuerOfSplitBB = cfg.getRescuerBBFor(splitBB);
                    if (rescuerOfSplitBB != null) {
                        cfg.addEdge(clonedSource, rescuerOfSplitBB, EdgeType.EXCEPTION);
                    } else {
                        cfg.addEdge(clonedSource, cfg.getExitBB(), EdgeType.EXIT);                       
                    }
                } else {
                    cfg.addEdge(clonedSource, splitBB, e.getType());
                }
            }
        }

        // SSS FIXME: Are these used anywhere post-CFG building?
        // 5. Clone exception regions
        List<ExceptionRegion> exceptionRegions = cfg.getOutermostExceptionRegions();
        for (ExceptionRegion r : methodCFG.getOutermostExceptionRegions()) {
            exceptionRegions.add(r.cloneForInlining(ii));
        }

        // 6. Update bb rescuer map
        // 6a. splitBB will be protected by the same bb as callBB
        BasicBlock callBBrescuer = cfg.getRescuerBBFor(callBB);
        if (callBBrescuer != null) cfg.setRescuerBB(splitBB, callBBrescuer);

        BasicBlock callBBensurer = cfg.getEnsurerBBFor(callBB);
        if (callBBensurer != null) cfg.setEnsurerBB(splitBB, callBBensurer);

        // 6b. remap existing protections for bbs in mcfg to their renamed bbs.
        // 6c. bbs in mcfg that aren't protected by an existing bb will be protected by callBBrescuer.
        for (BasicBlock x : methodBBs) {
            if (x != mEntry && x != mExit) {
                BasicBlock xRenamed = ii.getRenamedBB(x);
                BasicBlock xProtector = methodCFG.getRescuerBBFor(x);
                if (xProtector != null) {
                    cfg.setRescuerBB(xRenamed, ii.getRenamedBB(xProtector));
                } else if (callBBrescuer != null) {
                    cfg.setRescuerBB(xRenamed, callBBrescuer);
                }

                BasicBlock xEnsurer = methodCFG.getEnsurerBBFor(x);
                if (xEnsurer != null) {
                    cfg.setEnsurerBB(xRenamed, ii.getRenamedBB(xEnsurer));
                } else if (callBBensurer != null) {
                    cfg.setEnsurerBB(xRenamed, callBBensurer);
                }
            }
        }

        // 7. Add inline guard that verifies that the method inlined is the same
        // that gets called in future invocations.  In addition to the guard, add
        // a failure path code.
        Label failurePathLabel = hostScope.getNewLabel();
        callBB.addInstr(new ModuleVersionGuardInstr(implClass, classToken, call.getReceiver(), failurePathLabel));

        BasicBlock failurePathBB = new BasicBlock(cfg, failurePathLabel);
        cfg.addBasicBlock(failurePathBB);
        failurePathBB.addInstr(call);
View Full Code Here

Examples of org.jruby.ir.IRScope

            if (((Array)yieldInstrArg).size() == blockArityValue) canMapArgsStatically = true;
        } else {
            // SSS FIXME: The code below is not entirely correct.  We have to process 'yi.getYieldArg()' similar
            // to how InterpretedIRBlockBody (1.8 and 1.9 modes) processes it.  We may need a special instruction
            // that takes care of aligning the stars and bringing good fortune to arg yielder and arg receiver.
            IRScope callerScope   = getHostScope();
            Variable yieldArgArray = callerScope.createTemporaryVariable();
            yieldBB.addInstr(new ToAryInstr(yieldArgArray, yieldInstrArg));
            yieldArg = yieldArgArray;
        }

        yieldResult = yi.getResult();
View Full Code Here

Examples of org.jruby.ir.IRScope

    }

    public void inlineMethod(IRScope scope, RubyModule implClass, int classToken, BasicBlock callBB, CallBase call, boolean cloneHost) {
        // Temporarily turn off inlining of recursive methods
        // Conservative turning off for inlining of a method in a closure nested within the same method
        IRScope hostScope = cfg.getScope();
        if (hostScope.getNearestMethod() == scope) return;

/*
        System.out.println("Looking for: " + call.getIPC() + ": " + call);
        System.out.println("host cfg   :" + cfg.toStringGraph());
        System.out.println("host instrs:" + cfg.toStringInstrs());
        System.out.println("source cfg   :" + scope.getCFG().toStringGraph());
        System.out.println("source instrs:" + scope.getCFG().toStringInstrs());
*/

        // Find callBB
        if (callBB == null) {
            for (BasicBlock x: cfg.getBasicBlocks()) {
                for (Instr i: x.getInstrs()) {
                    // System.out.println("IPC " + i.getIPC() + " = " + i);
                    if (i.getIPC() == call.getIPC()) {
                        // System.out.println("Found it!!!! -- " + call);
                        callBB = x;
                        break;
                    }
                }
            }
        }

        if (callBB == null) {
            System.out.println("----------------------------------");
            System.out.println("Did not find BB with call: " + call);
            System.out.println("Host cfg   :" + cfg.toStringGraph());
            System.out.println("Host instrs:" + cfg.toStringInstrs());
            System.out.println("----------------------------------");
            return;
        }

        // Split callsite bb, move outbound edges from callsite bb to split bb, and unhook call bb
        Label splitBBLabel = hostScope.getNewLabel();
        BasicBlock splitBB = callBB.splitAtInstruction(call, splitBBLabel, false);
        cfg.addBasicBlock(splitBB);
        for (Edge<BasicBlock> e : cfg.getOutgoingEdges(callBB)) {
            cfg.addEdge(splitBB, e.getDestination().getData(), e.getType());
        }
        cfg.removeAllOutgoingEdgesForBB(callBB);

        SimpleCloneInfo hostCloneInfo = cloneHost ? cloneHostInstrs(cfg) : null;

        // Host method data init
        Operand callReceiver = call.getReceiver();
        Variable callReceiverVar;
        if (callReceiver instanceof Variable) {
            callReceiverVar = (Variable)callReceiver;
        } else {
            callReceiverVar = hostScope.createTemporaryVariable();
        }

        InlineCloneInfo ii = new InlineCloneInfo(call, cfg, callReceiverVar);

        // Inlinee method data init
        CFG methodCFG = scope.getCFG();
        List<BasicBlock> methodBBs = new ArrayList<BasicBlock>();
        for (BasicBlock b: methodCFG.getBasicBlocks()) methodBBs.add(b);

        // Check if we are inlining a recursive method
        if (hostScope.getNearestMethod() == scope) {
            // 1. clone self
            // SSS: FIXME: We need a clone-graph api method in cfg and graph
            CFG selfClone = cloneSelf(ii);

            // 2. add callee bbs and their edges
            // SSS: FIXME: We need a swallow-graph api method in cfg and graph
            for (BasicBlock b : selfClone.getBasicBlocks()) {
                cfg.addBasicBlock(b);
                for (Edge<BasicBlock> e : selfClone.getOutgoingEdges(b)) {
                    cfg.addEdge(b, e.getDestination().getData(), e.getType());
                }
            }
        } else {
            // clone callee and add it to the host cfg
            for (BasicBlock b : methodCFG.getBasicBlocks()) {
                if (!b.isEntryBB() && !b.isExitBB()) cfg.addBasicBlock(b.cloneForInlining(ii));
            }
            for (BasicBlock x : methodCFG.getBasicBlocks()) {
                if (x.isEntryBB() || x.isExitBB()) continue;

                BasicBlock rx = ii.getRenamedBB(x);
                for (Edge<BasicBlock> e : methodCFG.getOutgoingEdges(x)) {
                    BasicBlock b = e.getDestination().getData();
                    if (!b.isExitBB()) cfg.addEdge(rx, ii.getRenamedBB(b), e.getType());
                }
            }
        }

        // Hook up entry edges
        assert methodCFG.outDegree(methodCFG.getEntryBB()) == 2: "Entry BB of inlinee method does not have outdegree 2: " + methodCFG.toStringGraph();
        for (BasicBlock destination : methodCFG.getOutgoingDestinations(methodCFG.getEntryBB())) {
            if (destination.isExitBB()) continue;

            BasicBlock dstBB = ii.getRenamedBB(destination);
            if (callReceiver != callReceiverVar) {
                dstBB.insertInstr(new CopyInstr(callReceiverVar, callReceiver));
            }

            if (!ii.canMapArgsStatically()) {
                // SSS FIXME: This is buggy!
                // This code has to mimic whatever CallBase.prepareArguments does!
                // We may need a special instruction that takes care of this.
                Operand args;
                Operand[] callArgs = call.cloneCallArgs(hostCloneInfo);
                if (callArgs.length == 1 && callArgs[0] instanceof Splat) {
                    args = callArgs[0];
                } else {
                    args = new Array(callArgs);
                }
                dstBB.insertInstr(new CopyInstr((Variable)ii.getArgs(), args));
            }
            cfg.addEdge(callBB, dstBB, CFG.EdgeType.FALL_THROUGH);
        }

        // Hook up exit edges
        for (Edge<BasicBlock> e : methodCFG.getIncomingEdges(methodCFG.getExitBB())) {
            BasicBlock source = e.getSource().getData();
            if (source.isEntryBB()) continue;

            BasicBlock clonedSource = ii.getRenamedBB(source);
            if (e.getType() == EdgeType.EXCEPTION) {
                // e._src has an explicit throw that returns from the callee
                // after inlining, if the caller instruction has a rescuer, then the
                // throw has to be captured by the rescuer as well.
                BasicBlock rescuerOfSplitBB = cfg.getRescuerBBFor(splitBB);
                if (rescuerOfSplitBB != null) {
                    cfg.addEdge(clonedSource, rescuerOfSplitBB, EdgeType.EXCEPTION);
                } else {
                    cfg.addEdge(clonedSource, cfg.getExitBB(), EdgeType.EXIT);
                }
            } else {
                cfg.addEdge(clonedSource, splitBB, e.getType());
            }
        }

        // Update bb rescuer map
        // splitBB will be protected by the same bb as callBB
        BasicBlock callBBrescuer = cfg.getRescuerBBFor(callBB);
        if (callBBrescuer != null) cfg.setRescuerBB(splitBB, callBBrescuer);

        // Remap existing protections for bbs in mcfg to their renamed bbs.
        // bbs in mcfg that aren't protected by an existing bb will be protected by callBBrescuer.
        for (BasicBlock x : methodBBs) {
            if (x.isEntryBB() || x.isExitBB()) continue;

            BasicBlock xRenamed = ii.getRenamedBB(x);
            BasicBlock xProtector = methodCFG.getRescuerBBFor(x);
            if (xProtector != null) {
                cfg.setRescuerBB(xRenamed, ii.getRenamedBB(xProtector));
            } else if (callBBrescuer != null) {
                cfg.setRescuerBB(xRenamed, callBBrescuer);
            }
        }

        // Add inline guard that verifies that the method inlined is the same
        // that gets called in future invocations.  In addition to the guard, add
        // a failure path code.
        Label failurePathLabel = hostScope.getNewLabel();
        callBB.addInstr(new ModuleVersionGuardInstr(implClass, classToken, call.getReceiver(), failurePathLabel));

        BasicBlock failurePathBB = new BasicBlock(cfg, failurePathLabel);
        cfg.addBasicBlock(failurePathBB);
        failurePathBB.addInstr(call);
View Full Code Here

Examples of org.jruby.ir.IRScope

        dfVarMap.put(v, dfv);
        varDfVarMap.put(dfv, v);

        if (v instanceof LocalVariable && !v.isSelf()) {
            //System.out.println("Adding df var for " + v + ":" + dfv.id);
            IRScope s = getScope();
            for (int n = ((LocalVariable) v).getScopeDepth(); s != null && n >= 0; n--) {
                if (s instanceof IREvalScript) {
                    // If a variable is at the topmost scope of the eval OR crosses an eval boundary,
                    // it is going to be marked always live since it could be used by other evals (n = 0)
                    // or by enclosing scopes (n > 0)
                    alwaysLiveVars.add((LocalVariable) v);
                    break;
                }

                s = s.getLexicalParent();
            }
            localVars.add((LocalVariable) v);
        }
    }
View Full Code Here

Examples of org.jruby.ir.IRScope

         }
         return value;
    }

    boolean addClosureExitStoreLocalVars(ListIterator<Instr> instrs, Set<LocalVariable> dirtyVars, Map<Operand, Operand> varRenameMap) {
        IRScope scope        = getScope();
        boolean addedStores  = false;
        boolean isEvalScript = scope instanceof IREvalScript;
        for (LocalVariable v : dirtyVars) {
            if (isEvalScript || !(v instanceof ClosureLocalVariable) || (scope != ((ClosureLocalVariable)v).definingScope)) {
                addedStores = true;
View Full Code Here

Examples of org.jruby.ir.IRScope

         * vars from the parent scope have been stored.
         * -------------------------------------------------------------------- */
        boolean mightRequireGlobalEnsureBlock = false;

        Set<LocalVariable> dirtyVars = null;
        IRScope cfgScope = getScope();
        CFG     cfg      = cfgScope.cfg();

        this.scopeHasLocalVarStores      = false;
        this.scopeHasUnrescuedExceptions = false;

        if (cfgScope instanceof IRClosure) {
            mightRequireGlobalEnsureBlock = true;
            dirtyVars = new HashSet<LocalVariable>();
        }

        // Add local-var stores
        for (StoreLocalVarPlacementNode bspn: flowGraphNodes) {
            boolean bbAddedStores;
            // SSS: This is highly conservative.  If the bb has an exception raising instr.
            // and we dont have a rescuer, only then do we have unrescued exceptions.
            // Right now, we are only checking for rescuers.
            boolean bbHasUnrescuedExceptions = !bspn.hasExceptionsRescued();
            if (mightRequireGlobalEnsureBlock && bbHasUnrescuedExceptions) {
                bbAddedStores = bspn.addStores(varRenameMap, dirtyVars);
            } else {
                bbAddedStores = bspn.addStores(varRenameMap, null);
            }

            scopeHasUnrescuedExceptions = scopeHasUnrescuedExceptions || bbHasUnrescuedExceptions;
            scopeHasLocalVarStores      = scopeHasLocalVarStores || bbAddedStores;
        }

        // Allocate global-ensure block, if necessary
        if ((mightRequireGlobalEnsureBlock == true) && !dirtyVars.isEmpty()) {
            ListIterator<Instr> instrs;
            BasicBlock geb = cfg.getGlobalEnsureBB();
            if (geb == null) {
                Variable exc = cfgScope.createTemporaryVariable();
                geb = new BasicBlock(cfg, Label.getGlobalEnsureBlockLabel());
                geb.addInstr(new ReceiveJRubyExceptionInstr(exc)); // JRuby implementation exception handling
                geb.addInstr(new ThrowExceptionInstr(exc));
                cfg.addGlobalEnsureBB(geb);
            }
View Full Code Here

Examples of org.jruby.ir.IRScope

        dirtyVars = new HashSet<LocalVariable>(inDirtyVars);
    }

    @Override
    public void applyTransferFunction(Instr i) {
        IRScope scope = problem.getScope();
        boolean scopeBindingHasEscaped = scope.bindingHasEscaped();

        // Process closure accepting instrs specially -- these are the sites of binding stores!
        if (i instanceof ClosureAcceptingInstr) {
            Operand o = ((ClosureAcceptingInstr)i).getClosureArg();
            // At this site, a binding will get allocated if it has not been already!
View Full Code Here

Examples of org.jruby.ir.IRScope

    public String toString() {
        return "";
    }

    public boolean addStores(Map<Operand, Operand> varRenameMap, Set<LocalVariable> excTargetDirtyVars) {
        IRScope scope = problem.getScope();

        boolean addedStores            = false;
        boolean isClosure              = scope instanceof IRClosure;
        boolean scopeBindingHasEscaped = scope.bindingHasEscaped();

        ListIterator<Instr> instrs    = basicBlock.getInstrs().listIterator();

        initSolution();

        // If this is the exit BB, we need a binding store on exit only for vars that are both:
        //
        //   (a) dirty,
        //   (b) live on exit from the closure
        //       condition reqd. because the variable could be dirty but not used outside.
        //         Ex: s=0; a.each { |i| j = i+1; sum += j; }; puts sum
        //       i,j are dirty inside the block, but not used outside

        if (basicBlock.isExitBB()) {
            LiveVariablesProblem lvp = (LiveVariablesProblem)scope.getDataFlowSolution(DataFlowConstants.LVP_NAME);
            java.util.Collection<LocalVariable> liveVars = lvp.getVarsLiveOnScopeExit();
            if (liveVars != null) {
                dirtyVars.retainAll(liveVars); // Intersection with variables live on exit from the scope
            } else {
                dirtyVars.clear();
            }
        }

        while (instrs.hasNext()) {
            Instr i = instrs.next();

            // Process closure accepting instrs specially -- these are the sites of binding stores!
            if (i instanceof ClosureAcceptingInstr) {
                Operand o = ((ClosureAcceptingInstr)i).getClosureArg();
                if (o != null && o instanceof WrappedIRClosure) {
                    IRClosure cl = ((WrappedIRClosure) o).getClosure();

                    // Add before call -- hence instrs.previous & instrs.next
                    instrs.previous();

                    // If the call is a dataflow barrier, we have to spill everything here
                    boolean spillAllVars = scopeBindingHasEscaped;

                    // Unless we have to spill everything, spill only those dirty variables that are:
                    // - used in the closure (FIXME: Strictly only those vars that are live at the call site -- but we dont have this info!)
                    Set<LocalVariable> newDirtyVars = new HashSet<LocalVariable>(dirtyVars);
                    for (LocalVariable v : dirtyVars) {
                        // We have to spill the var that is defined in the closure as well because the load var pass
                        // will attempt to load the var always.  So, if the call doesn't actually call the closure,
                        // we'll be in trouble in that scenario!
                        if (spillAllVars || cl.usesLocalVariable(v) || cl.definesLocalVariable(v)) {
                            addedStores = true;
                            instrs.add(new StoreLocalVarInstr(problem.getLocalVarReplacement(v, varRenameMap), scope, v));
                            newDirtyVars.remove(v);
                        }
                    }
                    dirtyVars = newDirtyVars;
                    instrs.next();
                } else if (scopeBindingHasEscaped) { // Call has no closure && it requires stores
                    // Add before call -- hence instrs.previous & instrs.next
                    instrs.previous();
                    for (LocalVariable v : dirtyVars) {
                        addedStores = true;
                        instrs.add(new StoreLocalVarInstr(problem.getLocalVarReplacement(v, varRenameMap), scope, v));
                    }
                    instrs.next();
                    dirtyVars.clear();
                } else {
                    instrs.previous();

                    // All variables not local to the current scope have to be always spilled because of
                    // multi-threading scenarios where some other scope could load this variable concurrently.
                    //
                    // Allocate a new hash-set and modify it to get around ConcurrentModificationException on dirtyVars
                    Set<LocalVariable> newDirtyVars = new HashSet<LocalVariable>(dirtyVars);
                    for (LocalVariable v : dirtyVars) {
                        // SSS FIXME: I guess we cannot use v.getScopeDepth() > 0 because the variable could be a cloned
                        // instance from a different depth and that could mislead us. See if there is a way to fix this.
                        // If we introduced 'definingScope' in all local variables, we could simply check for scope match
                        // without the instanceof check here.
                        if (   (v instanceof ClosureLocalVariable && ((ClosureLocalVariable)v).definingScope != scope)
                            || (!(v instanceof ClosureLocalVariable) && scope.getScopeType().isClosureType()))
                        {
                            addedStores = true;
                            instrs.add(new StoreLocalVarInstr(problem.getLocalVarReplacement(v, varRenameMap), scope, v));
                            newDirtyVars.remove(v);
                        }
                    }
                    dirtyVars = newDirtyVars;
                    instrs.next();
                }
            } else if ((isClosure && (i instanceof ReturnInstr)) || (i instanceof BreakInstr)) {
                // At closure return and break instructions (both of which are exits from the closure),
                // we need a binding store on exit only for vars that are both:
                //
                //   (a) dirty,
                //   (b) live on exit from the closure
                //       condition reqd. because the variable could be dirty but not used outside.
                //         Ex: s=0; a.each { |i| j = i+1; sum += j; return if j < 5; sum += 1; }; puts sum
                //       i,j are dirty inside the block, but not used outside
                //
                // If this also happens to be exit BB, we would have intersected already earlier -- so no need to do it again!

                if (!basicBlock.isExitBB()) {
                    LiveVariablesProblem lvp = (LiveVariablesProblem)scope.getDataFlowSolution(DataFlowConstants.LVP_NAME);
                    if (lvp == null) {
                        System.out.println("LVP missing for " + scope);
                    }
                    java.util.Collection<LocalVariable> liveVars = lvp.getVarsLiveOnScopeExit();
                    if (liveVars != null) {
View Full Code Here
TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.