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());
  }
 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);
    }
  }