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 }