001    /*
002     *                    BioJava development code
003     *
004     * This code may be freely distributed and modified under the
005     * terms of the GNU Lesser General Public Licence.  This should
006     * be distributed with the code.  If you do not have a copy,
007     * see:
008     *
009     *      http://www.gnu.org/copyleft/lesser.html
010     *
011     * Copyright for this code is held jointly by the individual
012     * authors.  These should be listed in @author doc comments.
013     *
014     * For more information on the BioJava project and its aims,
015     * or to join the biojava-l mailing list, visit the home page
016     * at:
017     *
018     *      http://www.biojava.org/
019     *
020     */
021    package org.biojava.utils.bytecode;
022    
023    import java.util.*;
024    
025    /**
026     * A list of Instructions and/or other CodeGenerator objects.
027     *
028     * @author Thomas Down
029     * @author Matthew Pocock
030     */
031    
032    public class InstructionVector implements CodeGenerator {
033      private final List instructions;
034      private final Label startLabel;
035      private final Label endLabel;
036      
037      private StatsCache statsCache; // gets set to null on edits
038      
039      {
040        instructions = new ArrayList();
041        startLabel = new Label();
042        endLabel = new Label();
043        statsCache = null;
044      }
045      
046      public void add(CodeGenerator g) {
047        statsCache = null;
048        instructions.add(g);
049      }
050      
051      public int size() {
052        return instructions.size();
053      }
054      
055      public void add(int pos, CodeGenerator g) {
056        statsCache = null;
057        instructions.add(pos, g);
058      }
059      
060      public void remove(int pos) {
061        statsCache = null;
062        instructions.remove(pos);
063      }
064      
065      public CodeGenerator generatorAt(int pos) {
066        return (CodeGenerator) instructions.get(pos);
067      }
068      
069      public Label getStartLabel() {
070        return startLabel;
071      }
072      
073      public Label getEndLabel() {
074        return endLabel;
075      }
076      
077      public void writeCode(CodeContext ctx) throws CodeException {
078        CodeContext subctx = ctx.subContext();
079        subctx.open();
080        subctx.markLabel(startLabel);
081        for (Iterator i = instructions.iterator(); i.hasNext(); ) {
082          CodeGenerator cg = (CodeGenerator) i.next();
083          cg.writeCode(subctx);
084        }
085        subctx.markLabel(endLabel);
086        subctx.close(); // Wrap up the subcontt
087      }
088      
089      public int stackDepth() {
090        StatsCache statsCache = getStatsCache();
091        
092        return statsCache.depth;
093      }
094      
095      public int stackDelta() {
096        StatsCache statsCache = getStatsCache();
097        
098        return statsCache.delta;
099      }
100      
101      private StatsCache getStatsCache() {
102        if(statsCache == null) {
103          int depth = 0;
104          int delta = 0;
105          
106          for(Iterator i = instructions.iterator(); i.hasNext(); ) {
107            CodeGenerator cg = (CodeGenerator) i.next();
108            int dp = cg.stackDepth();
109            int dl = cg.stackDelta();
110            
111            dp += delta;
112            delta += dl;
113    
114            depth = Math.max(depth, dp);
115          }
116          
117          statsCache = new StatsCache(depth, delta);
118        }
119        
120        return statsCache;
121      }
122      
123      private static class StatsCache {
124        public final int depth;
125        public final int delta;
126        
127        public StatsCache(int depth, int delta) {
128          this.depth = depth;
129          this.delta = delta;
130        }
131      }
132    }