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.
  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 
 24 package jdk.experimental.bytecode;
 25 
 26 import java.util.Iterator;
 27 
 28 /**
 29  * Helper to create and manipulate type descriptors, where type descriptors
 30  * are represented as JVM type descriptor strings and symbols are represented
 31  * as name strings
 32  */
 33 public class BasicTypeHelper implements TypeHelper<String, String> {
 34 
 35     @Override
 36     public String elemtype(String s) {
 37         if (!s.startsWith("[")) {
 38             throw new IllegalStateException();
 39         }
 40         return s.substring(1);
 41     }
 42 
 43     @Override
 44     public String arrayOf(String s) {
 45         return "[" + s;
 46     }
 47 
 48     @Override
 49     public String type(String s) {
 50         return "L" + s + ";";
 51     }
 52 
 53 
 54     @Override
 55     public TypeTag tag(String s) {
 56         switch (s.charAt(0)) {
 57             case '[':
 58             case 'L':
 59                 return TypeTag.A;
 60             case 'B':
 61             case 'C':
 62             case 'Z':
 63             case 'S':
 64             case 'I':
 65                 return TypeTag.I;
 66             case 'F':
 67                 return TypeTag.F;
 68             case 'J':
 69                 return TypeTag.J;
 70             case 'D':
 71                 return TypeTag.D;
 72             case 'V':
 73                 return TypeTag.V;
 74             default:
 75                 if (s == nullType()) {
 76                     return TypeTag.A;
 77                 }
 78                 throw new IllegalStateException("Bad type: " + s);
 79         }
 80     }
 81 
 82     @Override
 83     public String nullType() {
 84         // Needed in TypedCodeBuilder; ACONST_NULL pushes a 'null' onto the stack,
 85         // and stack maps handle null differently
 86         return "<null>";
 87     }
 88 
 89     @Override
 90     public String commonSupertype(String t1, String t2) {
 91         if (t1.equals(t2)) {
 92             return t1;
 93         } else {
 94             try {
 95                 Class<?> c1 = from(t1);
 96                 Class<?> c2 = from(t2);
 97                 if (c1.isAssignableFrom(c2)) {
 98                     return t1;
 99                 } else if (c2.isAssignableFrom(c1)) {
100                     return t2;
101                 } else {
102                     return "Ljava/lang/Object;";
103                 }
104             } catch (Exception e) {
105                 return null;
106             }
107         }
108     }
109 
110     public Class<?> from(String desc) throws ReflectiveOperationException {
111         if (desc.startsWith("[")) {
112             return Class.forName(desc.replaceAll("/", "."));
113         } else {
114             return Class.forName(symbol(desc).replaceAll("/", "."));
115         }
116     }
117 
118     @Override
119     public Iterator<String> parameterTypes(String s) {
120         //TODO: gracefully non-method types
121         return new Iterator<String>() {
122             int ch = 1;
123 
124             @Override
125             public boolean hasNext() {
126                 return s.charAt(ch) != ')';
127             }
128 
129             @Override
130             public String next() {
131                 char curr = s.charAt(ch);
132                 switch (curr) {
133                     case 'C':
134                     case 'B':
135                     case 'S':
136                     case 'I':
137                     case 'J':
138                     case 'F':
139                     case 'D':
140                     case 'Z':
141                         ch++;
142                         return String.valueOf(curr);
143                     case '[':
144                         ch++;
145                         return "[" + next();
146                     case 'L':
147                         StringBuilder builder = new StringBuilder();
148                         while (curr != ';') {
149                             builder.append(curr);
150                             curr = s.charAt(++ch);
151                         }
152                         builder.append(';');
153                         ch++;
154                         return builder.toString();
155                     default:
156                         throw new AssertionError("cannot parse string: " + s);
157                 }
158             }
159         };
160     }
161 
162     @Override
163     public String symbolFrom(String s) {
164         return s;
165     }
166 
167     @Override
168     public String fromTag(TypeTag tag) {
169         return tag.name();
170     }
171 
172     @Override
173     public String symbol(String type) {
174         return (type.startsWith("L") || type.startsWith("Q")) ? type.substring(1, type.length() - 1) : type;
175     }
176 
177     @Override
178     public String returnType(String s) {
179         return s.substring(s.indexOf(')') + 1, s.length());
180     }
181 
182 }