Added support for stack allocation. Check for NULL before calling memory checker.
[repair.git] / Repair / RepairCompiler / MCC / IR / DotExpr.java
1 package MCC.IR;
2
3 import java.util.*;
4
5 public class DotExpr extends Expr {
6     
7     Expr left;
8     String field;
9     Expr index;
10     
11     static boolean DOMEMCHECKS=true;
12     static boolean DOTYPECHECKS=false;
13     static boolean DONULL=false;
14
15     public Set freeVars() {
16         Set lset=left.freeVars();
17         Set iset=null;
18         if (index!=null)
19             iset=index.freeVars();
20         if (lset==null)
21             return iset;
22         if (iset!=null)
23             lset.addAll(iset);
24         return lset;
25     }
26
27     /*
28     static int memoryindents = 0;
29
30     public static void generate_memory_endblocks(CodeWriter cr) {
31         while (memoryindents > 0) {
32             memoryindents --;
33             cr.endblock();
34         }
35         memoryindents = 0;
36     }
37     */
38
39     FieldDescriptor fd;
40     TypeDescriptor fieldtype;
41     Expr intindex;
42
43     public String name() {
44         String name=left.name()+"."+field;
45         if (index!=null)
46             name+="["+index.name()+"]";
47         return name;
48     }
49     
50     public boolean usesDescriptor(Descriptor d) {
51         if (d==fd)
52             return true;
53         return left.usesDescriptor(d)||((intindex!=null)&&intindex.usesDescriptor(d));
54     }
55
56     public boolean equals(Map remap, Expr e) {
57         if (e==null||!(e instanceof DotExpr))
58             return false;
59         DotExpr de=(DotExpr)e;
60         if (!de.field.equals(field))
61             return false;
62         if (index==null) {
63             if (de.index!=null)
64                 return false;
65         } else if (!index.equals(remap,de.index))
66             return false;
67         if (!left.equals(remap,de.left))
68             return false;
69         return true;
70     }
71
72     
73     public DotExpr(Expr left, String field, Expr index) {
74         this.left = left;
75         this.field = field;
76         this.index = index;
77     }
78
79     public Set getRequiredDescriptors() {
80         Set v = left.getRequiredDescriptors();
81         
82         if (index != null) {
83             v.addAll(index.getRequiredDescriptors());
84         }
85         return v;
86     }
87
88     public Expr getExpr() {
89         return left;
90     }
91
92     public FieldDescriptor getField() {
93         return fd;
94     }
95
96     public Expr getIndex() {
97         return intindex;
98     }
99
100     public void generate(CodeWriter writer, VarDescriptor dest) {
101         VarDescriptor leftd = VarDescriptor.makeNew("left");
102
103         writer.output("// " +  leftd.getSafeSymbol() + " <-- ");
104         left.prettyPrint(writer);
105         writer.outputline("");
106
107         left.generate(writer, leftd);
108
109         writer.output("// " +  leftd.getSafeSymbol() + " = ");
110         left.prettyPrint(writer);
111         writer.outputline("");
112       
113         StructureTypeDescriptor struct = (StructureTypeDescriptor) left.getType();
114         Expr intindex = index;
115         Expr offsetbits;
116
117         // #ATTN#: getOffsetExpr needs to be called with the fielddescriptor obect that is in teh vector list
118         // this means that if the field is an arraydescriptor you have to call getOffsetExpr with the array 
119         // descriptor not the underlying field descriptor
120
121         /* we calculate the offset in bits */
122         offsetbits = struct.getOffsetExpr(fd);
123
124         if (fd instanceof ArrayDescriptor) {
125             fd = ((ArrayDescriptor) fd).getField();
126         } 
127         
128         if (intindex != null) {
129             if (intindex instanceof IntegerLiteralExpr && ((IntegerLiteralExpr) intindex).getValue() == 0) {
130                 /* short circuit for constant 0 */                
131             } else {
132                 Expr basesize = fd.getBaseSizeExpr();
133                 offsetbits = new OpExpr(Opcode.ADD, offsetbits, new OpExpr(Opcode.MULT, basesize, intindex));
134             }
135         }
136         
137         final SymbolTable st = writer.getSymbolTable();
138         TypeDescriptor td = offsetbits.typecheck(new SemanticAnalyzer() {
139                 public IRErrorReporter getErrorReporter() { throw new IRException("badness"); }
140                 public SymbolTable getSymbolTable() { return st; }
141             });
142
143         if (td == null) {
144             throw new IRException();
145         } else if (td != ReservedTypeDescriptor.INT) {
146             throw new IRException();
147         }
148                
149         boolean dotypecheck = false;
150
151         if (offsetbits instanceof IntegerLiteralExpr) {
152             int offsetinbits = ((IntegerLiteralExpr) offsetbits).getValue();
153             int offset = offsetinbits >> 3; /* offset in bytes */
154
155             if (fd.getType() instanceof ReservedTypeDescriptor && !fd.getPtr()) {
156                 int shift = offsetinbits - (offset << 3);            
157                 int mask = bitmask(((IntegerLiteralExpr)fd.getType().getSizeExpr()).getValue());
158                                
159                 /* type var = ((*(int *) (base + offset)) >> shift) & mask */
160                 writer.outputline(getType().getGenerateType() + " "+dest.getSafeSymbol()+"=0;");
161                 writer.outputline("if ("+leftd.getSafeSymbol()+")");
162                 writer.outputline(dest.getSafeSymbol() + " = ((*(int *)" + 
163                                   "(" + leftd.getSafeSymbol() + " + " + offset + ")) " + 
164                                   " >> " + shift + ") & 0x" + Integer.toHexString(mask) + ";");
165                 writer.outputline("else maybe=1;");
166             } else { /* a structure address or a ptr! */
167                 String ptr = fd.getPtr() ? "*(int *)" : "";
168                 /* type var = [*(int *)] (base + offset) */
169                 writer.outputline("int " + dest.getSafeSymbol()+"=0;");
170                 writer.outputline("if ("+leftd.getSafeSymbol()+")");
171                 writer.startblock();
172                 writer.outputline(dest.getSafeSymbol() + 
173                                   " = " + ptr + "(" + leftd.getSafeSymbol() + " + " + offset + ");");  
174                 if (fd.getPtr()) {
175                     writer.outputline("if ("+dest.getSafeSymbol()+")");
176                     writer.startblock();
177                     VarDescriptor typevar=VarDescriptor.makeNew("typechecks");
178                     if (DOMEMCHECKS&&(!DOTYPECHECKS)) {
179                         writer.outputline("bool "+typevar.getSafeSymbol()+"=assertvalidmemory(" + dest.getSafeSymbol() + ", " + this.td.getId() + ");");
180                         dotypecheck = true;
181                     } else if (DOTYPECHECKS) {
182                         writer.outputline("bool "+typevar.getSafeSymbol()+"=assertvalidtype(" + dest.getSafeSymbol() + ", " + this.td.getId() + ");");
183                     }
184                     writer.outputline("if (!"+typevar.getSafeSymbol()+")");
185                     writer.startblock();
186                     writer.outputline(dest.getSafeSymbol()+"=0;");
187                     if (DONULL)
188                         writer.outputline(ptr + "(" + leftd.getSafeSymbol() + " + " + offset + ")=0;");
189                     writer.endblock();
190                     writer.endblock();
191                 }
192                 writer.endblock();
193                 writer.outputline("else maybe=1;");
194             }
195         } else { /* offset in bits is an expression that must be generated */                        
196             VarDescriptor ob = VarDescriptor.makeNew("offsetinbits");
197             writer.output("// " + ob.getSafeSymbol() + " <-- ");
198             offsetbits.prettyPrint(writer);
199             writer.outputline("");
200             offsetbits.generate(writer, ob);
201             writer.output("// " + ob.getSafeSymbol() + " = ");
202             offsetbits.prettyPrint(writer);
203             writer.outputline("");
204
205             /* derive offset in bytes */
206             VarDescriptor offset = VarDescriptor.makeNew("offset");
207             writer.outputline("int " + offset.getSafeSymbol() + " = " + ob.getSafeSymbol() + " >> 3;");
208             
209             if (fd.getType() instanceof ReservedTypeDescriptor && !fd.getPtr()) {
210                 VarDescriptor shift = VarDescriptor.makeNew("shift");
211                 writer.outputline("int " + shift.getSafeSymbol() + " = " + ob.getSafeSymbol() + 
212                                   " - (" + offset.getSafeSymbol() + " << 3);");
213                 int mask = bitmask(((IntegerLiteralExpr)fd.getType().getSizeExpr()).getValue());
214                 
215                 /* type var = ((*(int *) (base + offset)) >> shift) & mask */
216                 writer.outputline(getType().getGenerateType() + " " + dest.getSafeSymbol()+"=0;");
217                 writer.outputline("if ("+leftd.getSafeSymbol()+")");
218                 writer.outputline(dest.getSafeSymbol() + 
219                                   " = ((*(int *)" + 
220                                   "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ")) " + 
221                                   " >> " + shift.getSafeSymbol() + ") & 0x" + Integer.toHexString(mask) + ";");  
222                 writer.outputline("else maybe=1;");
223             } else { /* a structure address or a ptr */
224                 String ptr = fd.getPtr() ? "*(int *)" : "";
225                 /* type var = [*(int *)] (base + offset) */
226                 writer.outputline("int " + dest.getSafeSymbol() +"=0;"); 
227                 writer.outputline("if ("+leftd.getSafeSymbol()+")");
228                 writer.startblock();
229                 writer.outputline(dest.getSafeSymbol() + 
230                                   " = " + ptr + "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ");");  
231                 if (fd.getPtr()) {
232                     writer.outputline("if ("+dest.getSafeSymbol()+")");
233                     writer.startblock();
234                     VarDescriptor typevar=VarDescriptor.makeNew("typechecks");
235                     if (DOMEMCHECKS&&(!DOTYPECHECKS)) {
236                         writer.outputline("bool "+typevar.getSafeSymbol()+"=assertvalidmemory(" + dest.getSafeSymbol() + ", " + this.td.getId() + ");");
237                         dotypecheck = true;
238                     } else if (DOTYPECHECKS) {
239                         writer.outputline("bool "+typevar.getSafeSymbol()+"=assertvalidtype(" + dest.getSafeSymbol() + ", " + this.td.getId() + ");");
240                     }
241                     writer.outputline("if (!"+typevar.getSafeSymbol()+")");
242                     writer.startblock();
243                     writer.outputline(dest.getSafeSymbol()+"=0;");
244                     if (DONULL)
245                         writer.outputline(ptr + "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ")=0;");
246                     writer.endblock();
247                     writer.endblock();
248                 }
249                 writer.endblock();
250                 writer.outputline("else maybe=1;");
251             }
252         }
253     }
254
255     private int bitmask(int bits) {
256         int mask = 0;
257         
258         for (int i = 0; i < bits; i++) {
259             mask <<= 1;
260             mask += 1;
261         }
262
263         return mask;            
264     }
265
266     public void prettyPrint(PrettyPrinter pp) {
267         left.prettyPrint(pp);
268         pp.output("." + field);
269         if (index != null) {
270             pp.output("[");
271             index.prettyPrint(pp);
272             pp.output("]");
273         }
274     }
275
276     public TypeDescriptor typecheck(SemanticAnalyzer sa) {
277         TypeDescriptor lefttype = left.typecheck(sa);
278         TypeDescriptor indextype = index == null ? null : index.typecheck(sa);
279         
280         {
281             /* finished typechecking...so we can fill the fields in */
282             StructureTypeDescriptor struct = (StructureTypeDescriptor) left.getType();        
283             FieldDescriptor fd = struct.getField(field);
284             LabelDescriptor ld = struct.getLabel(field);
285             if (ld != null) { /* label */
286                 assert fd == null;
287                 fieldtype = ld.getType(); // d.s ==> Superblock, while,  d.b ==> Block
288                 fd = ld.getField();
289                 assert fd != null;
290                 assert intindex == null;
291                 intindex = ld.getIndex();
292             } else {
293                 fieldtype = fd.getType();
294                 intindex=index;
295             }
296             this.fd=fd;
297         }
298
299         if ((lefttype == null) || (index != null && indextype == null)) {
300             return null;
301         }
302
303         if (indextype != null) {
304             if (indextype != ReservedTypeDescriptor.INT) {
305                 sa.getErrorReporter().report(null, "Index must be of type 'int' not '" + indextype.getSymbol() + "'");
306                 return null;
307             }
308         }
309
310         if (lefttype instanceof StructureTypeDescriptor) {            
311             StructureTypeDescriptor struct = (StructureTypeDescriptor) lefttype;
312             FieldDescriptor fd = struct.getField(field);
313             LabelDescriptor ld = struct.getLabel(field);
314
315             if (fd != null) { /* field */
316                 assert ld == null;
317
318                 if (indextype == null && fd instanceof ArrayDescriptor) {
319                     sa.getErrorReporter().report(null, "Must specify an index what accessing array field '" + struct.getSymbol() + "." + fd.getSymbol() + "'");
320                     return null;                
321                 } else if (indextype != null && !(fd instanceof ArrayDescriptor)) {
322                     sa.getErrorReporter().report(null, "Cannot specify an index when accessing non-array field '" + struct.getSymbol() + "." + fd.getSymbol() + "'");
323                     return null;
324                 }
325                 
326                 this.td = fd.getType();
327             } else if (ld != null) { /* label */
328                 assert fd == null;
329
330                 if (index != null) { 
331                     sa.getErrorReporter().report(null, "A label cannot be accessed as an array");
332                     return null;
333                 }
334                 
335                 this.td = ld.getType();
336             } else {
337                 sa.getErrorReporter().report(null, "No such field or label '" + field + "' in structure '" + struct.getSymbol() + "'");
338                 return null;
339             }
340
341             /* we promote bit, byte and short to integer types */
342             if (this.td == ReservedTypeDescriptor.BIT ||
343                 this.td == ReservedTypeDescriptor.BYTE ||
344                 this.td == ReservedTypeDescriptor.SHORT) {
345                 this.td = ReservedTypeDescriptor.INT;
346             }
347
348             return this.td;
349         } else {
350             sa.getErrorReporter().report(null, "Left hand side of . expression must be a structure type, not '" + lefttype.getSymbol() + "'");
351             return null;
352         }
353         
354         
355     }
356
357 }
358