예제 #1
0
 static boolean derivesFrom(Class<?> c, String className) {
   while (c != null) {
     if (c.getName().equals(className)) return true;
     c = c.getSuperclass();
   }
   return false;
 }
예제 #2
0
  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;
  }
예제 #3
0
 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;
 }
예제 #4
0
  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());
  }
예제 #5
0
 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);
 }
예제 #6
0
  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());
  }
예제 #7
0
  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);
  }
예제 #8
0
 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;
 }
예제 #9
0
 String getCPPClassName(Class<?> declaringClass) {
   return declaringClass.getSimpleName();
 }
예제 #10
0
  @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);
    }
  }