예제 #1
0
 Pointer.Releaser newCPPReleaser(final Type type) {
   try {
     final Class<?> typeClass = Utils.getClass(type);
     NativeLibrary lib = BridJ.getNativeLibrary(typeClass);
     return newCPPReleaser(type, typeClass, lib);
   } catch (Throwable th) {
     throw new RuntimeException(
         "Failed to create a C++ destructor for type " + Utils.toString(type) + " : " + th, th);
   }
 }
예제 #2
0
  protected boolean installSyntheticVTablePtr(Type type, NativeLibrary library, Pointer<?> peer) {
    synchronized (syntheticVirtualTables) {
      VTable vtable = syntheticVirtualTables.get(type);
      if (vtable == null) {
        if (!typesThatDontNeedASyntheticVirtualTable.contains(type)) {
          List<VirtMeth> methods = new ArrayList<VirtMeth>();
          listVirtualMethods(Utils.getClass(type), methods);
          boolean needsASyntheticVirtualTable = false;
          for (VirtMeth method : methods)
            if (!Modifier.isNative(method.implementation.getModifiers())) {
              needsASyntheticVirtualTable = true;
              break;
            }
          if (needsASyntheticVirtualTable) {
            Type parentType = Utils.getParent(type);
            Pointer<Pointer> parentVTablePtr = null;
            if (CPPObject.class.isAssignableFrom(Utils.getClass(parentType))) {
              parentVTablePtr = peer.getPointer(Pointer.class);
              if (BridJ.debug) {
                BridJ.info(
                    "Found parent virtual table pointer = "
                        + ptrToString(parentVTablePtr, library));
                /*Pointer<Pointer> expectedParentVTablePtr = pointerToAddress(getVirtualTable(parentType, library), Pointer.class);
                if (expectedParentVTablePtr != null && !Utils.eq(parentVTablePtr, expectedParentVTablePtr))
                    BridJ.warning("Weird parent virtual table pointer : expected " + ptrToString(expectedParentVTablePtr, library) + ", got " + ptrToString(parentVTablePtr, library));
                */

              }
              // parentVTablePtr = pointerToAddress(getVirtualTable(parentType, library),
              // Pointer.class);
            }
            syntheticVirtualTables.put(
                type, vtable = synthetizeVirtualTable(type, parentVTablePtr, methods, library));
          } else {
            typesThatDontNeedASyntheticVirtualTable.add(type);
          }
        }
      }
      if (vtable != null) {
        if (BridJ.debug)
          BridJ.info(
              "Installing synthetic vtable pointer "
                  + vtable.ptr
                  + " to instance at "
                  + peer
                  + " (type = "
                  + Utils.toString(type)
                  + ", "
                  + vtable.callbacks.size()
                  + " callbacks)");
        peer.setPointer(vtable.ptr);
        return vtable.ptr != null;
      } else return false;
    }
  }
예제 #3
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;
  }
예제 #4
0
  protected <T extends CPPObject> Pointer<T> newCPPInstance(
      T instance, final Type type, int constructorId, Object... args) {
    Pointer<T> peer = null;
    try {
      final Class<T> typeClass = Utils.getClass(type);
      NativeLibrary lib = BridJ.getNativeLibrary(typeClass);

      if (BridJ.debug)
        info("Creating C++ instance of type " + type + " with args " + Arrays.asList(args));
      Pointer.Releaser releaser = newCPPReleaser(type, typeClass, lib);

      long size = sizeOf(type, null);
      peer = (Pointer) Pointer.allocateBytes(PointerIO.getInstance(type), size, releaser).as(type);

      DynamicFunction constructor =
          constructorId == SKIP_CONSTRUCTOR
              ? null
              : getConstructor(typeClass, type, lib, constructorId);

      if (lib != null && CPPObject.class.isAssignableFrom(typeClass)) {
        installRegularVTablePtr(type, lib, peer);
      } else {
        // TODO ObjCObject : call alloc on class type !!
      }

      // Setting the C++ template parameters in the instance :
      int templateParametersCount = getTemplateParametersCount(typeClass);
      if (templateParametersCount > 0) {
        Object[] templateArgs = new Object[templateParametersCount];
        System.arraycopy(args, 0, templateArgs, 0, templateParametersCount);
        setTemplateParameters(instance, typeClass, templateArgs);
      }

      // Calling the constructor with the non-template parameters :
      if (constructor != null) {
        Object[] consThisArgs = new Object[args.length - templateParametersCount + 1];
        consThisArgs[0] = peer;
        System.arraycopy(
            args, templateParametersCount, consThisArgs, 1, args.length - templateParametersCount);

        constructor.apply(consThisArgs);
      }

      // Install synthetic virtual table and associate the Java instance to the corresponding native
      // pointer :
      if (CPPObject.class.isAssignableFrom(typeClass)) {
        if (installSyntheticVTablePtr(type, lib, peer))
          BridJ.setJavaObjectFromNativePeer(peer.getPeer(), instance);
      } else {
        // TODO ObjCObject : call alloc on class type !!
      }
      return peer;
    } catch (Exception ex) {
      ex.printStackTrace();
      if (peer != null) {
        peer.release();
      }
      throw new RuntimeException("Failed to allocate new instance of type " + type, ex);
    }
  }
