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