6 public class DotExpr extends Expr {
12 static boolean DOMEMCHECKS=false;
13 static boolean DOTYPECHECKS=false;
14 static boolean DONULL=false;
17 public DotExpr(Expr left, String field, Expr index) {
23 public boolean isInvariant(Set vars) {
24 if (!left.isInvariant(vars))
27 return intindex.isInvariant(vars);
32 public Set findInvariants(Set vars) {
33 if (isInvariant(vars)) {
38 Set ls=left.findInvariants(vars);
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));
57 public boolean isSafe() {
60 FieldDescriptor tmpfd=fd;
61 if (tmpfd instanceof ArrayDescriptor)
62 return false; // Arrays could be out of bounds
63 if (tmpfd.getPtr()) // Pointers cound be invalid
68 public Set freeVars() {
69 Set lset=left.freeVars();
72 iset=intindex.freeVars();
81 static int memoryindents = 0;
83 public static void generate_memory_endblocks(CodeWriter cr) {
84 while (memoryindents > 0) {
93 TypeDescriptor fieldtype;
96 public String name() {
97 String name=left.name()+"."+field;
99 name+="["+index.name()+"]";
103 public void findmatch(Descriptor d, Set s) {
108 intindex.findmatch(d,s);
111 public Set useDescriptor(Descriptor d) {
112 HashSet newset=new HashSet();
115 newset.addAll(left.useDescriptor(d));
117 newset.addAll(intindex.useDescriptor(d));
121 public boolean usesDescriptor(Descriptor d) {
124 return left.usesDescriptor(d)||((intindex!=null)&&intindex.usesDescriptor(d));
127 public boolean equals(Map remap, Expr e) {
128 if (e==null||!(e instanceof DotExpr))
130 DotExpr de=(DotExpr)e;
131 if (!de.field.equals(field))
136 } else if (!index.equals(remap,de.index))
138 if (!left.equals(remap,de.left))
144 public Set getRequiredDescriptors() {
145 Set v = left.getRequiredDescriptors();
147 if (intindex != null) {
148 v.addAll(intindex.getRequiredDescriptors());
153 public Expr getExpr() {
157 public FieldDescriptor getField() {
161 public Expr getIndex() {
165 public void generate(CodeWriter writer, VarDescriptor dest) {
166 VarDescriptor leftd = VarDescriptor.makeNew("left");
168 if (writer.getInvariantValue()!=null&&
169 writer.getInvariantValue().isInvariant(this)) {
170 writer.addDeclaration(getType().getGenerateType().getSafeSymbol().toString(), dest.getSafeSymbol());
171 writer.outputline(dest.getSafeSymbol()+"="+writer.getInvariantValue().getValue(this).getSafeSymbol()+";");
172 writer.outputline("maybe="+writer.getInvariantValue().getMaybe(this).getSafeSymbol()+";");
176 writer.output("/* " + leftd.getSafeSymbol() + " <-- ");
177 left.prettyPrint(writer);
178 writer.outputline("*/");
180 left.generate(writer, leftd);
182 writer.output("/* " + leftd.getSafeSymbol() + " = ");
183 left.prettyPrint(writer);
184 writer.outputline("*/");
186 StructureTypeDescriptor struct = (StructureTypeDescriptor) left.getType();
189 // #ATTN#: getOffsetExpr needs to be called with the fielddescriptor object that is in the vector list
190 // this means that if the field is an arraydescriptor you have to call getOffsetExpr with the array
191 // descriptor not the underlying field descriptor
193 /* we calculate the offset in bits */
195 offsetbits = struct.getOffsetExpr(fd);
197 FieldDescriptor fd=this.fd;
198 if (fd instanceof ArrayDescriptor)
199 fd=((ArrayDescriptor)fd).getField();
200 boolean doboundscheck=true;
201 boolean performedboundscheck=false;
203 writer.addDeclaration(getType().getGenerateType().toString(),dest.getSafeSymbol());
204 writer.outputline(dest.getSafeSymbol()+"=0;");
206 if (intindex != null) {
207 if (intindex instanceof IntegerLiteralExpr && ((IntegerLiteralExpr) intindex).getValue() == 0) {
208 /* short circuit for constant 0 */
210 Expr basesize = fd.getBaseSizeExpr();
212 VarDescriptor indexvd=VarDescriptor.makeNew("index");
213 indexvd.setType(ReservedTypeDescriptor.INT);
214 writer.getSymbolTable().add(indexvd);
216 writer.output("/* " + indexvd.getSafeSymbol() + " <-- ");
218 intindex.prettyPrint(writer);
219 writer.outputline("*/");
220 intindex.generate(writer, indexvd);
221 writer.output("/* " + indexvd.getSafeSymbol() + " = ");
222 intindex.prettyPrint(writer);
223 writer.outputline("*/");
224 Expr indexbound=((ArrayDescriptor)this.fd).getIndexBound();
225 VarDescriptor indexboundvd=VarDescriptor.makeNew("indexbound");
227 indexbound.generate(writer,indexboundvd);
229 writer.outputline("if ("+indexvd.getSafeSymbol()+">=0 &&"+indexvd.getSafeSymbol()+"<"+indexboundvd.getSafeSymbol()+")");
231 VarExpr indexve=new VarExpr(indexvd);
232 offsetbits = new OpExpr(Opcode.ADD, offsetbits, new OpExpr(Opcode.MULT, basesize, indexve));
234 performedboundscheck=true;
236 offsetbits = new OpExpr(Opcode.ADD, offsetbits, new OpExpr(Opcode.MULT, basesize, intindex));
240 final SymbolTable st = writer.getSymbolTable();
241 TypeDescriptor td2 = offsetbits.typecheck(new SemanticAnalyzer() {
242 public IRErrorReporter getErrorReporter() { throw new IRException("badness"); }
243 public SymbolTable getSymbolTable() { return st; }
247 throw new IRException();
248 } else if (td2 != ReservedTypeDescriptor.INT) {
249 throw new IRException();
252 boolean dotypecheck = false;
254 VarDescriptor ob = VarDescriptor.makeNew("offsetinbits");
255 writer.output("/* " + ob.getSafeSymbol() + " <-- ");
256 offsetbits.prettyPrint(writer);
257 writer.outputline("*/");
258 offsetbits.generate(writer, ob);
259 writer.output("/* " + ob.getSafeSymbol() + " = ");
260 offsetbits.prettyPrint(writer);
261 writer.outputline("*/");
263 /* derive offset in bytes */
264 VarDescriptor offset = VarDescriptor.makeNew("offset");
265 writer.addDeclaration("int", offset.getSafeSymbol());
266 writer.outputline(offset.getSafeSymbol() + " = " + ob.getSafeSymbol() + " >> 3;");
268 if (fd.getType() instanceof ReservedTypeDescriptor && !fd.getPtr()) {
269 VarDescriptor shift = VarDescriptor.makeNew("shift");
270 writer.addDeclaration("int", shift.getSafeSymbol());
271 writer.outputline(shift.getSafeSymbol() + " = " + ob.getSafeSymbol() +
272 " - (" + offset.getSafeSymbol() + " << 3);");
273 int mask = bitmask(((IntegerLiteralExpr)fd.getType().getSizeExpr()).getValue());
275 /* type var = ((*(int *) (base + offset)) >> shift) & mask */
276 writer.outputline("if ("+leftd.getSafeSymbol()+")");
277 writer.outputline(dest.getSafeSymbol() + " = ((*(int *)" +
278 "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ")) " +
279 " >> " + shift.getSafeSymbol() + ") & 0x" + Integer.toHexString(mask) + ";");
280 writer.outputline("else maybe=1;");
281 } else { /* a structure address or a ptr */
282 String ptr = fd.getPtr() ? "*(int *)" : "";
283 /* type var = [*(int *)] (base + offset) */
284 writer.outputline("if ("+leftd.getSafeSymbol()+")");
286 writer.outputline(dest.getSafeSymbol() +
287 " = " + ptr + "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ");");
289 writer.outputline("if ("+dest.getSafeSymbol()+")");
291 VarDescriptor typevar=VarDescriptor.makeNew("typechecks");
292 if (DOMEMCHECKS&&(!DOTYPECHECKS)) {
293 writer.addDeclaration("bool", typevar.getSafeSymbol());
294 writer.outputline(typevar.getSafeSymbol()+"=assertvalidmemory(" + dest.getSafeSymbol() + ", " + this.td.getId() + ");");
296 } else if (DOTYPECHECKS) {
297 writer.addDeclaration("bool", typevar.getSafeSymbol());
298 writer.outputline(typevar.getSafeSymbol()+"=assertvalidtype(" + dest.getSafeSymbol() + ", " + this.td.getId() + ");");
301 if (DOTYPECHECKS||DOMEMCHECKS) {
302 writer.outputline("if (!"+typevar.getSafeSymbol()+")");
304 writer.outputline(dest.getSafeSymbol()+"=0;");
306 writer.outputline(ptr + "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ")=0;");
313 writer.outputline("else maybe=1;");
315 if (performedboundscheck) {
317 writer.outputline(" else ");
319 writer.outputline(dest.getSafeSymbol()+"=0;");
320 writer.outputline("maybe=1;");
321 if (!Compiler.REPAIR)
322 writer.outputline("printf(\"Array Index Out of Bounds\");");
327 private int bitmask(int bits) {
330 for (int i = 0; i < bits; i++) {
338 public void prettyPrint(PrettyPrinter pp) {
339 left.prettyPrint(pp);
340 pp.output("." + field);
343 index.prettyPrint(pp);
348 public boolean isValue(TypeDescriptor td) {
349 FieldDescriptor tmpfd=fd;
350 if (tmpfd instanceof ArrayDescriptor)
351 tmpfd=((ArrayDescriptor)tmpfd).getField();
352 return (tmpfd.getPtr()||(tmpfd.getType() instanceof ReservedTypeDescriptor));
355 public boolean isPtr() {
356 FieldDescriptor tmpfd=fd;
357 if (tmpfd instanceof ArrayDescriptor)
358 tmpfd=((ArrayDescriptor)tmpfd).getField();
359 return tmpfd.getPtr();
362 boolean typechecked=false;
363 public TypeDescriptor typecheck(SemanticAnalyzer sa) {
366 else typechecked=true;
367 TypeDescriptor lefttype = left.typecheck(sa);
368 TypeDescriptor indextype = index == null ? null : index.typecheck(sa);
371 /* finished typechecking...so we can fill the fields in */
372 StructureTypeDescriptor struct = (StructureTypeDescriptor) left.getType();
373 FieldDescriptor fd = struct.getField(field);
374 LabelDescriptor ld = struct.getLabel(field);
375 if (ld != null) { /* label */
377 fieldtype = ld.getType(); // d.s ==> Superblock, while, d.b ==> Block
380 assert intindex == null;
381 intindex = ld.getIndex();
383 fieldtype = fd.getType();
387 if (fieldtype instanceof MissingTypeDescriptor)
388 throw new Error(fieldtype.getSymbol()+" type undefined!");
391 if ((lefttype == null) || (index != null && indextype == null)) {
395 if (indextype != null) {
396 if (indextype != ReservedTypeDescriptor.INT) {
397 sa.getErrorReporter().report(null, "Index must be of type 'int' not '" + indextype.getSymbol() + "'");
402 if (lefttype instanceof StructureTypeDescriptor) {
403 StructureTypeDescriptor struct = (StructureTypeDescriptor) lefttype;
404 FieldDescriptor fd = struct.getField(field);
405 LabelDescriptor ld = struct.getLabel(field);
407 if (fd != null) { /* field */
410 if (indextype == null && fd instanceof ArrayDescriptor) {
411 sa.getErrorReporter().report(null, "Must specify an index what accessing array field '" + struct.getSymbol() + "." + fd.getSymbol() + "'");
413 } else if (indextype != null && !(fd instanceof ArrayDescriptor)) {
414 sa.getErrorReporter().report(null, "Cannot specify an index when accessing non-array field '" + struct.getSymbol() + "." + fd.getSymbol() + "'");
418 this.td = fd.getType();
419 } else if (ld != null) { /* label */
423 sa.getErrorReporter().report(null, "A label cannot be accessed as an array");
427 this.td = ld.getType();
429 sa.getErrorReporter().report(null, "No such field or label '" + field + "' in structure '" + struct.getSymbol() + "'");
433 /* we promote bit, byte and short to integer types */
434 if (this.td == ReservedTypeDescriptor.BIT ||
435 this.td == ReservedTypeDescriptor.BYTE ||
436 this.td == ReservedTypeDescriptor.SHORT) {
437 this.td = ReservedTypeDescriptor.INT;
442 sa.getErrorReporter().report(null, "Left hand side of . expression must be a structure type, not '" + lefttype.getSymbol() + "'");