001    /* Copyright (c) 2005-2008, Torbjorn Ekman
002     * All rights reserved.
003     *
004     * Redistribution and use in source and binary forms, with or without
005     * modification, are permitted provided that the following conditions are met:
006     *
007     * 1. Redistributions of source code must retain the above copyright notice,
008     * this list of conditions and the following disclaimer.
009     *
010     * 2. Redistributions in binary form must reproduce the above copyright notice,
011     * this list of conditions and the following disclaimer in the documentation
012     * and/or other materials provided with the distribution.
013     *
014     * 3. Neither the name of the copyright holder nor the names of its
015     * contributors may be used to endorse or promote products derived from this
016     * software without specific prior written permission.
017     *
018     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021     * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
022     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
028     * POSSIBILITY OF SUCH DAMAGE.
029     */
030    
031    aspect AutoBoxingCodegen {
032        // Code generation for Boxing Conversion
033      refine CodeGenerationConversions void BooleanType.emitCastTo(CodeGeneration gen, TypeDecl type) {
034        if (type.unboxed() == this || type.isObject()) {
035          boxed().emitBoxingOperation(gen);
036        }
037      }
038      void ReferenceType.byteToThis(CodeGeneration gen) {
039        if (isUnknown()) {
040          throw new Error("Trying to cast to Unknown");
041        }
042        if (!isNumericType()) {
043          typeByte().boxed().byteToThis(gen);
044        } else {
045          unboxed().byteToThis(gen);
046          emitBoxingOperation(gen);
047        }
048      }
049      void ReferenceType.charToThis(CodeGeneration gen) {
050        if (isUnknown()) {
051          throw new Error("Trying to cast to Unknown");
052        }
053        if (!isNumericType()) {
054          typeChar().boxed().charToThis(gen);
055        } else {
056          unboxed().charToThis(gen);
057          emitBoxingOperation(gen);
058        }
059      }
060      void ReferenceType.shortToThis(CodeGeneration gen) {
061        if (isUnknown()) {
062          throw new Error("Trying to cast to Unknown");
063        }
064        if (!isNumericType()) {
065          typeShort().boxed().shortToThis(gen);
066        } else {
067          unboxed().shortToThis(gen);
068          emitBoxingOperation(gen);
069        }
070      }
071      void ReferenceType.intToThis(CodeGeneration gen) {
072        if (isUnknown()) {
073          throw new Error("Trying to cast to Unknown");
074        }
075        if (!isNumericType()) {
076          typeInt().boxed().intToThis(gen);
077        } else {
078          unboxed().intToThis(gen);
079          emitBoxingOperation(gen);
080        }
081      }
082      void ReferenceType.longToThis(CodeGeneration gen) {
083        if (isUnknown()) {
084          throw new Error("Trying to cast to Unknown");
085        }
086        if (!isNumericType()) {
087          typeLong().boxed().longToThis(gen);
088        } else {
089          unboxed().longToThis(gen);
090          emitBoxingOperation(gen);
091        }
092      }
093      void ReferenceType.floatToThis(CodeGeneration gen) {
094        if (isUnknown()) {
095          throw new Error("Trying to cast to Unknown");
096        }
097        if (!isNumericType()) {
098          typeFloat().boxed().floatToThis(gen);
099        } else {
100          unboxed().floatToThis(gen);
101          emitBoxingOperation(gen);
102        }
103      }
104      void ReferenceType.doubleToThis(CodeGeneration gen) {
105        if (isUnknown()) {
106          throw new Error("Trying to cast to Unknown");
107        }
108        if (!isNumericType()) {
109          typeDouble().boxed().doubleToThis(gen);
110        } else {
111          unboxed().doubleToThis(gen);
112          emitBoxingOperation(gen);
113        }
114      }
115      protected void TypeDecl.emitBoxingOperation(CodeGeneration gen) {
116        // Box the value on the stack into this Reference type
117        String classname = constantPoolName();
118        String desc = "(" + unboxed().typeDescriptor() + ")" + typeDescriptor();
119        String name = "valueOf";
120        int index = gen.constantPool().addMethodref(classname, name, desc);
121        gen.emit(Bytecode.INVOKESTATIC, variableSize() - unboxed().variableSize()).add2(index);
122      }
123    
124      // Code generation for Unboxing Conversion
125      refine CodeGenerationConversions public void ReferenceType.emitCastTo(CodeGeneration gen, TypeDecl type) {
126        if (type instanceof PrimitiveType) {
127          emitUnboxingOperation(gen);
128          unboxed().emitCastTo(gen, type);
129        } else {
130          refined(gen, type);
131        }
132      }
133      protected void TypeDecl.emitUnboxingOperation(CodeGeneration gen) {
134        // Unbox the value on the stack from this Reference type
135        String classname = constantPoolName();
136        String desc = "(" + ")" + unboxed().typeDescriptor();
137        String name = unboxed().name() + "Value";
138        int index = gen.constantPool().addMethodref(classname, name, desc);
139        gen.emit(Bytecode.INVOKEVIRTUAL, unboxed().variableSize() - 1).add2(index);
140      }
141    
142      /**
143       * Generate unboxing code for conditions
144       * 14.9 If, 14.12 While, 14.13 Do, 14.14 For
145       *
146       * branchTrue is used to emit the condition from these constructs
147       * refine behavior to include unboxing of the value when needed
148       */
149      refine CreateBCode public void Expr.branchTrue(CodeGeneration gen, int target) {
150        // branch when true
151        if (type().isReferenceType()) {
152          createBCode(gen);
153          type().emitUnboxingOperation(gen);
154          gen.emitCompare(Bytecode.IFNE, target);
155          //gen.IFNE(target);
156        } else {
157          refined(gen, target);
158        }
159      }
160    
161      refine CreateBCode public void Expr.branchFalse(CodeGeneration gen, int target) {
162        // branch when false
163        if (type().isReferenceType()) {
164          createBCode(gen);
165          type().emitUnboxingOperation(gen);
166          gen.emitCompare(Bytecode.IFEQ, target);
167          //gen.IFEQ(target);
168        } else {
169          refined(gen, target);
170        }
171      }
172    
173      // 14.11 Switch
174      refine CreateBCode public void SwitchStmt.createBCode(CodeGeneration gen) {
175        super.createBCode(gen);
176        int cond_label = gen.constantPool().newLabel();
177        int switch_label = gen.constantPool().newLabel();
178    
179        gen.emitGoto(cond_label);
180        getBlock().createBCode(gen);
181        if (canCompleteNormally()) {
182          gen.emitGoto(end_label());
183        }
184        gen.addLabel(cond_label);
185        getExpr().createBCode(gen);
186        if (getExpr().type().isReferenceType()) {
187          getExpr().type().emitUnboxingOperation(gen);
188        }
189    
190        TreeMap map = new TreeMap();
191        for (int i = 0; i < getBlock().getNumStmt(); i++) {
192          if (getBlock().getStmt(i) instanceof ConstCase) {
193            ConstCase ca = (ConstCase) getBlock().getStmt(i);
194            map.put(new Integer(ca.getValue().constant().intValue()), ca);
195          }
196        }
197    
198        long low = map.isEmpty() ? 0 : ((Integer) map.firstKey()).intValue();
199        long high = map.isEmpty() ? 0 : ((Integer) map.lastKey()).intValue();
200    
201        long tableSwitchSize = 8L + (high - low + 1L) * 4L;
202        long lookupSwitchSize = 4L + map.size() * 8L;
203    
204        gen.addLabel(switch_label);
205        if (tableSwitchSize < lookupSwitchSize) {
206          gen.emit(Bytecode.TABLESWITCH);
207          int pad = emitPad(gen);
208          int defaultOffset = defaultOffset(gen, switch_label);
209          if (defaultOffset == 0) {
210            defaultOffset = 1 + pad + 4 + 4 + 4 + 4 * (int)(high - low + 1);
211          }
212          gen.add4(defaultOffset);
213          gen.add4((int) low);
214          gen.add4((int) high);
215          for (long i = low; i <= high; i++) {
216            ConstCase ca = (ConstCase) map.get(new Integer((int) i));
217            if (ca != null) {
218              int offset = gen.addressOf(ca.label())
219                - gen.addressOf(switch_label);
220              gen.add4(offset);
221            } else {
222              gen.add4(defaultOffset);
223            }
224          }
225        } else {
226          gen.emit(Bytecode.LOOKUPSWITCH);
227          int pad = emitPad(gen);
228          int defaultOffset = defaultOffset(gen, switch_label);
229          if (defaultOffset == 0) {
230            defaultOffset = 1 + pad + 4 + 4 + 8 * numCase();
231          }
232          gen.add4(defaultOffset);
233          gen.add4(map.size());
234          for (Iterator iter = map.values().iterator(); iter.hasNext(); ) {
235            ConstCase ca = (ConstCase) iter.next();
236            gen.add4(ca.getValue().constant().intValue());
237            int offset = gen.addressOf(ca.label())
238              - gen.addressOf(switch_label);
239            gen.add4(offset);
240          }
241        }
242        gen.addLabel(end_label());
243      }
244    
245      // 15.12.2 Determine Method Signature
246    
247    
248      // 15.14.2 Postix Increment Operator ++
249      // 15.14.3 Postix Decrement Operator --
250      refine CreateBCode public void Unary.emitPostfix(CodeGeneration gen, int constant) {
251        Expr operand = getOperand();
252        while (operand instanceof ParExpr) {
253          operand = ((ParExpr) operand).getExpr();
254        }
255        Access access = ((Access) operand).lastAccess();
256        access.createAssignLoadDest(gen);
257        if (needsPush()) {
258          access.createPushAssignmentResult(gen);
259        }
260        TypeDecl type = access.type().binaryNumericPromotion(typeInt());
261        access.type().emitCastTo(gen, type); // Added for AutoBoxing
262        type.emitPushConstant(gen, constant);
263        type.add(gen);
264        type.emitCastTo(gen, access.type());
265        access.emitStore(gen);
266      }
267    
268      // 15.15.1 Prefix Increment Operator ++
269      // 15.15.2 Prefix Decrement Operator --
270      refine CreateBCode public void Unary.emitPrefix(CodeGeneration gen, int constant) {
271        Expr operand = getOperand();
272        while (operand instanceof ParExpr) {
273          operand = ((ParExpr) operand).getExpr();
274        }
275        Access access = ((Access) operand).lastAccess();
276        access.createAssignLoadDest(gen);
277        TypeDecl type = access.type().binaryNumericPromotion(typeInt());
278        access.type().emitCastTo(gen, type); // Added for AutoBoxing
279        type.emitPushConstant(gen, constant);
280        type.add(gen);
281        type.emitCastTo(gen, access.type());
282        if (needsPush()) {
283          access.createPushAssignmentResult(gen);
284        }
285        access.emitStore(gen);
286      }
287    
288      refine CreateBCode public void ArrayCreationExpr.createBCode(CodeGeneration gen) {
289        if (hasArrayInit()){
290          getArrayInit().createBCode(gen);
291        } else {
292          getTypeAccess().createBCode(gen); // push array sizes
293          if (type().componentType().isPrimitive() && !type().componentType().isReferenceType()) {
294            gen.emit(Bytecode.NEWARRAY).add(type().componentType().arrayPrimitiveTypeDescriptor());
295          } else {
296            if (numArrays() == 1) {
297              String n = type().componentType().arrayTypeDescriptor();
298              int index = gen.constantPool().addClass(n);
299              gen.emit(Bytecode.ANEWARRAY).add2(index);
300            } else {
301              String n = type().arrayTypeDescriptor();
302              int index = gen.constantPool().addClass(n);
303              gen.emit(Bytecode.MULTIANEWARRAY, 1 - numArrays()).add2(index).add(numArrays());
304            }
305          }
306        }
307      }
308    
309      refine CreateBCode public void ArrayTypeWithSizeAccess.createBCode(CodeGeneration gen) {
310        getAccess().createBCode(gen);
311        getExpr().createBCode(gen);
312        if (getExpr().type().isReferenceType()) {
313          getExpr().type().emitUnboxingOperation(gen);
314        }
315      }
316    
317      refine CreateBCode public void ArrayInit.createBCode(CodeGeneration gen) {
318        IntegerLiteral.push(gen, getNumInit());
319        if (type().componentType().isPrimitive() && !type().componentType().isReferenceType()) {
320          gen.emit(Bytecode.NEWARRAY).add(type().componentType().arrayPrimitiveTypeDescriptor());
321        } else {
322          String n = type().componentType().arrayTypeDescriptor();
323          int index = gen.constantPool().addClass(n);
324          gen.emit(Bytecode.ANEWARRAY).add2(index);
325        }
326        for (int i = 0; i < getNumInit(); i++) {
327          gen.emitDup();
328          IntegerLiteral.push(gen, i);
329          getInit(i).createBCode(gen);
330          if (getInit(i) instanceof ArrayInit) {
331            gen.emit(Bytecode.AASTORE);
332          } else {
333            getInit(i).type().emitAssignConvTo(gen, expectedType()); // AssignConversion
334            gen.emit(expectedType().arrayStore());
335          }
336        }
337      }
338    
339      refine CodeGenerationConversions void TypeDecl.emitAssignConvTo(CodeGeneration gen, TypeDecl type) {
340        if (!type.isIntegralType() || !isIntegralType() || type.isLong() || type.isReferenceType() || isReferenceType()) {
341          emitCastTo(gen, type);
342        }
343      }
344    
345    
346      protected void Unary.boxingGen(CodeGeneration gen) {
347        getOperand().createBCode(gen);
348        TypeDecl type = getOperand().type();
349        if (type.isReferenceType()) {
350          type.emitCastTo(gen, type());
351        }
352        emitOperation(gen);
353      }
354    
355      public void MinusExpr.createBCode(CodeGeneration gen) { boxingGen(gen); }
356      public void PlusExpr.createBCode(CodeGeneration gen) { boxingGen(gen); }
357      public void BitNotExpr.createBCode(CodeGeneration gen) { boxingGen(gen); }
358    
359      refine CreateBCode public void AssignExpr.createBCode(CodeGeneration gen) {
360        TypeDecl dest = getDest().type();
361        TypeDecl source = getSource().type();
362        TypeDecl type;
363        if (dest.isNumericType() && source.isNumericType()) {
364          type = dest.binaryNumericPromotion(source);
365        } else if (dest.isBoolean() && source.isBoolean()) {
366          type = dest.isReferenceType() ? dest.unboxed() : dest;
367        } else {
368          type = dest;
369        }
370        getDest().createAssignLoadDest(gen);
371        dest.emitCastTo(gen, type);
372        getSource().createBCode(gen);
373        source.emitCastTo(gen, type);
374        createAssignOp(gen, type);
375        type.emitCastTo(gen, dest);
376        if (needsPush()) {
377          getDest().createPushAssignmentResult(gen);
378        }
379        getDest().emitStore(gen);
380      }
381    
382      public void EqualityExpr.branchTrue(CodeGeneration gen, int target) {
383        // branch when true
384        if (isConstant()) {
385          if (isTrue()) {
386            gen.emitGoto(target);
387            //gen.GOTO(target);
388            return;
389          }
390        } else {
391          TypeDecl type = getLeftOperand().type();
392          if (type.isNumericType() && !(type.isReferenceType() && getRightOperand().type().isReferenceType())) {
393            type = binaryNumericPromotedType();
394            getLeftOperand().createBCode(gen);
395            getLeftOperand().type().emitCastTo(gen, type); // Binary numeric promotion
396            getRightOperand().createBCode(gen);
397            getRightOperand().type().emitCastTo(gen, type); // Binary numeric promotion
398          } else if (type.isBoolean() && type != getRightOperand().type()) {
399            type = binaryNumericPromotedType();
400            getLeftOperand().createBCode(gen);
401            getLeftOperand().type().emitCastTo(gen, type); // Binary numeric promotion
402            getRightOperand().createBCode(gen);
403            getRightOperand().type().emitCastTo(gen, type); // Binary numeric promotion
404          } else {
405            getLeftOperand().createBCode(gen);
406            getRightOperand().createBCode(gen);
407          }
408          compareBranch(gen, target, type);
409        }
410      }
411    
412      public void EqualityExpr.branchFalse(CodeGeneration gen, int target) {
413        // branch when false
414        if (isConstant()) {
415          if (isFalse()) {
416            gen.emitGoto(target);
417            //gen.GOTO(target);
418            return;
419          }
420        } else {
421          TypeDecl type = getLeftOperand().type();
422          if (type.isNumericType() && !(type.isReferenceType() && getRightOperand().type().isReferenceType())) {
423            type = binaryNumericPromotedType();
424            getLeftOperand().createBCode(gen);
425            getLeftOperand().type().emitCastTo(gen, type); // Binary numeric promotion
426            getRightOperand().createBCode(gen);
427            getRightOperand().type().emitCastTo(gen, type); // Binary numeric promotion
428          } else if (type.isBoolean() && type != getRightOperand().type()) {
429            type = binaryNumericPromotedType();
430            getLeftOperand().createBCode(gen);
431            getLeftOperand().type().emitCastTo(gen, type); // Binary numeric promotion
432            getRightOperand().createBCode(gen);
433            getRightOperand().type().emitCastTo(gen, type); // Binary numeric promotion
434          } else {
435            getLeftOperand().createBCode(gen);
436            getRightOperand().createBCode(gen);
437          }
438          compareNotBranch(gen, target, type);
439        }
440      }
441    
442      refine CreateBCode public void ArrayAccess.createBCode(CodeGeneration gen) {
443        prevExpr().createBCode(gen);
444        getExpr().createBCode(gen);
445        getExpr().type().emitCastTo(gen, typeInt());
446        gen.emit(type().arrayLoad());
447      }
448    
449      refine CreateBCode public void ArrayAccess.createAssignSimpleLoadDest(CodeGeneration gen) {
450        prevExpr().createBCode(gen);
451        getExpr().createBCode(gen);
452        getExpr().type().emitCastTo(gen, typeInt());
453      }
454    
455      refine CreateBCode public void ArrayAccess.createAssignLoadDest(CodeGeneration gen) {
456        prevExpr().createBCode(gen);
457        gen.emitDup();
458        getExpr().createBCode(gen);
459        getExpr().type().emitCastTo(gen, typeInt());
460        typeInt().emitDup_x1(gen);
461        gen.emit(type().arrayLoad());
462      }
463    
464      public void ConditionalExpr.emitBooleanCondition(CodeGeneration gen) {
465        super.emitBooleanCondition(gen);
466        if (type().isReferenceType()) {
467          type().emitBoxingOperation(gen);
468        }
469      }
470    
471    }