ScriptClassInfo.java revision 1326:a35490e96dc5
1/*
2 * Copyright (c) 2010, 2013, 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 java.util.Collections;
29import java.util.HashMap;
30import java.util.LinkedList;
31import java.util.List;
32import java.util.Map;
33import jdk.internal.org.objectweb.asm.Type;
34import jdk.nashorn.internal.objects.annotations.Constructor;
35import jdk.nashorn.internal.objects.annotations.Function;
36import jdk.nashorn.internal.objects.annotations.Getter;
37import jdk.nashorn.internal.objects.annotations.Property;
38import jdk.nashorn.internal.objects.annotations.ScriptClass;
39import jdk.nashorn.internal.objects.annotations.Setter;
40import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
41import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
42import jdk.nashorn.internal.objects.annotations.Where;
43import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind;
44
45/**
46 * All annotation information from a class that is annotated with
47 * the annotation com.sun.oracle.objects.annotations.ScriptClass.
48 *
49 */
50public final class ScriptClassInfo {
51    // descriptots for various annotations
52    static final String SCRIPT_CLASS_ANNO_DESC  = Type.getDescriptor(ScriptClass.class);
53    static final String CONSTRUCTOR_ANNO_DESC   = Type.getDescriptor(Constructor.class);
54    static final String FUNCTION_ANNO_DESC      = Type.getDescriptor(Function.class);
55    static final String GETTER_ANNO_DESC        = Type.getDescriptor(Getter.class);
56    static final String SETTER_ANNO_DESC        = Type.getDescriptor(Setter.class);
57    static final String PROPERTY_ANNO_DESC      = Type.getDescriptor(Property.class);
58    static final String WHERE_ENUM_DESC         = Type.getDescriptor(Where.class);
59    static final String LINK_LOGIC_DESC         = Type.getDescriptor(LinkLogic.class);
60    static final String SPECIALIZED_FUNCTION    = Type.getDescriptor(SpecializedFunction.class);
61
62    static final Map<String, Kind> annotations = new HashMap<>();
63
64    static {
65        annotations.put(SCRIPT_CLASS_ANNO_DESC, Kind.SCRIPT_CLASS);
66        annotations.put(FUNCTION_ANNO_DESC, Kind.FUNCTION);
67        annotations.put(CONSTRUCTOR_ANNO_DESC, Kind.CONSTRUCTOR);
68        annotations.put(GETTER_ANNO_DESC, Kind.GETTER);
69        annotations.put(SETTER_ANNO_DESC, Kind.SETTER);
70        annotations.put(PROPERTY_ANNO_DESC, Kind.PROPERTY);
71        annotations.put(SPECIALIZED_FUNCTION, Kind.SPECIALIZED_FUNCTION);
72    }
73
74    // name of the script class
75    private String name;
76    // member info for script properties
77    private List<MemberInfo> members = Collections.emptyList();
78    // java class name that is annotated with @ScriptClass
79    private String javaName;
80
81    /**
82     * @return the name
83     */
84    public String getName() {
85        return name;
86    }
87
88    /**
89     * @param name the name to set
90     */
91    public void setName(final String name) {
92        this.name = name;
93    }
94
95    /**
96     * @return the members
97     */
98    public List<MemberInfo> getMembers() {
99        return Collections.unmodifiableList(members);
100    }
101
102    /**
103     * @param members the members to set
104     */
105    public void setMembers(final List<MemberInfo> members) {
106        this.members = members;
107    }
108
109    MemberInfo getConstructor() {
110        for (final MemberInfo memInfo : members) {
111            if (memInfo.getKind() == Kind.CONSTRUCTOR) {
112                return memInfo;
113            }
114        }
115        return null;
116    }
117
118    List<MemberInfo> getSpecializedConstructors() {
119        final List<MemberInfo> res = new LinkedList<>();
120        for (final MemberInfo memInfo : members) {
121            if (memInfo.isSpecializedConstructor()) {
122                assert memInfo.getKind() == Kind.SPECIALIZED_FUNCTION;
123                res.add(memInfo);
124            }
125        }
126        return Collections.unmodifiableList(res);
127    }
128
129    boolean isConstructorNeeded() {
130        // Constructor class generation is needed if we one or
131        // more constructor properties are defined or @Constructor
132        // is defined in the class.
133        for (final MemberInfo memInfo : members) {
134            if (memInfo.getKind() == Kind.CONSTRUCTOR ||
135                memInfo.getWhere() == Where.CONSTRUCTOR) {
136                return true;
137            }
138        }
139        return false;
140    }
141
142    boolean isPrototypeNeeded() {
143        // Prototype class generation is needed if we have atleast one
144        // prototype property or @Constructor defined in the class.
145        for (final MemberInfo memInfo : members) {
146            if (memInfo.getWhere() == Where.PROTOTYPE || memInfo.isConstructor()) {
147                return true;
148            }
149        }
150        return false;
151    }
152
153    int getPrototypeMemberCount() {
154        int count = 0;
155        for (final MemberInfo memInfo : members) {
156            switch (memInfo.getKind()) {
157                case SETTER:
158                case SPECIALIZED_FUNCTION:
159                    // SETTER was counted when GETTER was encountered.
160                    // SPECIALIZED_FUNCTION was counted as FUNCTION already.
161                    continue;
162            }
163
164            if (memInfo.getWhere() == Where.PROTOTYPE) {
165                count++;
166            }
167        }
168        return count;
169    }
170
171    int getConstructorMemberCount() {
172        int count = 0;
173        for (final MemberInfo memInfo : members) {
174            switch (memInfo.getKind()) {
175                case CONSTRUCTOR:
176                case SETTER:
177                case SPECIALIZED_FUNCTION:
178                    // SETTER was counted when GETTER was encountered.
179                    // Constructor and constructor SpecializedFunctions
180                    // are not added as members and so not counted.
181                    continue;
182            }
183
184            if (memInfo.getWhere() == Where.CONSTRUCTOR) {
185                count++;
186            }
187        }
188        return count;
189    }
190
191    int getInstancePropertyCount() {
192        int count = 0;
193        for (final MemberInfo memInfo : members) {
194            switch (memInfo.getKind()) {
195                case SETTER:
196                case SPECIALIZED_FUNCTION:
197                    // SETTER was counted when GETTER was encountered.
198                    // SPECIALIZED_FUNCTION was counted as FUNCTION already.
199                    continue;
200            }
201
202            if (memInfo.getWhere() == Where.INSTANCE) {
203                count++;
204            }
205        }
206        return count;
207    }
208
209    MemberInfo find(final String findJavaName, final String findJavaDesc, final int findAccess) {
210        for (final MemberInfo memInfo : members) {
211            if (memInfo.getJavaName().equals(findJavaName) &&
212                memInfo.getJavaDesc().equals(findJavaDesc) &&
213                memInfo.getJavaAccess() == findAccess) {
214                return memInfo;
215            }
216        }
217        return null;
218    }
219
220    List<MemberInfo> findSpecializations(final String methodName) {
221        final List<MemberInfo> res = new LinkedList<>();
222        for (final MemberInfo memInfo : members) {
223            if (memInfo.getName().equals(methodName) &&
224                memInfo.getKind() == Kind.SPECIALIZED_FUNCTION) {
225                res.add(memInfo);
226            }
227        }
228        return Collections.unmodifiableList(res);
229    }
230
231    MemberInfo findSetter(final MemberInfo getter) {
232        assert getter.getKind() == Kind.GETTER : "getter expected";
233        final String getterName = getter.getName();
234        final Where getterWhere = getter.getWhere();
235        for (final MemberInfo memInfo : members) {
236            if (memInfo.getKind() == Kind.SETTER &&
237                getterName.equals(memInfo.getName()) &&
238                getterWhere == memInfo.getWhere()) {
239                return memInfo;
240            }
241        }
242        return null;
243    }
244
245    /**
246     * @return the javaName
247     */
248    public String getJavaName() {
249        return javaName;
250    }
251
252    /**
253     * @param javaName the javaName to set
254     */
255    void setJavaName(final String javaName) {
256        this.javaName = javaName;
257    }
258
259    String getConstructorClassName() {
260        return getJavaName() + StringConstants.CONSTRUCTOR_SUFFIX;
261    }
262
263    String getPrototypeClassName() {
264        return getJavaName() + StringConstants.PROTOTYPE_SUFFIX;
265    }
266
267    void verify() {
268        boolean constructorSeen = false;
269        for (final MemberInfo memInfo : getMembers()) {
270            if (memInfo.isConstructor()) {
271                if (constructorSeen) {
272                    error("more than @Constructor method");
273                }
274                constructorSeen = true;
275            }
276            try {
277                memInfo.verify();
278            } catch (final Exception e) {
279                error(e.getMessage());
280            }
281        }
282    }
283
284    private void error(final String msg) throws RuntimeException {
285        throw new RuntimeException(javaName + " : " + msg);
286    }
287}
288