< prev index next >

src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/FunctionDescriptor.java

Print this page

 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 package jdk.incubator.foreign;
 26 
 27 import java.lang.constant.Constable;
 28 import java.lang.constant.ConstantDesc;
 29 import java.lang.constant.ConstantDescs;
 30 import java.lang.constant.DynamicConstantDesc;
 31 import java.util.ArrayList;
 32 import java.util.Arrays;
 33 import java.util.Collections;
 34 import java.util.HashMap;
 35 import java.util.List;
 36 import java.util.Map;
 37 import java.util.Objects;
 38 import java.util.Optional;
 39 import java.util.stream.Collectors;
 40 import java.util.stream.Stream;
 41 
 42 /**
 43  * A function descriptor is made up of zero or more argument layouts and zero or one return layout. A function descriptor
 44  * is used to model the signature of foreign functions.
 45  *
 46  * <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
 47  * elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
 48  */
 49 public final class FunctionDescriptor implements Constable {
 50 
 51     /**
 52      * The name of the function descriptor attribute (see {@link #attributes()} used to mark trivial functions. The
 53      * attribute value must be a boolean.
 54      */
 55     public static final String TRIVIAL_ATTRIBUTE_NAME = "abi/trivial";
 56 
 57     private final MemoryLayout resLayout;
 58     private final MemoryLayout[] argLayouts;
 59     private final Map<String, Constable> attributes;
 60 
 61     private FunctionDescriptor(MemoryLayout resLayout, Map<String, Constable> attributes, MemoryLayout... argLayouts) {
 62         this.resLayout = resLayout;
 63         this.attributes = attributes;
 64         this.argLayouts = argLayouts;
 65     }
 66 
 67     /**
 68      * Returns the attribute with the given name (if it exists).
 69      *
 70      * @param name the attribute name.
 71      * @return the attribute with the given name (if it exists).
 72      */
 73     public Optional<Constable> attribute(String name) {
 74         Objects.requireNonNull(name);
 75         return Optional.ofNullable(attributes.get(name));
 76     }
 77 
 78     /**
 79      * Returns a stream of the attribute names associated with this function descriptor.
 80      *
 81      * @return a stream of the attribute names associated with this function descriptor.
 82      */
 83     public Stream<String> attributes() {
 84         return attributes.keySet().stream();
 85     }
 86 
 87     /**
 88      * Returns a new function descriptor which features the same attributes as this descriptor, plus the newly specified attribute.
 89      * If this descriptor already contains an attribute with the same name, the existing attribute value is overwritten in the returned
 90      * descriptor.
 91      *
 92      * @param name the attribute name.
 93      * @param value the attribute value.
 94      * @return a new function descriptor which features the same attributes as this descriptor, plus the newly specified attribute.
 95      */
 96     public FunctionDescriptor withAttribute(String name, Constable value) {
 97         Objects.requireNonNull(name);
 98         Map<String, Constable> newAttributes = new HashMap<>(attributes);
 99         newAttributes.put(name, value);
100         return new FunctionDescriptor(resLayout, newAttributes, argLayouts);
101     }
102 
103     /**
104      * Returns the return layout associated with this function.
105      * @return the return layout.
106      */
107     public Optional<MemoryLayout> returnLayout() {
108         return Optional.ofNullable(resLayout);
109     }
110 
111     /**
112      * Returns the argument layouts associated with this function.
113      * @return the argument layouts.
114      */
115     public List<MemoryLayout> argumentLayouts() {
116         return Arrays.asList(argLayouts);
117     }
118 
119     /**
120      * Create a function descriptor with given return and argument layouts.
121      * @param resLayout the return layout.
122      * @param argLayouts the argument layouts.
123      * @return the new function descriptor.
124      */
125     public static FunctionDescriptor of(MemoryLayout resLayout, MemoryLayout... argLayouts) {
126         Objects.requireNonNull(resLayout);
127         Objects.requireNonNull(argLayouts);
128         Arrays.stream(argLayouts).forEach(Objects::requireNonNull);
129         return new FunctionDescriptor(resLayout, Map.of(), argLayouts);
130     }
131 
132     /**
133      * Create a function descriptor with given argument layouts and no return layout.
134      * @param argLayouts the argument layouts.
135      * @return the new function descriptor.
136      */
137     public static FunctionDescriptor ofVoid(MemoryLayout... argLayouts) {
138         Objects.requireNonNull(argLayouts);
139         Arrays.stream(argLayouts).forEach(Objects::requireNonNull);
140         return new FunctionDescriptor(null, Map.of(), argLayouts);
























141     }
142 
143     /**
144      * Create a new function descriptor with the given argument layouts appended to the argument layout array
145      * of this function descriptor.
146      * @param addedLayouts the argument layouts to append.
147      * @return the new function descriptor.
148      */
149     public FunctionDescriptor withAppendedArgumentLayouts(MemoryLayout... addedLayouts) {
150         Objects.requireNonNull(addedLayouts);
151         Arrays.stream(addedLayouts).forEach(Objects::requireNonNull);
152         MemoryLayout[] newLayouts = Arrays.copyOf(argLayouts, argLayouts.length + addedLayouts.length);
153         System.arraycopy(addedLayouts, 0, newLayouts, argLayouts.length, addedLayouts.length);
154         return new FunctionDescriptor(resLayout, attributes, newLayouts);
155     }
156 
157     /**
158      * Create a new function descriptor with the given memory layout as the new return layout.
159      * @param newReturn the new return layout.
160      * @return the new function descriptor.
161      */
162     public FunctionDescriptor withReturnLayout(MemoryLayout newReturn) {
163         Objects.requireNonNull(newReturn);
164         return new FunctionDescriptor(newReturn, attributes, argLayouts);
165     }
166 
167     /**
168      * Create a new function descriptor with the return layout dropped.
169      * @return the new function descriptor.
170      */
171     public FunctionDescriptor withVoidReturnLayout() {
172         return new FunctionDescriptor(null, attributes, argLayouts);
173     }
174 
175     /**
176      * Returns a string representation of this function descriptor.
177      * @return a string representation of this function descriptor.
178      */
179     @Override
180     public String toString() {
181         return String.format("(%s)%s",
182                 Stream.of(argLayouts)
183                         .map(Object::toString)
184                         .collect(Collectors.joining()),
185                 returnLayout().map(Object::toString).orElse("v"));
186     }
187 
188     /**
189      * Compares the specified object with this function descriptor for equality. Returns {@code true} if and only if the specified
190      * object is also a function descriptor, and all of the following conditions are met:
191      * <ul>
192      *     <li>the two function descriptors have equals return layouts (see {@link MemoryLayout#equals(Object)}), or both have no return layout</li>
193      *     <li>the two function descriptors have argument layouts that are pair-wise equal (see {@link MemoryLayout#equals(Object)})
194      * </ul>
195      *
196      * @param other the object to be compared for equality with this function descriptor.
197      * @return {@code true} if the specified object is equal to this function descriptor.
198      */
199     @Override
200     public boolean equals(Object other) {
201         if (this == other) {
202             return true;
203         }
204         if (!(other instanceof FunctionDescriptor)) {
205             return false;
206         }
207         FunctionDescriptor f = (FunctionDescriptor) other;
208         return Objects.equals(resLayout, f.resLayout) && Arrays.equals(argLayouts, f.argLayouts);
209     }
210 
211     /**
212      * Returns the hash code value for this function descriptor.
213      * @return the hash code value for this function descriptor.
214      */
215     @Override
216     public int hashCode() {
217         int hashCode = Arrays.hashCode(argLayouts);
218         return resLayout == null ? hashCode : resLayout.hashCode() ^ hashCode;
219     }
220 
221     @Override
222     public Optional<DynamicConstantDesc<FunctionDescriptor>> describeConstable() {
223         List<ConstantDesc> constants = new ArrayList<>();
224         constants.add(resLayout == null ? AbstractLayout.MH_VOID_FUNCTION : AbstractLayout.MH_FUNCTION);
225         if (resLayout != null) {
226             constants.add(resLayout.describeConstable().get());
227         }
228         for (MemoryLayout argLayout : argLayouts) {
229             constants.add(argLayout.describeConstable().get());
230         }
231         return Optional.of(DynamicConstantDesc.ofNamed(
232                     ConstantDescs.BSM_INVOKE, "function", AbstractLayout.CD_FUNCTION_DESC, constants.toArray(new ConstantDesc[0])));
233     }







































234 }

 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 package jdk.incubator.foreign;
 26 
 27 import java.lang.constant.Constable;
 28 import java.lang.constant.ConstantDesc;
 29 import java.lang.constant.ConstantDescs;
 30 import java.lang.constant.DynamicConstantDesc;
 31 import java.util.ArrayList;
 32 import java.util.Arrays;


 33 import java.util.List;

 34 import java.util.Objects;
 35 import java.util.Optional;
 36 import java.util.stream.Collectors;
 37 import java.util.stream.Stream;
 38 
 39 /**
 40  * A function descriptor is made up of zero or more argument layouts and zero or one return layout. A function descriptor
 41  * is used to model the signature of foreign functions.
 42  *
 43  * <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
 44  * elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
 45  */
 46 public sealed class FunctionDescriptor implements Constable permits FunctionDescriptor.VariadicFunction {






 47 
 48     private final MemoryLayout resLayout;
 49     private final MemoryLayout[] argLayouts;

 50 
 51     private FunctionDescriptor(MemoryLayout resLayout, MemoryLayout... argLayouts) {
 52         this.resLayout = resLayout;

 53         this.argLayouts = argLayouts;
 54     }
 55 




































 56     /**
 57      * Returns the return layout associated with this function.
 58      * @return the return layout.
 59      */
 60     public Optional<MemoryLayout> returnLayout() {
 61         return Optional.ofNullable(resLayout);
 62     }
 63 
 64     /**
 65      * Returns the argument layouts associated with this function.
 66      * @return the argument layouts.
 67      */
 68     public List<MemoryLayout> argumentLayouts() {
 69         return Arrays.asList(argLayouts);
 70     }
 71 
 72     /**
 73      * Create a function descriptor with given return and argument layouts.
 74      * @param resLayout the return layout.
 75      * @param argLayouts the argument layouts.
 76      * @return the new function descriptor.
 77      */
 78     public static FunctionDescriptor of(MemoryLayout resLayout, MemoryLayout... argLayouts) {
 79         Objects.requireNonNull(resLayout);
 80         Objects.requireNonNull(argLayouts);
 81         Arrays.stream(argLayouts).forEach(Objects::requireNonNull);
 82         return new FunctionDescriptor(resLayout, argLayouts);
 83     }
 84 
 85     /**
 86      * Create a function descriptor with given argument layouts and no return layout.
 87      * @param argLayouts the argument layouts.
 88      * @return the new function descriptor.
 89      */
 90     public static FunctionDescriptor ofVoid(MemoryLayout... argLayouts) {
 91         Objects.requireNonNull(argLayouts);
 92         Arrays.stream(argLayouts).forEach(Objects::requireNonNull);
 93         return new FunctionDescriptor(null, argLayouts);
 94     }
 95 
 96     /**
 97      * Obtain a specialized variadic function descriptor, by appending given variadic layouts to this
 98      * function descriptor argument layouts. The resulting function descriptor can report the position
 99      * of the {@linkplain #firstVariadicArgumentIndex() first variadic argument}, and cannot be altered
100      * in any way: for instance, calling {@link #withReturnLayout(MemoryLayout)} on the resulting descriptor
101      * will throw an {@link UnsupportedOperationException}.
102      * @param variadicLayouts the variadic argument layouts to be appended to this descriptor argument layouts.
103      * @return a new variadic function descriptor, or this descriptor if {@code variadicLayouts.length == 0}.
104      */
105     public FunctionDescriptor asVariadic(MemoryLayout... variadicLayouts) {
106         Objects.requireNonNull(variadicLayouts);
107         Arrays.stream(variadicLayouts).forEach(Objects::requireNonNull);
108         return variadicLayouts.length == 0 ? this : new VariadicFunction(this, variadicLayouts);
109     }
110 
111     /**
112      * The index of the first variadic argument layout (where defined).
113      * @return The index of the first variadic argument layout, or {@code -1} if this is not a
114      * {@linkplain #asVariadic(MemoryLayout...) variadic} layout.
115      */
116     public int firstVariadicArgumentIndex() {
117         return -1;
118     }
119 
120     /**
121      * Create a new function descriptor with the given argument layouts appended to the argument layout array
122      * of this function descriptor.
123      * @param addedLayouts the argument layouts to append.
124      * @return the new function descriptor.
125      */
126     public FunctionDescriptor withAppendedArgumentLayouts(MemoryLayout... addedLayouts) {
127         Objects.requireNonNull(addedLayouts);
128         Arrays.stream(addedLayouts).forEach(Objects::requireNonNull);
129         MemoryLayout[] newLayouts = Arrays.copyOf(argLayouts, argLayouts.length + addedLayouts.length);
130         System.arraycopy(addedLayouts, 0, newLayouts, argLayouts.length, addedLayouts.length);
131         return new FunctionDescriptor(resLayout, newLayouts);
132     }
133 
134     /**
135      * Create a new function descriptor with the given memory layout as the new return layout.
136      * @param newReturn the new return layout.
137      * @return the new function descriptor.
138      */
139     public FunctionDescriptor withReturnLayout(MemoryLayout newReturn) {
140         Objects.requireNonNull(newReturn);
141         return new FunctionDescriptor(newReturn, argLayouts);
142     }
143 
144     /**
145      * Create a new function descriptor with the return layout dropped.
146      * @return the new function descriptor.
147      */
148     public FunctionDescriptor withVoidReturnLayout() {
149         return new FunctionDescriptor(null, argLayouts);
150     }
151 
152     /**
153      * Returns a string representation of this function descriptor.
154      * @return a string representation of this function descriptor.
155      */
156     @Override
157     public String toString() {
158         return String.format("(%s)%s",
159                 Stream.of(argLayouts)
160                         .map(Object::toString)
161                         .collect(Collectors.joining()),
162                 returnLayout().map(Object::toString).orElse("v"));
163     }
164 
165     /**
166      * Compares the specified object with this function descriptor for equality. Returns {@code true} if and only if the specified
167      * object is also a function descriptor, and all the following conditions are met:
168      * <ul>
169      *     <li>the two function descriptors have equals return layouts (see {@link MemoryLayout#equals(Object)}), or both have no return layout</li>
170      *     <li>the two function descriptors have argument layouts that are pair-wise equal (see {@link MemoryLayout#equals(Object)})
171      * </ul>
172      *
173      * @param other the object to be compared for equality with this function descriptor.
174      * @return {@code true} if the specified object is equal to this function descriptor.
175      */
176     @Override
177     public boolean equals(Object other) {
178         if (this == other) {
179             return true;
180         }
181         if (!(other instanceof FunctionDescriptor f)) {
182             return false;
183         }

184         return Objects.equals(resLayout, f.resLayout) && Arrays.equals(argLayouts, f.argLayouts);
185     }
186 
187     /**
188      * Returns the hash code value for this function descriptor.
189      * @return the hash code value for this function descriptor.
190      */
191     @Override
192     public int hashCode() {
193         int hashCode = Arrays.hashCode(argLayouts);
194         return resLayout == null ? hashCode : resLayout.hashCode() ^ hashCode;
195     }
196 
197     @Override
198     public Optional<DynamicConstantDesc<FunctionDescriptor>> describeConstable() {
199         List<ConstantDesc> constants = new ArrayList<>();
200         constants.add(resLayout == null ? AbstractLayout.MH_VOID_FUNCTION : AbstractLayout.MH_FUNCTION);
201         if (resLayout != null) {
202             constants.add(resLayout.describeConstable().get());
203         }
204         for (MemoryLayout argLayout : argLayouts) {
205             constants.add(argLayout.describeConstable().get());
206         }
207         return Optional.of(DynamicConstantDesc.ofNamed(
208                     ConstantDescs.BSM_INVOKE, "function", AbstractLayout.CD_FUNCTION_DESC, constants.toArray(new ConstantDesc[0])));
209     }
210 
211     static final class VariadicFunction extends FunctionDescriptor {
212 
213         private final int firstVariadicIndex;
214 
215         public VariadicFunction(FunctionDescriptor descriptor, MemoryLayout... argLayouts) {
216             super(descriptor.returnLayout().orElse(null),
217                     Stream.concat(descriptor.argumentLayouts().stream(), Stream.of(argLayouts)).toArray(MemoryLayout[]::new));
218             this.firstVariadicIndex = descriptor.argumentLayouts().size();
219         }
220 
221         public boolean isVariadicIndex(int pos) {
222             return pos >= firstVariadicIndex;
223         }
224 
225         public int firstVariadicArgumentIndex() {
226             return firstVariadicIndex;
227         }
228 
229         @Override
230         public FunctionDescriptor withAppendedArgumentLayouts(MemoryLayout... addedLayouts) {
231             throw new UnsupportedOperationException();
232         }
233 
234         @Override
235         public FunctionDescriptor withReturnLayout(MemoryLayout newReturn) {
236             throw new UnsupportedOperationException();
237         }
238 
239         @Override
240         public FunctionDescriptor withVoidReturnLayout() {
241             throw new UnsupportedOperationException();
242         }
243 
244         @Override
245         public Optional<DynamicConstantDesc<FunctionDescriptor>> describeConstable() {
246             return Optional.empty();
247         }
248     }
249 }
< prev index next >