1 /*
   2  * Copyright (c) 2017, 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.experimental.bytecode;
  27 
  28 import java.util.Iterator;
  29 
  30 /**
  31  * Helper to create and manipulate type descriptors, where type descriptors
  32  * are represented as JVM type descriptor strings and symbols are represented
  33  * as name strings
  34  */
  35 public class BasicTypeHelper implements TypeHelper<String, String> {
  36 
  37     @Override
  38     public String elemtype(String s) {
  39         if (!s.startsWith("[")) {
  40             throw new IllegalStateException();
  41         }
  42         return s.substring(1);
  43     }
  44 
  45     @Override
  46     public String arrayOf(String s) {
  47         return "[" + s;
  48     }
  49 
  50     @Override
  51     public boolean isValue(String t) {
  52         return t.charAt(0) == 'Q' && t.endsWith(";");
  53     }
  54 
  55     @Override
  56     public String type(String s) {
  57         return "L" + s + ";";
  58     }
  59 
  60     @Override
  61     public String valueType(String s) {
  62         return "Q" + s + ";";
  63     }
  64 
  65     @Override
  66     public TypeTag tag(String s) {
  67         switch (s.charAt(0)) {
  68             case '[':
  69             case 'Q':
  70             case 'L':
  71                 return TypeTag.A;
  72             case 'B':
  73             case 'C':
  74             case 'Z':
  75             case 'S':
  76             case 'I':
  77                 return TypeTag.I;
  78             case 'F':
  79                 return TypeTag.F;
  80             case 'J':
  81                 return TypeTag.J;
  82             case 'D':
  83                 return TypeTag.D;
  84             case 'V':
  85                 return TypeTag.V;
  86             default:
  87                 if (s == nullType()) {
  88                     return TypeTag.A;
  89                 }
  90                 throw new IllegalStateException("Bad type: " + s);
  91         }
  92     }
  93 
  94     @Override
  95     public String nullType() {
  96         // Needed in TypedCodeBuilder; ACONST_NULL pushes a 'null' onto the stack,
  97         // and stack maps handle null differently
  98         return "<null>";
  99     }
 100 
 101     @Override
 102     public String commonSupertype(String t1, String t2) {
 103         if (t1.equals(t2)) {
 104             return t1;
 105         } else {
 106             try {
 107                 Class<?> c1 = from(t1);
 108                 Class<?> c2 = from(t2);
 109                 if (c1.isAssignableFrom(c2)) {
 110                     return t1;
 111                 } else if (c2.isAssignableFrom(c1)) {
 112                     return t2;
 113                 } else {
 114                     return "Ljava/lang/Object;";
 115                 }
 116             } catch (Exception e) {
 117                 return null;
 118             }
 119         }
 120     }
 121 
 122     public Class<?> from(String desc) throws ReflectiveOperationException {
 123         if (desc.startsWith("[")) {
 124             return Class.forName(desc.replaceAll("/", "."));
 125         } else {
 126             return Class.forName(symbol(desc).replaceAll("/", "."));
 127         }
 128     }
 129 
 130     @Override
 131     public Iterator<String> parameterTypes(String s) {
 132         //TODO: gracefully non-method types
 133         return new Iterator<String>() {
 134             int ch = 1;
 135 
 136             @Override
 137             public boolean hasNext() {
 138                 return s.charAt(ch) != ')';
 139             }
 140 
 141             @Override
 142             public String next() {
 143                 char curr = s.charAt(ch);
 144                 switch (curr) {
 145                     case 'C':
 146                     case 'B':
 147                     case 'S':
 148                     case 'I':
 149                     case 'J':
 150                     case 'F':
 151                     case 'D':
 152                     case 'Z':
 153                         ch++;
 154                         return String.valueOf(curr);
 155                     case '[':
 156                         ch++;
 157                         return "[" + next();
 158                     case 'Q':
 159                     case 'L':
 160                         StringBuilder builder = new StringBuilder();
 161                         while (curr != ';') {
 162                             builder.append(curr);
 163                             curr = s.charAt(++ch);
 164                         }
 165                         builder.append(';');
 166                         ch++;
 167                         return builder.toString();
 168                     default:
 169                         throw new AssertionError("cannot parse string: " + s);
 170                 }
 171             }
 172         };
 173     }
 174 
 175     @Override
 176     public String symbolFrom(String s) {
 177         return s;
 178     }
 179 
 180     @Override
 181     public String fromTag(TypeTag tag) {
 182         return tag.name();
 183     }
 184 
 185     @Override
 186     public String symbol(String type) {
 187         if (type.startsWith("L") || type.startsWith("Q")) {
 188             return type.substring(1, type.length() - 1);
 189         } else {
 190             return type;
 191         }
 192     }
 193 
 194     @Override
 195     public String returnType(String s) {
 196         return s.substring(s.indexOf(')') + 1, s.length());
 197     }
 198 
 199 }