505459f6846caae342d7caf5d34de0a8549beca5
[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                 writer.outputline("if (!"+typevar.getSafeSymbol()+")");
254                 writer.startblock();
255                 writer.outputline(dest.getSafeSymbol()+"=0;");
256                 if (DONULL)
257                     writer.outputline(ptr + "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ")=0;");
258                 writer.endblock();
259                 writer.endblock();
260             }
261             writer.endblock();
262             writer.outputline("else maybe=1;");
263         }
264         if (performedboundscheck) {
265             writer.endblock();
266             writer.outputline(" else ");
267             writer.startblock();
268             writer.outputline(dest.getSafeSymbol()+"=0;");
269             writer.outputline("maybe=1;");
270             if (!Compiler.REPAIR)
271                 writer.outputline("printf(\"Array Index Out of Bounds\");");
272             writer.endblock();
273         }
274     }
275
276     private int bitmask(int bits) {
277         int mask = 0;
278         
279         for (int i = 0; i < bits; i++) {
280             mask <<= 1;
281             mask += 1;
282         }
283
284         return mask;            
285     }
286
287     public void prettyPrint(PrettyPrinter pp) {
288         left.prettyPrint(pp);
289         pp.output("." + field);
290         if (index != null) {
291             pp.output("[");
292             index.prettyPrint(pp);
293             pp.output("]");
294         }
295     }
296
297     public boolean isValue() {
298         FieldDescriptor tmpfd=fd;
299         if (tmpfd instanceof ArrayDescriptor)
300             tmpfd=((ArrayDescriptor)tmpfd).getField();
301         return (tmpfd.getPtr()||(tmpfd.getType() instanceof ReservedTypeDescriptor));
302     }
303
304     boolean typechecked=false;
305     public TypeDescriptor typecheck(SemanticAnalyzer sa) {
306         if (typechecked)
307             return this.td;
308         else typechecked=true;
309         TypeDescriptor lefttype = left.typecheck(sa);
310         TypeDescriptor indextype = index == null ? null : index.typecheck(sa);
311         
312         {
313             /* finished typechecking...so we can fill the fields in */
314             StructureTypeDescriptor struct = (StructureTypeDescriptor) left.getType();
315             FieldDescriptor fd = struct.getField(field);
316             LabelDescriptor ld = struct.getLabel(field);
317             if (ld != null) { /* label */
318                 assert fd == null;
319                 fieldtype = ld.getType(); // d.s ==> Superblock, while,  d.b ==> Block
320                 fd = ld.getField();
321                 assert fd != null;
322                 assert intindex == null;
323                 intindex = ld.getIndex();
324             } else {
325                 fieldtype = fd.getType();
326                 intindex=index;
327             }
328             this.fd=fd;
329         }
330
331         if ((lefttype == null) || (index != null && indextype == null)) {
332             return null;
333         }
334
335         if (indextype != null) {
336             if (indextype != ReservedTypeDescriptor.INT) {
337                 sa.getErrorReporter().report(null, "Index must be of type 'int' not '" + indextype.getSymbol() + "'");
338                 return null;
339             }
340         }
341
342         if (lefttype instanceof StructureTypeDescriptor) {            
343             StructureTypeDescriptor struct = (StructureTypeDescriptor) lefttype;
344             FieldDescriptor fd = struct.getField(field);
345             LabelDescriptor ld = struct.getLabel(field);
346
347             if (fd != null) { /* field */
348                 assert ld == null;
349
350                 if (indextype == null && fd instanceof ArrayDescriptor) {
351                     sa.getErrorReporter().report(null, "Must specify an index what accessing array field '" + struct.getSymbol() + "." + fd.getSymbol() + "'");
352                     return null;                
353                 } else if (indextype != null && !(fd instanceof ArrayDescriptor)) {
354                     sa.getErrorReporter().report(null, "Cannot specify an index when accessing non-array field '" + struct.getSymbol() + "." + fd.getSymbol() + "'");
355                     return null;
356                 }
357                 
358                 this.td = fd.getType();
359             } else if (ld != null) { /* label */
360                 assert fd == null;
361
362                 if (index != null) { 
363                     sa.getErrorReporter().report(null, "A label cannot be accessed as an array");
364                     return null;
365                 }
366                 
367                 this.td = ld.getType();
368             } else {
369                 sa.getErrorReporter().report(null, "No such field or label '" + field + "' in structure '" + struct.getSymbol() + "'");
370                 return null;
371             }
372
373             /* we promote bit, byte and short to integer types */
374             if (this.td == ReservedTypeDescriptor.BIT ||
375                 this.td == ReservedTypeDescriptor.BYTE ||
376                 this.td == ReservedTypeDescriptor.SHORT) {
377                 this.td = ReservedTypeDescriptor.INT;
378             }
379
380             return this.td;
381         } else {
382             sa.getErrorReporter().report(null, "Left hand side of . expression must be a structure type, not '" + lefttype.getSymbol() + "'");
383             return null;
384         }
385     }
386 }
387