MemberInfo.java revision 2:da1e581c933b
1/*
2 * Copyright (c) 2010, 2012, 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 jdk.nashorn.internal.tools.nasgen;
27
28import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_ARRAY_DESC;
29import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
30
31import jdk.internal.org.objectweb.asm.Opcodes;
32import jdk.internal.org.objectweb.asm.Type;
33import jdk.nashorn.internal.objects.annotations.Where;
34
35/**
36 * Details about a Java method or field annotated with any of the field/method
37 * annotations from the jdk.nashorn.internal.objects.annotations package.
38 */
39public final class MemberInfo implements Cloneable {
40    /**
41     * The different kinds of available class annotations
42     */
43    public static enum Kind {
44        /** This is a script class */
45        SCRIPT_CLASS,
46        /** This is a constructor */
47        CONSTRUCTOR,
48        /** This is a function */
49        FUNCTION,
50        /** This is a getter */
51        GETTER,
52        /** This is a setter */
53        SETTER,
54        /** This is a property */
55        PROPERTY,
56        /** This is a specialized version of a function */
57        SPECIALIZED_FUNCTION,
58        /** This is a specialized version of a constructor */
59        SPECIALIZED_CONSTRUCTOR
60    }
61
62    // keep in sync with jdk.nashorn.internal.objects.annotations.Attribute
63    static final int DEFAULT_ATTRIBUTES = 0x0;
64
65    static final int DEFAULT_ARITY = -2;
66
67    // the kind of the script annotation - one of the above constants
68    private MemberInfo.Kind kind;
69    // script property name
70    private String name;
71    // script property attributes
72    private int attributes;
73    // name of the java member
74    private String javaName;
75    // type descriptor of the java member
76    private String javaDesc;
77    // access bits of the Java field or method
78    private int javaAccess;
79    // initial value for static @Property fields
80    private Object value;
81    // class whose object is created to fill property value
82    private String initClass;
83    // arity of the Function or Constructor
84    private int arity;
85
86    private Where where;
87
88    /**
89     * @return the kind
90     */
91    public Kind getKind() {
92        return kind;
93    }
94
95    /**
96     * @param kind the kind to set
97     */
98    public void setKind(final Kind kind) {
99        this.kind = kind;
100    }
101
102    /**
103     * @return the name
104     */
105    public String getName() {
106        return name;
107    }
108
109    /**
110     * @param name the name to set
111     */
112    public void setName(final String name) {
113        this.name = name;
114    }
115
116    /**
117     * @return the attributes
118     */
119    public int getAttributes() {
120        return attributes;
121    }
122
123    /**
124     * @param attributes the attributes to set
125     */
126    public void setAttributes(final int attributes) {
127        this.attributes = attributes;
128    }
129
130    /**
131     * @return the javaName
132     */
133    public String getJavaName() {
134        return javaName;
135    }
136
137    /**
138     * @param javaName the javaName to set
139     */
140    public void setJavaName(final String javaName) {
141        this.javaName = javaName;
142    }
143
144    /**
145     * @return the javaDesc
146     */
147    public String getJavaDesc() {
148        return javaDesc;
149    }
150
151    void setJavaDesc(final String javaDesc) {
152        this.javaDesc = javaDesc;
153    }
154
155    int getJavaAccess() {
156        return javaAccess;
157    }
158
159    void setJavaAccess(final int access) {
160        this.javaAccess = access;
161    }
162
163    Object getValue() {
164        return value;
165    }
166
167    void setValue(final Object value) {
168        this.value = value;
169    }
170
171    Where getWhere() {
172        return where;
173    }
174
175    void setWhere(final Where where) {
176        this.where = where;
177    }
178
179    boolean isFinal() {
180        return (javaAccess & Opcodes.ACC_FINAL) != 0;
181    }
182
183    boolean isStatic() {
184        return (javaAccess & Opcodes.ACC_STATIC) != 0;
185    }
186
187    boolean isStaticFinal() {
188        return isStatic() && isFinal();
189    }
190
191    boolean isInstanceGetter() {
192        return kind == Kind.GETTER && where == Where.INSTANCE;
193    }
194
195    /**
196     * Check whether this MemberInfo is a getter that resides in the instance
197     * @return true if instance setter
198     */
199    boolean isInstanceSetter() {
200        return kind == Kind.SETTER && where == Where.INSTANCE;
201    }
202
203    boolean isInstanceProperty() {
204        return kind == Kind.PROPERTY && where == Where.INSTANCE;
205    }
206
207    boolean isInstanceFunction() {
208        return kind == Kind.FUNCTION && where == Where.INSTANCE;
209    }
210
211    boolean isPrototypeGetter() {
212        return kind == Kind.GETTER && where == Where.PROTOTYPE;
213    }
214
215    boolean isPrototypeSetter() {
216        return kind == Kind.SETTER && where == Where.PROTOTYPE;
217    }
218
219    boolean isPrototypeProperty() {
220        return kind == Kind.PROPERTY && where == Where.PROTOTYPE;
221    }
222
223    boolean isPrototypeFunction() {
224        return kind == Kind.FUNCTION && where == Where.PROTOTYPE;
225    }
226
227    boolean isConstructorGetter() {
228        return kind == Kind.GETTER && where == Where.CONSTRUCTOR;
229    }
230
231    boolean isConstructorSetter() {
232        return kind == Kind.SETTER && where == Where.CONSTRUCTOR;
233    }
234
235    boolean isConstructorProperty() {
236        return kind == Kind.PROPERTY && where == Where.CONSTRUCTOR;
237    }
238
239    boolean isConstructorFunction() {
240        return kind == Kind.FUNCTION && where == Where.CONSTRUCTOR;
241    }
242
243    boolean isConstructor() {
244        return kind == Kind.CONSTRUCTOR;
245    }
246
247    void verify() {
248        if (kind == Kind.CONSTRUCTOR) {
249            final Type returnType = Type.getReturnType(javaDesc);
250            if (! returnType.toString().equals(OBJECT_DESC)) {
251                error("return value should be of Object type, found" + returnType);
252            }
253            final Type[] argTypes = Type.getArgumentTypes(javaDesc);
254            if (argTypes.length < 2) {
255                error("constructor methods should have at least 2 args");
256            }
257            if (! argTypes[0].equals(Type.BOOLEAN_TYPE)) {
258                error("first argument should be of boolean type, found" + argTypes[0]);
259            }
260            if (! argTypes[1].toString().equals(OBJECT_DESC)) {
261                error("second argument should be of Object type, found" + argTypes[0]);
262            }
263
264            if (argTypes.length > 2) {
265                for (int i = 2; i < argTypes.length - 1; i++) {
266                    if (! argTypes[i].toString().equals(OBJECT_DESC)) {
267                        error(i + "'th argument should be of Object type, found " + argTypes[i]);
268                    }
269                }
270
271                final String lastArgType = argTypes[argTypes.length - 1].toString();
272                final boolean isVarArg = lastArgType.equals(OBJECT_ARRAY_DESC);
273                if (!lastArgType.equals(OBJECT_DESC) && !isVarArg) {
274                    error("last argument is neither Object nor Object[] type: " + lastArgType);
275                }
276
277                if (isVarArg && argTypes.length > 3) {
278                    error("vararg constructor has more than 3 arguments");
279                }
280            }
281        } else if (kind == Kind.FUNCTION) {
282            final Type returnType = Type.getReturnType(javaDesc);
283            if (! returnType.toString().equals(OBJECT_DESC)) {
284                error("return value should be of Object type, found" + returnType);
285            }
286            final Type[] argTypes = Type.getArgumentTypes(javaDesc);
287            if (argTypes.length < 1) {
288                error("function methods should have at least 1 arg");
289            }
290            if (! argTypes[0].toString().equals(OBJECT_DESC)) {
291                error("first argument should be of Object type, found" + argTypes[0]);
292            }
293
294            if (argTypes.length > 1) {
295                for (int i = 1; i < argTypes.length - 1; i++) {
296                    if (! argTypes[i].toString().equals(OBJECT_DESC)) {
297                        error(i + "'th argument should be of Object type, found " + argTypes[i]);
298                    }
299                }
300
301                final String lastArgType = argTypes[argTypes.length - 1].toString();
302                final boolean isVarArg = lastArgType.equals(OBJECT_ARRAY_DESC);
303                if (!lastArgType.equals(OBJECT_DESC) && !isVarArg) {
304                    error("last argument is neither Object nor Object[] type: " + lastArgType);
305                }
306
307                if (isVarArg && argTypes.length > 2) {
308                    error("vararg function has more than 2 arguments");
309                }
310            }
311        } else if (kind == Kind.GETTER) {
312            final Type[] argTypes = Type.getArgumentTypes(javaDesc);
313            if (argTypes.length != 1) {
314                error("getter methods should have one argument");
315            }
316            if (! argTypes[0].toString().equals(OBJECT_DESC)) {
317                error("first argument of getter should be of Object type, found: " + argTypes[0]);
318            }
319            if (Type.getReturnType(javaDesc).equals(Type.VOID_TYPE)) {
320                error("return type of getter should not be void");
321            }
322        } else if (kind == Kind.SETTER) {
323            final Type[] argTypes = Type.getArgumentTypes(javaDesc);
324            if (argTypes.length != 2) {
325                error("setter methods should have two arguments");
326            }
327            if (! argTypes[0].toString().equals(OBJECT_DESC)) {
328                error("first argument of setter should be of Object type, found: " + argTypes[0]);
329            }
330            if (!Type.getReturnType(javaDesc).toString().equals("V")) {
331                error("return type of setter should be void, found: " + Type.getReturnType(javaDesc));
332            }
333        }
334    }
335
336    private void error(final String msg) {
337        throw new RuntimeException(javaName + javaDesc + " : " + msg);
338    }
339
340    /**
341     * @return the initClass
342     */
343    String getInitClass() {
344        return initClass;
345    }
346
347    /**
348     * @param initClass the initClass to set
349     */
350    void setInitClass(final String initClass) {
351        this.initClass = initClass;
352    }
353
354    @Override
355    protected Object clone() {
356        try {
357            return super.clone();
358        } catch (final CloneNotSupportedException e) {
359            assert false : "clone not supported " + e;
360            return null;
361        }
362    }
363
364    /**
365     * @return the arity
366     */
367    int getArity() {
368        return arity;
369    }
370
371    /**
372     * @param arity the arity to set
373     */
374    void setArity(final int arity) {
375        this.arity = arity;
376    }
377}
378