001/* 002 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.replacements.verifier; 024 025import java.util.*; 026 027import javax.annotation.processing.*; 028import javax.lang.model.element.*; 029import javax.lang.model.type.*; 030import javax.tools.Diagnostic.Kind; 031 032/** 033 * Pretty much copied from HotSpotSignature but using a different method for resolving types. This 034 * class should be rewritten, its just a quick hack to get signatures working. 035 */ 036final class APHotSpotSignature { 037 038 private final List<String> arguments = new ArrayList<>(); 039 private final String returnType; 040 private final String originalString; 041 private TypeMirror[] argumentTypes; 042 private TypeMirror returnTypeCache; 043 044 APHotSpotSignature(String signature) { 045 assert signature.length() > 0; 046 this.originalString = signature; 047 048 if (signature.charAt(0) == '(') { 049 int cur = 1; 050 while (cur < signature.length() && signature.charAt(cur) != ')') { 051 int nextCur = parseSignature(signature, cur); 052 arguments.add(signature.substring(cur, nextCur)); 053 cur = nextCur; 054 } 055 056 cur++; 057 int nextCur = parseSignature(signature, cur); 058 returnType = signature.substring(cur, nextCur); 059 if (nextCur != signature.length()) { 060 throw new RuntimeException("Invalid trailing characters."); 061 } 062 } else { 063 returnType = null; 064 } 065 } 066 067 private static int parseSignature(String signature, int start) { 068 int cur = start; 069 char first; 070 do { 071 first = signature.charAt(cur++); 072 } while (first == '['); 073 074 switch (first) { 075 case 'L': 076 while (signature.charAt(cur) != ';') { 077 cur++; 078 } 079 cur++; 080 break; 081 case 'V': 082 case 'I': 083 case 'B': 084 case 'C': 085 case 'D': 086 case 'F': 087 case 'J': 088 case 'S': 089 case 'Z': 090 break; 091 default: 092 throw new RuntimeException("Invalid character at index " + cur + " in signature: " + signature); 093 } 094 return cur; 095 } 096 097 public int getParameterCount(boolean withReceiver) { 098 return arguments.size() + (withReceiver ? 1 : 0); 099 } 100 101 public TypeMirror getParameterType(ProcessingEnvironment env, int index) { 102 if (argumentTypes == null) { 103 argumentTypes = new TypeMirror[arguments.size()]; 104 } 105 TypeMirror type = argumentTypes[index]; 106 if (arguments.get(index) == null) { 107 throw new RuntimeException(String.format("Invalid argument at index %s.", index)); 108 } 109 110 if (type == null) { 111 argumentTypes[index] = lookupType(env, arguments.get(index)); 112 } 113 return argumentTypes[index]; 114 } 115 116 private static TypeMirror lookupType(ProcessingEnvironment env, String binaryName) { 117 if (binaryName.length() == 1) { 118 TypeKind kind = fromPrimitiveOrVoidTypeChar(binaryName.charAt(0)); 119 if (kind.isPrimitive()) { 120 return env.getTypeUtils().getPrimitiveType(kind); 121 } else if (kind == TypeKind.VOID) { 122 return env.getTypeUtils().getNoType(kind); 123 } 124 } 125 126 String canonicalName = binaryName; 127 if (canonicalName.startsWith("L") && canonicalName.endsWith(";")) { 128 canonicalName = canonicalName.substring(1, canonicalName.length() - 1); 129 } 130 env.getMessager().printMessage(Kind.ERROR, canonicalName); 131 132 int arrayDims = 0; 133 while (canonicalName.startsWith("[")) { 134 canonicalName = canonicalName.substring(1, canonicalName.length()); 135 arrayDims++; 136 } 137 138 canonicalName = canonicalName.replaceAll("/", "."); 139 TypeElement typeElement = env.getElementUtils().getTypeElement(canonicalName); 140 if (typeElement == null) { 141 throw new RuntimeException(String.format("Type with name %s not found.", canonicalName)); 142 } 143 TypeMirror mirror = typeElement.asType(); 144 for (int i = 0; i < arrayDims; i++) { 145 mirror = env.getTypeUtils().getArrayType(mirror); 146 } 147 return mirror; 148 } 149 150 /** 151 * Returns the kind from the character describing a primitive or void. 152 * 153 * @param ch the character 154 * @return the kind 155 */ 156 public static TypeKind fromPrimitiveOrVoidTypeChar(char ch) { 157 switch (ch) { 158 case 'Z': 159 return TypeKind.BOOLEAN; 160 case 'C': 161 return TypeKind.CHAR; 162 case 'F': 163 return TypeKind.FLOAT; 164 case 'D': 165 return TypeKind.DOUBLE; 166 case 'B': 167 return TypeKind.BYTE; 168 case 'S': 169 return TypeKind.SHORT; 170 case 'I': 171 return TypeKind.INT; 172 case 'J': 173 return TypeKind.LONG; 174 case 'V': 175 return TypeKind.VOID; 176 } 177 throw new IllegalArgumentException("unknown primitive or void type character: " + ch); 178 } 179 180 public TypeMirror getReturnType(ProcessingEnvironment env) { 181 if (returnTypeCache == null) { 182 if (returnType == null) { 183 throw new RuntimeException("Invalid return type."); 184 } 185 returnTypeCache = lookupType(env, returnType); 186 } 187 return returnTypeCache; 188 } 189 190 @Override 191 public String toString() { 192 return "Signature<" + originalString + ">"; 193 } 194}