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 */
021package org.biojava.utils.bytecode;
022
023import 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
032public 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}