public synchronized MemoryOperators getMemoryOperators() { if (memoryOperators == null) { try { NativeLibrary libStdCpp = BridJ.getNativeLibrary("stdc++"); memoryOperators = new MemoryOperators(libStdCpp); } catch (Exception ex) { BridJ.error(null, ex); } } return memoryOperators; }
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; }
private boolean matchesArgs(Type[] parameterTypes, Annotation[][] anns, int offset) { int totalArgs = offset; for (int i = 0, n = templateArguments == null ? 0 : templateArguments.length; i < n; i++) { if (totalArgs >= parameterTypes.length) { return false; } Type paramType = parameterTypes[offset + i]; TemplateArg arg = templateArguments[i]; if (arg instanceof TypeRef) { if (!paramType.equals(Class.class)) { return false; } } else if (arg instanceof Constant) { try { getTypeClass(paramType).cast(((Constant) arg).value); } catch (ClassCastException ex) { return false; } } totalArgs++; } for (int i = 0, n = paramTypes == null ? 0 : paramTypes.length; i < n; i++) { if (totalArgs >= parameterTypes.length) { return false; } TypeRef paramType = paramTypes[i]; Type parameterType = parameterTypes[totalArgs]; if (!paramType.matches(parameterType, annotations(anns == null ? null : anns[i]))) { return false; } totalArgs++; } if (totalArgs != parameterTypes.length) { BridJ.error("Not enough args for " + this); return false; } return true; }
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; }
@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); } }