001    /* Copyright (c) 2005-2008, Torbjorn Ekman
002     *                    2013, Jesper Öqvist <jesper.oqvist@cs.lth.se>
003     * All rights reserved.
004     *
005     * Redistribution and use in source and binary forms, with or without
006     * modification, are permitted provided that the following conditions are met:
007     *
008     * 1. Redistributions of source code must retain the above copyright notice,
009     * this list of conditions and the following disclaimer.
010     *
011     * 2. Redistributions in binary form must reproduce the above copyright notice,
012     * this list of conditions and the following disclaimer in the documentation
013     * and/or other materials provided with the distribution.
014     *
015     * 3. Neither the name of the copyright holder nor the names of its
016     * contributors may be used to endorse or promote products derived from this
017     * software without specific prior written permission.
018     *
019     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
020     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
021     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
022     * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
023     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
024     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
025     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
026     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
027     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
028     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
029     * POSSIBILITY OF SUCH DAMAGE.
030     */
031    
032    aspect LocalNum {
033      /**
034       * Computes size required for local variables of this statement.
035       * NB: only relevant for variable declaration statements.
036       * @return local size for declared variables
037       */
038      syn lazy int Stmt.localSize() = 0;
039    
040      eq VarDeclStmt.localSize() {
041        int size = 0;
042        for (VariableDeclaration decl: getSingleDeclList()) {
043          size += decl.localSize();
044        }
045        return size;
046      }
047    
048      syn lazy int VariableDeclaration.localSize() = type().variableSize();
049    
050      inh lazy int VariableDeclaration.localNum();
051    
052      eq VarDeclStmt.getSingleDecl(int index).localNum() {
053        if (index == 0) {
054          return localNum();
055        } else {
056          return getSingleDecl(index-1).localNum() + getSingleDecl(index-1).localSize();
057        }
058      }
059    
060      /**
061       * @return The next available local variable index.
062       */
063      inh lazy int Stmt.localNum();
064    
065      inh lazy int ParameterDeclaration.localNum();
066    
067      eq Program.getChild(int index).localNum() = 0;
068    
069      syn lazy int MethodDecl.offsetBeforeParameters() = isStatic() ? 0 : 1;
070    
071      syn lazy int MethodDecl.offsetAfterParameters() {
072        if (getNumParameter() == 0) {
073          return offsetBeforeParameters();
074        } else {
075          ParameterDeclaration last = getParameter(getNumParameter()-1);
076          return last.localNum() + last.type().variableSize();
077        }
078      }
079    
080      eq MethodDecl.getParameter(int index).localNum() {
081        if (index == 0) {
082          return offsetBeforeParameters();
083        } else {
084          ParameterDeclaration last = getParameter(index-1);
085          return last.localNum() + last.type().variableSize();
086        }
087      }
088    
089      eq InstanceInitializer.getBlock().localNum() {
090        int localNum = 1;
091        for (Iterator iter = hostType().constructors().iterator(); iter.hasNext(); ) {
092          ConstructorDecl c = (ConstructorDecl)iter.next();
093          int num = c.offsetAfterParameters();
094          if (num > localNum) {
095            localNum = num;
096          }
097        }
098        return localNum;
099      }
100    
101      inh lazy int ReturnStmt.resultSaveLocalNum();
102      eq MethodDecl.getBlock().resultSaveLocalNum() = offsetAfterParameters();
103      eq Program.getChild().resultSaveLocalNum() {
104        throw new Error("Unsupported operation resultSaveLocalNum");
105      }
106    
107      syn lazy int MethodDecl.resultOffset() = type().isVoid() ? 0 : type().variableSize();
108    
109      eq MethodDecl.getBlock().localNum() = offsetAfterParameters() + resultOffset();
110    
111      syn lazy int ConstructorDecl.offsetBeforeParameters() {
112        int i = 1;
113        if (hostType().needsEnclosing()) {
114          i++;
115        }
116        if (hostType().needsSuperEnclosing()) {
117          i++;
118        }
119        return i;
120      }
121    
122      syn lazy int ConstructorDecl.offsetFirstEnclosingVariable() {
123        int localIndex = offsetBeforeParameters();
124        Collection vars = hostType().enclosingVariables();
125        if (vars.isEmpty()) {
126          return localIndex;
127        }
128        String name = "val$" + ((Variable)vars.iterator().next()).name();
129        for (int i = 0; !getParameter(i).name().equals(name); i++) {
130          localIndex += getParameter(i).type().variableSize();
131        }
132        return localIndex;
133      }
134    
135      syn int ConstructorDecl.localIndexOfEnclosingVariable(Variable v) {
136        int localIndex  = offsetFirstEnclosingVariable();
137        Iterator iter = hostType().enclosingVariables().iterator();
138        Variable varDecl = (Variable)iter.next();
139        while(varDecl != v && iter.hasNext()) {
140          localIndex += varDecl.type().variableSize();
141          varDecl = (Variable)iter.next();
142        }
143        return localIndex;
144      }
145    
146      syn lazy int ConstructorDecl.offsetAfterParameters() {
147        if (getNumParameter() == 0) {
148          return offsetBeforeParameters();
149        } else {
150          ParameterDeclaration last = getParameter(getNumParameter()-1);
151          return last.localNum() + last.type().variableSize();
152        }
153      }
154    
155      eq ConstructorDecl.getParameter(int index).localNum() {
156        if (index == 0) {
157          return offsetBeforeParameters();
158        } else {
159          ParameterDeclaration last = getParameter(index-1);
160          return last.localNum() + last.type().variableSize();
161        }
162      }
163    
164      eq ConstructorDecl.getBlock().localNum() = offsetAfterParameters();
165    
166      eq ForStmt.getStmt().localNum() {
167        if (getNumInitStmt() == 0) {
168          return localNum();
169        } else {
170          Stmt last = getInitStmt(getNumInitStmt()-1);
171          return last.localNum() + last.localSize();
172        }
173      }
174    
175      eq ForStmt.getInitStmt(int index).localNum() {
176        if (index == 0) {
177          return localNum();
178        } else {
179          return getInitStmt(index-1).localNum() + getInitStmt(index-1).localSize();
180        }
181      }
182    
183      eq Block.getStmt(int index).localNum() {
184        if (index == 0) {
185          return localNum();
186        } else {
187          return getStmt(index-1).localNum() + getStmt(index-1).localSize();
188        }
189      }
190    
191      eq TryStmt.getChild().localNum() = localNum();
192      eq TryStmt.getFinally().localNum() = localNum();
193      eq TryStmt.getExceptionHandler().localNum() = localNum() + 1;// leave room for throwable stored by exceptionHandler
194    
195      eq BasicCatch.getBlock().localNum() = getParameter().localNum() + getParameter().type().variableSize();
196    
197      eq SynchronizedStmt.getBlock().localNum() = localNum() + 3;
198    
199      syn int TypeDecl.variableSize() = 0;
200      eq ReferenceType.variableSize() = 1;
201      eq PrimitiveType.variableSize() = 1;
202      eq LongType.variableSize() = 2;
203      eq DoubleType.variableSize() = 2;
204      eq NullType.variableSize() = 1;
205    }
206