1/*
2 * Copyright (c) 1994, 2003, 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.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.tools.java;
27
28import sun.tools.tree.*;
29import java.util.Vector;
30import java.util.Hashtable;
31import java.io.IOException;
32import java.io.DataInputStream;
33import java.io.ByteArrayInputStream;
34
35/**
36 * This class represents a binary member
37 *
38 * WARNING: The contents of this source file are not part of any
39 * supported API.  Code that depends on them does so at its own risk:
40 * they are subject to change or removal without notice.
41 */
42public final
43class BinaryMember extends MemberDefinition {
44    Expression value;
45    BinaryAttribute atts;
46
47    /**
48     * Constructor
49     */
50    public BinaryMember(ClassDefinition clazz, int modifiers, Type type,
51                       Identifier name, BinaryAttribute atts) {
52        super(0, clazz, modifiers, type, name, null, null);
53        this.atts = atts;
54
55        // Was it compiled as deprecated?
56        if (getAttribute(idDeprecated) != null) {
57            this.modifiers |= M_DEPRECATED;
58        }
59
60        // Was it synthesized by the compiler?
61        if (getAttribute(idSynthetic) != null) {
62            this.modifiers |= M_SYNTHETIC;
63        }
64    }
65
66    /**
67     * Constructor for an inner class.
68     */
69    public BinaryMember(ClassDefinition innerClass) {
70        super(innerClass);
71    }
72
73    /**
74     * Inline allowed (currently only allowed for the constructor of Object).
75     */
76    public boolean isInlineable(Environment env, boolean fromFinal) {
77        // It is possible for 'getSuperClass()' to return null due to error
78        // recovery from cyclic inheritace.  Can this cause a problem here?
79        return isConstructor() && (getClassDefinition().getSuperClass() == null);
80    }
81
82    /**
83     * Get arguments
84     */
85    public Vector<MemberDefinition> getArguments() {
86        if (isConstructor() && (getClassDefinition().getSuperClass() == null)) {
87            Vector<MemberDefinition> v = new Vector<>();
88            v.addElement(new LocalMember(0, getClassDefinition(), 0,
89                                        getClassDefinition().getType(), idThis));
90            return v;
91        }
92        return null;
93    }
94
95    /**
96     * Get exceptions
97     */
98    public ClassDeclaration[] getExceptions(Environment env) {
99        if ((!isMethod()) || (exp != null)) {
100            return exp;
101        }
102        byte data[] = getAttribute(idExceptions);
103        if (data == null) {
104            return new ClassDeclaration[0];
105        }
106
107        try {
108            BinaryConstantPool cpool = ((BinaryClass)getClassDefinition()).getConstants();
109            DataInputStream in = new DataInputStream(new ByteArrayInputStream(data));
110            // JVM 4.7.5 Exceptions_attribute.number_of_exceptions
111            int n = in.readUnsignedShort();
112            exp = new ClassDeclaration[n];
113            for (int i = 0 ; i < n ; i++) {
114                // JVM 4.7.5 Exceptions_attribute.exception_index_table[]
115                exp[i] = cpool.getDeclaration(env, in.readUnsignedShort());
116            }
117            return exp;
118        } catch (IOException e) {
119            throw new CompilerError(e);
120        }
121    }
122
123    /**
124     * Get documentation
125     */
126    public String getDocumentation() {
127        if (documentation != null) {
128            return documentation;
129        }
130        byte data[] = getAttribute(idDocumentation);
131        if (data == null) {
132            return null;
133        }
134        try {
135            return documentation = new DataInputStream(new ByteArrayInputStream(data)).readUTF();
136        } catch (IOException e) {
137            throw new CompilerError(e);
138        }
139    }
140
141    /**
142     * Check if constant:  Will it inline away to a constant?
143     * This override is needed to solve bug 4128266.  It is also
144     * integral to the solution of 4119776.
145     */
146    private boolean isConstantCache = false;
147    private boolean isConstantCached = false;
148    public boolean isConstant() {
149        if (!isConstantCached) {
150            isConstantCache = isFinal()
151                              && isVariable()
152                              && getAttribute(idConstantValue) != null;
153            isConstantCached = true;
154        }
155        return isConstantCache;
156    }
157
158    /**
159     * Get the value
160     */
161    public Node getValue(Environment env) {
162        if (isMethod()) {
163            return null;
164        }
165        if (!isFinal()) {
166            return null;
167        }
168        if (getValue() != null) {
169            return (Expression)getValue();
170        }
171        byte data[] = getAttribute(idConstantValue);
172        if (data == null) {
173            return null;
174        }
175
176        try {
177            BinaryConstantPool cpool = ((BinaryClass)getClassDefinition()).getConstants();
178            // JVM 4.7.3 ConstantValue.constantvalue_index
179            Object obj = cpool.getValue(new DataInputStream(new ByteArrayInputStream(data)).readUnsignedShort());
180            switch (getType().getTypeCode()) {
181              case TC_BOOLEAN:
182                setValue(new BooleanExpression(0, ((Number)obj).intValue() != 0));
183                break;
184              case TC_BYTE:
185              case TC_SHORT:
186              case TC_CHAR:
187              case TC_INT:
188                setValue(new IntExpression(0, ((Number)obj).intValue()));
189                break;
190              case TC_LONG:
191                setValue(new LongExpression(0, ((Number)obj).longValue()));
192                break;
193              case TC_FLOAT:
194                setValue(new FloatExpression(0, ((Number)obj).floatValue()));
195                break;
196              case TC_DOUBLE:
197                setValue(new DoubleExpression(0, ((Number)obj).doubleValue()));
198                break;
199              case TC_CLASS:
200                setValue(new StringExpression(0, (String)cpool.getValue(((Number)obj).intValue())));
201                break;
202            }
203            return (Expression)getValue();
204        } catch (IOException e) {
205            throw new CompilerError(e);
206        }
207    }
208
209    /**
210     * Get a field attribute
211     */
212    public byte[] getAttribute(Identifier name) {
213        for (BinaryAttribute att = atts ; att != null ; att = att.next) {
214            if (att.name.equals(name)) {
215                return att.data;
216            }
217        }
218        return null;
219    }
220
221    public boolean deleteAttribute(Identifier name) {
222        BinaryAttribute walker = null, next = null;
223
224        boolean succeed = false;
225
226        while (atts.name.equals(name)) {
227            atts = atts.next;
228            succeed = true;
229        }
230        for (walker = atts; walker != null; walker = next) {
231            next = walker.next;
232            if (next != null) {
233                if (next.name.equals(name)) {
234                    walker.next = next.next;
235                    next = next.next;
236                    succeed = true;
237                }
238            }
239        }
240        for (walker = atts; walker != null; walker = walker.next) {
241            if (walker.name.equals(name)) {
242                throw new InternalError("Found attribute " + name);
243            }
244        }
245
246        return succeed;
247    }
248
249
250
251    /*
252     * Add an attribute to a field
253     */
254    public void addAttribute(Identifier name, byte data[], Environment env) {
255        this.atts = new BinaryAttribute(name, data, this.atts);
256        // Make sure that the new attribute is in the constant pool
257        ((BinaryClass)(this.clazz)).cpool.indexString(name.toString(), env);
258    }
259
260}
261