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