static boolean derivesFrom(Class<?> c, String className) { while (c != null) { if (c.getName().equals(className)) return true; c = c.getSuperclass(); } 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; }
int getAbsoluteVirtualIndex(Method method, int virtualIndex, Class<?> type) { Class<?> superclass = type.getSuperclass(); int virtualOffset = getVirtualMethodsCount(superclass); boolean isNewVirtual = true; if (superclass != null) { try { // TODO handle polymorphism in overloads : superclass.getMethod(method.getName(), method.getParameterTypes()); isNewVirtual = false; } catch (NoSuchMethodException ex) { } } int absoluteVirtualIndex = isNewVirtual ? virtualOffset + virtualIndex : virtualIndex; return absoluteVirtualIndex; }
protected void listVirtualMethods(Class<?> type, List<VirtMeth> out) { if (!CPPObject.class.isAssignableFrom(type)) { return; } Class<?> sup = type.getSuperclass(); if (sup != CPPObject.class) { listVirtualMethods(sup, out); } int nParentMethods = out.size(); Map<Integer, VirtMeth> newVirtuals = new TreeMap<Integer, VirtMeth>(); methods: for (Method method : type.getDeclaredMethods()) { String methodName = method.getName(); Type[] methodParameterTypes = method.getGenericParameterTypes(); for (int iParentMethod = 0; iParentMethod < nParentMethods; iParentMethod++) { VirtMeth pvm = out.get(iParentMethod); Method parentMethod = pvm.definition; if (parentMethod.getDeclaringClass() == type) continue; // was just added in the same listVirtualMethods call ! // if (parentMethod.getAnnotation(Virtual.class) == null) // continue; // not a virtual method, too bad if (parentMethod.getName().equals(methodName) && isOverridenSignature( parentMethod.getGenericParameterTypes(), methodParameterTypes, 0)) { VirtMeth vm = new VirtMeth(); vm.definition = pvm.definition; vm.implementation = method; out.set(iParentMethod, vm); continue methods; } } Virtual virtual = method.getAnnotation(Virtual.class); if (virtual != null) { VirtMeth vm = new VirtMeth(); vm.definition = vm.implementation = method; newVirtuals.put(virtual.value(), vm); } } out.addAll(newVirtuals.values()); }
public void appendToSignature( int iParam, ValueType type, Class<?> parameterType, Type genericParameterType, StringBuilder javaSig, StringBuilder dcSig, StringBuilder asmSig) { char dcChar; String javaChar, asmChar = null; switch (type) { case eVoidValue: dcChar = DC_SIGCHAR_VOID; javaChar = "V"; break; case eIntValue: dcChar = DC_SIGCHAR_INT; javaChar = "I"; break; case eLongValue: dcChar = DC_SIGCHAR_LONGLONG; javaChar = "J"; break; case eSizeTValue: javaChar = "J"; if (Platform.SIZE_T_SIZE == 8) { dcChar = DC_SIGCHAR_LONGLONG; } else { dcChar = DC_SIGCHAR_INT; direct = false; } break; case eShortValue: dcChar = DC_SIGCHAR_SHORT; javaChar = "S"; break; case eDoubleValue: dcChar = DC_SIGCHAR_DOUBLE; javaChar = "D"; break; case eFloatValue: dcChar = DC_SIGCHAR_FLOAT; javaChar = "F"; break; case eByteValue: dcChar = DC_SIGCHAR_CHAR; javaChar = "B"; break; case eBooleanValue: dcChar = DC_SIGCHAR_BOOL; javaChar = "Z"; break; case eWCharValue: switch (Platform.WCHAR_T_SIZE) { case 1: dcChar = DC_SIGCHAR_CHAR; direct = false; break; case 2: dcChar = DC_SIGCHAR_SHORT; break; case 4: dcChar = DC_SIGCHAR_INT; direct = false; break; default: throw new RuntimeException( "Unhandled sizeof(wchar_t) in GetJavaTypeSignature: " + Platform.WCHAR_T_SIZE); } javaChar = "C"; break; case eIntFlagSet: dcChar = DC_SIGCHAR_INT; javaChar = "L" + parameterType.getName().replace('.', '/') + ";"; // "Lorg/bridj/ValuedEnum;"; direct = false; break; case eCLongObjectValue: dcChar = DC_SIGCHAR_POINTER; javaChar = "Lorg/bridj/CLong;"; direct = false; break; case eSizeTObjectValue: dcChar = DC_SIGCHAR_POINTER; javaChar = "Lorg/bridj/SizeT;"; direct = false; break; case eTimeTObjectValue: dcChar = DC_SIGCHAR_POINTER; javaChar = "Lorg/bridj/TimeT;"; direct = false; break; case ePointerValue: dcChar = DC_SIGCHAR_POINTER; javaChar = "L" + parameterType.getName().replace('.', '/') + ";"; // javaChar = "Lorg/bridj/Pointer;"; direct = false; break; case eNativeObjectValue: dcChar = DC_SIGCHAR_STRUCT; // TODO : unroll struct signature ? javaChar = "L" + parameterType.getName().replace('.', '/') + ";"; direct = false; // if (parameterType.equals(declaringClass)) { // // special case of self-returning pointers // dcChar = DC_SIGCHAR_POINTER; break; case eEllipsis: javaChar = "[Ljava/lang/Object;"; dcChar = '?'; break; default: direct = false; throw new RuntimeException("Unhandled " + ValueType.class.getSimpleName() + ": " + type); } if (genericParameterType instanceof ParameterizedType && iParam < 0) { ParameterizedType pt = (ParameterizedType) genericParameterType; // TODO handle all cases !!! Type[] ts = pt.getActualTypeArguments(); if (ts != null && ts.length == 1) { Type t = ts[0]; if (t instanceof ParameterizedType) t = ((ParameterizedType) t).getRawType(); if (t instanceof Class) { Class c = (Class) t; if (javaChar.endsWith(";")) { asmChar = javaChar.substring(0, javaChar.length() - 1) + "<*L" + c.getName().replace('.', '/') + ";>"; // asmChar += ";"; } } } } if (javaSig != null) javaSig.append(javaChar); if (asmChar == null) asmChar = javaChar; if (asmSig != null) asmSig.append(asmChar); if (dcSig != null) dcSig.append(dcChar); }
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()); }
protected void init( AnnotatedElement annotatedElement, Class returnType, Type genericReturnType, Annotation[] returnAnnotations, Class[] parameterTypes, Type[] genericParameterTypes, Annotation[][] paramsAnnotations, boolean prependJNIPointers, boolean isVirtual, boolean isDirectModeAllowed) { assert returnType != null; assert genericReturnType != null; assert parameterTypes != null; assert genericParameterTypes != null; assert returnAnnotations != null; assert parameterTypes.length == genericParameterTypes.length; assert paramsAnnotations.length == genericParameterTypes.length; int nParams = genericParameterTypes.length; paramsValueTypes = new int[nParams]; direct = isDirectModeAllowed; // TODO on native side : test number of parameters (on 64 bits win : // must be <= 4) StringBuilder javaSig = new StringBuilder(64), asmSig = new StringBuilder(64), dcSig = new StringBuilder(16); javaSig.append('('); asmSig.append('('); if (prependJNIPointers) // !isCPlusPlus) dcSig .append(DC_SIGCHAR_POINTER) .append(DC_SIGCHAR_POINTER); // JNIEnv*, jobject: always present in native-bound functions if (BridJ.debug) BridJ.info( "Analyzing " + (declaringClass == null ? "anonymous method" : declaringClass.getName() + "." + methodName)); if (isObjCBlock) appendToSignature( 0, ValueType.ePointerValue, Pointer.class, Pointer.class, null, dcSig, null); for (int iParam = 0; iParam < nParams; iParam++) { // Options paramOptions = paramsOptions[iParam] = new Options(); Type genericParameterType = genericParameterTypes[iParam]; Class<?> parameterType = parameterTypes[iParam]; ValueType paramValueType = getValueType( iParam, nParams, parameterType, genericParameterType, null, paramsAnnotations[iParam]); if (BridJ.veryVerbose) BridJ.info("\tparam " + paramValueType); paramsValueTypes[iParam] = paramValueType.ordinal(); appendToSignature( iParam, paramValueType, parameterType, genericParameterType, javaSig, dcSig, asmSig); } javaSig.append(')'); asmSig.append(')'); dcSig.append(')'); ValueType retType = getValueType( -1, nParams, returnType, genericReturnType, annotatedElement, returnAnnotations); if (BridJ.veryVerbose) BridJ.info("\treturns " + retType); appendToSignature(-1, retType, returnType, genericReturnType, javaSig, dcSig, asmSig); returnValueType = retType.ordinal(); javaSignature = javaSig.toString(); asmSignature = asmSig.toString(); dcSignature = dcSig.toString(); isCPlusPlus = isCPlusPlus || isVirtual; if (isCPlusPlus && !isStatic) { if (!startsWithThis) direct = false; bNeedsThisPointer = true; if (Platform.isWindows()) { if (!Platform.is64Bits()) setDcCallingConvention(DC_CALL_C_X86_WIN32_THIS_MS); } else { // if (!Platform.is64Bits()) // setDcCallingConvention(DC_CALL_C_X86_WIN32_THIS_GNU); } } if (nParams > Platform.getMaxDirectMappingArgCount()) this.direct = false; if (BridJ.veryVerbose) { BridJ.info("\t-> direct " + direct); BridJ.info("\t-> javaSignature " + javaSignature); BridJ.info("\t-> callIOs " + callIOs); BridJ.info("\t-> asmSignature " + asmSignature); BridJ.info("\t-> dcSignature " + dcSignature); } if (BridJ.veryVerbose) BridJ.info((direct ? "[mappable as direct] " : "[not mappable as direct] ") + method); }
static int getTemplateParametersCount(Class<?> typeClass) { Template t = typeClass.getAnnotation(Template.class); // TODO do something with these args ! int templateParametersCount = t == null ? 0 : t.value().length; return templateParametersCount; }
String getCPPClassName(Class<?> declaringClass) { return declaringClass.getSimpleName(); }
@Override protected void registerNativeMethod( Class<?> type, NativeLibrary typeLibrary, Method method, NativeLibrary methodLibrary, Builder builder, MethodCallInfoBuilder methodCallInfoBuilder) throws FileNotFoundException { int modifiers = method.getModifiers(); boolean isCPPClass = CPPObject.class.isAssignableFrom(method.getDeclaringClass()); // Annotation[][] anns = method.getParameterAnnotations(); if (!isCPPClass) { super.registerNativeMethod( type, typeLibrary, method, methodLibrary, builder, methodCallInfoBuilder); return; } MethodCallInfo mci = methodCallInfoBuilder.apply(method); Virtual va = method.getAnnotation(Virtual.class); if (va == null) { Symbol symbol = methodLibrary.getSymbol(method); mci.setForwardedPointer(symbol == null ? 0 : symbol.getAddress()); if (mci.getForwardedPointer() == 0) { assert error( "Method " + method.toGenericString() + " is not virtual but its address could not be resolved in the library."); return; } if (Modifier.isStatic(modifiers)) { builder.addFunction(mci); if (debug) info("Registering " + method + " as function or static C++ method " + symbol.getName()); } else { builder.addFunction(mci); if (debug) info("Registering " + method + " as C++ method " + symbol.getName()); } } else { if (Modifier.isStatic(modifiers)) { warning( "Method " + method.toGenericString() + " is native and maps to a function, but is not static."); } int theoreticalVirtualIndex = va.value(); int theoreticalAbsoluteVirtualIndex = theoreticalVirtualIndex < 0 ? -1 : getAbsoluteVirtualIndex(method, theoreticalVirtualIndex, type); int absoluteVirtualIndex; Pointer<Pointer<?>> pVirtualTable = isCPPClass && typeLibrary != null ? (Pointer) pointerToAddress(getVirtualTable(type, typeLibrary), Pointer.class) : null; if (pVirtualTable == null) { if (theoreticalAbsoluteVirtualIndex < 0) { error( "Method " + method.toGenericString() + " is virtual but the virtual table of class " + type.getName() + " was not found and the virtual method index is not provided in its @Virtual annotation."); return; } absoluteVirtualIndex = theoreticalAbsoluteVirtualIndex; } else { int guessedAbsoluteVirtualIndex = getPositionInVirtualTable(pVirtualTable, method, typeLibrary); if (guessedAbsoluteVirtualIndex < 0) { if (theoreticalAbsoluteVirtualIndex < 0) { error( "Method " + method.toGenericString() + " is virtual but its position could not be found in the virtual table."); return; } else { absoluteVirtualIndex = theoreticalAbsoluteVirtualIndex; } } else { if (theoreticalAbsoluteVirtualIndex >= 0 && guessedAbsoluteVirtualIndex != theoreticalAbsoluteVirtualIndex) { warning( "Method " + method.toGenericString() + " has @Virtual annotation indicating virtual index " + theoreticalAbsoluteVirtualIndex + ", but analysis of the actual virtual table rather indicates it has index " + guessedAbsoluteVirtualIndex + " (using the guess)"); } absoluteVirtualIndex = guessedAbsoluteVirtualIndex; } } mci.setVirtualIndex(absoluteVirtualIndex); if (debug) info( "Registering " + method.toGenericString() + " as virtual C++ method with absolute virtual table index = " + absoluteVirtualIndex); builder.addVirtualMethod(mci); } }