1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage com.android.dx.rop.type;
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.HashMap;
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
22ed0fe6c2f310f8c2cc28c35c2b473d8de36db8a4Jesse Wilson * Representation of a method descriptor. Instances of this class are
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * generally interned and may be usefully compared with each other
2499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * using {@code ==}.
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic final class Prototype implements Comparable<Prototype> {
2799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} intern table mapping string descriptors to instances */
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final HashMap<String, Prototype> internTable =
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        new HashMap<String, Prototype>(500);
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} method descriptor */
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final String descriptor;
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} return type */
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final Type returnType;
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} list of parameter types */
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final StdTypeList parameterTypes;
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
4099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code null-ok;} list of parameter frame types, if calculated */
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private StdTypeList parameterFrameTypes;
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
44de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     * Returns the unique instance corresponding to the
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * given method descriptor. See vmspec-2 sec4.3.3 for details on the
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * field descriptor syntax.
47de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
4899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param descriptor {@code non-null;} the descriptor
4999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the corresponding instance
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @throws IllegalArgumentException thrown if the descriptor has
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * invalid syntax
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public static Prototype intern(String descriptor) {
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (descriptor == null) {
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("descriptor == null");
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
58590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        Prototype result;
59590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        synchronized (internTable) {
60590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao            result = internTable.get(descriptor);
61590f78fc4b6e3268149c5eacb7c8b7dd33497f44jeffhao        }
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (result != null) {
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return result;
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Type[] params = makeParameterArray(descriptor);
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int paramCount = 0;
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int at = 1;
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (;;) {
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int startAt = at;
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            char c = descriptor.charAt(at);
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (c == ')') {
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                at++;
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // Skip array markers.
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            while (c == '[') {
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                at++;
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                c = descriptor.charAt(at);
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (c == 'L') {
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // It looks like the start of a class name; find the end.
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int endAt = descriptor.indexOf(';', at);
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (endAt == -1) {
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw new IllegalArgumentException("bad descriptor");
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                at = endAt + 1;
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                at++;
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            params[paramCount] =
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Type.intern(descriptor.substring(startAt, at));
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            paramCount++;
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Type returnType = Type.internReturnType(descriptor.substring(at));
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        StdTypeList parameterTypes = new StdTypeList(paramCount);
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < paramCount; i++) {
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            parameterTypes.set(i, params[i]);
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        result = new Prototype(descriptor, returnType, parameterTypes);
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return putIntern(result);
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Helper for {@link #intern} which returns an empty array to
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * populate with parsed parameter types, and which also ensures
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * that there is a '(' at the start of the descriptor and a
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * single ')' somewhere before the end.
116de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
11799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param descriptor {@code non-null;} the descriptor string
11899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} array large enough to hold all parsed parameter
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * types, but which is likely actually larger than needed
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static Type[] makeParameterArray(String descriptor) {
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int length = descriptor.length();
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (descriptor.charAt(0) != '(') {
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IllegalArgumentException("bad descriptor");
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * This is a cheesy way to establish an upper bound on the
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * number of parameters: Just count capital letters.
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int closeAt = 0;
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int maxParams = 0;
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 1; i < length; i++) {
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            char c = descriptor.charAt(i);
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (c == ')') {
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                closeAt = i;
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if ((c >= 'A') && (c <= 'Z')) {
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                maxParams++;
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((closeAt == 0) || (closeAt == (length - 1))) {
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IllegalArgumentException("bad descriptor");
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (descriptor.indexOf(')', closeAt + 1) != -1) {
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IllegalArgumentException("bad descriptor");
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return new Type[maxParams];
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Interns an instance, adding to the descriptor as necessary based
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * on the given definer, name, and flags. For example, an init
15999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * method has an uninitialized object of type {@code definer}
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * as its first argument.
161de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
16299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param descriptor {@code non-null;} the descriptor string
16399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param definer {@code non-null;} class the method is defined on
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param isStatic whether this is a static method
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param isInit whether this is an init method
16699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the interned instance
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public static Prototype intern(String descriptor, Type definer,
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            boolean isStatic, boolean isInit) {
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Prototype base = intern(descriptor);
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (isStatic) {
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return base;
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (isInit) {
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            definer = definer.asUninitialized(Integer.MAX_VALUE);
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return base.withFirstParameter(definer);
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Interns an instance which consists of the given number of
18599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code int}s along with the given return type
186de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
18799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param returnType {@code non-null;} the return type
18899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param count {@code > 0;} the number of elements in the prototype
18999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the interned instance
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public static Prototype internInts(Type returnType, int count) {
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Make the descriptor...
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        StringBuffer sb = new StringBuffer(100);
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sb.append('(');
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < count; i++) {
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            sb.append('I');
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sb.append(')');
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sb.append(returnType.getDescriptor());
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // ...and intern it.
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return intern(sb.toString());
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs an instance. This is a private constructor; use one
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * of the public static methods to get instances.
212de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
21399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param descriptor {@code non-null;} the descriptor string
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private Prototype(String descriptor, Type returnType,
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            StdTypeList parameterTypes) {
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (descriptor == null) {
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("descriptor == null");
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (returnType == null) {
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("returnType == null");
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (parameterTypes == null) {
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("parameterTypes == null");
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.descriptor = descriptor;
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.returnType = returnType;
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.parameterTypes = parameterTypes;
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.parameterFrameTypes = null;
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public boolean equals(Object other) {
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (this == other) {
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * Since externally-visible instances are interned, this
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * check helps weed out some easy cases.
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return true;
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!(other instanceof Prototype)) {
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return descriptor.equals(((Prototype) other).descriptor);
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int hashCode() {
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return descriptor.hashCode();
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int compareTo(Prototype other) {
261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (this == other) {
262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return 0;
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
264de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * The return type is the major order, and then args in order,
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * and then the shorter list comes first (similar to string
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * sorting).
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int result = returnType.compareTo(other.returnType);
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (result != 0) {
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return result;
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int thisSize = parameterTypes.size();
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int otherSize = other.parameterTypes.size();
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int size = Math.min(thisSize, otherSize);
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < size; i++) {
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Type thisType = parameterTypes.get(i);
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Type otherType = other.parameterTypes.get(i);
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            result = thisType.compareTo(otherType);
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (result != 0) {
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return result;
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (thisSize < otherSize) {
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return -1;
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else if (thisSize > otherSize) {
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return 1;
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return 0;
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public String toString() {
304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return descriptor;
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the descriptor string.
309de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
31099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the descriptor
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public String getDescriptor() {
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return descriptor;
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the return type.
318de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
31999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the return type
320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public Type getReturnType() {
322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return returnType;
323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the list of parameter types.
327de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
32899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the list of parameter types
329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public StdTypeList getParameterTypes() {
331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return parameterTypes;
332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the list of frame types corresponding to the list of parameter
336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * types. The difference between the two lists (if any) is that all
337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * "intlike" types (see {@link Type#isIntlike}) are replaced by
338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * {@link Type#INT}.
339de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
34099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the list of parameter frame types
341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public StdTypeList getParameterFrameTypes() {
343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (parameterFrameTypes == null) {
344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int sz = parameterTypes.size();
345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            StdTypeList list = new StdTypeList(sz);
346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            boolean any = false;
347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            for (int i = 0; i < sz; i++) {
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Type one = parameterTypes.get(i);
349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (one.isIntlike()) {
350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    any = true;
351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    one = Type.INT;
352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                list.set(i, one);
354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            parameterFrameTypes = any ? list : parameterTypes;
356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return parameterFrameTypes;
359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Returns a new interned instance, which is the same as this instance,
363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * except that it has an additional parameter prepended to the original's
364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * argument list.
365de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
36699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param param {@code non-null;} the new first parameter
36799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} an appropriately-constructed instance
368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public Prototype withFirstParameter(Type param) {
370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String newDesc = "(" + param.getDescriptor() + descriptor.substring(1);
371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        StdTypeList newParams = parameterTypes.withFirst(param);
372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        newParams.setImmutable();
374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Prototype result =
376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            new Prototype(newDesc, returnType, newParams);
377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return putIntern(result);
379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Puts the given instance in the intern table if it's not already
383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * there. If a conflicting value is already in the table, then leave it.
384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Return the interned value.
385de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
38699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param desc {@code non-null;} instance to make interned
38799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the actual interned object
388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
389f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static Prototype putIntern(Prototype desc) {
390f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        synchronized (internTable) {
391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            String descriptor = desc.getDescriptor();
392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Prototype already = internTable.get(descriptor);
393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (already != null) {
394f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return already;
395f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
396f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            internTable.put(descriptor, desc);
397f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return desc;
398f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
400f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
401