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 }