1 /* 2 * Copyright (c) 2020, 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 27 package jdk.internal.jextract.impl; 28 29 import java.util.List; 30 import java.util.Objects; 31 import java.util.Optional; 32 import java.util.OptionalLong; 33 import java.util.function.Supplier; 34 35 import jdk.incubator.foreign.FunctionDescriptor; 36 import jdk.incubator.foreign.MemoryLayout; 37 import jdk.incubator.foreign.ValueLayout; 38 import jdk.incubator.jextract.Declaration; 39 import jdk.incubator.jextract.Type; 40 41 import static jdk.incubator.foreign.ValueLayout.ADDRESS; 42 43 public abstract class TypeImpl implements Type { 44 45 public static final boolean IS_WINDOWS = System.getProperty("os.name").startsWith("Windows"); 46 47 @Override 48 public boolean isErroneous() { 49 return false; 50 } 51 52 static boolean equals(Type t1, Type.Delegated t2) { 53 assert t1 != null; 54 assert t2 != null; 55 56 return (t2.kind() == Delegated.Kind.TYPEDEF) && t1.equals(t2.type()); 57 } 58 59 public static final TypeImpl ERROR = new TypeImpl() { 60 @Override 61 public <R, D> R accept(Visitor<R, D> visitor, D data) { 62 return visitor.visitType(this, data); 63 } 64 65 @Override 66 public boolean isErroneous() { 67 return true; 68 } 69 }; 70 71 public static final class PrimitiveImpl extends TypeImpl implements Type.Primitive { 72 73 private final Primitive.Kind kind; 74 75 public PrimitiveImpl(Kind kind) { 76 this.kind = Objects.requireNonNull(kind); 77 } 78 79 @Override 80 public <R, D> R accept(Visitor<R, D> visitor, D data) { 81 return visitor.visitPrimitive(this, data); 82 } 83 84 @Override 85 public Kind kind() { 86 return kind; 87 } 88 89 @Override 90 public boolean equals(Object o) { 91 if (this == o) return true; 92 if (!(o instanceof Type.Primitive)) { 93 return (o instanceof Delegated) && equals(this, (Delegated)o); 94 } 95 Type.Primitive primitive = (Type.Primitive) o; 96 return kind == primitive.kind(); 97 } 98 99 @Override 100 public int hashCode() { 101 return Objects.hash(kind); 102 } 103 } 104 105 static abstract class DelegatedBase extends TypeImpl implements Type.Delegated { 106 Delegated.Kind kind; 107 Optional<String> name; 108 109 DelegatedBase(Kind kind, Optional<String> name) { 110 this.kind = Objects.requireNonNull(kind); 111 this.name = Objects.requireNonNull(name); 112 } 113 114 @Override 115 public <R, D> R accept(Visitor<R, D> visitor, D data) { 116 return visitor.visitDelegated(this, data); 117 } 118 119 @Override 120 public final Delegated.Kind kind() { 121 return kind; 122 } 123 124 @Override 125 public final Optional<String> name() { 126 return name; 127 } 128 129 @Override 130 public boolean equals(Object o) { 131 if (this == o) return true; 132 if (!(o instanceof Type.Delegated)) { 133 return (o instanceof Type) && equals((Type)o, this); 134 } 135 Type.Delegated that = (Type.Delegated) o; 136 return kind == that.kind() && 137 name.equals(that.name()); 138 } 139 140 @Override 141 public int hashCode() { 142 return Objects.hash(kind, name); 143 } 144 } 145 146 public static final class QualifiedImpl extends DelegatedBase { 147 private final Type type; 148 149 public QualifiedImpl(Kind kind, Type type) { 150 this(kind, Optional.empty(), type); 151 } 152 153 public QualifiedImpl(Kind kind, String name, Type type) { 154 this(kind, Optional.of(name), type); 155 } 156 157 private QualifiedImpl(Kind kind, Optional<String> name, Type type) { 158 super(kind, name); 159 this.type = type; 160 } 161 162 @Override 163 public Type type() { 164 return type; 165 } 166 167 @Override 168 public boolean equals(Object o) { 169 if (this == o) return true; 170 if (!(o instanceof Type.Delegated)) return false; 171 if (!super.equals(o)) { 172 return (o instanceof Delegated) && equals(this, (Delegated) o); 173 } 174 Type.Delegated qualified = (Type.Delegated) o; 175 return Objects.equals(type, qualified.type()); 176 } 177 178 @Override 179 public int hashCode() { 180 return (kind() == Kind.TYPEDEF)? type().hashCode() : Objects.hash(super.hashCode(), type); 181 } 182 } 183 184 public static final class PointerImpl extends DelegatedBase { 185 public static final ValueLayout.OfAddress POINTER_LAYOUT = ADDRESS.withBitAlignment(64); 186 187 private final Supplier<Type> pointeeFactory; 188 189 public PointerImpl(Supplier<Type> pointeeFactory) { 190 super(Kind.POINTER, Optional.empty()); 191 this.pointeeFactory = Objects.requireNonNull(pointeeFactory); 192 } 193 194 public PointerImpl(Type pointee) { 195 this(() -> pointee); 196 } 197 198 @Override 199 public Type type() { 200 return pointeeFactory.get(); 201 } 202 } 203 204 public static final class DeclaredImpl extends TypeImpl implements Type.Declared { 205 206 private final Declaration.Scoped declaration; 207 208 public DeclaredImpl(Declaration.Scoped declaration) { 209 super(); 210 this.declaration = Objects.requireNonNull(declaration); 211 } 212 213 @Override 214 public <R, D> R accept(Visitor<R, D> visitor, D data) { 215 return visitor.visitDeclared(this, data); 216 } 217 218 @Override 219 public Declaration.Scoped tree() { 220 return declaration; 221 } 222 223 @Override 224 public boolean equals(Object o) { 225 if (this == o) return true; 226 if (!(o instanceof Type.Declared)) { 227 return (o instanceof Delegated) && equals(this, (Delegated) o); 228 } 229 Type.Declared declared = (Type.Declared) o; 230 return declaration.equals(declared.tree()); 231 } 232 233 @Override 234 public int hashCode() { 235 return Objects.hash(declaration); 236 } 237 } 238 239 public static final class FunctionImpl extends TypeImpl implements Type.Function { 240 241 private final boolean varargs; 242 private final List<Type> argtypes; 243 private final Type restype; 244 private final Optional<List<String>> paramNames; 245 246 public FunctionImpl(boolean varargs, List<Type> argtypes, Type restype, List<String> paramNames) { 247 super(); 248 this.varargs = varargs; 249 this.argtypes = Objects.requireNonNull(argtypes); 250 this.restype = Objects.requireNonNull(restype); 251 this.paramNames = Optional.ofNullable(paramNames); 252 } 253 254 public FunctionImpl(boolean varargs, List<Type> argtypes, Type restype) { 255 this(varargs, argtypes, restype, null); 256 } 257 258 @Override 259 public <R, D> R accept(Visitor<R, D> visitor, D data) { 260 return visitor.visitFunction(this, data); 261 } 262 263 @Override 264 public boolean varargs() { 265 return varargs; 266 } 267 268 @Override 269 public List<Type> argumentTypes() { 270 return argtypes; 271 } 272 273 @Override 274 public Type returnType() { 275 return restype; 276 } 277 278 @Override 279 public Type.Function withParameterNames(List<String> paramNames) { 280 Objects.requireNonNull(paramNames); 281 return new FunctionImpl(varargs, argtypes, restype, paramNames); 282 } 283 284 @Override 285 public Optional<List<String>> parameterNames() { 286 return paramNames; 287 } 288 289 @Override 290 public boolean equals(Object o) { 291 if (this == o) return true; 292 if (!(o instanceof Type.Function)) { 293 return (o instanceof Delegated) && equals(this, (Delegated) o); 294 } 295 Type.Function function = (Type.Function) o; 296 return varargs == function.varargs() && 297 argtypes.equals(function.argumentTypes()) && 298 restype.equals(function.returnType()); 299 } 300 301 @Override 302 public int hashCode() { 303 return Objects.hash(varargs, argtypes, restype); 304 } 305 } 306 307 public static final class ArrayImpl extends TypeImpl implements Type.Array { 308 309 private final Kind kind; 310 private final OptionalLong elemCount; 311 private final Type elemType; 312 313 public ArrayImpl(Kind kind, long count, Type elemType) { 314 this(kind, elemType, OptionalLong.of(count)); 315 } 316 317 public ArrayImpl(Kind kind, Type elemType) { 318 this(kind, elemType, OptionalLong.empty()); 319 } 320 321 private ArrayImpl(Kind kind, Type elemType, OptionalLong elemCount) { 322 super(); 323 this.kind = Objects.requireNonNull(kind); 324 this.elemCount = Objects.requireNonNull(elemCount); 325 this.elemType = Objects.requireNonNull(elemType); 326 } 327 328 @Override 329 public <R, D> R accept(Visitor<R, D> visitor, D data) { 330 return visitor.visitArray(this, data); 331 } 332 333 @Override 334 public OptionalLong elementCount() { 335 return elemCount; 336 } 337 338 @Override 339 public Type elementType() { 340 return elemType; 341 } 342 343 @Override 344 public Kind kind() { 345 return kind; 346 } 347 348 @Override 349 public boolean equals(Object o) { 350 if (this == o) return true; 351 if (!(o instanceof Type.Array)) { 352 return (o instanceof Delegated) && equals(this, (Delegated) o); 353 } 354 Type.Array array = (Type.Array) o; 355 return kind == array.kind() && 356 elemType.equals(array.elementType()); 357 } 358 359 @Override 360 public int hashCode() { 361 return Objects.hash(kind, elemType); 362 } 363 } 364 365 public boolean isPointer() { 366 return this instanceof Type.Delegated delegated && 367 delegated.kind() == Type.Delegated.Kind.POINTER; 368 } 369 370 @Override 371 public String toString() { 372 return PrettyPrinter.type(this); 373 } 374 375 // Utilities to fetch layouts/descriptor from types 376 377 public static Optional<MemoryLayout> getLayout(jdk.incubator.jextract.Type t) { 378 try { 379 return Optional.of(getLayoutInternal(t)); 380 } catch (Throwable ex) { 381 return Optional.empty(); 382 } 383 } 384 385 public static Optional<FunctionDescriptor> getDescriptor(Function t) { 386 try { 387 MemoryLayout[] args = t.argumentTypes().stream() 388 .map(TypeImpl::getLayoutInternal) 389 .toArray(MemoryLayout[]::new); 390 Type retType = t.returnType(); 391 if (isVoidType(retType)) { 392 return Optional.of(FunctionDescriptor.ofVoid(args)); 393 } else { 394 return Optional.of(FunctionDescriptor.of(getLayoutInternal(retType), args)); 395 } 396 } catch (Throwable ex) { 397 return Optional.empty(); 398 } 399 } 400 401 private static boolean isVoidType(jdk.incubator.jextract.Type type) { 402 if (type instanceof jdk.incubator.jextract.Type.Primitive) { 403 jdk.incubator.jextract.Type.Primitive pt = (jdk.incubator.jextract.Type.Primitive)type; 404 return pt.kind() == jdk.incubator.jextract.Type.Primitive.Kind.Void; 405 } else if (type instanceof jdk.incubator.jextract.Type.Delegated) { 406 jdk.incubator.jextract.Type.Delegated dt = (jdk.incubator.jextract.Type.Delegated)type; 407 return dt.kind() == jdk.incubator.jextract.Type.Delegated.Kind.TYPEDEF? isVoidType(dt.type()) : false; 408 } 409 return false; 410 } 411 412 public static MemoryLayout getLayoutInternal(jdk.incubator.jextract.Type t) { 413 return t.accept(layoutMaker, null); 414 } 415 416 private static jdk.incubator.jextract.Type.Visitor<MemoryLayout, Void> layoutMaker = new jdk.incubator.jextract.Type.Visitor<>() { 417 @Override 418 public MemoryLayout visitPrimitive(jdk.incubator.jextract.Type.Primitive t, Void _ignored) { 419 return t.kind().layout().orElseThrow(UnsupportedOperationException::new); 420 } 421 422 @Override 423 public MemoryLayout visitDelegated(jdk.incubator.jextract.Type.Delegated t, Void _ignored) { 424 if (t.kind() == jdk.incubator.jextract.Type.Delegated.Kind.POINTER) { 425 return PointerImpl.POINTER_LAYOUT; 426 } else { 427 return t.type().accept(this, null); 428 } 429 } 430 431 @Override 432 public MemoryLayout visitFunction(jdk.incubator.jextract.Type.Function t, Void _ignored) { 433 /* 434 * // pointer to function declared as function like this 435 * 436 * typedef void CB(int); 437 * void func(CB cb); 438 */ 439 return PointerImpl.POINTER_LAYOUT; 440 } 441 442 @Override 443 public MemoryLayout visitDeclared(jdk.incubator.jextract.Type.Declared t, Void _ignored) { 444 return t.tree().layout().orElseThrow(UnsupportedOperationException::new); 445 } 446 447 @Override 448 public MemoryLayout visitArray(jdk.incubator.jextract.Type.Array t, Void _ignored) { 449 MemoryLayout elem = t.elementType().accept(this, null); 450 if (t.elementCount().isPresent()) { 451 return MemoryLayout.sequenceLayout(t.elementCount().getAsLong(), elem); 452 } else { 453 return MemoryLayout.sequenceLayout(elem); 454 } 455 } 456 457 @Override 458 public MemoryLayout visitType(jdk.incubator.jextract.Type t, Void _ignored) { 459 throw new UnsupportedOperationException(); 460 } 461 }; 462 }