001: /***
002: * StackModel.java
003: *
004: * Description: Model Flash engine stack for peep-hole optimizer
005: */package org.openlaszlo.sc;
006:
007: import java.io.*;
008: import java.util.*;
009: import org.openlaszlo.sc.Instructions.*;
010:
011: /***
012: * StackModel models the stack in the peephole block. It obeys
013: * List operations and is manipulated as a List by all
014: * instructions other than PUSH. PUSH uses a special entry to annotate
015: * the data it pushes with the push responsible for the data. This
016: * annotation is used by the push merging logic. Any modification of
017: * the data in the model by a normal instruction will clear the
018: * associated push annotation
019: */
020: public class StackModel extends ArrayList {
021: // Why protected is stupid!
022: private static class RemovableArrayList extends ArrayList {
023: public RemovableArrayList(Collection c) {
024: super (c);
025: }
026:
027: public void removeRange(int fromIndex, int toIndex) {
028: super .removeRange(fromIndex, toIndex);
029: }
030: }
031:
032: RemovableArrayList pushes;
033:
034: public StackModel(Collection c) {
035: // model of stack for computing arity of vararg instr's
036: super (c);
037: // push instruction that created corresponding data
038: // Note that a push is not cleared until the stack is
039: // popped below it
040: this .pushes = new RemovableArrayList(Collections.nCopies(c
041: .size() + 1, null));
042: }
043:
044: public StackModel() {
045: this (Collections.EMPTY_LIST);
046: }
047:
048: public void add(int index, Object value) {
049: if (index < 0)
050: index += this .size();
051: // don't clobber the push at i, to permit the prepend
052: // optimization
053: this .pushes.add(index + 1, null);
054: super .add(index, value);
055: }
056:
057: public boolean add(Object value) {
058: this .add(this .size(), value);
059: return true;
060: }
061:
062: public boolean addAll(int index, Collection c) {
063: if (index < 0)
064: index += this .size();
065: // don't clobber the push at i, to permit the prepend
066: // optimization
067: int l = c.size();
068: // Interior add should not clobber successor
069: if (index != this .size())
070: l -= 1;
071: this .pushes.addAll(index + 1, Collections.nCopies(l, null));
072: return super .addAll(index, c);
073: }
074:
075: public boolean addAll(Collection c) {
076: return this .addAll(this .size(), c);
077: }
078:
079: public void clear() {
080: this .pushes.clear();
081: super .clear();
082: }
083:
084: public Object clone() {
085: return new StackModel(this );
086: }
087:
088: // contains just works
089:
090: public void ensureCapacity(int minCapacity) {
091: super .ensureCapacity(minCapacity);
092: this .pushes.ensureCapacity(minCapacity + 1);
093: }
094:
095: public Object get(int index) {
096: if (index < 0)
097: index += this .size();
098: return super .get(index);
099: }
100:
101: // indexOf just works
102:
103: // isEmpty just works
104:
105: // lastIndexOf just works
106:
107: public Object remove(int index) {
108: if (index < 0)
109: index += this .size();
110: // don't clobber the push at i, to permit the prepend
111: // optimization
112: this .pushes.remove(index + 1);
113: return super .remove(index);
114: }
115:
116: protected void removeRange(int fromIndex, int toIndex) {
117: int l = this .size();
118: if (fromIndex < 0)
119: fromIndex += l;
120: if (fromIndex > l)
121: fromIndex = l;
122: if (toIndex < 0)
123: toIndex += l;
124: if (toIndex > l)
125: toIndex = l;
126: // don't clobber the push at i, to permit the prepend
127: // optimization
128: this .pushes.removeRange(fromIndex + 1, toIndex + 1);
129: super .removeRange(fromIndex, toIndex);
130: }
131:
132: public Object set(int index, Object value) {
133: if (index < 0)
134: index += this .size();
135: // don't clobber the push at i, to permit the prepend
136: // optimization
137: this .pushes.set(index + 1, null);
138: return super .set(index, value);
139: }
140:
141: // toArray just works
142:
143: public void trimToSize() {
144: this .pushes.trimToSize();
145: super .trimToSize();
146: }
147:
148: public void notePush(PUSHInstruction instr, List data) {
149: // System.out.println("notePush: " + instr + " || " + data);
150: // Replace the last instruction noted with this instruction
151: this .pushes.removeRange(this .size(), this .pushes.size());
152: this .pushes.addAll(this .size(), Collections.nCopies(
153: data.size() + 1, instr));
154: super .addAll(data);
155: }
156:
157: public PUSHInstruction lastPush() {
158: if (this .pushes.size() > this .size()) {
159: return (PUSHInstruction) (this .pushes.get(this .size()));
160: } else {
161: return null;
162: }
163: }
164:
165: // How many arguments from this instruction are still on the stack.
166: // (instr must be the last instruction)
167: public int pushDepth(PUSHInstruction instr) {
168: // --- slow for deep models
169: // return this.size() - this.pushes.indexOf(instr);
170: int l = this .size();
171: List p = this .pushes;
172: // search from top of stack down
173: for (int i = l - 1; i >= 0; i--) {
174: if (p.get(i) != instr) {
175: return l - (i + 1);
176: }
177: }
178: return l;
179: }
180:
181: public String toString() {
182: StringBuffer b = new StringBuffer();
183: int i = -1;
184: for (ListIterator li = super .listIterator(); li.hasNext();) {
185: i = li.nextIndex();
186: Object v = li.next();
187: b.append(v != null ? v.toString() : "None");
188: b.append("(");
189: Object p = this .pushes.get(i);
190: b.append(p != null ? "" + this .pushes.indexOf(p) : "None");
191: b.append(")");
192: if (li.hasNext())
193: b.append(", ");
194: }
195: for (i++; i < this .pushes.size(); i++) {
196: if (i > 0)
197: b.append(", ");
198: b.append("None (");
199: Object p = this .pushes.get(i);
200: b.append(p != null ? "" + this .pushes.indexOf(p) : "None");
201: b.append(")");
202: }
203: return b.toString();
204: }
205: }
|