/** * Copyright 2013, Landz and its contributors. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package z.znr.invoke.types; import z.znr.invoke.linux.x64.Util; import java.lang.invoke.MethodType; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * Native function call context * * This class holds all the information that JFFI needs to correctly call a * native function, or to implement a callback from native code to java. */ public final class Signature { public static final int DEFAULT = 0x1; public static final int SAVE_ERRNO = 0x2; public static final int FAULT_PROTECT = 0x4; private static final int VALID_FLAGS = (DEFAULT | SAVE_ERRNO | FAULT_PROTECT); /** The return type of this function */ private final ResultType resultType; /** The parameter types of this function */ private final ParameterType[] parameterTypes; private final int flags; private com.kenai.jffi.CallContext jffiContext; /** * Returns a {@link Signature} instance. This may return a previously cached instance that matches * the signature requested, and should be used in preference to instantiating new instances. * * @param resultType The return type of the native function. * @param parameterTypes The parameter types the function accepts. * @return An instance of Signature */ public static Signature getSignature(ResultType resultType, ParameterType[] parameterTypes) { return new Signature(resultType, parameterTypes, DEFAULT); } /** * Returns a {@link Signature} instance. This may return a previously cached instance that matches * the signature requested, and should be used in preference to instantiating new instances. * * @param resultType The return type of the native function. * @param parameterTypes The parameter types the function accepts. * @param flags the flags for the call. * @return An instance of Signature */ public static Signature getSignature(ResultType resultType, ParameterType[] parameterTypes, int flags) { return new Signature(resultType, parameterTypes, flags); } /** * Returns a {@link Signature} instance. This may return a previously cached instance that matches * the signature requested, and should be used in preference to instantiating new instances. * * @param resultType The return type of the native function. * @param parameterTypes The parameter types the function accepts. * @param saveErrno Indicates that the errno should be saved * @return An instance of Signature */ public static Signature getSignature(ResultType resultType, ParameterType[] parameterTypes, boolean saveErrno) { return new Signature(resultType, parameterTypes, (saveErrno ? SAVE_ERRNO : 0)); } public static Signature getSignature(ResultType resultType, ParameterType[] parameterTypes, boolean saveErrno, boolean faultProtect) { return new Signature(resultType, parameterTypes, (saveErrno ? SAVE_ERRNO : 0) | (faultProtect ? FAULT_PROTECT : 0)); } /** * Returns a {@link Signature} instance. This may return a previously cached instance that matches * the signature requested, and should be used in preference to instantiating new instances. * * @param flags Flags. * @param resultType The return type of the native function. * @param parameterTypes The parameter types the function accepts. * @return An instance of Signature */ public static Signature getSignature(int flags, ResultType resultType, ParameterType... parameterTypes) { return new Signature(resultType, parameterTypes, flags); } /** * Creates a new instance of <tt>Function</tt>. * * @param resultType The return type of the native function. * @param parameterTypes The parameter types the function accepts. */ private Signature(ResultType resultType, ParameterType[] parameterTypes, int flags) { this.resultType = resultType; this.parameterTypes = parameterTypes.clone(); this.flags = flags & VALID_FLAGS; } /** * Gets the number of parameters the native function accepts. * * @return The number of parameters the native function accepts. */ public final int getParameterCount() { return parameterTypes.length; } /** * Gets the native return type of this function. * * @return The native return type of this function. */ public final ResultType getResultType() { return resultType; } /** * Gets the type of a parameter. * * @param index The index of the parameter in the function signature * @return The <tt>Type</tt> of the parameter. */ public final ParameterType getParameterType(int index) { return parameterTypes[index]; } public com.kenai.jffi.CallContext getNativeCallContext() { return jffiContext != null ? jffiContext : createNativeCallContext(); } public boolean saveErrno() { return (flags & SAVE_ERRNO) != 0; } private synchronized com.kenai.jffi.CallContext createNativeCallContext() { if (jffiContext != null) { return jffiContext; } com.kenai.jffi.Type[] nativeParamTypes = new com.kenai.jffi.Type[parameterTypes.length]; for (int i = 0; i < nativeParamTypes.length; ++i) { nativeParamTypes[i] = parameterTypes[i].jffiType(); } return jffiContext = com.kenai.jffi.CallContext.getCallContext(resultType.jffiType(), nativeParamTypes, jffiConvention(flags), saveErrno(), (flags & FAULT_PROTECT) != 0); } public MethodType methodType() { return MethodType.methodType(resultType.javaType(), Util.javaTypeArray(parameterTypes)); } public ParameterType[] parameterTypeArray() { return parameterTypes.clone(); } public List<ParameterType> parameterTypeList() { return Collections.unmodifiableList(Arrays.asList(parameterTypes)); } public Signature asPrimitiveContext() { return getSignature(flags, resultType.asPrimitiveType(), Util.asPrimitiveTypes(parameterTypes)); } static com.kenai.jffi.CallingConvention jffiConvention(int flags) { return com.kenai.jffi.CallingConvention.DEFAULT; } }