001    /*
002     * The JastAdd Extensible Java Compiler (http://jastadd.org) is covered
003     * by the modified BSD License. You should have received a copy of the
004     * modified BSD license with this compiler.
005     * 
006     * Copyright (c) 2005-2008, Torbjorn Ekman
007     * All rights reserved.
008     */
009    
010    aspect AutoBoxingCodegen {
011        // Code generation for Boxing Conversion
012      refine CodeGenerationConversions void BooleanType.emitCastTo(CodeGeneration gen, TypeDecl type) {
013        if(type.unboxed() == this || type.isObject())
014          boxed().emitBoxingOperation(gen);
015      }
016      void ReferenceType.byteToThis(CodeGeneration gen) {
017        if(isUnknown()) throw new Error("Trying to cast to Unknown");
018        if(!isNumericType())
019          typeByte().boxed().byteToThis(gen);
020        else {
021          unboxed().byteToThis(gen);
022          emitBoxingOperation(gen);
023        }
024      }
025      void ReferenceType.charToThis(CodeGeneration gen) {
026        if(isUnknown()) throw new Error("Trying to cast to Unknown");
027        if(!isNumericType())
028          typeChar().boxed().charToThis(gen);
029        else {
030          unboxed().charToThis(gen);
031          emitBoxingOperation(gen);
032        }
033      }
034      void ReferenceType.shortToThis(CodeGeneration gen) {
035        if(isUnknown()) throw new Error("Trying to cast to Unknown");
036        if(!isNumericType())
037          typeShort().boxed().shortToThis(gen);
038        else {
039          unboxed().shortToThis(gen);
040          emitBoxingOperation(gen);
041        }
042      }
043      void ReferenceType.intToThis(CodeGeneration gen) {
044        if(isUnknown()) throw new Error("Trying to cast to Unknown");
045        if(!isNumericType())
046          typeInt().boxed().intToThis(gen);
047        else {
048          unboxed().intToThis(gen);
049          emitBoxingOperation(gen);
050        }
051      }
052      void ReferenceType.longToThis(CodeGeneration gen) {
053        if(isUnknown()) throw new Error("Trying to cast to Unknown");
054        if(!isNumericType())
055          typeLong().boxed().longToThis(gen);
056        else {
057          unboxed().longToThis(gen);
058          emitBoxingOperation(gen);
059        }
060      }
061      void ReferenceType.floatToThis(CodeGeneration gen) {
062        if(isUnknown()) throw new Error("Trying to cast to Unknown");
063        if(!isNumericType())
064          typeFloat().boxed().floatToThis(gen);
065        else {
066          unboxed().floatToThis(gen);
067          emitBoxingOperation(gen);
068        }
069      }
070      void ReferenceType.doubleToThis(CodeGeneration gen) {
071        if(isUnknown()) throw new Error("Trying to cast to Unknown");
072        if(!isNumericType())
073          typeDouble().boxed().doubleToThis(gen);
074        else {
075          unboxed().doubleToThis(gen);
076          emitBoxingOperation(gen);
077        }
078      }
079      protected void TypeDecl.emitBoxingOperation(CodeGeneration gen) {
080        // Box the value on the stack into this Reference type
081        String classname = constantPoolName();
082        String desc = "(" + unboxed().typeDescriptor() + ")" + typeDescriptor();
083        String name = "valueOf";
084        int index = gen.constantPool().addMethodref(classname, name, desc);
085        gen.emit(Bytecode.INVOKESTATIC, variableSize() - unboxed().variableSize()).add2(index);
086      }
087    
088      // Code generation for Unboxing Conversion
089      refine CodeGenerationConversions public void ReferenceType.emitCastTo(CodeGeneration gen, TypeDecl type) {
090        if(type instanceof PrimitiveType) {
091          emitUnboxingOperation(gen);
092          unboxed().emitCastTo(gen, type);
093        }
094        else 
095          refined(gen, type);
096      }
097      protected void TypeDecl.emitUnboxingOperation(CodeGeneration gen) {
098        // Unbox the value on the stack from this Reference type
099        String classname = constantPoolName();
100        String desc = "(" + ")" + unboxed().typeDescriptor();
101        String name = unboxed().name() + "Value";
102        int index = gen.constantPool().addMethodref(classname, name, desc);
103        gen.emit(Bytecode.INVOKEVIRTUAL, unboxed().variableSize() - 1).add2(index);
104      }
105    
106      // Generate unboxing code for conditions
107      // 14.9 If, 14.12 While, 14.13 Do, 14.14 For
108      // 
109      // emitEvalBranch is used to emit the condition from these constructs
110      // refine behavior to include unboxing of the value when needed
111      refine CreateBCode public void Expr.emitEvalBranch(CodeGeneration gen) {
112        if(type().isReferenceType()) {
113          createBCode(gen);
114          type().emitUnboxingOperation(gen);
115          gen.emitCompare(Bytecode.IFEQ, false_label());
116          gen.emitGoto(true_label());
117        }
118        else {
119          refined(gen);
120        }
121      }
122    
123    
124      // 14.11 Switch
125      refine CreateBCode public void SwitchStmt.createBCode(CodeGeneration gen) {
126        super.createBCode(gen);
127        int cond_label = hostType().constantPool().newLabel();
128        int switch_label = hostType().constantPool().newLabel();
129    
130        gen.emitGoto(cond_label);
131        getBlock().createBCode(gen);
132        if(canCompleteNormally())
133          gen.emitGoto(end_label());
134        gen.addLabel(cond_label);
135        getExpr().createBCode(gen);
136        if(getExpr().type().isReferenceType())
137          getExpr().type().emitUnboxingOperation(gen);
138    
139        TreeMap map = new TreeMap();
140        for(int i = 0; i < getBlock().getNumStmt(); i++) {
141          if(getBlock().getStmt(i) instanceof ConstCase) {
142            ConstCase ca = (ConstCase)getBlock().getStmt(i);
143            map.put(new Integer(ca.getValue().constant().intValue()), ca);
144          }        
145        }
146    
147        long low = map.isEmpty() ? 0 : ((Integer)map.firstKey()).intValue();
148        long high = map.isEmpty() ? 0 : ((Integer)map.lastKey()).intValue();
149    
150        long tableSwitchSize = 8L + (high - low + 1L) * 4L;
151        long lookupSwitchSize = 4L + map.size() * 8L;
152    
153        gen.addLabel(switch_label);
154        if(tableSwitchSize < lookupSwitchSize) {
155          gen.emit(Bytecode.TABLESWITCH);
156          int pad = emitPad(gen);
157          int defaultOffset = defaultOffset(gen, switch_label);
158          if(defaultOffset == 0) {
159            defaultOffset = 1 + pad + 4 + 4 + 4 + 4 * (int)(high - low + 1);
160          }
161          gen.add4(defaultOffset);
162          gen.add4((int)low);
163          gen.add4((int)high);
164          for(long i = low; i <= high; i++) {
165            ConstCase ca = (ConstCase)map.get(new Integer((int)i));
166            if(ca != null) {
167              int offset = gen.addressOf(ca.label(gen))
168                - gen.addressOf(switch_label);
169              gen.add4(offset);
170            }
171            else {
172              gen.add4(defaultOffset);
173            }
174          }
175        }
176        else {
177          gen.emit(Bytecode.LOOKUPSWITCH);
178          int pad = emitPad(gen);
179          int defaultOffset = defaultOffset(gen, switch_label);
180          if(defaultOffset == 0) {
181            defaultOffset = 1 + pad + 4 + 4 + 8 * numCase();
182          }
183          gen.add4(defaultOffset);
184          gen.add4(map.size());
185          for(Iterator iter = map.values().iterator(); iter.hasNext(); ) {
186            ConstCase ca = (ConstCase)iter.next();
187            gen.add4(ca.getValue().constant().intValue());
188            int offset = gen.addressOf(ca.label(gen))
189              - gen.addressOf(switch_label);
190            gen.add4(offset);
191          }
192        }
193        gen.addLabel(end_label());
194      }
195    
196      // 15.12.2 Determine Method Signature
197    
198     
199      // 15.14.2 Postix Increment Operator ++
200      // 15.14.3 Postix Decrement Operator --
201      refine CreateBCode public void Unary.emitPostfix(CodeGeneration gen, int constant) {
202        Expr operand = getOperand();
203        while(operand instanceof ParExpr)
204          operand = ((ParExpr)operand).getExpr();
205        Access access = ((Access)operand).lastAccess();
206        access.createAssignLoadDest(gen);
207        if(needsPush())
208          access.createPushAssignmentResult(gen);
209        TypeDecl type = access.type().binaryNumericPromotion(typeInt());
210        access.type().emitCastTo(gen, type); // Added for AutoBoxing
211        type.emitPushConstant(gen, constant);
212        type.add(gen);
213        type.emitCastTo(gen, access.type());
214        access.emitStore(gen);
215      }
216    
217      // 15.15.1 Prefix Increment Operator ++
218      // 15.15.2 Prefix Decrement Operator --
219      refine CreateBCode public void Unary.emitPrefix(CodeGeneration gen, int constant) {
220        Expr operand = getOperand();
221        while(operand instanceof ParExpr)
222          operand = ((ParExpr)operand).getExpr();
223        Access access = ((Access)operand).lastAccess();
224        access.createAssignLoadDest(gen);
225        TypeDecl type = access.type().binaryNumericPromotion(typeInt());
226        access.type().emitCastTo(gen, type); // Added for AutoBoxing
227        type.emitPushConstant(gen, constant);
228        type.add(gen);
229        type.emitCastTo(gen, access.type());
230        if(needsPush())
231          access.createPushAssignmentResult(gen);
232        access.emitStore(gen);
233      }
234    
235      refine CreateBCode public void ArrayCreationExpr.createBCode(CodeGeneration gen) {
236        if(hasArrayInit()){
237          getArrayInit().createBCode(gen);
238        }
239        else {
240          getTypeAccess().createBCode(gen); // push array sizes
241          if(type().componentType().isPrimitive() && !type().componentType().isReferenceType()) {
242            gen.emit(Bytecode.NEWARRAY).add(type().componentType().arrayPrimitiveTypeDescriptor());
243          }
244          else {
245            if(numArrays() == 1) {
246              String n = type().componentType().arrayTypeDescriptor();
247              int index = gen.constantPool().addClass(n);
248              gen.emit(Bytecode.ANEWARRAY).add2(index);
249            }
250            else {
251              String n = type().arrayTypeDescriptor();
252              int index = gen.constantPool().addClass(n);
253              gen.emit(Bytecode.MULTIANEWARRAY, 1 - numArrays()).add2(index).add(numArrays());
254            }
255          }
256        }
257      }
258    
259      refine CreateBCode public void ArrayTypeWithSizeAccess.createBCode(CodeGeneration gen) {
260        getAccess().createBCode(gen);
261        getExpr().createBCode(gen);
262        if(getExpr().type().isReferenceType())
263          getExpr().type().emitUnboxingOperation(gen);
264      }
265    
266      refine CreateBCode public void ArrayInit.createBCode(CodeGeneration gen) {
267        IntegerLiteral.push(gen, getNumInit());
268        if(type().componentType().isPrimitive() && !type().componentType().isReferenceType()) {
269          gen.emit(Bytecode.NEWARRAY).add(type().componentType().arrayPrimitiveTypeDescriptor());
270        } 
271        else {
272          String n = type().componentType().arrayTypeDescriptor();
273          int index = gen.constantPool().addClass(n);
274          gen.emit(Bytecode.ANEWARRAY).add2(index);
275        }
276        for(int i = 0; i < getNumInit(); i++) {
277          gen.emitDup();
278          IntegerLiteral.push(gen, i);
279          getInit(i).createBCode(gen);
280          if(getInit(i) instanceof ArrayInit)
281            gen.emit(Bytecode.AASTORE);
282          else {
283            getInit(i).type().emitAssignConvTo(gen, expectedType()); // AssignConversion
284            gen.emit(expectedType().arrayStore());
285          }
286        }
287      }
288    
289      refine CodeGenerationConversions void TypeDecl.emitAssignConvTo(CodeGeneration gen, TypeDecl type) {
290        if(!type.isIntegralType() || !isIntegralType() || type.isLong() || type.isReferenceType() || isReferenceType())
291          emitCastTo(gen, type);
292      }
293    
294    
295      protected void Unary.boxingGen(CodeGeneration gen) {
296        getOperand().createBCode(gen);
297        TypeDecl type = getOperand().type();
298        if(type.isReferenceType())
299          type.emitCastTo(gen, type());
300        emitOperation(gen);
301      }
302    
303      public void MinusExpr.createBCode(CodeGeneration gen) { boxingGen(gen); } 
304      public void PlusExpr.createBCode(CodeGeneration gen) { boxingGen(gen); } 
305      public void BitNotExpr.createBCode(CodeGeneration gen) { boxingGen(gen); } 
306    
307      refine CreateBCode public void AssignExpr.createBCode(CodeGeneration gen) {
308        TypeDecl dest = getDest().type();
309        TypeDecl source = getSource().type();
310        TypeDecl type;
311        if(dest.isNumericType() && source.isNumericType())
312          type = dest.binaryNumericPromotion(source);
313        else if(dest.isBoolean() && source.isBoolean()) {
314          type = dest.isReferenceType() ? dest.unboxed() : dest;
315        }
316        else
317          type = dest;
318        getDest().createAssignLoadDest(gen);
319        dest.emitCastTo(gen, type);
320        getSource().createBCode(gen);
321        source.emitCastTo(gen, type);
322        createAssignOp(gen, type);
323        type.emitCastTo(gen, dest);
324        if(needsPush()) {
325          getDest().createPushAssignmentResult(gen);
326        }
327        getDest().emitStore(gen);
328      }
329    
330      public void EqualityExpr.emitEvalBranch(CodeGeneration gen) {
331        if(isTrue())
332          gen.emitGoto(true_label());
333        else if(isFalse())
334          gen.emitGoto(false_label());
335        else {
336          TypeDecl type = getLeftOperand().type();
337          if(type.isNumericType() && !(type.isReferenceType() && getRightOperand().type().isReferenceType())) {
338            type = binaryNumericPromotedType();
339            getLeftOperand().createBCode(gen);
340            getLeftOperand().type().emitCastTo(gen, type); // Binary numeric promotion
341            getRightOperand().createBCode(gen);
342            getRightOperand().type().emitCastTo(gen, type); // Binary numeric promotion
343          }
344          else if(type.isBoolean() && type != getRightOperand().type()) {
345            type = binaryNumericPromotedType();
346            getLeftOperand().createBCode(gen);
347            getLeftOperand().type().emitCastTo(gen, type); // Binary numeric promotion
348            getRightOperand().createBCode(gen);
349            getRightOperand().type().emitCastTo(gen, type); // Binary numeric promotion
350          }
351          else {
352            getLeftOperand().createBCode(gen);
353            getRightOperand().createBCode(gen);
354          }
355          compareBranch(gen, true_label(), type);
356          gen.emitGoto(false_label());
357          // compareNotBranch does not work for float comparison with NaN
358          //compareNotBranch(gen, false_label(), type);
359          //gen.emitGoto(true_label());
360        }
361      }
362    
363      refine CreateBCode public void ArrayAccess.createBCode(CodeGeneration gen) {
364        prevExpr().createBCode(gen);
365        getExpr().createBCode(gen);
366        getExpr().type().emitCastTo(gen, typeInt());
367        gen.emit(type().arrayLoad());
368      }
369    
370      refine CreateBCode public void ArrayAccess.createAssignSimpleLoadDest(CodeGeneration gen) {
371        prevExpr().createBCode(gen);
372        getExpr().createBCode(gen);
373        getExpr().type().emitCastTo(gen, typeInt());
374      }
375    
376      refine CreateBCode public void ArrayAccess.createAssignLoadDest(CodeGeneration gen) {
377        prevExpr().createBCode(gen);
378        gen.emitDup();
379        getExpr().createBCode(gen);
380        getExpr().type().emitCastTo(gen, typeInt());
381        typeInt().emitDup_x1(gen);
382        gen.emit(type().arrayLoad());
383      }
384    
385      public void ConditionalExpr.emitBooleanCondition(CodeGeneration gen) {
386        super.emitBooleanCondition(gen);
387        if(type().isReferenceType())
388          type().emitBoxingOperation(gen);
389      }
390    
391    }