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    }