1 /* 2 * Copyright (c) 2015, 2016, 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 com.sun.tools.jextract; 24 25 import java.foreign.memory.Callback; 26 import java.foreign.memory.Pointer; 27 import java.util.Objects; 28 29 /** 30 * A Java Type descriptor 31 */ 32 public abstract class JType { 33 34 /** 35 * The descriptor of this type 36 * 37 * @return The type descriptor as defined in JVMS 4.3 38 */ 39 public abstract String getDescriptor(); 40 41 public abstract String getSourceSignature(boolean isArgument); 42 43 public final static JType Void = new PrimitiveType("V", of(Void.class), "void"); 44 public final static JType Byte = new PrimitiveType("B", of(Byte.class), "byte"); 45 public final static JType Bool = new PrimitiveType("Z", of(Boolean.class), "boolean"); 46 public final static JType Char = new PrimitiveType("C", of(Character.class), "char"); 47 public final static JType Short = new PrimitiveType("S", of(Short.class), "short"); 48 public final static JType Int = new PrimitiveType("I", of(Integer.class), "int"); 49 public final static JType Long = new PrimitiveType("J", of(Long.class), "long"); 50 public final static JType Float = new PrimitiveType("F", of(Float.class), "float"); 51 public final static JType Double = new PrimitiveType("D", of(Double.class), "double"); 52 public final static JType Object = of(java.lang.Object.class); 53 54 public static JType of(final Class<?> cls) { 55 if (cls.getEnclosingClass() != null) { 56 throw new IllegalArgumentException("nested/inner class: " + cls.getName()); 57 } 58 59 if (cls.isArray()) { 60 return new ArrayType(JType.of(cls.getComponentType())); 61 } 62 if (cls.isPrimitive()) { 63 switch (cls.getTypeName()) { 64 case "int": 65 return JType.Int; 66 case "long": 67 return JType.Long; 68 case "byte": 69 return JType.Byte; 70 case "char": 71 return JType.Char; 72 case "float": 73 return JType.Float; 74 case "double": 75 return JType.Double; 76 case "short": 77 return JType.Short; 78 case "boolean": 79 return JType.Bool; 80 case "void": 81 return JType.Void; 82 } 83 } 84 if (cls == Object.class) { 85 return JType.Object; 86 } 87 // assuming reference 88 return new ClassType(binaryName(cls)); 89 } 90 91 private static String binaryName(Class<?> cls) { 92 return cls.getName().replace('.', '/'); 93 } 94 95 public JType box() { 96 return this; 97 } 98 99 public static class PrimitiveType extends JType { 100 final String desc; 101 final JType boxed; 102 final String name; 103 104 PrimitiveType(String desc, JType boxed, String name) { 105 this.desc = desc; 106 this.boxed = boxed; 107 this.name = name; 108 } 109 110 @Override 111 public JType box() { 112 return boxed; 113 } 114 115 @Override 116 public String getDescriptor() { 117 return desc; 118 } 119 120 @Override 121 public String getSourceSignature(boolean isArgument) { 122 return name; 123 } 124 } 125 126 public static class ClassType extends JType { 127 // FIXME: for nested/inner types are just one-level deep. 128 // If we generate deeply nested types, we have to revisit this. 129 130 final String enclosingName; 131 final String simpleName; 132 final String clsName; 133 final String externalName; 134 135 ClassType(String clsName) { 136 this.enclosingName = null; 137 this.simpleName = null; 138 this.clsName = Objects.requireNonNull(clsName); 139 this.externalName = clsName.replace('/', '.'); 140 } 141 142 ClassType(String enclosingName, String simpleName) { 143 this.enclosingName = Objects.requireNonNull(enclosingName); 144 this.simpleName = Objects.requireNonNull(simpleName); 145 this.clsName = enclosingName + "$" + simpleName; 146 this.externalName = enclosingName.replace('/', '.') + "." + simpleName; 147 } 148 149 @Override 150 public String getDescriptor() { 151 return "L" + clsName + ";"; 152 } 153 154 @Override 155 public String getSourceSignature(boolean isArgument) { 156 // java.foreign.* is imported 157 if (externalName.startsWith("java.lang.") || 158 externalName.startsWith("java.foreign.")) { 159 return externalName.substring(externalName.lastIndexOf(".") + 1); 160 } else { 161 return externalName; 162 } 163 } 164 165 public String getSimpleName() { 166 int innerEnd = clsName.lastIndexOf('$'); 167 int packageEnd = clsName.lastIndexOf('.'); 168 if (innerEnd != -1) { 169 return clsName.substring(innerEnd + 1); 170 } else if (packageEnd != -1) { 171 return clsName.substring(packageEnd + 1); 172 } else { 173 return clsName; 174 } 175 } 176 } 177 178 public final static class ArrayType extends JType { 179 final JType elementType; 180 181 ArrayType(JType type) { 182 elementType = type; 183 } 184 185 @Override 186 public String getDescriptor() { 187 return JType.of(java.foreign.memory.Array.class).getDescriptor(); 188 } 189 190 @Override 191 public String getSourceSignature(boolean isArgument) { 192 StringBuilder sb = new StringBuilder(); 193 sb.append("Array"); // java.foreign.memory.* will be imported 194 sb.append("<"); 195 JType pt = elementType; 196 sb.append(pt.box().getSourceSignature(isArgument)); 197 sb.append(">"); 198 return sb.toString(); 199 } 200 201 public JType getElementType() { 202 return elementType; 203 } 204 } 205 206 public final static class Function extends JType { 207 final JType returnType; 208 final JType[] args; 209 final boolean isVarArgs; 210 final java.foreign.layout.Function layout; 211 212 Function(java.foreign.layout.Function layout, boolean isVarArgs, JType returnType, JType... args) { 213 this.layout = layout; 214 this.returnType = returnType; 215 this.args = args; 216 for (int i = 0; i < args.length; i++) { 217 args[i] = arrayAsPointer(args[i]); 218 } 219 this.isVarArgs = isVarArgs; 220 } 221 222 private static JType arrayAsPointer(JType t) { 223 return t instanceof ArrayType ? 224 GenericType.ofPointer(((ArrayType)t).elementType) : 225 t; 226 } 227 228 @Override 229 public String getDescriptor() { 230 StringBuilder sb = new StringBuilder(); 231 sb.append('('); 232 // ensure sequence 233 for (int i = 0; i < args.length; i++) { 234 sb.append(args[i].getDescriptor()); 235 } 236 if (isVarArgs) { 237 sb.append("[Ljava/lang/Object;"); 238 } 239 sb.append(')'); 240 sb.append(returnType.getDescriptor()); 241 return sb.toString(); 242 } 243 244 @Override 245 public String getSourceSignature(boolean isArgument) { 246 throw new UnsupportedOperationException(); 247 } 248 249 public String getNativeDescriptor() { 250 return layout.toString(); 251 } 252 } 253 254 final static class FunctionalInterfaceType extends ClassType { 255 final Function fn; 256 257 FunctionalInterfaceType(String enclosingName, String name, Function fn) { 258 super(enclosingName, name); 259 this.fn = fn; 260 } 261 262 Function getFunction() { 263 return fn; 264 } 265 } 266 267 public static class GenericType extends ClassType { 268 JType targ; 269 270 GenericType(String base, JType targ) { 271 super(base); 272 this.targ = targ; 273 } 274 275 public JType getTypeArgument() { 276 return targ; 277 } 278 279 @Override 280 public String getSourceSignature(boolean isArgument) { 281 StringBuilder sb = new StringBuilder(); 282 sb.append(super.getSourceSignature(isArgument)); 283 sb.append("<"); 284 if (targ == JType.Void && isArgument) { 285 sb.append('?'); 286 } else { 287 if (targ instanceof GenericType && isArgument) { 288 sb.append("? extends "); 289 } 290 sb.append(targ.box().getSourceSignature(isArgument)); 291 } 292 sb.append(">"); 293 return sb.toString(); 294 } 295 296 public static GenericType ofPointer(JType targ) { 297 return new GenericType(JType.binaryName(Pointer.class), targ); 298 } 299 300 public static GenericType ofCallback(JType targ) { 301 return new GenericType(JType.binaryName(Callback.class), targ); 302 } 303 } 304 }