adc872120c5e865d2d8bcf36c71c512863bb19df
[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     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 Set useDescriptor(Descriptor d) {
71         HashSet newset=new HashSet();
72         if (d==fd)
73             newset.add(this);
74         newset.addAll(left.useDescriptor(d));
75         if (intindex!=null)
76             newset.addAll(intindex.useDescriptor(d));
77         return newset;
78     }
79
80     public boolean usesDescriptor(Descriptor d) {
81         if (d==fd)
82             return true;
83         return left.usesDescriptor(d)||((intindex!=null)&&intindex.usesDescriptor(d));
84     }
85
86     public boolean equals(Map remap, Expr e) {
87         if (e==null||!(e instanceof DotExpr))
88             return false;
89         DotExpr de=(DotExpr)e;
90         if (!de.field.equals(field))
91             return false;
92         if (index==null) {
93             if (de.index!=null)
94                 return false;
95         } else if (!index.equals(remap,de.index))
96             return false;
97         if (!left.equals(remap,de.left))
98             return false;
99         return true;
100     }
101
102     
103     public DotExpr(Expr left, String field, Expr index) {
104         this.left = left;
105         this.field = field;
106         this.index = index;
107     }
108
109     public Set getRequiredDescriptors() {
110         Set v = left.getRequiredDescriptors();
111         
112         if (index != null) {
113             v.addAll(index.getRequiredDescriptors());
114         }
115         return v;
116     }
117
118     public Expr getExpr() {
119         return left;
120     }
121
122     public FieldDescriptor getField() {
123         return fd;
124     }
125
126     public Expr getIndex() {
127         return intindex;
128     }
129
130     public void generate(CodeWriter writer, VarDescriptor dest) {
131         VarDescriptor leftd = VarDescriptor.makeNew("left");
132
133         writer.output("// " +  leftd.getSafeSymbol() + " <-- ");
134         left.prettyPrint(writer);
135         writer.outputline("");
136
137         left.generate(writer, leftd);
138
139         writer.output("// " +  leftd.getSafeSymbol() + " = ");
140         left.prettyPrint(writer);
141         writer.outputline("");
142       
143         StructureTypeDescriptor struct = (StructureTypeDescriptor) left.getType();
144         Expr intindex = index;
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