Pointer.Releaser newCPPReleaser(final Type type) { try { final Class<?> typeClass = Utils.getClass(type); NativeLibrary lib = BridJ.getNativeLibrary(typeClass); return newCPPReleaser(type, typeClass, lib); } catch (Throwable th) { throw new RuntimeException( "Failed to create a C++ destructor for type " + Utils.toString(type) + " : " + th, th); } }
protected boolean installSyntheticVTablePtr(Type type, NativeLibrary library, Pointer<?> peer) { synchronized (syntheticVirtualTables) { VTable vtable = syntheticVirtualTables.get(type); if (vtable == null) { if (!typesThatDontNeedASyntheticVirtualTable.contains(type)) { List<VirtMeth> methods = new ArrayList<VirtMeth>(); listVirtualMethods(Utils.getClass(type), methods); boolean needsASyntheticVirtualTable = false; for (VirtMeth method : methods) if (!Modifier.isNative(method.implementation.getModifiers())) { needsASyntheticVirtualTable = true; break; } if (needsASyntheticVirtualTable) { Type parentType = Utils.getParent(type); Pointer<Pointer> parentVTablePtr = null; if (CPPObject.class.isAssignableFrom(Utils.getClass(parentType))) { parentVTablePtr = peer.getPointer(Pointer.class); if (BridJ.debug) { BridJ.info( "Found parent virtual table pointer = " + ptrToString(parentVTablePtr, library)); /*Pointer<Pointer> expectedParentVTablePtr = pointerToAddress(getVirtualTable(parentType, library), Pointer.class); if (expectedParentVTablePtr != null && !Utils.eq(parentVTablePtr, expectedParentVTablePtr)) BridJ.warning("Weird parent virtual table pointer : expected " + ptrToString(expectedParentVTablePtr, library) + ", got " + ptrToString(parentVTablePtr, library)); */ } // parentVTablePtr = pointerToAddress(getVirtualTable(parentType, library), // Pointer.class); } syntheticVirtualTables.put( type, vtable = synthetizeVirtualTable(type, parentVTablePtr, methods, library)); } else { typesThatDontNeedASyntheticVirtualTable.add(type); } } } if (vtable != null) { if (BridJ.debug) BridJ.info( "Installing synthetic vtable pointer " + vtable.ptr + " to instance at " + peer + " (type = " + Utils.toString(type) + ", " + vtable.callbacks.size() + " callbacks)"); peer.setPointer(vtable.ptr); return vtable.ptr != null; } else return false; } }
long getVirtualTable(Type type, NativeLibrary library) { Long vtable = vtables.get(type); if (vtable == null) { final Class<?> typeClass = Utils.getClass(type); if (false) { String className = typeClass.getSimpleName(); String vtableSymbol; if (Platform.isWindows()) vtableSymbol = "??_7" + className + "@@6B@"; else vtableSymbol = "_ZTV" + className.length() + className; vtables.put(type, vtable = library.getSymbolAddress(vtableSymbol)); } else { Symbol symbol = library.getFirstMatchingSymbol( new SymbolAccepter() { public boolean accept(Symbol symbol) { return symbol.matchesVirtualTable(typeClass); } }); if (symbol != null) { if (BridJ.debug) info("Registering vtable of " + Utils.toString(type) + " as " + symbol.getName()); // Pointer<Pointer> pp = pointerToAddress(symbol.getAddress(), // Pointer.class); // // for (int i = 0; i < 6; i++) { // Pointer p = pp.get(i); //// if (p == null) //// break; // String n = p == null ? null : // library.getSymbolName(p.getPeer()); // info("\tVtable entry " + i + " = " + p + " (" + n + ")"); //// if (n == null) //// break; // } } else if (getVirtualMethodsCount(typeClass) > 0) error("Failed to find a vtable for type " + Utils.toString(type)); if (symbol != null) { long address = symbol.getAddress(); vtable = library.isMSVC() ? address : address + 2 * Pointer.SIZE; } else { vtable = 0L; } vtables.put(type, vtable); // */ } } return vtable; }
protected <T extends CPPObject> Pointer<T> newCPPInstance( T instance, final Type type, int constructorId, Object... args) { Pointer<T> peer = null; try { final Class<T> typeClass = Utils.getClass(type); NativeLibrary lib = BridJ.getNativeLibrary(typeClass); if (BridJ.debug) info("Creating C++ instance of type " + type + " with args " + Arrays.asList(args)); Pointer.Releaser releaser = newCPPReleaser(type, typeClass, lib); long size = sizeOf(type, null); peer = (Pointer) Pointer.allocateBytes(PointerIO.getInstance(type), size, releaser).as(type); DynamicFunction constructor = constructorId == SKIP_CONSTRUCTOR ? null : getConstructor(typeClass, type, lib, constructorId); if (lib != null && CPPObject.class.isAssignableFrom(typeClass)) { installRegularVTablePtr(type, lib, peer); } else { // TODO ObjCObject : call alloc on class type !! } // Setting the C++ template parameters in the instance : int templateParametersCount = getTemplateParametersCount(typeClass); if (templateParametersCount > 0) { Object[] templateArgs = new Object[templateParametersCount]; System.arraycopy(args, 0, templateArgs, 0, templateParametersCount); setTemplateParameters(instance, typeClass, templateArgs); } // Calling the constructor with the non-template parameters : if (constructor != null) { Object[] consThisArgs = new Object[args.length - templateParametersCount + 1]; consThisArgs[0] = peer; System.arraycopy( args, templateParametersCount, consThisArgs, 1, args.length - templateParametersCount); constructor.apply(consThisArgs); } // Install synthetic virtual table and associate the Java instance to the corresponding native // pointer : if (CPPObject.class.isAssignableFrom(typeClass)) { if (installSyntheticVTablePtr(type, lib, peer)) BridJ.setJavaObjectFromNativePeer(peer.getPeer(), instance); } else { // TODO ObjCObject : call alloc on class type !! } return peer; } catch (Exception ex) { ex.printStackTrace(); if (peer != null) { peer.release(); } throw new RuntimeException("Failed to allocate new instance of type " + type, ex); } }
@Override public <T extends NativeObject> Class<? extends T> getActualInstanceClass( Pointer<T> pInstance, Type officialType) { // String className = null; // For C++ classes in general, take type info at offset -1 of vtable (if first field matches the // address of a known static or dynamic virtual table) and use it to create the correct // instance. // Pointer<?> vptr = pInstance.getPointer(0); // Symbol symbol = BridJ.getSymbolByAddress(vptr.getPeer()); // if (symbol != null && symbol.isVirtualTable()) { // if (symbol.enclosingType.matches(officialType)) // return officialType; // // try { // Class<?> type = BridJ.getCPPRuntime().getCPPClass(symbol.enclosingType); // if (officialType == null || officialType.isAssignableFrom(type)) // return type; // } catch (ClassNotFoundException ex) {} // return officialType; // // /*long tinf = JNI.get_pointer(ptr - Pointer.SIZE); // symbol = BridJ.getSymbolByAddress(tinf); // if (symbol != null && symbol.isTypeInfo()) { // // }*/ // } // For Objective-C classes, use "const char* className = class_getName([yourObject class]);" and // match to registered classes or more // Bundle auto-generated type mappings files : bridj::CPPTest=org.bridj.test.cpp.CPPTest // return Utils.getClass(officialType); }
public MethodCallInfo( Type genericReturnType, Annotation[] returnAnnotations, Type[] parameterTypes, Annotation[][] paramsAnnotations, boolean prependJNIPointers) { init( null, Utils.getClass(genericReturnType), genericReturnType, returnAnnotations, Utils.getClasses(parameterTypes), parameterTypes, paramsAnnotations, prependJNIPointers, false, true); }
protected boolean matchesConstructor(Type type, java.lang.reflect.Constructor<?> constr) { if (memberName != SpecialName.Constructor) { return false; } if (!matchesEnclosingType(type)) { return false; } Template temp = Utils.getClass(type).getAnnotation(Template.class); Annotation[][] anns = constr.getParameterAnnotations(); Type[] parameterTypes = constr.getGenericParameterTypes(); int overrideOffset = Utils.getEnclosedConstructorParametersOffset(constr); if (!matchesArgs( parameterTypes, anns, overrideOffset + (temp == null ? 0 : temp.value().length))) { return false; } return true; }
@Override public T createReturnInstance() { try { Object[] templateParameters = getTemplateParameters(type); T instance = (T) getCastClass().newInstance(); initialize(instance, SKIP_CONSTRUCTOR, templateParameters); // setTemplateParameters(instance, typeClass, getTemplateParameters(type)); return instance; } catch (Throwable th) { throw new RuntimeException( "Failed to create a return instance for type " + Utils.toString(type) + " : " + th, th); } }
public boolean matchesConstructor(Type type, java.lang.reflect.Constructor<?> constr) { if (!symbol.contains(Utils.getClass(type).getSimpleName())) { return false; } parse(); try { if (ref != null) { return ref.matchesConstructor(type, constr); } } catch (Exception ex) { ex.printStackTrace(); } return false; }
protected boolean installRegularVTablePtr(Type type, NativeLibrary library, Pointer<?> peer) { long vtablePtr = getVirtualTable(type, library); if (vtablePtr != 0) { if (BridJ.debug) BridJ.info( "Installing regular vtable pointer " + Pointer.pointerToAddress(vtablePtr) + " to instance at " + peer + " (type = " + Utils.toString(type) + ")"); peer.setSizeT(vtablePtr); return true; } return false; }
CPPDestructor getDestructor(final Class<?> typeClass, Type type, NativeLibrary lib) { CPPDestructor destructor = destructors.get(type); if (destructor == null) { Symbol symbol = lib.getFirstMatchingSymbol( new SymbolAccepter() { public boolean accept(Symbol symbol) { return symbol.matchesDestructor(typeClass); } }); if (BridJ.debug && symbol != null) info("Registering destructor of " + Utils.toString(type) + " as " + symbol.getName()); if (symbol != null) destructors.put( type, destructor = pointerToAddress(symbol.getAddress(), CPPDestructor.class).get()); } return destructor; }
protected VTable synthetizeVirtualTable( Type type, Pointer<Pointer> parentVTablePtr, List<VirtMeth> methods, NativeLibrary library) { int nMethods = methods.size(); // Pointer<Pointer> parentVTablePtr = pointerToAddress(getVirtualTable(Utils.getParent(type), // library), Pointer.class); VTable vtable = new VTable(); vtable.ptr = allocatePointers(nMethods + 2) .next( 2); // leave two null pointers at index -2 and -1, to say there's no runtime type // information available. Class<?> c = Utils.getClass(type); for (int iMethod = 0; iMethod < nMethods; iMethod++) { VirtMeth vm = methods.get(iMethod); Pointer<?> pMethod; if (Modifier.isNative(vm.implementation.getModifiers())) { pMethod = parentVTablePtr == null ? null : parentVTablePtr.get(iMethod); } else { try { MethodCallInfo mci = new MethodCallInfo(vm.implementation, vm.definition); mci.setDeclaringClass(vm.implementation.getDeclaringClass()); pMethod = createCToJavaCallback(mci, c); vtable.callbacks.put(vm.implementation, pMethod); } catch (Throwable th) { BridJ.error( "Failed to register overridden method " + vm.implementation + " for type " + type + " (original method = " + vm.definition + ")", th); pMethod = null; } } vtable.ptr.set(iMethod, (Pointer) pMethod); } return vtable; }
public ValueType getValueType( int iParam, int nParams, Class<?> c, Type t, AnnotatedElement element, Annotation... directAnnotations) { boolean isPtr = isAnnotationPresent(Ptr.class, element, directAnnotations); boolean isCLong = isAnnotationPresent(org.bridj.ann.CLong.class, element, directAnnotations); Constructor cons = getAnnotation(Constructor.class, element, directAnnotations); if (isPtr || cons != null || isCLong) { if (!(c == Long.class || c == Long.TYPE)) throw new RuntimeException( "Annotation should only be used on a long parameter, not on a " + c.getName()); if (isPtr) { if (!Platform.is64Bits()) direct = false; } else if (isCLong) { if (Platform.CLONG_SIZE != 8) direct = false; } else if (cons != null) { isCPlusPlus = true; startsWithThis = true; if (iParam != 0) throw new RuntimeException( "Annotation " + Constructor.class.getName() + " cannot have more than one (long) argument"); } return ValueType.eSizeTValue; } if (c == null || c.equals(Void.TYPE)) return ValueType.eVoidValue; if (c == Integer.class || c == Integer.TYPE) return ValueType.eIntValue; if (c == Long.class || c == Long.TYPE) { return !isPtr || Platform.is64Bits() ? ValueType.eLongValue : ValueType.eIntValue; } if (c == Short.class || c == Short.TYPE) return ValueType.eShortValue; if (c == Byte.class || c == Byte.TYPE) return ValueType.eByteValue; if (c == Boolean.class || c == Boolean.TYPE) return ValueType.eBooleanValue; if (c == Float.class || c == Float.TYPE) { usesFloats(); return ValueType.eFloatValue; } if (c == char.class || c == Character.TYPE) { if (Platform.WCHAR_T_SIZE != 2) direct = false; return ValueType.eWCharValue; } if (c == Double.class || c == Double.TYPE) { usesFloats(); return ValueType.eDoubleValue; } if (c == CLong.class) { direct = false; return ValueType.eCLongObjectValue; } if (c == SizeT.class) { direct = false; return ValueType.eSizeTObjectValue; } if (c == TimeT.class) { direct = false; return ValueType.eTimeTObjectValue; } if (Pointer.class.isAssignableFrom(c)) { direct = false; CallIO cio = CallIO.Utils.createPointerCallIO(c, t); if (BridJ.veryVerbose) BridJ.info("CallIO : " + cio); addCallIO(cio); return ValueType.ePointerValue; } if (c.isArray() && iParam == nParams - 1) { direct = false; return ValueType.eEllipsis; } if (ValuedEnum.class.isAssignableFrom(c)) { direct = false; CallIO cio = CallIO.Utils.createValuedEnumCallIO( (Class) Utils.getClass(Utils.getUniqueParameterizedTypeParameter(t))); if (BridJ.veryVerbose) BridJ.info("CallIO : " + cio); addCallIO(cio); return ValueType.eIntFlagSet; } if (NativeObject.class.isAssignableFrom(c)) { Pointer<DCstruct> pStruct = null; if (StructObject.class.isAssignableFrom(c)) { StructIO io = StructIO.getInstance(c, t); try { pStruct = DyncallStructs.buildDCstruct(io.desc); } catch (Throwable th) { BridJ.error( "Unable to create low-level struct metadata for " + Utils.toString(t) + " : won't be able to use it as a by-value function argument.", th); } } addCallIO(new CallIO.NativeObjectHandler((Class<? extends NativeObject>) c, t, pStruct)); direct = false; return ValueType.eNativeObjectValue; } throw new NoSuchElementException( "No " + ValueType.class.getSimpleName() + " for class " + c.getName()); }
public static Annotations annotations(final Type e) { return annotations((AnnotatedElement) Utils.getClass(e)); }
DynamicFunction getConstructor( final Class<?> typeClass, final Type type, NativeLibrary lib, int constructorId) { Pair<Type, Integer> key = new Pair<Type, Integer>(type, constructorId); DynamicFunction constructor = constructors.get(key); if (constructor == null) { try { final Constructor<?> constr; try { constr = findConstructor(typeClass, constructorId, true); if (debug) BridJ.info("Found constructor for " + Utils.toString(type) + " : " + constr); } catch (NoSuchMethodException ex) { if (debug) BridJ.info("No constructor for " + Utils.toString(type)); return null; } Symbol symbol = lib == null ? null : lib.getFirstMatchingSymbol( new SymbolAccepter() { public boolean accept(Symbol symbol) { return symbol.matchesConstructor( constr.getDeclaringClass() == Utils.getClass(type) ? type : constr.getDeclaringClass() /* TODO */, constr); } }); if (symbol == null) { if (debug) BridJ.info("No matching constructor for " + Utils.toString(type) + " (" + constr + ")"); return null; } if (debug) info("Registering constructor " + constr + " as " + symbol.getName()); // TODO do something with these args ! int templateParametersCount = getTemplateParametersCount(typeClass); Class<?>[] consParamTypes = constr.getParameterTypes(); Class<?>[] consThisParamTypes = new Class[consParamTypes.length + 1 - templateParametersCount]; consThisParamTypes[0] = Pointer.class; System.arraycopy( consParamTypes, templateParametersCount, consThisParamTypes, 1, consParamTypes.length - templateParametersCount); DynamicFunctionFactory constructorFactory = getDynamicFunctionFactory(lib, Style.ThisCall, void.class, consThisParamTypes); constructor = constructorFactory.newInstance(pointerToAddress(symbol.getAddress())); constructors.put(key, constructor); } catch (Throwable th) { th.printStackTrace(); throw new RuntimeException( "Unable to create constructor " + constructorId + " for " + type + " : " + th, th); } } return constructor; }