1 /*
  2  * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 package org.openjdk.asmtools.jasm;
 24 
 25 import org.openjdk.asmtools.jasm.Tables.AttrTag;
 26 import org.openjdk.asmtools.jasm.ConstantPool.ConstCell;
 27 import java.io.IOException;
 28 import java.util.ArrayList;
 29 import java.util.List;
 30 import java.util.TreeMap;
 31 
 32 /**
 33  *
 34  */
 35 class MethodData extends MemberData {
 36 
 37     /**
 38      * MethodParamData
 39      */
 40     class ParamNameData implements Data {
 41 
 42         int access;
 43         ConstCell name;
 44 
 45         public ParamNameData(int access, ConstCell name) {
 46             this.access = access;
 47             this.name = name;
 48         }
 49 
 50         @Override
 51         public int getLength() {
 52             return 4;
 53         }
 54 
 55         @Override
 56         public void write(CheckedDataOutputStream out) throws IOException {
 57             int nm = 0;
 58             int ac = 0;
 59             if (name != null) {
 60                 nm = name.arg;
 61                 ac = access;
 62             }
 63             out.writeShort(nm);
 64             out.writeShort(ac);
 65         }
 66     }// end class MethodParamData
 67 
 68     /**
 69      * Used to store Parameter Arrays (as attributes)
 70      */
 71     static public class DataPArrayAttr<T extends Data> extends AttrData implements Constants {
 72 
 73         TreeMap<Integer, ArrayList<T>> elements; // Data
 74         int paramsTotal;
 75 
 76         public DataPArrayAttr(ClassData cls, String name, int paramsTotal, TreeMap<Integer, ArrayList<T>> elements) {
 77             super(cls, name);
 78             this.paramsTotal = paramsTotal;
 79             this.elements = elements;
 80         }
 81 
 82         public DataPArrayAttr(ClassData cls, String name, int paramsTotal) {
 83             this(cls, name, paramsTotal, new TreeMap<Integer, ArrayList<T>>());
 84         }
 85 
 86         public void put(int paramNum, T element) {
 87             ArrayList<T> v = get(paramNum);
 88             if (v == null) {
 89                 v = new ArrayList<>();
 90                 elements.put(paramNum, v);
 91             }
 92 
 93             v.add(element);
 94         }
 95 
 96         public ArrayList<T> get(int paramNum) {
 97             return elements.get(paramNum);
 98         }
 99 
100         @Override
101         public int attrLength() {
102             int length = 1;  // One byte for the parameter count
103 
104             // calculate overall size here rather than in add()
105             // because it may not be available at the time of invoking of add()
106             for (int i = 0; i < paramsTotal; i++) {
107                 ArrayList<T> attrarray = get(i);
108                 if (attrarray != null) {
109                     for (Data item : attrarray) {
110                         length += item.getLength();
111                     }
112                 }
113                 length += 2; // 2 bytes for the annotation count for each parameter
114             }
115 
116             return length;
117         }
118 
119         @Override
120         public void write(CheckedDataOutputStream out) throws IOException {
121             super.write(out);  // attr name, attr len
122             out.writeByte(paramsTotal); // number of parameters total (in byte)
123 
124             for (int i = 0; i < paramsTotal; i++) {
125                 ArrayList<T> attrarray = get(i);
126                 if (attrarray != null) {
127                     // write out the number of annotations for the current param
128                     out.writeShort(attrarray.size());
129                     for (T item : attrarray) {
130                         item.write(out); // write the current annotation
131                     }
132                 } else {
133                     out.writeShort(0);
134                     // No annotations to write out
135                 }
136             }
137         }
138     }// end class DataPArrayAttr
139 
140 
141     /* Method Data Fields */
142     protected Environment env;
143     protected ConstCell nameCell, sigCell;
144     protected CodeAttr code;
145     protected DataVectorAttr<ConstCell> exceptions = null;
146     protected DataVectorAttr<ParamNameData> paramNames = null;
147     protected DataPArrayAttr<AnnotationData> pannotAttrVis = null;
148     protected DataPArrayAttr<AnnotationData> pannotAttrInv = null;
149     protected DefaultAnnotationAttr defaultAnnot = null;
150 
151     public MethodData(ClassData cls, int acc,
152             ConstCell name, ConstCell sig, ArrayList<ConstCell> exc_table) {
153         super(cls, acc);
154         this.env = cls.env;
155         nameCell = name;
156         sigCell = sig;
157         if ((exc_table != null) && (!exc_table.isEmpty())) {
158             exceptions = new DataVectorAttr<>(cls,
159                     AttrTag.ATT_Exceptions.parsekey(),
160                     exc_table);
161         }
162         // Normalize the modifiers to access flags
163         if (Modifiers.hasPseudoMod(acc)) {
164             createPseudoMod();
165         }
166     }
167 
168     public void addMethodParameter(int totalParams, int paramNum, ConstCell name, int access) {
169         env.traceln("addMethodParameter Param[" + paramNum + "] (name: " + name.toString() + ", Flags (" + access + ").");
170         if (paramNames == null) {
171             paramNames = new DataVectorAttr<>(cls, AttrTag.ATT_MethodParameters.parsekey(), true);
172             for (int i = 0; i < totalParams; i++) {
173                 // initialize the paramName array (in case the name is not given in Jasm syntax)
174                 paramNames.add(new ParamNameData(0, null));
175             }
176         }
177         paramNames.put(paramNum, new ParamNameData(access, name));
178     }
179 
180     public CodeAttr startCode(int pos, int paramcnt, Argument max_stack, Argument max_locals) {
181         code = new CodeAttr(this, pos, paramcnt, max_stack, max_locals);
182         return code;
183     }
184 
185     public void addDefaultAnnotation(DefaultAnnotationAttr data) {
186         defaultAnnot = data;
187     }
188 
189     public void addParamAnnotation(int totalParams, int paramNum, AnnotationData data) {
190         if (!data.invisible) {
191             if (pannotAttrVis == null) {
192                 pannotAttrVis = new DataPArrayAttr<>(cls,
193                         AttrTag.ATT_RuntimeVisibleParameterAnnotations.parsekey(),
194                         totalParams);
195             }
196             pannotAttrVis.put(paramNum, data);
197 
198         } else {
199             if (pannotAttrInv == null) {
200                 pannotAttrInv = new DataPArrayAttr<>(cls,
201                         AttrTag.ATT_RuntimeInvisibleParameterAnnotations.parsekey(),
202                         totalParams);
203             }
204             pannotAttrInv.put(paramNum, data);
205         }
206     }
207 
208     @Override
209     protected DataVector getAttrVector() {
210         DataVector dv = getDataVector( exceptions, syntheticAttr, deprecatedAttr, paramNames, code, defaultAnnot);
211         if (pannotAttrVis != null) {
212             dv.add(pannotAttrVis);
213         }
214         if (pannotAttrInv != null) {
215             dv.add(pannotAttrInv);
216         }
217         return dv;
218     }
219 
220     /*====================================================== Write */
221     public void write(CheckedDataOutputStream out) throws IOException, Parser.CompilerError {
222         out.writeShort(access);
223         out.writeShort(nameCell.arg);
224         out.writeShort(sigCell.arg);
225         getAttrVector().write(out);
226     }
227 } // end MethodData
228