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