001/*
002 * BridJ - Dynamic and blazing-fast native interop for Java.
003 * http://bridj.googlecode.com/
004 *
005 * Copyright (c) 2010-2013, Olivier Chafik (http://ochafik.com/)
006 * All rights reserved.
007 *
008 * Redistribution and use in source and binary forms, with or without
009 * modification, are permitted provided that the following conditions are met:
010 * 
011 *     * Redistributions of source code must retain the above copyright
012 *       notice, this list of conditions and the following disclaimer.
013 *     * Redistributions in binary form must reproduce the above copyright
014 *       notice, this list of conditions and the following disclaimer in the
015 *       documentation and/or other materials provided with the distribution.
016 *     * Neither the name of Olivier Chafik nor the
017 *       names of its contributors may be used to endorse or promote products
018 *       derived from this software without specific prior written permission.
019 * 
020 * THIS SOFTWARE IS PROVIDED BY OLIVIER CHAFIK AND CONTRIBUTORS ``AS IS'' AND ANY
021 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
023 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
024 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
027 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
030 */
031package org.bridj;
032
033import org.bridj.util.Utils;
034import java.io.FileNotFoundException;
035import java.io.IOException;
036import java.lang.annotation.Annotation;
037import java.lang.reflect.Constructor;
038import java.lang.reflect.InvocationTargetException;
039import java.lang.reflect.Method;
040import java.lang.reflect.Modifier;
041import java.util.HashSet;
042import java.util.Map;
043import java.util.Set;
044import java.util.List;
045import java.util.ArrayList;
046
047import org.bridj.demangling.Demangler.Symbol;
048import org.bridj.NativeEntities.Builder;
049import org.bridj.ann.Convention;
050import org.bridj.ann.JNIBound;
051import org.bridj.util.ConcurrentCache;
052import static org.bridj.BridJ.*;
053import static org.bridj.util.AnnotationUtils.*;
054import java.lang.reflect.Type;
055import java.util.Arrays;
056import java.util.concurrent.atomic.AtomicReference;
057import org.bridj.ann.Optional;
058
059/**
060 * C runtime (used by default when no {@link org.bridj.ann.Runtime} annotation
061 * is found).<br>
062 * Deals with registration and lifecycle of structs, functions, callbacks.<br>
063 * A shared C runtime instance can be retrieved with {@link CRuntime#getInstance()
064 * }.
065 *
066 * @author ochafik
067 */
068public class CRuntime extends AbstractBridJRuntime {
069
070    final static Set<Type> registeredTypes = new HashSet<Type>();
071    final AtomicReference<CallbackNativeImplementer> _callbackNativeImplementer = new AtomicReference<CallbackNativeImplementer>();
072
073    /**
074     * @deprecated use {@link CRuntime#getInstance() } instead
075     */
076    @Deprecated
077    public CRuntime() {
078    }
079
080    public CallbackNativeImplementer getCallbackNativeImplementer() {
081        CallbackNativeImplementer impl = _callbackNativeImplementer.get();
082        if (impl == null) {
083            CallbackNativeImplementer newImpl = new CallbackNativeImplementer(BridJ.getOrphanEntities(), this);
084            if (_callbackNativeImplementer.compareAndSet(null, newImpl)) {
085                impl = newImpl;
086            } else {
087                impl = _callbackNativeImplementer.get();
088            }
089        }
090        return impl;
091    }
092
093    public boolean isAvailable() {
094        return true;
095    }
096
097    public static CRuntime getInstance() {
098        return BridJ.getRuntimeByRuntimeClass(CRuntime.class);
099    }
100
101    //@Override
102    public <T extends NativeObject> Class<? extends T> getActualInstanceClass(Pointer<T> pInstance, Type officialType) {
103        return Utils.getClass(officialType);
104    }
105
106    protected boolean shouldWarnIfNoFieldsInStruct() {
107        return true;
108    }
109
110    public class CTypeInfo<T extends NativeObject> implements TypeInfo<T> {
111
112        public CTypeInfo(Type type) {
113            this.type = type;
114            this.typeClass = Utils.getClass(type);
115            this.structIO = StructIO.getInstance(typeClass, type);
116            if (structIO != null) {
117                structIO.desc.build();
118                if (BridJ.verbose
119                        && structIO.desc.getAggregatedFields().isEmpty()
120                        && shouldWarnIfNoFieldsInStruct()) {
121                    BridJ.info("No fields found in " + Utils.toString(type) + " (maybe they weren't declared as public ?)");
122                }
123            }
124            this.pointerIO = (PointerIO<T>) PointerIO.getInstance(structIO);
125            //this.castClass = getTypeForCast(typeClass);
126            register(typeClass);
127        }
128        protected final Type type;
129        protected final Class<T> typeClass;
130        protected final StructIO structIO;
131        protected final PointerIO<T> pointerIO;
132        protected volatile Class<T> castClass;
133
134        //@Override
135        public long sizeOf() {
136            return structIO.desc.getStructSize();
137        }
138        //@Override
139
140        public boolean equal(T instance, T other) {
141            if (structIO != null) {
142                if (((StructObject) instance).io != structIO) {
143                    throw new IllegalArgumentException("This is not this instance's StructIO");
144                }
145
146                if (((StructObject) other).io != structIO) {
147                    return false;
148                }
149
150                return structIO.equal((StructObject) instance, (StructObject) other);
151            } else {
152                return instance.peer.equals(other.peer);
153            }
154        }
155        //@Override
156
157        public int compare(T instance, T other) {
158            if (structIO != null) {
159                if (((StructObject) instance).io != structIO) {
160                    throw new IllegalArgumentException("This is not this instance's StructIO");
161                }
162
163                if (((StructObject) other).io != structIO) {
164                    return 1;
165                }
166
167                return structIO.compare((StructObject) instance, (StructObject) other);
168            } else {
169                return instance.peer.compareTo(other.peer);
170            }
171        }
172
173        //@Override
174        public BridJRuntime getRuntime() {
175            return CRuntime.this;
176        }
177        //@Override
178
179        public Type getType() {
180            return type;
181        }
182
183        protected Class<T> getCastClass() {
184            if (castClass == null) {
185                castClass = (Class<T>) getTypeForCast(typeClass);
186            }
187            return castClass;
188        }
189
190        protected T newCastInstance() throws NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
191            Class<?> cc = getCastClass();
192            try {
193                return (T) cc.newInstance();
194            } catch (IllegalAccessException ex) {
195                Constructor<T> constructor = (Constructor<T>) cc.getConstructor();
196                constructor.setAccessible(true);
197                return constructor.newInstance();
198            }
199        }
200
201        //@Override
202        public T cast(Pointer peer) {
203            try {
204                T instance = newCastInstance();
205                // TODO template parameters here !!!
206                initialize(instance, peer);
207                return instance;
208            } catch (Exception ex) {
209                throw new RuntimeException("Failed to cast pointer " + peer + " to instance of type " + Utils.toString(type), ex);
210            }
211        }
212        //@Override
213
214        public T createReturnInstance() {
215            try {
216                T instance = newCastInstance();
217                initialize(instance);
218                return instance;
219            } catch (Exception ex) {
220                throw new RuntimeException("Failed to create return instance for type " + Utils.toString(type), ex);
221            }
222        }
223        //@Override
224
225        public void writeToNative(T instance) {
226            if (instance instanceof StructObject) {
227                structIO.writeFieldsToNative((StructObject) instance);
228            }
229        }
230        //@Override
231
232        public void readFromNative(T instance) {
233            if (instance instanceof StructObject) {
234                structIO.readFieldsFromNative((StructObject) instance);
235            }
236        }
237
238        public void copyNativeObjectToAddress(T instance, Pointer<T> ptr) {
239            if (instance instanceof StructObject) {
240                // TODO override in C++ to call operator=
241                ((StructObject) instance).peer.copyBytesTo(ptr, structIO.desc.getStructSize());
242            }
243        }
244        //@Override
245
246        public String describe(T instance) {
247            if (instance instanceof StructObject) {
248                return structIO.describe((StructObject) instance);
249            } else {
250                return instance.toString();
251            }
252        }
253        //@Override
254
255        public String describe() {
256            if (structIO != null) {
257                return structIO.desc.describe();
258            } else {
259                return Utils.toString(typeClass);
260            }
261        }
262
263        //@Override
264        public void initialize(T instance) {
265            if (!BridJ.isCastingNativeObjectInCurrentThread()) {
266                if (instance instanceof CallbackInterface) {
267                    if (!(instance instanceof DynamicFunction)) {
268                        setNativeObjectPeer(instance, registerCallbackInstance((CallbackInterface) instance));
269                    }
270                } else {
271                    initialize(instance, -1);
272                }
273
274                if (instance instanceof StructObject) {
275                    structIO.readFieldsFromNative((StructObject) instance);
276                }
277            } else if (instance instanceof StructObject) {
278                ((StructObject) instance).io = structIO;
279            }
280        }
281        //@Override
282
283        public void initialize(T instance, Pointer peer) {
284            instance.peer = peer;
285            if (instance instanceof StructObject) {
286                ((StructObject) instance).io = structIO;
287                structIO.readFieldsFromNative((StructObject) instance);
288            }
289        }
290
291        protected <V> Pointer<V> allocateStructMemory(PointerIO<V> pointerIO) {
292            return Pointer.allocate(pointerIO);
293        }
294
295        //@Override
296        public void initialize(T instance, int constructorId, Object... args) {
297            StructObject s = (StructObject) instance;
298            if (constructorId < 0) {
299                s.io = structIO;
300                if (instance.peer == null) {
301                    instance.peer = allocateStructMemory(pointerIO);
302                }
303            } else {
304                throw new UnsupportedOperationException("TODO implement structs constructors !");
305            }
306        }
307
308        //@Override
309        public T clone(T instance) throws CloneNotSupportedException {
310            if (instance == null) {
311                return null;
312            }
313
314            try {
315                T clone = (T) typeClass.newInstance();
316                Pointer<T> p = allocateStructMemory(pointerIO);
317                Pointer.getPointer(instance).copyTo(p);
318                initialize(clone, p);
319                return clone;
320            } catch (Exception ex) {
321                throw new RuntimeException("Failed to clone instance of type " + getType());
322            }
323        }
324
325        //@Override
326        public void destroy(T instance) {
327            if (instance instanceof CallbackInterface) {
328                return;
329            }
330        }
331    }
332    /// Needs not be fast : TypeInfo will be cached in BridJ anyway !
333    //@Override
334
335    public <T extends NativeObject> TypeInfo<T> getTypeInfo(final Type type) {
336        return new CTypeInfo(type);
337    }
338
339    public Type getType(Class<?> cls, Object[] targs, int[] typeParamCount) {
340        return cls;
341    }
342
343    //@Override
344    public void register(Type type) {
345        register(type, null, null);
346    }
347
348    public static class MethodCallInfoBuilder {
349
350        public MethodCallInfo apply(Method method) throws FileNotFoundException {
351            return new MethodCallInfo(method);
352        }
353    }
354
355    @Override
356    public void unregister(Type type) {
357        Class typeClass = Utils.getClass(type);
358        registeredTypes.remove(typeClass);
359    }
360
361    synchronized void register(Type type, NativeLibrary forcedLibrary, MethodCallInfoBuilder methodCallInfoBuilder) {
362        Class typeClass = Utils.getClass(type);
363        if (!BridJ.getRuntimeClass(typeClass).isInstance(this)) {
364            BridJ.register(typeClass);
365            return;
366        }
367        synchronized (registeredTypes) {
368            if (!registeredTypes.add(typeClass)) {
369                return;
370            }
371        }
372
373        if (methodCallInfoBuilder == null) {
374            methodCallInfoBuilder = new MethodCallInfoBuilder();
375        }
376
377        if (verbose) {
378            info("Registering type " + Utils.toString(type));
379        }
380
381        int typeModifiers = typeClass.getModifiers();
382
383        NativeLibrary typeLibrary = null;
384        try {
385            typeLibrary = forcedLibrary == null ? getNativeLibrary(typeClass) : forcedLibrary;
386        } catch (Throwable th) {
387        }
388
389        ConcurrentCache<NativeEntities, NativeEntities.Builder> builders = new ConcurrentCache<NativeEntities, NativeEntities.Builder>(NativeEntities.Builder.class);
390        try {
391            Set<Method> handledMethods = new HashSet<Method>();
392            /*if (StructObject.class.isAssignableFrom(typeClass)) {
393             StructIO io = StructIO.getInstance(typeClass, type, this); // TODO handle differently with templates...
394             io.build();
395             StructIO.FieldIO[] fios = io == null ? null : io.getFields();
396             if (fios != null)
397             for (StructIO.FieldIO fio : fios) {
398             NativeEntities.Builder builder = builders.get(BridJ.getOrphanEntities());
399
400             try {
401             {
402             MethodCallInfo getter = new MethodCallInfo(fio.getter);
403             getter.setIndex(fio.index);
404             builder.addGetter(getter);
405             handledMethods.add(fio.getter);
406             }
407             if (fio.setter != null) {
408             MethodCallInfo setter = new MethodCallInfo(fio.setter);
409             setter.setIndex(fio.index);
410             builder.addSetter(setter);
411             handledMethods.add(fio.setter);
412             }
413             } catch (Exception ex) {
414             BridJ.error("Failed to register field " + fio.name + " in struct " + type);
415             ex.printStackTrace();
416             }
417             }
418             }*/
419
420            if (CallbackInterface.class.isAssignableFrom(typeClass)) {
421                if (rootCallbackClasses.contains(type)) {
422                    return;
423                }
424
425                if (Modifier.isAbstract(typeModifiers)) {
426                    getCallbackNativeImplementer().getCallbackImplType((Class) type, forcedLibrary);
427                }
428            }
429
430
431//              for (; type != null && type != Object.class; type = type.getSuperclass()) {
432            List<Method> nativeMethods = new ArrayList<Method>();
433            for (Method method : typeClass.getDeclaredMethods()) {
434                int modifiers = method.getModifiers();
435                if (Modifier.isNative(modifiers)) {
436                    if (!isAnnotationPresent(JNIBound.class, method)) {
437                        nativeMethods.add(method);
438                    }
439                }
440            }
441
442            if (!nativeMethods.isEmpty()) {
443                try {
444                    for (Method method : nativeMethods) {
445                        if (!handledMethods.add(method)) {
446                            continue;
447                        }
448
449                        try {
450                            NativeLibrary methodLibrary = forcedLibrary == null ? BridJ.getNativeLibrary(method) : forcedLibrary;
451                            NativeEntities nativeEntities = methodLibrary == null ? BridJ.getOrphanEntities() : methodLibrary.getNativeEntities();
452                            NativeEntities.Builder builder = builders.get(nativeEntities);
453
454                            registerNativeMethod(typeClass, typeLibrary, method, methodLibrary, builder, methodCallInfoBuilder);
455                        } catch (Exception ex) {
456                            if (verbose) {
457                                error("Method " + method.toGenericString() + " cannot be mapped : " + ex, ex);
458                            }
459                        }
460                    }
461                } catch (Exception ex) {
462                    throw new RuntimeException("Failed to register class " + Utils.toString(type), ex);
463                }
464            }
465//              }
466        } finally {
467            for (Map.Entry<NativeEntities, NativeEntities.Builder> e : builders.entrySet()) {
468                e.getKey().addDefinitions(typeClass, e.getValue());
469            }
470            registerFamily(type, forcedLibrary, methodCallInfoBuilder);
471        }
472    }
473
474    protected void registerFamily(Type type, NativeLibrary forcedLibrary, MethodCallInfoBuilder methodCallInfoBuilder) {
475        Class typeClass = Utils.getClass(type);
476
477        for (Class<?> child : typeClass.getClasses()) {
478            register(child, forcedLibrary, methodCallInfoBuilder);
479        }
480
481        typeClass = typeClass.getSuperclass();
482        if (typeClass != null && typeClass != Object.class) {
483            register(typeClass, forcedLibrary, methodCallInfoBuilder);
484        }
485    }
486
487    protected NativeLibrary getNativeLibrary(Class<?> type) throws IOException {
488        return BridJ.getNativeLibrary(type);
489    }
490
491    protected boolean isSymbolOptional(Method method) {
492        return getInheritableAnnotation(Optional.class, method) != null;
493    }
494
495    protected void registerNativeMethod(
496            Class<?> type,
497            NativeLibrary typeLibrary,
498            Method method,
499            NativeLibrary methodLibrary,
500            Builder builder,
501            MethodCallInfoBuilder methodCallInfoBuilder) throws FileNotFoundException {
502        MethodCallInfo mci;
503        try {
504            mci = methodCallInfoBuilder.apply(method);
505            if (mci == null) {
506                return;
507            }
508            //System.out.println("method.dcCallingConvention = " + mci.dcCallingConvention + " (for method " + type.getName() + ", method " + method + ", type = " + type.getName() + ", enclosingClass = " + method.getDeclaringClass().getName() + ")");
509        } catch (Throwable th) {
510            error("Unable to register " + method + " : " + th);
511            th.printStackTrace();
512            return;
513        }
514        if (CallbackInterface.class.isAssignableFrom(type)) {
515            if (debug) {
516                info("Registering java -> native callback : " + method);
517            }
518            builder.addJavaToNativeCallback(mci);
519        } else {
520            Symbol symbol = methodLibrary == null ? null : methodLibrary.getSymbol(method);
521            if (symbol == null) {
522//                for (Demangler.Symbol symbol : methodLibrary.getSymbols()) {
523//                    if (symbol.matches(method)) {
524//                        address = symbol.getAddress();
525//                        break;
526//                    }
527//                }
528//                if (address == null) {
529                if (!isSymbolOptional(method)) {
530                    error("Failed to get address of method " + method);
531                }
532                return;
533//                }
534            }
535            mci.setForwardedPointer(symbol.getAddress());
536            if (!mci.hasCallingConvention()) {
537                Convention.Style cc = symbol.getInferredCallingConvention();
538                if (cc != null) {
539                    mci.setCallingConvention(cc);
540                }
541            }
542            builder.addFunction(mci);
543            if (debug) {
544                info("Registering " + method + " as C function " + symbol.getName() + " (address = 0x" + Long.toHexString(symbol.getAddress()) + ")");
545            }
546        }
547    }
548
549    public <T extends NativeObject> Pointer<T> allocate(Class<T> type, int constructorId, Object... args) {
550        if (CallbackInterface.class.isAssignableFrom(type)) {
551            if (constructorId != -1 || args.length != 0) {
552                throw new RuntimeException("Callback should have a constructorId == -1 and no constructor args !");
553            }
554            return null;//newCallbackInstance(type);
555        }
556        throw new RuntimeException("Cannot allocate instance of type " + type.getName() + " (unhandled NativeObject subclass)");
557    }
558    static final int defaultObjectSize = Platform.is64Bits() ? 8 : 4;
559    public static final String PROPERTY_bridj_c_defaultObjectSize = "bridj.c.defaultObjectSize";
560
561    public int getDefaultStructSize() {
562        String s = System.getProperty(PROPERTY_bridj_c_defaultObjectSize);
563        if (s != null) {
564            try {
565                return Integer.parseInt(s);
566            } catch (Throwable th) {
567                error("Invalid value for property " + PROPERTY_bridj_c_defaultObjectSize + " : '" + s + "'");
568            }
569        }
570        return defaultObjectSize;
571    }
572
573    public long sizeOf(Type structType, StructIO io) {
574        if (io == null) {
575            io = StructIO.getInstance(Utils.getClass(structType), structType);
576        }
577        long size;
578        if (io == null || (size = io.desc.getStructSize()) <= 0) {
579            return getDefaultStructSize();
580        }
581        return size;
582    }
583    protected Set<Class> rootCallbackClasses = new HashSet<Class>(Arrays.asList(Callback.class, DynamicFunction.class));
584
585    public Method getUniqueCallbackMethod(Class type) {
586        return getCallbackMethod(type, true);
587    }
588    public Method getFastestCallbackMethod(Class type) {
589        return getCallbackMethod(type, false);
590    }
591
592    private Method getSingleAbstractMethodMethod(Class type) {
593        assert Modifier.isAbstract(type.getModifiers());
594        Method method = null;
595        Method[] declaredMethods = type.getDeclaredMethods();
596        for (Method dm : declaredMethods) {
597            int modifiers = dm.getModifiers();
598            if (!Modifier.isAbstract(modifiers)) {
599                continue;
600            }
601
602            if (method == null) {
603                method = dm;
604            } else {
605                throw new RuntimeException("Callback " + type.getName() + " has more than one abstract method (" + dm + " and " + method + ")");
606            }
607            //break;
608        }
609        return method;
610    }
611    
612    private boolean sameBindings(Method m1, Method m2) {
613        Class<?>[] params1 = m1.getParameterTypes(), params2 = m2.getParameterTypes();
614        Class<?> r1 = m1.getReturnType(), r2 = m2.getReturnType();
615        if (!sameBindings(r1, r2) || params1.length != params2.length) {
616            return false;
617        }
618        for (int i = 0; i < params1.length; i++) {
619            Class p1 = params1[i], p2 = params2[i];
620            if (!sameBindings(p1, p2)) {
621                return false;
622            }
623        }
624        return true;
625    }
626    
627    private static int getSignatureObjectCount(Class t) {
628        return t.isPrimitive() ? 0 : 1;
629    }
630    private int getSignatureObjectCount(Method m) {
631        int count = getSignatureObjectCount(m.getReturnType());
632        for (Class<?> param : m.getParameterTypes()) {
633            count += getSignatureObjectCount(param);
634        }
635        return count;
636    }
637
638    public List<Method> getApplyMethods(Class type) {
639        List<Method> ret = new ArrayList<Method>();
640        for (Method method : type.getDeclaredMethods()) {
641            if (method.getName().equals("apply")) {
642                ret.add(method);
643            }
644        }
645        return ret;
646    }
647    
648    public Class<?> getAbstractCallback(Class type) {
649        Class<?> parent = null;
650        while ((parent = type.getSuperclass()) != null && !rootCallbackClasses.contains(parent)) {
651            type = parent;
652        }
653        if (!Modifier.isAbstract(type.getModifiers())) {
654            throw new RuntimeException("Callback definition " + type.getName() + " must be abstract.");
655        }
656        return type;
657    }
658    
659    public Method getCallbackMethod(Class<?> type, boolean expectUniqueMethod) {
660        Class<?> abstractCallback = getAbstractCallback(type);
661        Method singleAbstractMethod = getSingleAbstractMethodMethod(abstractCallback);
662        if (singleAbstractMethod != null) {
663            return singleAbstractMethod;
664        }
665
666        List<Method> applyList = getApplyMethods(type);
667        if (applyList.isEmpty()) {
668            throw new RuntimeException("Type doesn't have any abstract method nor any 'apply' method: " + abstractCallback.getName());
669        }
670        
671        Method m0 = applyList.get(0);
672        for (int i = 1, n = applyList.size(); i < n; i++) {
673            Method mi = applyList.get(i);
674            if (!sameBindings(m0, mi)) {
675                throw new RuntimeException("Callback apply methods don't match: " + m0 + " vs. " + mi);
676            }
677        }
678
679        boolean overridesOnlyOneMethod = applyList.size() == 1;
680        if (expectUniqueMethod) {
681            if (!overridesOnlyOneMethod) {
682                throw new RuntimeException("Expected only one overridden apply method in " + type.getName() + ", but got " + applyList);
683            }
684        }
685        if (overridesOnlyOneMethod) {
686            return applyList.get(0);
687        } else {
688            int bestCount = Integer.MAX_VALUE;
689            Method best = null;
690            for (Method m : applyList) {
691                int count = getSignatureObjectCount(m);
692                if (count < bestCount) {
693                    bestCount = count;
694                    best = m;
695                }
696            }
697            return best;
698        }
699    }
700    private static boolean sameBindings(Class t1, Class t2) {
701        return t1.equals(t2) ||
702            t1 == long.class && Pointer.class.isAssignableFrom(t2) ||
703            t2 == long.class && Pointer.class.isAssignableFrom(t1) ||
704            t1 == int.class && IntValuedEnum.class.isAssignableFrom(t2) ||
705            t2 == int.class && IntValuedEnum.class.isAssignableFrom(t1);
706    }
707    
708    public <T extends NativeObject> Class<? extends T> getTypeForCast(Type type) {
709        Class<?> typeClass = Utils.getClass(type);
710        if (CallbackInterface.class.isAssignableFrom(typeClass)) {
711            return getCallbackNativeImplementer().getCallbackImplType((Class) typeClass, null);
712        } else {
713            return (Class<? extends T>) typeClass;
714        }
715    }
716
717    /**
718     * Get a shared factory of native function wrappers that have a given
719     * signatures.
720     *
721     * @param library library to which the allocated native thunks will be bound
722     * (can be null, in which case the native allocations will be bound to {@link BridJ#getOrphanEntities()
723     * })
724     * @param callingConvention calling convention used by the functions (if
725     * null, default is typically {@link org.bridj.ann.Convention.Style#CDecl})
726     * @param returnType return type of the functions
727     * @param parameterTypes parameter types of the functions Also see
728     * {@link DynamicFunction} and {@link Pointer#asDynamicFunction(org.bridj.ann.Convention.Style, java.lang.reflect.Type, java.lang.reflect.Type[])
729     * }.
730     */
731    public DynamicFunctionFactory getDynamicFunctionFactory(NativeLibrary library, Convention.Style callingConvention, Type returnType, Type... parameterTypes) {
732        return getCallbackNativeImplementer().getDynamicCallback(library, callingConvention, returnType, parameterTypes);
733    }
734
735    public static <T> Pointer<T> createCToJavaCallback(MethodCallInfo mci, Type t) {
736        mci.prependCallbackCC();
737        final long handle = JNI.createCToJavaCallback(mci);
738        long peer = JNI.getActualCToJavaCallback(handle);
739
740        final Throwable stackTrace = BridJ.debugPointers
741                ? new RuntimeException().fillInStackTrace() : null;
742
743        return (Pointer) Pointer.pointerToAddress(peer, t, new Pointer.Releaser() {
744            //@Override
745            public void release(Pointer<?> p) {
746                if (BridJ.debugPointers) {
747                    BridJ.info("Freeing callback pointer " + p + "\n(Creation trace = \n\t" + Utils.toString(p.creationTrace).replaceAll("\n", "\n\t") + "\n)", new RuntimeException().fillInStackTrace());
748                }
749
750                if (BridJ.debugNeverFree) {
751                    return;
752                }
753
754                JNI.freeCToJavaCallback(handle);//p.getPeer());
755            }
756        });
757    }
758
759    protected <T extends CallbackInterface> Pointer<T> registerCallbackInstance(T instance) {
760        try {
761            Class<?> c = instance.getClass();
762            MethodCallInfo mci = new MethodCallInfo(getFastestCallbackMethod(c));
763            mci.setDeclaringClass(c);
764            mci.setJavaCallback(instance);
765            return createCToJavaCallback(mci, c);
766        } catch (Exception e) {
767            throw new RuntimeException("Failed to register callback instance of type " + instance.getClass().getName(), e);
768        }
769    }
770
771    protected void setNativeObjectPeer(NativeObjectInterface instance, Pointer<? extends NativeObjectInterface> peer) {
772        ((NativeObject) instance).peer = (Pointer<NativeObject>) peer;
773    }
774}