001    package AST;
002    
003    import java.util.HashSet;
004    import java.io.File;
005    import java.util.*;
006    import beaver.*;
007    import java.util.ArrayList;
008    import java.util.zip.*;
009    import java.io.*;
010    import java.io.FileNotFoundException;
011    import java.util.Collection;
012    /**
013      * @ast class
014     * 
015     */
016    public class CodeGeneration extends java.lang.Object {
017    
018        private ByteArray bytes = new ByteArray();
019    
020    
021        private ConstantPool constantPool;
022    
023    
024    
025        public void clearCodeGeneration() {
026          bytes = null;
027          constantPool = null;
028          variableScopeLabelAddress = null;
029          variableScopeLabelUses = null;
030          localVariableTable = null;
031          lineNumberTable = null;
032          exceptions = null;
033          address = null;
034          uses = null;
035        }
036    
037    
038        
039        private boolean wideGoto = false;
040    
041    
042    
043        private boolean numberFormatError = false;
044    
045    
046        public boolean numberFormatError() { return numberFormatError; }
047    
048    
049    
050        public CodeGeneration(ConstantPool constantPool) {
051          this.constantPool = constantPool;
052        }
053    
054    
055    
056        public CodeGeneration(ConstantPool constantPool, boolean wideGoto) {
057          this.constantPool = constantPool;
058          this.wideGoto = wideGoto;
059        }
060    
061    
062    
063        public ConstantPool constantPool() {
064          return constantPool;
065        }
066    
067    
068        
069        private int variableScopeLabel = 1;
070    
071    
072        public int variableScopeLabel() {
073          return variableScopeLabel++;
074        }
075    
076    
077        public void addVariableScopeLabel(int label) {
078          Integer label_object = new Integer(label);
079          variableScopeLabelAddress.put(label_object, new Integer(pos()));
080          // Update all reference to this label
081          if(variableScopeLabelUses.containsKey(label_object)) {
082            ArrayList array = (ArrayList)variableScopeLabelUses.get(label_object);
083            for(Iterator iter = array.iterator(); iter.hasNext(); ) {
084              LocalVariableEntry e = (LocalVariableEntry)iter.next();
085              e.length = pos() - e.start_pc;
086            }
087          }
088        }
089    
090     
091        private HashMap variableScopeLabelAddress = new HashMap();
092    
093    
094        private HashMap variableScopeLabelUses = new HashMap();
095    
096    
097    
098        class LocalVariableEntry {
099          int start_pc;
100          int length;
101          int name_index;
102          int descriptor_index;
103          int index;
104        }
105    
106    
107        public Collection localVariableTable = new ArrayList();
108    
109    
110        public void addLocalVariableEntryAtCurrentPC(String name, String typeDescriptor, int localNum, int variableScopeEndLabel) {
111          LocalVariableEntry e = new LocalVariableEntry();
112          e.start_pc = pos();
113          e.length = 0;
114          e.name_index = constantPool().addUtf8(name);
115          e.descriptor_index = constantPool().addUtf8(typeDescriptor);
116          e.index = localNum;
117          localVariableTable.add(e);
118          Integer label_object = new Integer(variableScopeEndLabel);
119          if(!variableScopeLabelUses.containsKey(label_object))
120            variableScopeLabelUses.put(label_object, new ArrayList());
121          Collection c = (Collection)variableScopeLabelUses.get(label_object);
122          c.add(e);
123        }
124    
125    
126    
127        // at each variable declaration and parameter declaration
128        // inh int VariableDeclaration.variableScopeEndLabel(CodeGeneration gen); 
129        // addLocalVariableEntryAtCurrentPC(this, variableScopeEndLabel());
130        // syn lazy int Block.variableScopeEndLabel(CodeGeneration gen) = gen.variableScopeLabel();
131        //  Block.createBCode() { ... gen.addLabel(variableScopeLabel());
132        
133        class LineNumberEntry {
134          int start_pc;
135          int line_number;
136        }
137    
138    
139        public Collection lineNumberTable = new ArrayList();
140    
141    
142        public void addLineNumberEntryAtCurrentPC(ASTNode node) {
143          LineNumberEntry e = new LineNumberEntry();
144          e.start_pc = pos();
145          e.line_number = node.sourceLineNumber();
146          if(e.line_number != -1 && e.line_number != 65535)
147            lineNumberTable.add(e);
148        }
149    
150    
151        
152        public Collection exceptions = new ArrayList();
153    
154    
155        public void addException(int start_pc, int end_pc, int handler_pc, int catch_type) {
156          ExceptionEntry e = new ExceptionEntry();
157          e.start_pc = start_pc;
158          e.end_pc = end_pc;
159          e.handler_pc = handler_pc;
160          e.catch_type = catch_type;
161          if(e.start_pc != e.end_pc)
162            exceptions.add(e);
163        }
164    
165    
166        class ExceptionEntry {
167          int start_pc;
168          int end_pc;
169          int handler_pc;
170          int catch_type;
171        }
172    
173    
174        public void createExceptionTable(TryStmt tryStmt) {  
175          for(int i = 0; i < tryStmt.getNumCatchClause(); i++) {
176            tryStmt.getCatchClause(i).exceptionTableEntries(this, tryStmt);
177          }
178          if(tryStmt.hasFinally()) {
179            addException(
180                addressOf(tryStmt.label_begin()),
181                addressOf(tryStmt.label_finally()),
182                addressOf(tryStmt.label_exception_handler()),
183                0
184                );
185          }
186        }
187    
188    
189        public void createExceptionTable(SynchronizedStmt stmt) {  
190          addException(
191              addressOf(stmt.label_begin()),
192              addressOf(stmt.label_finally()),
193              addressOf(stmt.label_exception_handler()),
194              0
195              );
196        }
197    
198    
199    
200        public int maxLocals() {
201          return maxLocals+1;
202        }
203    
204    
205        int maxLocals = 0;
206    
207    
208    
209        /*
210        public int label() {
211          return labelCounter++;
212        }
213        private static int labelCounter = 1;
214        */
215        private HashMap address = new HashMap();
216    
217    
218        private HashMap uses = new HashMap();
219    
220    
221        public void addLabel(int label) {
222          Integer label_object = new Integer(label);
223          /*
224          if(pos() - 3 == bytes.lastGotoPos() && bytes.get(pos() - 3) == Bytecode.GOTO) {
225            if(uses.containsKey(label_object)) {
226              ArrayList array = (ArrayList)uses.get(label_object);
227              for(int i = 0; i < array.size(); i++) {
228                int p = ((Integer)array.get(i)).intValue();
229                if(pos() - 3 == p) {
230                  //System.out.println("Found direct branch");
231                  array.remove(i);
232                  i--;
233                }
234              }
235              bytes.setPos(pos() - 3);
236            }
237          }
238          */
239          address.put(label_object, new Integer(pos()));
240          // Update all reference to this label
241          if(uses.containsKey(label_object)) {
242            ArrayList array = (ArrayList)uses.get(label_object);
243            for(int i = 0; i < array.size(); i++) {
244              int p = ((Integer)array.get(i)).intValue();
245              if(bytes.get(p) == Bytecode.GOTO_W)
246                setAddress32(p + 1, pos() - p);
247              else
248                setAddress(p + 1, pos() -  p);
249            }
250          }
251        }
252    
253     
254        public int addressOf(int label) {
255          Integer label_object = new Integer(label);
256          if(!address.containsKey(label_object))
257            throw new Error("Can not compute address of unplaced label");
258          return ((Integer)address.get(label_object)).intValue();
259        }
260    
261    
262        private int jump(int label) {
263          Integer label_object = new Integer(label);
264          if(!uses.containsKey(label_object))
265            uses.put(label_object, new ArrayList());
266          ArrayList a = (ArrayList)uses.get(label_object);
267          a.add(new Integer(pos())); // position of the 16-bits reference
268          Integer val = (Integer)address.get(label_object);
269          if(val != null)
270            return val.intValue() - pos();
271          return 0; // a position of 0 means not calculated yet
272        }
273    
274    
275        private void setAddress(int position, int address) {
276          if(address > Short.MAX_VALUE || address < Short.MIN_VALUE)
277            numberFormatError = true;
278          bytes.set(position + 0, (byte)((address&0xff00)>>8));
279          bytes.set(position + 1, (byte)(address&0xff));
280        }
281    
282    
283        private void setAddress32(int position, int address) {
284          bytes.set(position + 0, (byte)(address >> 24 & 0xff));
285          bytes.set(position + 1, (byte)(address >> 16 & 0xff));
286          bytes.set(position + 2, (byte)(address >> 8 & 0xff));
287          bytes.set(position + 3, (byte)(address & 0xff));
288        }
289    
290    
291    
292    
293        public void emitStoreReference(int pos) {
294          maxLocals = Math.max(maxLocals, pos+1);
295          if(pos == 0) emit(Bytecode.ASTORE_0);
296          else if(pos == 1) emit(Bytecode.ASTORE_1);
297          else if(pos == 2) emit(Bytecode.ASTORE_2);
298          else if(pos == 3) emit(Bytecode.ASTORE_3);
299          else if(pos < 256) emit(Bytecode.ASTORE).add(pos);
300          else emit(Bytecode.WIDE).emit(Bytecode.ASTORE).add2(pos);
301        }
302    
303    
304        public void emitLoadReference(int pos) {
305          maxLocals = Math.max(maxLocals, pos+1);
306          if(pos == 0) emit(Bytecode.ALOAD_0);
307          else if(pos == 1) emit(Bytecode.ALOAD_1);
308          else if(pos == 2) emit(Bytecode.ALOAD_2);
309          else if(pos == 3) emit(Bytecode.ALOAD_3);
310          else if(pos < 256) emit(Bytecode.ALOAD).add(pos);
311          else emit(Bytecode.WIDE).emit(Bytecode.ALOAD).add2(pos);
312        }
313    
314    
315    
316        public void emitReturn() {
317          bytes.emit(Bytecode.RETURN);
318        }
319    
320       
321    
322        public void emitThrow() {
323          bytes.emit(Bytecode.ATHROW);
324        }
325    
326    
327    
328        public void emitInstanceof(TypeDecl type) {
329          int p = constantPool().addClass(type.isArrayDecl() ? type.typeDescriptor() : type.constantPoolName());
330          bytes.emit(Bytecode.INSTANCEOF).add2(p);
331        }
332    
333    
334        public void emitCheckCast(TypeDecl type) {
335          int p = constantPool().addClass(type.isArrayDecl() ? type.typeDescriptor() : type.constantPoolName());
336          bytes.emit(Bytecode.CHECKCAST).add2(p);
337        }
338    
339    
340    
341        public void emitDup() {
342          bytes.emit(Bytecode.DUP);
343        }
344    
345    
346        public void emitDup2() {
347          bytes.emit(Bytecode.DUP2);
348        }
349    
350    
351    
352        public void emitPop() {
353          bytes.emit(Bytecode.POP);
354        }
355    
356    
357        
358        public void emitSwap() {
359          bytes.emit(Bytecode.SWAP);
360        }
361    
362    
363    
364        public void emitBranchNonNull(int label) {
365          int p = jump(label);
366          bytes.emit(Bytecode.IFNONNULL).add2(p);
367        }
368    
369    
370    
371        public void emitGoto(int label) {
372          int p = jump(label);
373          if(wideGoto)
374            bytes.emitGoto(Bytecode.GOTO_W).add4(p);
375          else {
376            if(p > Short.MAX_VALUE || p < Short.MIN_VALUE)
377              numberFormatError = true;
378            bytes.emitGoto(Bytecode.GOTO).add2(p);
379          }
380        }
381    
382    
383    
384        public void emitJsr(int label) {
385          int p = jump(label);
386          bytes.emit(Bytecode.JSR).add2(p);
387        }
388    
389    
390    
391        public void emitCompare(byte bytecode, int label) {
392          int p = jump(label);
393          bytes.emit(bytecode).add2(p);
394        }
395    
396    
397    
398        public String toString() {
399          return bytes.toString();
400        }
401    
402    
403        public int size() {return bytes.size();}
404    
405    
406        public int pos() {return bytes.pos();}
407    
408    
409        public byte[] toArray() {return bytes.toArray();}
410    
411    
412        CodeGeneration add(int i) { return add((byte)i); }
413    
414    
415        CodeGeneration add(byte b) { bytes.add(b); return this; }
416    
417    
418        CodeGeneration add2(int index) {
419          bytes.add2(index);
420          return this; 
421        }
422    
423    
424        CodeGeneration add4(int index) {
425          bytes.add4(index);
426          return this;
427        }
428    
429    
430        CodeGeneration emit(byte b) {
431          bytes.emit(b);
432          return this;
433        }
434    
435    
436        CodeGeneration emit(byte b, int stackChange) {
437          bytes.emit(b, stackChange);
438          return this;
439        }
440    
441    
442        public int maxStackDepth() {
443          return bytes.maxStackDepth();
444        }
445    
446    
447        public int stackDepth() {
448          return bytes.stackDepth();
449        }
450    
451    
452        public void changeStackDepth(int i) {
453          bytes.changeStackDepth(i);
454        }
455    
456    
457    }