1/***
2 * ASM: a very small and fast Java bytecode manipulation framework
3 * Copyright (c) 2000-2005 INRIA, France Telecom
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holders nor the names of its
15 *    contributors may be used to endorse or promote products derived from
16 *    this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 */
30package com.sleepycat.asm;
31
32/**
33 * An {@link FieldVisitor} that generates Java fields in bytecode form.
34 *
35 * @author Eric Bruneton
36 */
37final class FieldWriter implements FieldVisitor {
38
39    /**
40     * Next field writer (see {@link ClassWriter#firstField firstField}).
41     */
42    FieldWriter next;
43
44    /**
45     * The class writer to which this field must be added.
46     */
47    private ClassWriter cw;
48
49    /**
50     * Access flags of this field.
51     */
52    private int access;
53
54    /**
55     * The index of the constant pool item that contains the name of this
56     * method.
57     */
58    private int name;
59
60    /**
61     * The index of the constant pool item that contains the descriptor of this
62     * field.
63     */
64    private int desc;
65
66    /**
67     * The index of the constant pool item that contains the signature of this
68     * field.
69     */
70    private int signature;
71
72    /**
73     * The index of the constant pool item that contains the constant value of
74     * this field.
75     */
76    private int value;
77
78    /**
79     * The runtime visible annotations of this field. May be <tt>null</tt>.
80     */
81    private AnnotationWriter anns;
82
83    /**
84     * The runtime invisible annotations of this field. May be <tt>null</tt>.
85     */
86    private AnnotationWriter ianns;
87
88    /**
89     * The non standard attributes of this field. May be <tt>null</tt>.
90     */
91    private Attribute attrs;
92
93    // ------------------------------------------------------------------------
94    // Constructor
95    // ------------------------------------------------------------------------
96
97    /**
98     * Constructs a new {@link FieldWriter}.
99     *
100     * @param cw the class writer to which this field must be added.
101     * @param access the field's access flags (see {@link Opcodes}).
102     * @param name the field's name.
103     * @param desc the field's descriptor (see {@link Type}).
104     * @param signature the field's signature. May be <tt>null</tt>.
105     * @param value the field's constant value. May be <tt>null</tt>.
106     */
107    protected FieldWriter(
108        final ClassWriter cw,
109        final int access,
110        final String name,
111        final String desc,
112        final String signature,
113        final Object value)
114    {
115        if (cw.firstField == null) {
116            cw.firstField = this;
117        } else {
118            cw.lastField.next = this;
119        }
120        cw.lastField = this;
121        this.cw = cw;
122        this.access = access;
123        this.name = cw.newUTF8(name);
124        this.desc = cw.newUTF8(desc);
125        if (signature != null) {
126            this.signature = cw.newUTF8(signature);
127        }
128        if (value != null) {
129            this.value = cw.newConstItem(value).index;
130        }
131    }
132
133    // ------------------------------------------------------------------------
134    // Implementation of the FieldVisitor interface
135    // ------------------------------------------------------------------------
136
137    public AnnotationVisitor visitAnnotation(
138        final String desc,
139        final boolean visible)
140    {
141        ByteVector bv = new ByteVector();
142        // write type, and reserve space for values count
143        bv.putShort(cw.newUTF8(desc)).putShort(0);
144        AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
145        if (visible) {
146            aw.next = anns;
147            anns = aw;
148        } else {
149            aw.next = ianns;
150            ianns = aw;
151        }
152        return aw;
153    }
154
155    public void visitAttribute(final Attribute attr) {
156        attr.next = attrs;
157        attrs = attr;
158    }
159
160    public void visitEnd() {
161    }
162
163    // ------------------------------------------------------------------------
164    // Utility methods
165    // ------------------------------------------------------------------------
166
167    /**
168     * Returns the size of this field.
169     *
170     * @return the size of this field.
171     */
172    int getSize() {
173        int size = 8;
174        if (value != 0) {
175            cw.newUTF8("ConstantValue");
176            size += 8;
177        }
178        if ((access & Opcodes.ACC_SYNTHETIC) != 0
179                && (cw.version & 0xffff) < Opcodes.V1_5)
180        {
181            cw.newUTF8("Synthetic");
182            size += 6;
183        }
184        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
185            cw.newUTF8("Deprecated");
186            size += 6;
187        }
188        if (cw.version == Opcodes.V1_4 && (access & Opcodes.ACC_ENUM) != 0) {
189            cw.newUTF8("Enum");
190            size += 6;
191        }
192        if (signature != 0) {
193            cw.newUTF8("Signature");
194            size += 8;
195        }
196        if (anns != null) {
197            cw.newUTF8("RuntimeVisibleAnnotations");
198            size += 8 + anns.getSize();
199        }
200        if (ianns != null) {
201            cw.newUTF8("RuntimeInvisibleAnnotations");
202            size += 8 + ianns.getSize();
203        }
204        if (attrs != null) {
205            size += attrs.getSize(cw, null, 0, -1, -1);
206        }
207        return size;
208    }
209
210    /**
211     * Puts the content of this field into the given byte vector.
212     *
213     * @param out where the content of this field must be put.
214     */
215    void put(final ByteVector out) {
216        out.putShort(access).putShort(name).putShort(desc);
217        int attributeCount = 0;
218        if (value != 0) {
219            ++attributeCount;
220        }
221        if ((access & Opcodes.ACC_SYNTHETIC) != 0
222                && (cw.version & 0xffff) < Opcodes.V1_5)
223        {
224            ++attributeCount;
225        }
226        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
227            ++attributeCount;
228        }
229        if (cw.version == Opcodes.V1_4 && (access & Opcodes.ACC_ENUM) != 0) {
230            ++attributeCount;
231        }
232        if (signature != 0) {
233            ++attributeCount;
234        }
235        if (anns != null) {
236            ++attributeCount;
237        }
238        if (ianns != null) {
239            ++attributeCount;
240        }
241        if (attrs != null) {
242            attributeCount += attrs.getCount();
243        }
244        out.putShort(attributeCount);
245        if (value != 0) {
246            out.putShort(cw.newUTF8("ConstantValue"));
247            out.putInt(2).putShort(value);
248        }
249        if ((access & Opcodes.ACC_SYNTHETIC) != 0
250                && (cw.version & 0xffff) < Opcodes.V1_5)
251        {
252            out.putShort(cw.newUTF8("Synthetic")).putInt(0);
253        }
254        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
255            out.putShort(cw.newUTF8("Deprecated")).putInt(0);
256        }
257        if (cw.version == Opcodes.V1_4 && (access & Opcodes.ACC_ENUM) != 0) {
258            out.putShort(cw.newUTF8("Enum")).putInt(0);
259        }
260        if (signature != 0) {
261            out.putShort(cw.newUTF8("Signature"));
262            out.putInt(2).putShort(signature);
263        }
264        if (anns != null) {
265            out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
266            anns.put(out);
267        }
268        if (ianns != null) {
269            out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
270            ianns.put(out);
271        }
272        if (attrs != null) {
273            attrs.put(cw, null, 0, -1, -1, out);
274        }
275    }
276}
277