1 /*
   2  * Copyright (c) 2013, 2015, 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 org.graalvm.compiler.replacements.verifier;
  24 
  25 import java.util.ArrayList;
  26 import java.util.List;
  27 
  28 import javax.annotation.processing.ProcessingEnvironment;
  29 import javax.lang.model.element.TypeElement;
  30 import javax.lang.model.type.TypeKind;
  31 import javax.lang.model.type.TypeMirror;
  32 import javax.tools.Diagnostic.Kind;
  33 
  34 /**
  35  * Pretty much copied from HotSpotSignature but using a different method for resolving types. This
  36  * class should be rewritten, its just a quick hack to get signatures working.
  37  */
  38 final class APHotSpotSignature {
  39 
  40     private final List<String> arguments = new ArrayList<>();
  41     private final String returnType;
  42     private final String originalString;
  43     private TypeMirror[] argumentTypes;
  44     private TypeMirror returnTypeCache;
  45 
  46     APHotSpotSignature(String signature) {
  47         assert signature.length() > 0;
  48         this.originalString = signature;
  49 
  50         if (signature.charAt(0) == '(') {
  51             int cur = 1;
  52             while (cur < signature.length() && signature.charAt(cur) != ')') {
  53                 int nextCur = parseSignature(signature, cur);
  54                 arguments.add(signature.substring(cur, nextCur));
  55                 cur = nextCur;
  56             }
  57 
  58             cur++;
  59             int nextCur = parseSignature(signature, cur);
  60             returnType = signature.substring(cur, nextCur);
  61             if (nextCur != signature.length()) {
  62                 throw new RuntimeException("Invalid trailing characters.");
  63             }
  64         } else {
  65             returnType = null;
  66         }
  67     }
  68 
  69     private static int parseSignature(String signature, int start) {
  70         int cur = start;
  71         char first;
  72         do {
  73             first = signature.charAt(cur++);
  74         } while (first == '[');
  75 
  76         switch (first) {
  77             case 'L':
  78                 while (signature.charAt(cur) != ';') {
  79                     cur++;
  80                 }
  81                 cur++;
  82                 break;
  83             case 'V':
  84             case 'I':
  85             case 'B':
  86             case 'C':
  87             case 'D':
  88             case 'F':
  89             case 'J':
  90             case 'S':
  91             case 'Z':
  92                 break;
  93             default:
  94                 throw new RuntimeException("Invalid character at index " + cur + " in signature: " + signature);
  95         }
  96         return cur;
  97     }
  98 
  99     public int getParameterCount(boolean withReceiver) {
 100         return arguments.size() + (withReceiver ? 1 : 0);
 101     }
 102 
 103     public TypeMirror getParameterType(ProcessingEnvironment env, int index) {
 104         if (argumentTypes == null) {
 105             argumentTypes = new TypeMirror[arguments.size()];
 106         }
 107         TypeMirror type = argumentTypes[index];
 108         if (arguments.get(index) == null) {
 109             throw new RuntimeException(String.format("Invalid argument at index %s.", index));
 110         }
 111 
 112         if (type == null) {
 113             argumentTypes[index] = lookupType(env, arguments.get(index));
 114         }
 115         return argumentTypes[index];
 116     }
 117 
 118     private static TypeMirror lookupType(ProcessingEnvironment env, String binaryName) {
 119         if (binaryName.length() == 1) {
 120             TypeKind kind = fromPrimitiveOrVoidTypeChar(binaryName.charAt(0));
 121             if (kind.isPrimitive()) {
 122                 return env.getTypeUtils().getPrimitiveType(kind);
 123             } else if (kind == TypeKind.VOID) {
 124                 return env.getTypeUtils().getNoType(kind);
 125             }
 126         }
 127 
 128         String canonicalName = binaryName;
 129         if (canonicalName.startsWith("L") && canonicalName.endsWith(";")) {
 130             canonicalName = canonicalName.substring(1, canonicalName.length() - 1);
 131         }
 132         env.getMessager().printMessage(Kind.ERROR, canonicalName);
 133 
 134         int arrayDims = 0;
 135         while (canonicalName.startsWith("[")) {
 136             canonicalName = canonicalName.substring(1, canonicalName.length());
 137             arrayDims++;
 138         }
 139 
 140         canonicalName = canonicalName.replaceAll("/", ".");
 141         TypeElement typeElement = env.getElementUtils().getTypeElement(canonicalName);
 142         if (typeElement == null) {
 143             throw new RuntimeException(String.format("Type with name %s not found.", canonicalName));
 144         }
 145         TypeMirror mirror = typeElement.asType();
 146         for (int i = 0; i < arrayDims; i++) {
 147             mirror = env.getTypeUtils().getArrayType(mirror);
 148         }
 149         return mirror;
 150     }
 151 
 152     /**
 153      * Returns the kind from the character describing a primitive or void.
 154      *
 155      * @param ch the character
 156      * @return the kind
 157      */
 158     public static TypeKind fromPrimitiveOrVoidTypeChar(char ch) {
 159         switch (ch) {
 160             case 'Z':
 161                 return TypeKind.BOOLEAN;
 162             case 'C':
 163                 return TypeKind.CHAR;
 164             case 'F':
 165                 return TypeKind.FLOAT;
 166             case 'D':
 167                 return TypeKind.DOUBLE;
 168             case 'B':
 169                 return TypeKind.BYTE;
 170             case 'S':
 171                 return TypeKind.SHORT;
 172             case 'I':
 173                 return TypeKind.INT;
 174             case 'J':
 175                 return TypeKind.LONG;
 176             case 'V':
 177                 return TypeKind.VOID;
 178         }
 179         throw new IllegalArgumentException("unknown primitive or void type character: " + ch);
 180     }
 181 
 182     public TypeMirror getReturnType(ProcessingEnvironment env) {
 183         if (returnTypeCache == null) {
 184             if (returnType == null) {
 185                 throw new RuntimeException("Invalid return type.");
 186             }
 187             returnTypeCache = lookupType(env, returnType);
 188         }
 189         return returnTypeCache;
 190     }
 191 
 192     @Override
 193     public String toString() {
 194         return "Signature<" + originalString + ">";
 195     }
 196 }