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