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 EnhancedForToBytecode { 032 // Code generation 033 syn lazy int EnhancedForStmt.cond_label() = hostType().constantPool().newLabel(); 034 syn lazy int EnhancedForStmt.update_label() = hostType().constantPool().newLabel(); 035 syn lazy int EnhancedForStmt.end_label() = hostType().constantPool().newLabel(); 036 037 syn lazy int EnhancedForStmt.extraLocalIndex() = localNum(); 038 eq EnhancedForStmt.getVariableDeclaration().localNum() = localNum() + (getExpr().type().isArrayDecl() ? 2 : 1); 039 eq EnhancedForStmt.getStmt().localNum() = getVariableDeclaration().localNum() + getVariableDeclaration().type().size(); 040 041 // EnhancedForStmt can be both break and continue target 042 eq EnhancedForStmt.break_label() = end_label(); 043 eq EnhancedForStmt.continue_label() = update_label(); 044 045 syn lazy int EnhancedForStmt.variableScopeEndLabel(CodeGeneration gen) = 046 gen.variableScopeLabel(); 047 048 public void EnhancedForStmt.createBCode(CodeGeneration gen) { 049 VariableDeclaration decl = getVariableDeclaration(); 050 gen.addLocalVariableEntryAtCurrentPC(decl.name(), decl.type().typeDescriptor(), extraLocalIndex(), variableScopeEndLabel(gen)); 051 if (getExpr().type().isArrayDecl()) { 052 getExpr().createBCode(gen); 053 gen.emitStoreReference(extraLocalIndex()); 054 IntegerLiteral.push(gen, 0); 055 gen.emit(Bytecode.ISTORE).add(extraLocalIndex()+1); 056 gen.addLabel(cond_label()); 057 gen.emit(Bytecode.ILOAD).add(extraLocalIndex()+1); 058 gen.emitLoadReference(extraLocalIndex()); 059 gen.emit(Bytecode.ARRAYLENGTH); 060 gen.emitCompare(Bytecode.IF_ICMPGE, end_label()); 061 gen.emitLoadReference(extraLocalIndex()); 062 gen.emit(Bytecode.ILOAD).add(extraLocalIndex()+1); 063 gen.emit(getExpr().type().componentType().arrayLoad()); 064 getExpr().type().componentType().emitCastTo(gen, getVariableDeclaration().type()); 065 getVariableDeclaration().type().emitStoreLocal(gen, getVariableDeclaration().localNum()); 066 getStmt().createBCode(gen); 067 gen.addLabel(update_label()); 068 gen.emit(Bytecode.IINC).add(extraLocalIndex()+1).add(1); 069 gen.emitGoto(cond_label()); 070 gen.addLabel(end_label()); 071 } else { 072 TypeDecl typeIterable = lookupType("java.lang", "Iterable"); 073 TypeDecl typeIterator = lookupType("java.util", "Iterator"); 074 MethodDecl iteratorMethod = getMethod(typeIterable, "iterator"); 075 MethodDecl hasNextMethod = getMethod(typeIterator, "hasNext"); 076 MethodDecl nextMethod = getMethod(typeIterator, "next"); 077 getExpr().createBCode(gen); 078 iteratorMethod.emitInvokeMethod(gen, typeIterable); 079 gen.emitStoreReference(extraLocalIndex()); 080 gen.addLabel(cond_label()); 081 gen.emitLoadReference(extraLocalIndex()); 082 hasNextMethod.emitInvokeMethod(gen, typeIterator); 083 gen.emitCompare(Bytecode.IFEQ, end_label()); 084 gen.emitLoadReference(extraLocalIndex()); 085 nextMethod.emitInvokeMethod(gen, typeIterator); 086 VariableDeclaration obj = getVariableDeclaration(); 087 if (!obj.type().boxed().isUnknown()) { 088 gen.emitCheckCast(obj.type().boxed()); 089 obj.type().boxed().emitCastTo(gen, obj.type()); 090 obj.type().emitStoreLocal(gen, obj.localNum()); 091 } else { 092 gen.emitCheckCast(obj.type()); 093 gen.emitStoreReference(obj.localNum()); 094 } 095 getStmt().createBCode(gen); 096 gen.addLabel(update_label()); 097 gen.emitGoto(cond_label()); 098 gen.addLabel(end_label()); 099 } 100 gen.addVariableScopeLabel(variableScopeEndLabel(gen)); 101 } 102 103 /** 104 * Finds one method with the given name, and no parameters, in the specified 105 * type. 106 * @param type type to search for the method declaration 107 * @param name name of the method 108 * @return method declaration 109 */ 110 protected static MethodDecl ASTNode.getMethod(TypeDecl type, String name) { 111 Collection<MethodDecl> methods = (Collection<MethodDecl>) type.memberMethods(name); 112 for (MethodDecl method: methods) { 113 if (method.getNumParameter() == 0) { 114 return method; 115 } 116 } 117 throw new Error("Could not find " + type.typeName() + 118 "." + name + "()"); 119 } 120 }