1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/*
2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2007 The Android Open Source Project
3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License.
6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at
7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and
14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License.
15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
17579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpackage com.android.dx.rop.type;
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.HashMap;
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/**
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Representation of a method descriptor. Instances of this class are
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * generally interned and may be usefully compared with each other
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * using {@code ==}.
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic final class Prototype implements Comparable<Prototype> {
27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} intern table mapping string descriptors to instances */
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static final HashMap<String, Prototype> internTable =
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        new HashMap<String, Prototype>(500);
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} method descriptor */
32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final String descriptor;
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} return type */
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final Type returnType;
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} list of parameter types */
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final StdTypeList parameterTypes;
39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code null-ok;} list of parameter frame types, if calculated */
41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private StdTypeList parameterFrameTypes;
42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns the unique instance corresponding to the
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * given method descriptor. See vmspec-2 sec4.3.3 for details on the
46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * field descriptor syntax.
47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param descriptor {@code non-null;} the descriptor
49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the corresponding instance
50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @throws IllegalArgumentException thrown if the descriptor has
51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * invalid syntax
52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static Prototype intern(String descriptor) {
54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (descriptor == null) {
55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("descriptor == null");
56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Prototype result;
59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        synchronized (internTable) {
60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result = internTable.get(descriptor);
61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (result != null) {
63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return result;
64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Type[] params = makeParameterArray(descriptor);
67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int paramCount = 0;
68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int at = 1;
69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (;;) {
71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int startAt = at;
72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            char c = descriptor.charAt(at);
73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (c == ')') {
74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                at++;
75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                break;
76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            // Skip array markers.
79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            while (c == '[') {
80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                at++;
81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                c = descriptor.charAt(at);
82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (c == 'L') {
85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                // It looks like the start of a class name; find the end.
86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                int endAt = descriptor.indexOf(';', at);
87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (endAt == -1) {
88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    throw new IllegalArgumentException("bad descriptor");
89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                at = endAt + 1;
91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else {
92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                at++;
93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            params[paramCount] =
96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                Type.intern(descriptor.substring(startAt, at));
97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            paramCount++;
98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Type returnType = Type.internReturnType(descriptor.substring(at));
101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        StdTypeList parameterTypes = new StdTypeList(paramCount);
102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < paramCount; i++) {
104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            parameterTypes.set(i, params[i]);
105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        result = new Prototype(descriptor, returnType, parameterTypes);
108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return putIntern(result);
109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Helper for {@link #intern} which returns an empty array to
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * populate with parsed parameter types, and which also ensures
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * that there is a '(' at the start of the descriptor and a
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * single ')' somewhere before the end.
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param descriptor {@code non-null;} the descriptor string
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} array large enough to hold all parsed parameter
119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * types, but which is likely actually larger than needed
120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static Type[] makeParameterArray(String descriptor) {
122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int length = descriptor.length();
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (descriptor.charAt(0) != '(') {
125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalArgumentException("bad descriptor");
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * This is a cheesy way to establish an upper bound on the
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * number of parameters: Just count capital letters.
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int closeAt = 0;
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int maxParams = 0;
134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 1; i < length; i++) {
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            char c = descriptor.charAt(i);
136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (c == ')') {
137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                closeAt = i;
138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                break;
139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if ((c >= 'A') && (c <= 'Z')) {
141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                maxParams++;
142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if ((closeAt == 0) || (closeAt == (length - 1))) {
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalArgumentException("bad descriptor");
147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (descriptor.indexOf(')', closeAt + 1) != -1) {
150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalArgumentException("bad descriptor");
151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return new Type[maxParams];
154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Interns an instance, adding to the descriptor as necessary based
158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * on the given definer, name, and flags. For example, an init
159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * method has an uninitialized object of type {@code definer}
160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * as its first argument.
161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param descriptor {@code non-null;} the descriptor string
163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param definer {@code non-null;} class the method is defined on
164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param isStatic whether this is a static method
165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param isInit whether this is an init method
166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the interned instance
167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static Prototype intern(String descriptor, Type definer,
169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            boolean isStatic, boolean isInit) {
170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Prototype base = intern(descriptor);
171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (isStatic) {
173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return base;
174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (isInit) {
177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            definer = definer.asUninitialized(Integer.MAX_VALUE);
178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return base.withFirstParameter(definer);
181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Interns an instance which consists of the given number of
185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code int}s along with the given return type
186579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param returnType {@code non-null;} the return type
188579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param count {@code > 0;} the number of elements in the prototype
189579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the interned instance
190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static Prototype internInts(Type returnType, int count) {
192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // Make the descriptor...
193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        StringBuffer sb = new StringBuffer(100);
195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append('(');
197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < count; i++) {
199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append('I');
200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(')');
203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(returnType.getDescriptor());
204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // ...and intern it.
206579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return intern(sb.toString());
207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
210579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Constructs an instance. This is a private constructor; use one
211579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * of the public static methods to get instances.
212579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
213579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param descriptor {@code non-null;} the descriptor string
214579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
215579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private Prototype(String descriptor, Type returnType,
216579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            StdTypeList parameterTypes) {
217579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (descriptor == null) {
218579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("descriptor == null");
219579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
220579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
221579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (returnType == null) {
222579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("returnType == null");
223579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
224579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
225579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (parameterTypes == null) {
226579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("parameterTypes == null");
227579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
228579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
229579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.descriptor = descriptor;
230579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.returnType = returnType;
231579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.parameterTypes = parameterTypes;
232579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.parameterFrameTypes = null;
233579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
234579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
235579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
236579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
237579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public boolean equals(Object other) {
238579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (this == other) {
239579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            /*
240579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * Since externally-visible instances are interned, this
241579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * check helps weed out some easy cases.
242579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             */
243579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return true;
244579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
245579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
246579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (!(other instanceof Prototype)) {
247579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return false;
248579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
249579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
250579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return descriptor.equals(((Prototype) other).descriptor);
251579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
252579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
253579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
254579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
255579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public int hashCode() {
256579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return descriptor.hashCode();
257579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
258579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
259579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
260579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public int compareTo(Prototype other) {
261579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (this == other) {
262579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return 0;
263579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
264579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
265579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
266579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * The return type is the major order, and then args in order,
267579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * and then the shorter list comes first (similar to string
268579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * sorting).
269579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
270579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
271579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int result = returnType.compareTo(other.returnType);
272579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
273579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (result != 0) {
274579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return result;
275579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
276579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
277579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int thisSize = parameterTypes.size();
278579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int otherSize = other.parameterTypes.size();
279579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int size = Math.min(thisSize, otherSize);
280579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
281579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < size; i++) {
282579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Type thisType = parameterTypes.get(i);
283579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Type otherType = other.parameterTypes.get(i);
284579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
285579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result = thisType.compareTo(otherType);
286579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
287579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (result != 0) {
288579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return result;
289579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
290579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
291579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
292579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (thisSize < otherSize) {
293579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return -1;
294579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else if (thisSize > otherSize) {
295579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return 1;
296579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else {
297579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return 0;
298579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
299579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
300579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
301579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
302579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
303579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public String toString() {
304579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return descriptor;
305579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
306579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
307579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
308579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the descriptor string.
309579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
310579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the descriptor
311579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
312579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public String getDescriptor() {
313579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return descriptor;
314579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
315579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
316579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
317579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the return type.
318579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
319579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the return type
320579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
321579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public Type getReturnType() {
322579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return returnType;
323579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
324579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
325579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
326579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the list of parameter types.
327579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
328579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the list of parameter types
329579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
330579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public StdTypeList getParameterTypes() {
331579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return parameterTypes;
332579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
333579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
334579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
335579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the list of frame types corresponding to the list of parameter
336579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * types. The difference between the two lists (if any) is that all
337579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * "intlike" types (see {@link Type#isIntlike}) are replaced by
338579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@link Type#INT}.
339579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
340579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the list of parameter frame types
341579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
342579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public StdTypeList getParameterFrameTypes() {
343579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (parameterFrameTypes == null) {
344579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int sz = parameterTypes.size();
345579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            StdTypeList list = new StdTypeList(sz);
346579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            boolean any = false;
347579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            for (int i = 0; i < sz; i++) {
348579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                Type one = parameterTypes.get(i);
349579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (one.isIntlike()) {
350579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    any = true;
351579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    one = Type.INT;
352579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
353579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                list.set(i, one);
354579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
355579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            parameterFrameTypes = any ? list : parameterTypes;
356579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
357579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
358579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return parameterFrameTypes;
359579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
360579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
361579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
362579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns a new interned instance, which is the same as this instance,
363579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * except that it has an additional parameter prepended to the original's
364579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * argument list.
365579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
366579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param param {@code non-null;} the new first parameter
367579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} an appropriately-constructed instance
368579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
369579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public Prototype withFirstParameter(Type param) {
370579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        String newDesc = "(" + param.getDescriptor() + descriptor.substring(1);
371579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        StdTypeList newParams = parameterTypes.withFirst(param);
372579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
373579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        newParams.setImmutable();
374579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
375579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Prototype result =
376579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            new Prototype(newDesc, returnType, newParams);
377579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
378579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return putIntern(result);
379579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
380579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
381579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
382579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Puts the given instance in the intern table if it's not already
383579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * there. If a conflicting value is already in the table, then leave it.
384579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Return the interned value.
385579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
386579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param desc {@code non-null;} instance to make interned
387579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the actual interned object
388579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
389579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static Prototype putIntern(Prototype desc) {
390579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        synchronized (internTable) {
391579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            String descriptor = desc.getDescriptor();
392579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Prototype already = internTable.get(descriptor);
393579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (already != null) {
394579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return already;
395579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
396579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            internTable.put(descriptor, desc);
397579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return desc;
398579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
399579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
400579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
401