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