1 /* 2 * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package jdk.vm.ci.hotspot; 24 25 import java.util.ArrayList; 26 import java.util.List; 27 28 import jdk.vm.ci.meta.JavaKind; 29 import jdk.vm.ci.meta.JavaType; 30 import jdk.vm.ci.meta.ResolvedJavaType; 31 import jdk.vm.ci.meta.Signature; 32 import jdk.vm.ci.meta.UnresolvedJavaType; 33 34 /** 35 * Represents a method signature. 36 */ 37 public class HotSpotSignature implements Signature { 38 39 private final List<String> parameters = new ArrayList<>(); 40 private final String returnType; 41 private final String originalString; 42 private ResolvedJavaType[] parameterTypes; 43 private ResolvedJavaType returnTypeCache; 44 private final HotSpotJVMCIRuntime runtime; 45 46 public HotSpotSignature(HotSpotJVMCIRuntime runtime, String signature) { 47 this.runtime = runtime; 48 if (signature.length() == 0) { 49 throw new IllegalArgumentException("Signature cannot be empty"); 50 } 51 this.originalString = signature; 52 53 if (signature.charAt(0) == '(') { 54 int cur = 1; 55 while (cur < signature.length() && signature.charAt(cur) != ')') { 56 int nextCur = parseSignature(signature, cur); 57 parameters.add(signature.substring(cur, nextCur)); 58 cur = nextCur; 59 } 60 61 cur++; 62 int nextCur = parseSignature(signature, cur); 63 returnType = signature.substring(cur, nextCur); 64 if (nextCur != signature.length()) { 65 throw new IllegalArgumentException("Extra characters at end of signature: " + signature); 66 } 67 } else { 68 throw new IllegalArgumentException("Signature must start with a '(': " + signature); 69 } 70 } 71 72 public HotSpotSignature(HotSpotJVMCIRuntime runtime, ResolvedJavaType returnType, ResolvedJavaType... parameterTypes) { 73 this.runtime = runtime; 74 this.parameterTypes = parameterTypes.clone(); 75 this.returnTypeCache = returnType; 76 this.returnType = returnType.getName(); 77 StringBuilder sb = new StringBuilder("("); 78 for (JavaType type : parameterTypes) { 79 parameters.add(type.getName()); 80 sb.append(type.getName()); 81 } 82 sb.append(")").append(returnType.getName()); 83 this.originalString = sb.toString(); 84 assert new HotSpotSignature(runtime, originalString).equals(this); 85 } 86 87 private static int parseSignature(String signature, int start) { 88 try { 89 int cur = start; 90 char first; 91 do { 92 first = signature.charAt(cur); 93 cur++; 94 } while (first == '['); 95 96 switch (first) { 97 case 'L': 98 while (signature.charAt(cur) != ';') { 99 if (signature.charAt(cur) == '.') { 100 throw new IllegalArgumentException("Class name in signature contains '.' at index " + cur + ": " + signature); 101 } 102 cur++; 103 } 104 cur++; 105 break; 106 case 'V': 107 case 'I': 108 case 'B': 109 case 'C': 110 case 'D': 111 case 'F': 112 case 'J': 113 case 'S': 114 case 'Z': 115 break; 116 default: 117 throw new IllegalArgumentException("Invalid character '" + signature.charAt(cur - 1) + "' at index " + (cur - 1) + " in signature: " + signature); 118 } 119 return cur; 120 } catch (StringIndexOutOfBoundsException e) { 121 throw new IllegalArgumentException("Truncated signature: " + signature); 122 } 123 } 124 125 @Override 126 public int getParameterCount(boolean withReceiver) { 127 return parameters.size() + (withReceiver ? 1 : 0); 128 } 129 130 @Override 131 public JavaKind getParameterKind(int index) { 132 return JavaKind.fromTypeString(parameters.get(index)); 133 } 134 135 private static boolean checkValidCache(ResolvedJavaType type, ResolvedJavaType accessingClass) { 136 assert accessingClass != null; 137 if (type == null) { 138 return false; 139 } else if (type instanceof HotSpotResolvedObjectTypeImpl) { 140 return ((HotSpotResolvedObjectTypeImpl) type).isDefinitelyResolvedWithRespectTo(accessingClass); 141 } 142 return true; 143 } 144 145 private static JavaType getUnresolvedOrPrimitiveType(HotSpotJVMCIRuntime runtime, String name) { 146 if (name.length() == 1) { 147 JavaKind kind = JavaKind.fromPrimitiveOrVoidTypeChar(name.charAt(0)); 148 return runtime.getHostJVMCIBackend().getMetaAccess().lookupJavaType(kind.toJavaClass()); 149 } 150 return UnresolvedJavaType.create(name); 151 } 152 153 @Override 154 public JavaType getParameterType(int index, ResolvedJavaType accessingClass) { 155 if (accessingClass == null) { 156 // Caller doesn't care about resolution context so return an unresolved 157 // or primitive type (primitive type resolution is context free) 158 return getUnresolvedOrPrimitiveType(runtime, parameters.get(index)); 159 } 160 if (parameterTypes == null) { 161 parameterTypes = new ResolvedJavaType[parameters.size()]; 162 } 163 164 ResolvedJavaType type = parameterTypes[index]; 165 if (!checkValidCache(type, accessingClass)) { 166 JavaType result = runtime.lookupType(parameters.get(index), (HotSpotResolvedObjectType) accessingClass, false); 167 if (result instanceof ResolvedJavaType) { 168 type = (ResolvedJavaType) result; 169 parameterTypes[index] = type; 170 } else { 171 assert result != null; 172 return result; 173 } 174 } 175 assert type != null; 176 return type; 177 } 178 179 @Override 180 public String toMethodDescriptor() { 181 assert originalString.equals(Signature.super.toMethodDescriptor()) : originalString + " != " + Signature.super.toMethodDescriptor(); 182 return originalString; 183 } 184 185 @Override 186 public JavaKind getReturnKind() { 187 return JavaKind.fromTypeString(returnType); 188 } 189 190 @Override 191 public JavaType getReturnType(ResolvedJavaType accessingClass) { 192 if (accessingClass == null) { 193 // Caller doesn't care about resolution context so return an unresolved 194 // or primitive type (primitive type resolution is context free) 195 return getUnresolvedOrPrimitiveType(runtime, returnType); 196 } 197 if (!checkValidCache(returnTypeCache, accessingClass)) { 198 JavaType result = runtime.lookupType(returnType, (HotSpotResolvedObjectType) accessingClass, false); 199 if (result instanceof ResolvedJavaType) { 200 returnTypeCache = (ResolvedJavaType) result; 201 } else { 202 return result; 203 } 204 } 205 return returnTypeCache; 206 } 207 208 @Override 209 public String toString() { 210 return "HotSpotSignature<" + originalString + ">"; 211 } 212 213 @Override 214 public boolean equals(Object obj) { 215 if (obj instanceof HotSpotSignature) { 216 HotSpotSignature other = (HotSpotSignature) obj; 217 if (other.originalString.equals(originalString)) { 218 assert other.parameters.equals(parameters); 219 assert other.returnType.equals(returnType); 220 return true; 221 } 222 } 223 return false; 224 } 225 226 @Override 227 public int hashCode() { 228 return originalString.hashCode(); 229 } 230 }