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