1917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/*
2917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Copyright (C) 2007 The Android Open Source Project
3917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
4917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Licensed under the Apache License, Version 2.0 (the "License");
5917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * you may not use this file except in compliance with the License.
6917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * You may obtain a copy of the License at
7917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
8917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *      http://www.apache.org/licenses/LICENSE-2.0
9917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
10917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Unless required by applicable law or agreed to in writing, software
11917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * distributed under the License is distributed on an "AS IS" BASIS,
12917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * See the License for the specific language governing permissions and
14917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * limitations under the License.
15917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */
16917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
17917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpackage com.android.dexgen.rop.type;
18917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
19917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.HashMap;
20917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
21917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/**
22917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Representation of a method decriptor. Instances of this class are
23917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * generally interned and may be usefully compared with each other
24917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * using {@code ==}.
25917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */
26917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpublic final class Prototype implements Comparable<Prototype> {
27917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code non-null;} intern table mapping string descriptors to instances */
28917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static final HashMap<String, Prototype> internTable =
29917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        new HashMap<String, Prototype>(500);
30917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
31917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code non-null;} method descriptor */
32917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final String descriptor;
33917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
34917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code non-null;} return type */
35917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final Type returnType;
36917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
37917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code non-null;} list of parameter types */
38917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final StdTypeList parameterTypes;
39917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
40917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code null-ok;} list of parameter frame types, if calculated */
41917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private StdTypeList parameterFrameTypes;
42917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
43917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
44917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Returns the unique instance corresponding to the
45917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * given method descriptor. See vmspec-2 sec4.3.3 for details on the
46917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * field descriptor syntax.
47917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
48917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param descriptor {@code non-null;} the descriptor
49917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} the corresponding instance
50917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @throws IllegalArgumentException thrown if the descriptor has
51917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * invalid syntax
52917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
53917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public static Prototype intern(String descriptor) {
54917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (descriptor == null) {
55917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new NullPointerException("descriptor == null");
56917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
57917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        Prototype result = internTable.get(descriptor);
58917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (result != null) {
59917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return result;
60917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
61917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
62917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        Type[] params = makeParameterArray(descriptor);
63917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int paramCount = 0;
64917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int at = 1;
65917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
66917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (;;) {
67917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int startAt = at;
68917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            char c = descriptor.charAt(at);
69917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (c == ')') {
70917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                at++;
71917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
72917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
73917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
74917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            // Skip array markers.
75917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            while (c == '[') {
76917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                at++;
77917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                c = descriptor.charAt(at);
78917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
79917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
80917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (c == 'L') {
81917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                // It looks like the start of a class name; find the end.
82917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                int endAt = descriptor.indexOf(';', at);
83917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (endAt == -1) {
84917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    throw new IllegalArgumentException("bad descriptor");
85917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
86917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                at = endAt + 1;
87917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } else {
88917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                at++;
89917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
90917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
91917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            params[paramCount] =
92917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                Type.intern(descriptor.substring(startAt, at));
93917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            paramCount++;
94917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
95917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
96917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        Type returnType = Type.internReturnType(descriptor.substring(at));
97917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        StdTypeList parameterTypes = new StdTypeList(paramCount);
98917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
99917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < paramCount; i++) {
100917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            parameterTypes.set(i, params[i]);
101917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
102917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
103917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        result = new Prototype(descriptor, returnType, parameterTypes);
104917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return putIntern(result);
105917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
106917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
107917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
108917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper for {@link #intern} which returns an empty array to
109917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * populate with parsed parameter types, and which also ensures
110917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * that there is a '(' at the start of the descriptor and a
111917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * single ')' somewhere before the end.
112917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
113917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param descriptor {@code non-null;} the descriptor string
114917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} array large enough to hold all parsed parameter
115917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * types, but which is likely actually larger than needed
116917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
117917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static Type[] makeParameterArray(String descriptor) {
118917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int length = descriptor.length();
119917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
120917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (descriptor.charAt(0) != '(') {
121917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new IllegalArgumentException("bad descriptor");
122917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
123917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
124917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /*
125917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * This is a cheesy way to establish an upper bound on the
126917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * number of parameters: Just count capital letters.
127917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
128917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int closeAt = 0;
129917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int maxParams = 0;
130917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 1; i < length; i++) {
131917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            char c = descriptor.charAt(i);
132917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (c == ')') {
133917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                closeAt = i;
134917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
135917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
136917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if ((c >= 'A') && (c <= 'Z')) {
137917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                maxParams++;
138917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
139917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
140917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
141917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if ((closeAt == 0) || (closeAt == (length - 1))) {
142917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new IllegalArgumentException("bad descriptor");
143917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
144917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
145917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (descriptor.indexOf(')', closeAt + 1) != -1) {
146917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new IllegalArgumentException("bad descriptor");
147917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
148917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
149917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return new Type[maxParams];
150917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
151917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
152917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
153917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Interns an instance, adding to the descriptor as necessary based
154917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * on the given definer, name, and flags. For example, an init
155917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * method has an uninitialized object of type {@code definer}
156917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * as its first argument.
157917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
158917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param descriptor {@code non-null;} the descriptor string
159917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param definer {@code non-null;} class the method is defined on
160917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param isStatic whether this is a static method
161917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param isInit whether this is an init method
162917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} the interned instance
163917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
164917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public static Prototype intern(String descriptor, Type definer,
165917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            boolean isStatic, boolean isInit) {
166917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        Prototype base = intern(descriptor);
167917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
168917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (isStatic) {
169917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return base;
170917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
171917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
172917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (isInit) {
173917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            definer = definer.asUninitialized(Integer.MAX_VALUE);
174917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
175917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
176917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return base.withFirstParameter(definer);
177917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
178917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
179917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
180917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Interns an instance which consists of the given number of
181917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@code int}s along with the given return type
182917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
183917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param returnType {@code non-null;} the return type
184917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param count {@code > 0;} the number of elements in the prototype
185917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} the interned instance
186917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
187917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public static Prototype internInts(Type returnType, int count) {
188917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // Make the descriptor...
189917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
190917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        StringBuffer sb = new StringBuffer(100);
191917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
192917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        sb.append('(');
193917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
194917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < count; i++) {
195917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            sb.append('I');
196917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
197917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
198917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        sb.append(')');
199917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        sb.append(returnType.getDescriptor());
200917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
201917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // ...and intern it.
202917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return intern(sb.toString());
203917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
204917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
205917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
206917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Constructs an instance. This is a private constructor; use one
207917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * of the public static methods to get instances.
208917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
209917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param descriptor {@code non-null;} the descriptor string
210917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
211917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private Prototype(String descriptor, Type returnType,
212917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            StdTypeList parameterTypes) {
213917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (descriptor == null) {
214917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new NullPointerException("descriptor == null");
215917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
216917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
217917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (returnType == null) {
218917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new NullPointerException("returnType == null");
219917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
220917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
221917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (parameterTypes == null) {
222917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new NullPointerException("parameterTypes == null");
223917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
224917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
225917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.descriptor = descriptor;
226917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.returnType = returnType;
227917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.parameterTypes = parameterTypes;
228917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.parameterFrameTypes = null;
229917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
230917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
231917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@inheritDoc} */
232917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    @Override
233917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public boolean equals(Object other) {
234917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (this == other) {
235917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            /*
236917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * Since externally-visible instances are interned, this
237917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * check helps weed out some easy cases.
238917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             */
239917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return true;
240917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
241917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
242917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (!(other instanceof Prototype)) {
243917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return false;
244917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
245917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
246917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return descriptor.equals(((Prototype) other).descriptor);
247917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
248917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
249917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@inheritDoc} */
250917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    @Override
251917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public int hashCode() {
252917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return descriptor.hashCode();
253917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
254917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
255917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@inheritDoc} */
256917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public int compareTo(Prototype other) {
257917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (this == other) {
258917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return 0;
259917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
260917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
261917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /*
262917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * The return type is the major order, and then args in order,
263917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * and then the shorter list comes first (similar to string
264917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * sorting).
265917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
266917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
267917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int result = returnType.compareTo(other.returnType);
268917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
269917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (result != 0) {
270917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return result;
271917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
272917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
273917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int thisSize = parameterTypes.size();
274917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int otherSize = other.parameterTypes.size();
275917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int size = Math.min(thisSize, otherSize);
276917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
277917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < size; i++) {
278917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Type thisType = parameterTypes.get(i);
279917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Type otherType = other.parameterTypes.get(i);
280917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
281917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            result = thisType.compareTo(otherType);
282917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
283917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (result != 0) {
284917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return result;
285917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
286917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
287917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
288917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (thisSize < otherSize) {
289917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return -1;
290917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } else if (thisSize > otherSize) {
291917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return 1;
292917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } else {
293917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return 0;
294917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
295917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
296917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
297917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@inheritDoc} */
298917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    @Override
299917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public String toString() {
300917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return descriptor;
301917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
302917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
303917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
304917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the descriptor string.
305917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
306917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} the descriptor
307917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
308917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public String getDescriptor() {
309917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return descriptor;
310917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
311917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
312917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
313917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the return type.
314917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
315917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} the return type
316917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
317917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public Type getReturnType() {
318917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return returnType;
319917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
320917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
321917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
322917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the list of parameter types.
323917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
324917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} the list of parameter types
325917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
326917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public StdTypeList getParameterTypes() {
327917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return parameterTypes;
328917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
329917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
330917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
331917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the list of frame types corresponding to the list of parameter
332917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * types. The difference between the two lists (if any) is that all
333917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * "intlike" types (see {@link Type#isIntlike}) are replaced by
334917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@link Type#INT}.
335917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
336917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} the list of parameter frame types
337917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
338917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public StdTypeList getParameterFrameTypes() {
339917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (parameterFrameTypes == null) {
340917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int sz = parameterTypes.size();
341917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            StdTypeList list = new StdTypeList(sz);
342917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            boolean any = false;
343917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (int i = 0; i < sz; i++) {
344917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                Type one = parameterTypes.get(i);
345917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (one.isIntlike()) {
346917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    any = true;
347917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    one = Type.INT;
348917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
349917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                list.set(i, one);
350917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
351917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            parameterFrameTypes = any ? list : parameterTypes;
352917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
353917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
354917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return parameterFrameTypes;
355917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
356917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
357917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
358917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Returns a new interned instance, which is the same as this instance,
359917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * except that it has an additional parameter prepended to the original's
360917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * argument list.
361917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
362917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param param {@code non-null;} the new first parameter
363917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} an appropriately-constructed instance
364917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
365917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public Prototype withFirstParameter(Type param) {
366917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        String newDesc = "(" + param.getDescriptor() + descriptor.substring(1);
367917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        StdTypeList newParams = parameterTypes.withFirst(param);
368917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
369917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        newParams.setImmutable();
370917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
371917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        Prototype result =
372917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            new Prototype(newDesc, returnType, newParams);
373917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
374917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return putIntern(result);
375917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
376917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
377917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
378917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Puts the given instance in the intern table if it's not already
379917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * there. If a conflicting value is already in the table, then leave it.
380917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Return the interned value.
381917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
382917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param desc {@code non-null;} instance to make interned
383917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} the actual interned object
384917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
385917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static Prototype putIntern(Prototype desc) {
386917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        synchronized (internTable) {
387917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            String descriptor = desc.getDescriptor();
388917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Prototype already = internTable.get(descriptor);
389917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (already != null) {
390917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return already;
391917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
392917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            internTable.put(descriptor, desc);
393917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return desc;
394917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
395917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
396917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul}
397