예제 #5
0
 @Override
 public <T extends NativeObject> Class<? extends T> getActualInstanceClass(
     Pointer<T> pInstance, Type officialType) {
   // String className = null;
   // For C++ classes in general, take type info at offset -1 of vtable (if first field matches the
   // address of a known static or dynamic virtual table) and use it to create the correct
   // instance.
   //		Pointer<?> vptr = pInstance.getPointer(0);
   //		Symbol symbol = BridJ.getSymbolByAddress(vptr.getPeer());
   //		if (symbol != null && symbol.isVirtualTable()) {
   //			if (symbol.enclosingType.matches(officialType))
   //				return officialType;
   //
   //			try {
   //				Class<?> type = BridJ.getCPPRuntime().getCPPClass(symbol.enclosingType);
   //				if (officialType == null || officialType.isAssignableFrom(type))
   //					return type;
   //			} catch (ClassNotFoundException ex) {}
   //			return officialType;
   //
   //			/*long tinf = JNI.get_pointer(ptr - Pointer.SIZE);
   //			symbol = BridJ.getSymbolByAddress(tinf);
   //			if (symbol != null && symbol.isTypeInfo()) {
   //
   //			}*/
   //		}
   // For Objective-C classes, use "const char* className = class_getName([yourObject class]);" and
   // match to registered classes or more
   // Bundle auto-generated type mappings files : bridj::CPPTest=org.bridj.test.cpp.CPPTest
   //
   return Utils.getClass(officialType);
 }
예제 #6
0
 public MethodCallInfo(
     Type genericReturnType,
     Annotation[] returnAnnotations,
     Type[] parameterTypes,
     Annotation[][] paramsAnnotations,
     boolean prependJNIPointers) {
   init(
       null,
       Utils.getClass(genericReturnType),
       genericReturnType,
       returnAnnotations,
       Utils.getClasses(parameterTypes),
       parameterTypes,
       paramsAnnotations,
       prependJNIPointers,
       false,
       true);
 }
예제 #7
0
    protected boolean matchesConstructor(Type type, java.lang.reflect.Constructor<?> constr) {
      if (memberName != SpecialName.Constructor) {
        return false;
      }

      if (!matchesEnclosingType(type)) {
        return false;
      }

      Template temp = Utils.getClass(type).getAnnotation(Template.class);
      Annotation[][] anns = constr.getParameterAnnotations();
      Type[] parameterTypes = constr.getGenericParameterTypes();

      int overrideOffset = Utils.getEnclosedConstructorParametersOffset(constr);
      if (!matchesArgs(
          parameterTypes, anns, overrideOffset + (temp == null ? 0 : temp.value().length))) {
        return false;
      }

      return true;
    }
예제 #8
0
 @Override
 public T createReturnInstance() {
   try {
     Object[] templateParameters = getTemplateParameters(type);
     T instance = (T) getCastClass().newInstance();
     initialize(instance, SKIP_CONSTRUCTOR, templateParameters);
     // setTemplateParameters(instance, typeClass, getTemplateParameters(type));
     return instance;
   } catch (Throwable th) {
     throw new RuntimeException(
         "Failed to create a return instance for type " + Utils.toString(type) + " : " + th, th);
   }
 }
