compilestack.java

来自「Groovy动态语言 运行在JVM中的动态语言 可以方便的处理业务逻辑变化大的业」· Java 代码 · 共 653 行 · 第 1/2 页

JAVA
653
字号
        scope = null;
        mv=null;
        resetVariableIndex(false);
        superBlockNamedLabels.clear();
        currentBlockNamedLabels.clear();
        namedLoopBreakLabel.clear();
        namedLoopContinueLabel.clear();
        continueLabel=null;
        breakLabel=null;
        helper = null;
        thisStartLabel=null;
        thisEndLabel=null;
    }
    
    /**
     * initializes this class for a MethodNode. This method will
     * automatically define varibales for the method parameters
     * and will create references if needed. the created variables
     * can be get by getVariable
     * 
     */
    protected void init(VariableScope el, Parameter[] parameters, MethodVisitor mv, ClassNode cn) {
        if (!clear) throw new GroovyBugError("CompileStack#init called without calling clear before");
        clear=false;
        pushVariableScope(el);
        this.mv = mv;
        this.helper = new BytecodeHelper(mv);
        defineMethodVariables(parameters,el.isInStaticContext());
        this.className = BytecodeHelper.getTypeDescription(cn);
        currentClassIndex = -1; currentMetaClassIndex = -1;
    }

    /**
     * Causes the statestack to add an element and sets
     * the given scope as new current variable scope. Creates 
     * a element for the state stack so pop has to be called later
     */
    protected void pushVariableScope(VariableScope el) {
        pushState();
        scope = el;
        superBlockNamedLabels = new HashMap(superBlockNamedLabels);
        superBlockNamedLabels.putAll(currentBlockNamedLabels);
        currentBlockNamedLabels = new HashMap();
    }
    
    /**
     * Should be called when decending into a loop that defines
     * also a scope. Calls pushVariableScope and prepares labels 
     * for a loop structure. Creates a element for the state stack
     * so pop has to be called later 
     */
    protected void pushLoop(VariableScope el, String labelName) {
        pushVariableScope(el);
        initLoopLabels(labelName);
    }

    private void initLoopLabels(String labelName) {
        continueLabel = new Label();
        breakLabel = new Label();
        if (labelName!=null) {
        	namedLoopBreakLabel.put(labelName,breakLabel);
        	namedLoopContinueLabel.put(labelName,continueLabel);
        }
    }
    
    /**
     * Should be called when decending into a loop that does 
     * not define a scope. Creates a element for the state stack
     * so pop has to be called later
     */
    protected void pushLoop(String labelName) {
        pushState();
        initLoopLabels(labelName);
    }
    
    /**
     * Used for <code>break foo</code> inside a loop to end the
     * execution of the marked loop. This method will return the
     * break label of the loop if there is one found for the name.
     * If not, the current break label is returned.
     */
    protected Label getNamedBreakLabel(String name) {
    	Label label = getBreakLabel();
    	Label endLabel = null;
        if (name!=null) endLabel = (Label) namedLoopBreakLabel.get(name);
    	if (endLabel!=null) label = endLabel;
        return label;
    }
    
    /**
     * Used for <code>continue foo</code> inside a loop to continue
     * the execution of the marked loop. This method will return 
     * the break label of the loop if there is one found for the 
     * name. If not, getLabel is used.
     */
    protected Label getNamedContinueLabel(String name) {
    	Label label = getLabel(name);
    	Label endLabel = null;
        if (name!=null) endLabel = (Label) namedLoopContinueLabel.get(name);
    	if (endLabel!=null) label = endLabel;
        return label;
    }    
    
    /**
     * Creates a new break label and a element for the state stack
     * so pop has to be called later
     */
    protected Label pushSwitch(){
        pushState();
        breakLabel = new Label();
        return breakLabel;
    }
    
    /**
     * because a boolean Expression may not be evaluated completly
     * it is important to keep the registers clean
     */
    protected void pushBooleanExpression(){
        pushState();
    }
    
    private Variable defineVar(String name, ClassNode type, boolean methodParameterUsedInClosure) {
        makeNextVariableID(type);
        int index = currentVariableIndex;
        if (methodParameterUsedInClosure) {
            index = localVariableOffset++;
        }
        Variable answer = new Variable(index, type, name);
        usedVariables.add(answer);
        answer.setHolder(methodParameterUsedInClosure);
        return answer;
    }
    
    private void makeLocalVariablesOffset(Parameter[] paras,boolean isInStaticContext) {
        resetVariableIndex(isInStaticContext);
        
        for (int i = 0; i < paras.length; i++) {
            makeNextVariableID(paras[i].getType());
        }
        localVariableOffset = nextVariableIndex;
        
        resetVariableIndex(isInStaticContext);
    }
    
    private void defineMethodVariables(Parameter[] paras,boolean isInStaticContext) {
        Label startLabel  = new Label();
        thisStartLabel = startLabel;
        mv.visitLabel(startLabel);
        
        makeLocalVariablesOffset(paras,isInStaticContext);      
        
        boolean hasHolder = false;
        for (int i = 0; i < paras.length; i++) {
            String name = paras[i].getName();
            Variable answer;
            if (paras[i].isClosureSharedVariable()) {
                answer = defineVar(name, ClassHelper.getWrapper(paras[i].getType()), true);
                ClassNode type = paras[i].getType();
                helper.load(type,currentVariableIndex);
                helper.box(type);
                createReference(answer);
                hasHolder = true;
            } else {
                answer = defineVar(name,paras[i].getType(),false);
            }
            answer.setStartLabel(startLabel);
            stackVariables.put(name, answer);
        }
        
        if (hasHolder) {
            nextVariableIndex = localVariableOffset;
        }
    }

    private void createReference(Variable reference) {
        mv.visitTypeInsn(NEW, "groovy/lang/Reference");
        mv.visitInsn(DUP_X1);
        mv.visitInsn(SWAP);
        mv.visitMethodInsn(INVOKESPECIAL, "groovy/lang/Reference", "<init>", "(Ljava/lang/Object;)V");
        mv.visitVarInsn(ASTORE, reference.getIndex());
    }
    
    /**
     * Defines a new Variable using an AST variable.
     * @param initFromStack if true the last element of the 
     *                      stack will be used to initilize
     *                      the new variable. If false null
     *                      will be used.
     */
    public Variable defineVariable(org.codehaus.groovy.ast.Variable v, boolean initFromStack) {
        String name = v.getName();
        Variable answer = defineVar(name,v.getType(),false);
        if (v.isClosureSharedVariable()) answer.setHolder(true);
        stackVariables.put(name, answer);
        
        Label startLabel  = new Label();
        answer.setStartLabel(startLabel);
        if (answer.isHolder())  {
            if (!initFromStack) mv.visitInsn(ACONST_NULL);
            createReference(answer);
        } else {
            if (!initFromStack) mv.visitInsn(ACONST_NULL);
            mv.visitVarInsn(ASTORE, currentVariableIndex);            
        } 
        mv.visitLabel(startLabel);
        return answer;
    }

    /**
     * Returns true if a varibale is already defined
     */
    public boolean containsVariable(String name) {
        return stackVariables.containsKey(name);
    }
    
    /**
     * Calculates the index of the next free register stores ir
     * and sets the current variable index to the old value
     */
    private void makeNextVariableID(ClassNode type) {
        currentVariableIndex = nextVariableIndex;
        if (type==ClassHelper.long_TYPE || type==ClassHelper.double_TYPE) {
            nextVariableIndex++;
        }
        nextVariableIndex++;
    }
    
    /**
     * Returns the label for the given name 
     */
    public Label getLabel(String name) {
        if (name==null) return null;
        Label l = (Label) superBlockNamedLabels.get(name);
        if (l==null) l = createLocalLabel(name);
        return l;
    }
    
    /**
     * creates a new named label
     */
    public Label createLocalLabel(String name) {
        Label l = (Label) currentBlockNamedLabels.get(name);
        if (l==null) {
            l = new Label();
            currentBlockNamedLabels.put(name,l);
        }
        return l;
    }
    
    public int getCurrentClassIndex(){
        return currentClassIndex;
    }
    
    public void setCurrentClassIndex(int index){
        currentClassIndex=index;
    }
    
    public int getCurrentMetaClassIndex(){
        return currentMetaClassIndex;
    }
    
    public void setCurrentMetaClassIndex(int index){
        currentMetaClassIndex=index;
    }

    public void applyFinallyBlocks(Label label, boolean isBreakLabel) {
        // first find the state defining the label. That is the state
        // directly after the state not knowing this label. If no state
        // in the list knows that label, then the defining state is the
        // current state.
        StateStackElement result = null;
        for (ListIterator iter = stateStack.listIterator(stateStack.size()); iter.hasPrevious();) {
            StateStackElement element = (StateStackElement) iter.previous();
            if (!element._currentBlockNamedLabels.values().contains(label)) {
                if (isBreakLabel && element._breakLabel != label) {
                    result = element;
                    break;
                }
                if (!isBreakLabel && element._continueLabel != label) {
                    result = element;
                    break;
                }
            }
        }
        
        List blocksToRemove;
        if (result==null) {
            // all Blocks do know the label, so use all finally blocks
            blocksToRemove = Collections.EMPTY_LIST;
        } else {
            blocksToRemove = result._finallyBlocks;
        }
        
        ArrayList blocks = new ArrayList(finallyBlocks);
        blocks.removeAll(blocksToRemove);
        applyFinallyBlocks(blocks);
    }

    private void applyFinallyBlocks(List blocks) {
        for (Iterator iter = blocks.iterator(); iter.hasNext();) {
            Runnable block = (Runnable) iter.next();
            if (visitedBlocks.contains(block)) continue;
            visitedBlocks.add(block);
            block.run();
        }     
    }
    
    public void applyFinallyBlocks() {
        applyFinallyBlocks(finallyBlocks); 
    }

    public boolean hasFinallyBlocks() {
        return !finallyBlocks.isEmpty();
    }

    public void pushFinallyBlock(Runnable block) {
        finallyBlocks.addFirst(block);
        pushState();
    }

    public void popFinallyBlock() {
        popState();
        finallyBlocks.removeFirst();
    }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?