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 }