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