Package org.jruby.ir

Examples of org.jruby.ir.IRScope$LocalVariableAllocator


        // Ignore rescue entries -- dirty vars are handled specially for these
        if (!source.isRescueEntry()) inDirtyVars.addAll(n.outDirtyVars);
    }

    public boolean applyTransferFunction() {
        IRScope scope = problem.getScope();
        boolean scopeBindingHasEscaped = scope.bindingHasEscaped();

        // Rescue node, if any
        StoreLocalVarPlacementNode rescueNode = (StoreLocalVarPlacementNode)getNonExitBBExceptionTargetNode();

        Set<LocalVariable> dirtyVars = new HashSet<LocalVariable>(inDirtyVars);
View Full Code Here


        return addedStores;
    }

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

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

        ListIterator<Instr> instrs    = basicBlock.getInstrs().listIterator();
        Set<LocalVariable>  dirtyVars = new HashSet<LocalVariable>(inDirtyVars);

        // Rescue node, if any
        StoreLocalVarPlacementNode rescueNode = (StoreLocalVarPlacementNode)getNonExitBBExceptionTargetNode();

        // 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

        boolean amExitBB = basicBlock == scope.cfg().getExitBB();

        if (amExitBB) {
            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();

            if (i instanceof CallBase) {
                CallBase call = (CallBase) i;
                Operand o = call.getClosureArg(null);
                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 || call.targetRequiresCallersBinding();

                    // 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(getLocalVarReplacement(v, scope, varRenameMap), scope, v));
                            newDirtyVars.remove(v);
                        }
                    }
                    dirtyVars = newDirtyVars;
                    instrs.next();
                } else if (scopeBindingHasEscaped || call.targetRequiresCallersBinding()) { // 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(getLocalVarReplacement(v, scope, 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) {
                        if ((v instanceof ClosureLocalVariable) && ((ClosureLocalVariable)v).definingScope != scope) {
                            addedStores = true;
                            instrs.add(new StoreLocalVarInstr(getLocalVarReplacement(v, scope, 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 (!amExitBB) {
                    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();
View Full Code Here

        LoadLocalVarPlacementNode n = (LoadLocalVarPlacementNode) pred;
        inRequiredLoads.addAll(n.outRequiredLoads);
    }

    public boolean applyTransferFunction() {
        IRScope scope = problem.getScope();
        boolean scopeBindingHasEscaped = scope.bindingHasEscaped();

        Set<LocalVariable>  reqdLoads = new HashSet<LocalVariable>(inRequiredLoads);
        List<Instr>         instrs    = basicBlock.getInstrs();
        ListIterator<Instr> it        = instrs.listIterator(instrs.size());

        while (it.hasPrevious()) {
            Instr i = it.previous();
            // System.out.println("-----\nInstr " + i);
            // System.out.println("Before: " + java.util.Arrays.toString(reqdLoads.toArray()));

            // Right away, clear the variable defined by this instruction -- it doesn't have to be loaded!
            if (i instanceof ResultInstr) reqdLoads.remove(((ResultInstr) i).getResult());

            // Process calls specially -- these are the sites of binding loads!
            if (i instanceof CallBase) {
                CallBase call = (CallBase) i;
                Operand o = call.getClosureArg(null);
                if (o != null && o instanceof WrappedIRClosure) {
                    IRClosure cl = ((WrappedIRClosure) o).getClosure();

                    // Variables defined in the closure do not need to be loaded anymore at
                    // program points before the call, because they will be loaded after the
                    // call completes to fetch the latest value.
                    //
                    // Allocate a new hash-set and modify it to get around ConcurrentModificationException on reqdLoads
                    Set<LocalVariable> newReqdLoads = new HashSet<LocalVariable>(reqdLoads);
                    for (LocalVariable v: reqdLoads) {
                        if (cl.definesLocalVariable(v)) newReqdLoads.remove(v);
                    }
                    reqdLoads = newReqdLoads;
                }

                // In this case, we are going to blindly load everything -- so, at the call site, pending loads dont carry over!
                if (scopeBindingHasEscaped || call.targetRequiresCallersBinding()) {
                    reqdLoads.clear();
                } else {
                    // All variables not defined in the current scope have to be always loaded
                    // because of multi-threading scenarios where some other scope
                    // could update this variable concurrently.
                    //
                    // Allocate a new hash-set and modify it to get around ConcurrentModificationException on reqdLoads
                    Set<LocalVariable> newReqdLoads = new HashSet<LocalVariable>(reqdLoads);
                    for (LocalVariable v: reqdLoads) {
                        if (!scope.definesLocalVariable(v)) newReqdLoads.remove(v);
                    }
                    reqdLoads = newReqdLoads;
                }
            } else if (scopeBindingHasEscaped && (i.getOperation() == Operation.PUT_GLOBAL_VAR)) {
                // global-var tracing can execute closures set up in previous trace-var calls
View Full Code Here

    }

    public void addLoads(Map<Operand, Operand> varRenameMap) {
        LoadLocalVarPlacementProblem blp = (LoadLocalVarPlacementProblem) problem;

        IRScope scope                  = blp.getScope();
        boolean isEvalScript           = scope instanceof IREvalScript;
        boolean scopeBindingHasEscaped = scope.bindingHasEscaped();

        List<Instr>         instrs    = basicBlock.getInstrs();
        ListIterator<Instr> it        = instrs.listIterator(instrs.size());
        Set<LocalVariable>  reqdLoads = new HashSet<LocalVariable>(inRequiredLoads);

        while (it.hasPrevious()) {
            Instr i = it.previous();

            // Right away, clear the variable defined by this instruction -- it doesn't have to be loaded!
            if (i instanceof ResultInstr) reqdLoads.remove(((ResultInstr) i).getResult());

            if (i instanceof CallBase) {
                CallBase call = (CallBase) i;
                Operand o = call.getClosureArg(null);
                if (o != null && o instanceof WrappedIRClosure) {
                    IRClosure cl = ((WrappedIRClosure) o).getClosure();

                    // Only those variables that are defined in the closure, and are in the required loads set
                    // will need to be loaded from the binding after the call!  Rest can wait ..
                    //
                    // Allocate a new hash-set and modify it to get around ConcurrentModificationException on reqdLoads
                    Set<LocalVariable> newReqdLoads = new HashSet<LocalVariable>(reqdLoads);
                    it.next();
                    for (LocalVariable v : reqdLoads) {
                        if (cl.definesLocalVariable(v)) {
                            it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
                            it.previous();
                            newReqdLoads.remove(v);
                        }
                    }
                    it.previous();
                    reqdLoads = newReqdLoads;
                }

                // In this case, we are going to blindly load everything
                if (scopeBindingHasEscaped || call.targetRequiresCallersBinding()) {
                    it.next();
                    for (LocalVariable v: reqdLoads) {
                        it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
                        it.previous();
                    }
                    it.previous();
                    reqdLoads.clear();
                } else {
                    // All variables not defined in the current scope have to be always loaded
                    // because of multi-threading scenarios where some other scope
                    // could update this variable concurrently.
                    //
                    // Allocate a new hash-set and modify it to get around ConcurrentModificationException on reqdLoads
                    Set<LocalVariable> newReqdLoads = new HashSet<LocalVariable>(reqdLoads);
                    it.next();
                    for (LocalVariable v: reqdLoads) {
                        if (!scope.definesLocalVariable(v)) {
                            it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
                            it.previous();
                            newReqdLoads.remove(v);
                        }
                    }
                    it.previous();
                    reqdLoads = newReqdLoads;
                }
            } else if (scopeBindingHasEscaped && (i.getOperation() == Operation.PUT_GLOBAL_VAR)) {
                // global-var tracing can execute closures set up in previous trace-var calls
                // in which case we would have the 'scopeBindingHasEscaped' flag set to true
                it.next();
                for (LocalVariable v : reqdLoads) {
                    it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
                    it.previous();
                }
                it.previous();
                reqdLoads.clear();
            }

            if (i.getOperation() == Operation.BINDING_STORE) {
                LocalVariable lv = ((StoreLocalVarInstr)i).getLocalVar();
                if (!lv.isSelf()) {
                    reqdLoads.add(lv);
                    // SSS FIXME: Why is this reqd again?  Document with example
                    // Make sure there is a replacement var for all local vars
                    getLocalVarReplacement(lv, scope, varRenameMap);
                }
            } else {
                // The variables used as arguments will need to be loaded
                // %self is local to every scope and never crosses scope boundaries and need not be spilled/refilled
                for (Variable v : i.getUsedVariables()) {
                    if (!(v instanceof LocalVariable)) continue;

                    LocalVariable lv = (LocalVariable)v;
                    if (!lv.isSelf()) {
                        reqdLoads.add(lv);
                        // SSS FIXME: Why is this reqd again?  Document with example
                        // Make sure there is a replacement var for all local vars
                        getLocalVarReplacement(lv, scope, varRenameMap);
                    }
                }
            }
        }

        // Add loads on entry of a rescue block.
        if (basicBlock.isRescueEntry()) {
            for (LocalVariable v : reqdLoads) {
                it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
            }
        }

        // Load first use of variables in closures
        if ((scope instanceof IRClosure) && (basicBlock == problem.getScope().cfg().getEntryBB())) {
            // System.out.println("\n[In Entry BB] For CFG " + problem.getScope().cfg() + ":");
            // System.out.println("\t--> Reqd loads   : " + java.util.Arrays.toString(reqdLoads.toArray()));
            for (LocalVariable v : reqdLoads) {
                if (scope.usesLocalVariable(v) || scope.definesLocalVariable(v)) {
                    if (isEvalScript || !(v instanceof ClosureLocalVariable) || (scope != ((ClosureLocalVariable)v).definingScope)) {
                        it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
                    }
                }
            }
View Full Code Here

        dfVarMap.put(v, dfv);
        varDfVarMap.put(dfv.id, v);
        if ((v instanceof LocalVariable) && !((LocalVariable) v).isSelf()) {
            //System.out.println("Adding df var for " + v + ":" + dfv.id);
            int n = ((LocalVariable)v).getScopeDepth();
            IRScope s = getScope();
            while ((s != null) && (n >= 0)) {
                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();
                n--;
            }
            localVars.add((LocalVariable) v);
        }
    }
View Full Code Here

        boolean mightRequireGlobalEnsureBlock = false;

        Set<LocalVariable> dirtyVars = null;

        CFG     cfg      = getScope().cfg();
        IRScope cfgScope = cfg.getScope();

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

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

        // Add local-var stores
        for (FlowGraphNode n : flowGraphNodes) {
            StoreLocalVarPlacementNode bspn = (StoreLocalVarPlacementNode) n;
            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
        BasicBlock geb = null;
        if ((mightRequireGlobalEnsureBlock == true) && !dirtyVars.isEmpty()) {
            Variable exc = cfgScope.getNewTemporaryVariable();
            geb = new BasicBlock(cfg, new Label("_GLOBAL_ENSURE_BLOCK"));
            geb.addInstr(new ReceiveExceptionInstr(exc, false)); // No need to check type since it is not used before rethrowing
            for (LocalVariable v : dirtyVars) {
                Operand value = varRenameMap.get(v);
                if (value == null) {
                    value = cfgScope.getNewTemporaryVariable("%t_" + v.getName());
                    varRenameMap.put(v, value);
                }
                geb.addInstr(new StoreLocalVarInstr(value, (IRClosure) cfgScope, v));
            }
            geb.addInstr(new ThrowExceptionInstr(exc));
View Full Code Here

        // Gulp!
        this.instrs.addAll(foodBB.instrs);
    }

    public BasicBlock cloneForInlinedMethod(InlinerInfo ii) {
        IRScope hostScope = ii.getInlineHostScope();
        BasicBlock clonedBB = ii.getOrCreateRenamedBB(this);
        for (Instr i: getInstrs()) {
            Instr clonedInstr = i.cloneForInlinedScope(ii);
            if (clonedInstr != null) {
                clonedBB.addInstr(clonedInstr);
                if (clonedInstr instanceof YieldInstr) ii.recordYieldSite(clonedBB, (YieldInstr)clonedInstr);
                if (clonedInstr instanceof CallBase) {
                    CallBase call = (CallBase)clonedInstr;
                    Operand block = call.getClosureArg(null);
                    if (block instanceof WrappedIRClosure) hostScope.addClosure(((WrappedIRClosure)block).getClosure());
                }
            }
        }

        return clonedBB;
View Full Code Here

        return clonedBB;
    }

    public BasicBlock cloneForInlinedClosure(InlinerInfo ii) {
        // Update cfg for this bb
        IRScope hostScope = ii.getInlineHostScope();
        BasicBlock clonedBB = ii.getOrCreateRenamedBB(this);

        // Process instructions
        for (Instr i: getInstrs()) {
            Instr clonedInstr = i.cloneForInlinedClosure(ii);
            if (clonedInstr != null) {
                clonedBB.addInstr(clonedInstr);
                if (clonedInstr instanceof CallBase) {
                    CallBase call = (CallBase)clonedInstr;
                    Operand block = call.getClosureArg(null);
                    if (block instanceof WrappedIRClosure) hostScope.addClosure(((WrappedIRClosure)block).getClosure());
                }
            }
        }

        return clonedBB;
View Full Code Here

    public Object interpret(ThreadContext context, DynamicScope currDynScope, IRubyObject self, Object[] temp, Block aBlock) {
        DynamicScope argsDynScope = currDynScope;

        // Find args that need to be passed into super
        while (!argsDynScope.getStaticScope().isArgumentScope()) argsDynScope = argsDynScope.getNextCapturedScope();
        IRScope argsIRScope = ((IRStaticScope)argsDynScope.getStaticScope()).getIRScope();
        Operand[] superArgs = (argsIRScope instanceof IRMethod) ? ((IRMethod)argsIRScope).getCallArgs() : ((IRClosure)argsIRScope).getBlockArgs();

        // Prepare args -- but look up in 'argsDynScope', not 'currDynScope'
        IRubyObject[] args = prepareArguments(context, self, superArgs, argsDynScope, temp);
View Full Code Here

/* ---------- Protected / package fields, methods --------- */
    void markDeadInstructions() {
        // System.out.println("-- Identifying dead instructions for " + basicBlock.getID() + " -- ");
        LiveVariablesProblem lvp = (LiveVariablesProblem) problem;
        IRScope scope = lvp.getScope();
        boolean scopeBindingHasEscaped = scope.bindingHasEscaped();

        if (in == null) {
           // 'in' cannot be null for reachable bbs
           // This bb is unreachable! (or we have a mighty bug!)
           // Mark everything dead in here!
View Full Code Here

TOP

Related Classes of org.jruby.ir.IRScope$LocalVariableAllocator

Copyright © 2018 www.massapicom. 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.