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}