예제 #9
0
    public boolean matchesConstructor(Type type, java.lang.reflect.Constructor<?> constr) {
      if (!symbol.contains(Utils.getClass(type).getSimpleName())) {
        return false;
      }

      parse();

      try {
        if (ref != null) {
          return ref.matchesConstructor(type, constr);
        }
      } catch (Exception ex) {
        ex.printStackTrace();
      }
      return false;
    }
예제 #10
0
 protected boolean installRegularVTablePtr(Type type, NativeLibrary library, Pointer<?> peer) {
   long vtablePtr = getVirtualTable(type, library);
   if (vtablePtr != 0) {
     if (BridJ.debug)
       BridJ.info(
           "Installing regular vtable pointer "
               + Pointer.pointerToAddress(vtablePtr)
               + " to instance at "
               + peer
               + " (type = "
               + Utils.toString(type)
               + ")");
     peer.setSizeT(vtablePtr);
     return true;
   }
   return false;
 }
예제 #11
0
  CPPDestructor getDestructor(final Class<?> typeClass, Type type, NativeLibrary lib) {
    CPPDestructor destructor = destructors.get(type);
    if (destructor == null) {
      Symbol symbol =
          lib.getFirstMatchingSymbol(
              new SymbolAccepter() {
                public boolean accept(Symbol symbol) {
                  return symbol.matchesDestructor(typeClass);
                }
              });
      if (BridJ.debug && symbol != null)
        info("Registering destructor of " + Utils.toString(type) + " as " + symbol.getName());

      if (symbol != null)
        destructors.put(
            type, destructor = pointerToAddress(symbol.getAddress(), CPPDestructor.class).get());
    }
    return destructor;
  }
예제 #12
0
  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;
  }
예제 #13
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());
  }
예제 #14
0
 public static Annotations annotations(final Type e) {
   return annotations((AnnotatedElement) Utils.getClass(e));
 }
예제 #15
0
  DynamicFunction getConstructor(
      final Class<?> typeClass, final Type type, NativeLibrary lib, int constructorId) {
    Pair<Type, Integer> key = new Pair<Type, Integer>(type, constructorId);
    DynamicFunction constructor = constructors.get(key);
    if (constructor == null) {
      try {
        final Constructor<?> constr;
        try {
          constr = findConstructor(typeClass, constructorId, true);

          if (debug) BridJ.info("Found constructor for " + Utils.toString(type) + " : " + constr);
        } catch (NoSuchMethodException ex) {
          if (debug) BridJ.info("No constructor for " + Utils.toString(type));
          return null;
        }
        Symbol symbol =
            lib == null
                ? null
                : lib.getFirstMatchingSymbol(
                    new SymbolAccepter() {
                      public boolean accept(Symbol symbol) {
                        return symbol.matchesConstructor(
                            constr.getDeclaringClass() == Utils.getClass(type)
                                ? type
                                : constr.getDeclaringClass() /* TODO */,
                            constr);
                      }
                    });
        if (symbol == null) {
          if (debug)
            BridJ.info("No matching constructor for " + Utils.toString(type) + " (" + constr + ")");
          return null;
        }

        if (debug) info("Registering constructor " + constr + " as " + symbol.getName());

        // TODO do something with these args !
        int templateParametersCount = getTemplateParametersCount(typeClass);

        Class<?>[] consParamTypes = constr.getParameterTypes();
        Class<?>[] consThisParamTypes =
            new Class[consParamTypes.length + 1 - templateParametersCount];
        consThisParamTypes[0] = Pointer.class;
        System.arraycopy(
            consParamTypes,
            templateParametersCount,
            consThisParamTypes,
            1,
            consParamTypes.length - templateParametersCount);

        DynamicFunctionFactory constructorFactory =
            getDynamicFunctionFactory(lib, Style.ThisCall, void.class, consThisParamTypes);

        constructor = constructorFactory.newInstance(pointerToAddress(symbol.getAddress()));
        constructors.put(key, constructor);
      } catch (Throwable th) {
        th.printStackTrace();
        throw new RuntimeException(
            "Unable to create constructor " + constructorId + " for " + type + " : " + th, th);
      }
    }
    return constructor;
  }