private Type getReturnType(String anno, SootMethod method) {
    soot.Type sootType = method.getReturnType();
    if (hasPointerAnnotation(method)) {
      if (!sootType.equals(LongType.v())) {
        throw new IllegalArgumentException(
            anno
                + " annotated method "
                + method
                + " must return long when annotated with @Pointer");
      }
      return I8_PTR;
    }
    if (hasMachineSizedFloatAnnotation(method)) {
      if (!sootType.equals(DoubleType.v()) && !sootType.equals(FloatType.v())) {
        throw new IllegalArgumentException(
            anno
                + " annotated method "
                + method
                + " must return float or double when annotated with @MachineSizedFloat");
      }
      return config.getArch().is32Bit() ? FLOAT : DOUBLE;
    }
    if (hasMachineSizedSIntAnnotation(method) || hasMachineSizedUIntAnnotation(method)) {
      if (!sootType.equals(LongType.v())) {
        throw new IllegalArgumentException(
            anno
                + " annotated method "
                + method
                + " must return long when annotated with @MachineSizedSInt or @MachineSizedUInt");
      }
      return config.getArch().is32Bit() ? I32 : I64;
    }
    if (isStruct(sootType)) {
      if (!isPassByValue(method)) {
        // Structs are returned by reference by default
        return new PointerType(getStructType(sootType));
      }
      return getStructType(sootType);
    } else if (isNativeObject(sootType)) {
      // NativeObjects are always returned by reference.
      return I8_PTR;
    } else if (sootType instanceof PrimType || sootType == VoidType.v()) {
      return getType(sootType);
    }

    MarshalerMethod marshalerMethod =
        config.getMarshalerLookup().findMarshalerMethod(new MarshalSite(method));
    if (marshalerMethod instanceof ValueMarshalerMethod) {
      return ((ValueMarshalerMethod) marshalerMethod).getNativeType(config.getArch());
    } else {
      return I8_PTR;
    }
  }
 protected Value marshalPrimitiveToNative(Function fn, SootMethod method, Value value) {
   soot.Type type = method.getReturnType();
   if (hasPointerAnnotation(method)) {
     value = marshalLongToPointer(fn, value);
   } else if (hasMachineSizedFloatAnnotation(method) && type.equals(DoubleType.v())) {
     value = marshalDoubleToMachineSizedFloat(fn, value);
   } else if (hasMachineSizedFloatAnnotation(method) && type.equals(FloatType.v())) {
     value = marshalFloatToMachineSizedFloat(fn, value);
   } else if (hasMachineSizedSIntAnnotation(method) && type.equals(LongType.v())) {
     value = marshalLongToMachineSizedInt(fn, value);
   } else if (hasMachineSizedUIntAnnotation(method) && type.equals(LongType.v())) {
     value = marshalLongToMachineSizedInt(fn, value);
   }
   return value;
 }
 private static int getFieldAlignment(SootField f) {
   soot.Type t = f.getType();
   if (LongType.v().equals(t) && Modifier.isVolatile(f.getModifiers())) {
     // On ARM volatile longs must be 8 byte aligned
     return 8;
   }
   if (LongType.v().equals(t) && !f.isStatic() && Modifier.isFinal(f.getModifiers())) {
     // The Java Memory Model requires final instance fields to be written to using
     // volatile semantics. Because of ARM's alignment requirements we return 8 here too.
     return 8;
   }
   if (LongType.v().equals(t) || DoubleType.v().equals(t)) {
     return 4;
   }
   return getFieldSize(f);
 }
 private Function createFieldSetter(SootField field) {
   Function fn = FunctionBuilder.setter(field);
   Value fieldPtr = null;
   Value value = null;
   if (field.isStatic()) {
     fieldPtr = getClassFieldPtr(fn, field);
     value = fn.getParameterRef(1);
   } else {
     fieldPtr = getInstanceFieldPtr(fn, fn.getParameterRef(1), field);
     value = fn.getParameterRef(2);
   }
   if (Modifier.isVolatile(field.getModifiers())
       || !field.isStatic() && Modifier.isFinal(field.getModifiers())) {
     if (LongType.v().equals(field.getType())) {
       fn.add(new Store(value, fieldPtr, false, Ordering.unordered, 8));
     } else {
       fn.add(new Store(value, fieldPtr));
     }
     fn.add(new Fence(Ordering.seq_cst));
   } else {
     fn.add(new Store(value, fieldPtr));
   }
   fn.add(new Ret());
   return fn;
 }
 protected Value marshalNativeToPrimitive(
     Function fn, SootMethod method, int paramIndex, Value value) {
   soot.Type type = method.getParameterType(paramIndex);
   if (hasPointerAnnotation(method, paramIndex)) {
     value = marshalPointerToLong(fn, value);
   } else if (hasMachineSizedFloatAnnotation(method, paramIndex) && type.equals(DoubleType.v())) {
     value = marshalMachineSizedFloatToDouble(fn, value);
   } else if (hasMachineSizedFloatAnnotation(method, paramIndex) && type.equals(FloatType.v())) {
     value = marshalMachineSizedFloatToFloat(fn, value);
   } else if (hasMachineSizedSIntAnnotation(method, paramIndex) && type.equals(LongType.v())) {
     value = marshalMachineSizedSIntToLong(fn, value);
   } else if (hasMachineSizedUIntAnnotation(method, paramIndex) && type.equals(LongType.v())) {
     value = marshalMachineSizedUIntToLong(fn, value);
   }
   return value;
 }
Exemple #6
0
 public static String getDescriptor(soot.Type t) {
   if (t instanceof PrimType) {
     if (t.equals(BooleanType.v())) {
       return "Z";
     } else if (t.equals(ByteType.v())) {
       return "B";
     } else if (t.equals(ShortType.v())) {
       return "S";
     } else if (t.equals(CharType.v())) {
       return "C";
     } else if (t.equals(IntType.v())) {
       return "I";
     } else if (t.equals(LongType.v())) {
       return "J";
     } else if (t.equals(FloatType.v())) {
       return "F";
     } else {
       // DoubleType
       return "D";
     }
   } else if (t.equals(VoidType.v())) {
     return "V";
   } else if (t instanceof soot.ArrayType) {
     soot.ArrayType at = (soot.ArrayType) t;
     return "[" + getDescriptor(at.getElementType());
   } else {
     // RefType
     RefType rt = (RefType) t;
     return "L" + rt.getClassName().replace('.', '/') + ";";
   }
 }
Exemple #7
0
 public static Type getType(soot.Type sootType) {
   if (sootType.equals(soot.BooleanType.v())) {
     return Type.I8;
   } else if (sootType.equals(soot.ByteType.v())) {
     return Type.I8;
   } else if (sootType.equals(soot.ShortType.v())) {
     return Type.I16;
   } else if (sootType.equals(soot.CharType.v())) {
     return Type.I16;
   } else if (sootType.equals(soot.IntType.v())) {
     return Type.I32;
   } else if (sootType.equals(soot.LongType.v())) {
     return Type.I64;
   } else if (sootType.equals(soot.FloatType.v())) {
     return Type.FLOAT;
   } else if (sootType.equals(soot.DoubleType.v())) {
     return Type.DOUBLE;
   } else if (sootType.equals(soot.VoidType.v())) {
     return Type.VOID;
   } else if (sootType instanceof soot.RefLikeType || sootType.equals(BottomType.v())) {
     return OBJECT_PTR;
   } else {
     throw new IllegalArgumentException("Unknown Type: " + sootType);
   }
 }
Exemple #8
0
 public static int getFieldSize(Arch arch, SootField f) {
   soot.Type t = f.getType();
   if (LongType.v().equals(t) || DoubleType.v().equals(t)) {
     return 8;
   }
   if (IntType.v().equals(t) || FloatType.v().equals(t)) {
     return 4;
   }
   if (t instanceof RefLikeType) {
     return arch.is32Bit() ? 4 : 8;
   }
   if (ShortType.v().equals(t) || CharType.v().equals(t)) {
     return 2;
   }
   if (ByteType.v().equals(t) || BooleanType.v().equals(t)) {
     return 1;
   }
   throw new IllegalArgumentException("Unknown Type: " + t);
 }
 private static int getFieldSize(SootField f) {
   soot.Type t = f.getType();
   if (LongType.v().equals(t) || DoubleType.v().equals(t)) {
     return 8;
   }
   if (IntType.v().equals(t) || FloatType.v().equals(t)) {
     return 4;
   }
   if (t instanceof RefLikeType) {
     // Assume pointers are 32-bit
     return 4;
   }
   if (ShortType.v().equals(t) || CharType.v().equals(t)) {
     return 2;
   }
   if (ByteType.v().equals(t) || BooleanType.v().equals(t)) {
     return 1;
   }
   throw new IllegalArgumentException("Unknown Type: " + t);
 }
Exemple #10
0
 private Function createFieldGetter(SootField field) {
   Function fn = FunctionBuilder.getter(field);
   Value fieldPtr = null;
   if (field.isStatic()) {
     fieldPtr = getClassFieldPtr(fn, field);
   } else {
     fieldPtr = getInstanceFieldPtr(fn, fn.getParameterRef(1), field);
   }
   Variable result = fn.newVariable(getType(field.getType()));
   if (Modifier.isVolatile(field.getModifiers())) {
     fn.add(new Fence(Ordering.seq_cst));
     if (LongType.v().equals(field.getType())) {
       fn.add(new Load(result, fieldPtr, false, Ordering.unordered, 8));
     } else {
       fn.add(new Load(result, fieldPtr));
     }
   } else {
     fn.add(new Load(result, fieldPtr));
   }
   fn.add(new Ret(new VariableRef(result)));
   return fn;
 }
Exemple #11
0
 public void outALongBaseType(ALongBaseType node) {
   mProductions.addLast(LongType.v());
 }
  protected void readRefField(OpenCLField ref_field) {
    SootField soot_field = ref_field.getSootField();
    SootClass soot_class = Scene.v().getSootClass(soot_field.getDeclaringClass().getName());

    BytecodeLanguage bcl = m_bcl.top();
    Local gc_obj_visit = m_gcObjVisitor.top();
    BclMemory bcl_mem = new BclMemory(bcl, m_currMem.top());

    Local ref = bcl_mem.readRef();
    bcl_mem.useInstancePointer();
    bcl_mem.pushAddress();
    bcl_mem.setAddress(ref);

    // bcl.println("reading field: "+ref_field.getName());

    SootClass obj_class = Scene.v().getSootClass("java.lang.Object");
    SootClass string = Scene.v().getSootClass("java.lang.String");
    SootClass class_class = Scene.v().getSootClass("java.lang.Class");
    Local original_field_value;
    if (soot_class.isApplicationClass() == false) {
      if (ref_field.isInstance()) {
        bcl.pushMethod(
            gc_obj_visit, "readField", obj_class.getType(), obj_class.getType(), string.getType());
        original_field_value =
            bcl.invokeMethodRet(
                gc_obj_visit, m_objSerializing.top(), StringConstant.v(soot_field.getName()));
      } else {
        bcl.pushMethod(
            gc_obj_visit,
            "readStaticField",
            obj_class.getType(),
            class_class.getType(),
            string.getType());
        Local cls = bcl.classConstant(soot_field.getDeclaringClass().getType());
        original_field_value =
            bcl.invokeMethodRet(gc_obj_visit, cls, StringConstant.v(soot_field.getName()));
      }
    } else {
      if (ref_field.isInstance()) {
        original_field_value = bcl.refInstanceField(m_objSerializing.top(), ref_field.getName());
      } else {
        original_field_value = bcl.refStaticField(soot_class.getType(), ref_field.getName());
      }
    }
    bcl.pushMethod(
        gc_obj_visit,
        "readFromHeap",
        obj_class.getType(),
        obj_class.getType(),
        BooleanType.v(),
        LongType.v());
    int should_read = 1;
    Local ret_obj =
        bcl.invokeMethodRet(gc_obj_visit, original_field_value, IntConstant.v(should_read), ref);

    Type type = soot_field.getType();
    Local ret = bcl.cast(type, ret_obj);

    if (soot_class.isApplicationClass() == false) {
      if (ref_field.isInstance()) {
        bcl.pushMethod(
            gc_obj_visit,
            "writeField",
            VoidType.v(),
            obj_class.getType(),
            string.getType(),
            obj_class.getType());
        bcl.invokeMethodNoRet(
            gc_obj_visit, m_objSerializing.top(), StringConstant.v(soot_field.getName()), ret);
      } else {
        bcl.pushMethod(
            gc_obj_visit,
            "writeStaticField",
            VoidType.v(),
            class_class.getType(),
            string.getType(),
            obj_class.getType());
        Local cls = bcl.classConstant(soot_field.getDeclaringClass().getType());
        bcl.invokeMethodNoRet(gc_obj_visit, cls, StringConstant.v(soot_field.getName()), ret);
      }
    } else {
      if (ref_field.isInstance()) {
        bcl.setInstanceField(soot_field, m_objSerializing.top(), ret);
      } else {
        bcl.setStaticField(soot_field, ret);
      }
    }

    bcl_mem.popAddress();
  }
Exemple #13
0
  private StructureConstant createClassInfoStruct() {
    int flags = 0;

    if (Modifier.isPublic(sootClass.getModifiers())) {
      flags |= CI_PUBLIC;
    }
    if (Modifier.isFinal(sootClass.getModifiers())) {
      flags |= CI_FINAL;
    }
    if (Modifier.isInterface(sootClass.getModifiers())) {
      flags |= CI_INTERFACE;
    }
    if (Modifier.isAbstract(sootClass.getModifiers())) {
      flags |= CI_ABSTRACT;
    }
    if ((sootClass.getModifiers() & 0x1000) > 0) {
      flags |= CI_SYNTHETIC;
    }
    if (Modifier.isAnnotation(sootClass.getModifiers())) {
      flags |= CI_ANNOTATION;
    }
    if (Modifier.isEnum(sootClass.getModifiers())) {
      flags |= CI_ENUM;
    }
    if (attributesEncoder.classHasAttributes()) {
      flags |= CI_ATTRIBUTES;
    }
    if (hasFinalizer(sootClass)) {
      flags |= CI_FINALIZABLE;
    }

    // Create the ClassInfoHeader structure.
    StructureConstantBuilder header = new StructureConstantBuilder();
    header.add(new NullConstant(I8_PTR)); // Points to the runtime Class struct
    header.add(new IntegerConstant(flags));
    header.add(getString(getInternalName(sootClass)));
    if (sootClass.declaresMethod("<clinit>", Collections.emptyList(), VoidType.v())) {
      SootMethod method = sootClass.getMethod("<clinit>", Collections.emptyList(), VoidType.v());
      header.add(new FunctionRef(mangleMethod(method), getFunctionType(method)));
    } else {
      header.add(new NullConstant(I8_PTR));
    }
    header.add(sizeof(classType));
    header.add(sizeof(instanceType));
    if (!instanceFields.isEmpty()) {
      header.add(offsetof(instanceType, 1, 1));
    } else {
      header.add(sizeof(instanceType));
    }
    header.add(new IntegerConstant((short) countReferences(classFields)));
    header.add(new IntegerConstant((short) countReferences(instanceFields)));

    PackedStructureConstantBuilder body = new PackedStructureConstantBuilder();
    body.add(new IntegerConstant((short) sootClass.getInterfaceCount()));
    body.add(new IntegerConstant((short) sootClass.getFieldCount()));
    body.add(new IntegerConstant((short) sootClass.getMethodCount()));

    if (!sootClass.isInterface()) {
      body.add(
          getStringOrNull(
              sootClass.hasSuperclass() ? getInternalName(sootClass.getSuperclass()) : null));
    }

    if (attributesEncoder.classHasAttributes()) {
      body.add(new ConstantBitcast(attributesEncoder.getClassAttributes().ref(), I8_PTR));
    }

    for (SootClass s : sootClass.getInterfaces()) {
      body.add(getString(getInternalName(s)));
    }

    for (SootField f : sootClass.getFields()) {
      flags = 0;
      soot.Type t = f.getType();
      if (t instanceof PrimType) {
        if (t.equals(BooleanType.v())) {
          flags |= DESC_Z;
        } else if (t.equals(ByteType.v())) {
          flags |= DESC_B;
        } else if (t.equals(ShortType.v())) {
          flags |= DESC_S;
        } else if (t.equals(CharType.v())) {
          flags |= DESC_C;
        } else if (t.equals(IntType.v())) {
          flags |= DESC_I;
        } else if (t.equals(LongType.v())) {
          flags |= DESC_J;
        } else if (t.equals(FloatType.v())) {
          flags |= DESC_F;
        } else if (t.equals(DoubleType.v())) {
          flags |= DESC_D;
        }
        flags <<= 12;
      }
      if (Modifier.isPublic(f.getModifiers())) {
        flags |= FI_PUBLIC;
      } else if (Modifier.isPrivate(f.getModifiers())) {
        flags |= FI_PRIVATE;
      } else if (Modifier.isProtected(f.getModifiers())) {
        flags |= FI_PROTECTED;
      }
      if (Modifier.isStatic(f.getModifiers())) {
        flags |= FI_STATIC;
      }
      if (Modifier.isFinal(f.getModifiers())) {
        flags |= FI_FINAL;
      }
      if (Modifier.isVolatile(f.getModifiers())) {
        flags |= FI_VOLATILE;
      }
      if (Modifier.isTransient(f.getModifiers())) {
        flags |= FI_TRANSIENT;
      }
      if ((f.getModifiers() & 0x1000) > 0) {
        flags |= FI_SYNTHETIC;
      }
      if (Modifier.isEnum(f.getModifiers())) {
        flags |= FI_ENUM;
      }
      if (attributesEncoder.fieldHasAttributes(f)) {
        flags |= FI_ATTRIBUTES;
      }
      body.add(new IntegerConstant((short) flags));
      body.add(getString(f.getName()));
      if (!(t instanceof PrimType)) {
        body.add(getString(getDescriptor(f)));
      }
      if (f.isStatic()) {
        int index = classFields.indexOf(f);
        body.add(offsetof(classType, 1, index, 1));
      } else {
        int index = instanceFields.indexOf(f);
        body.add(offsetof(instanceType, 1, 1 + index, 1));
      }
      if (attributesEncoder.fieldHasAttributes(f)) {
        body.add(new ConstantBitcast(attributesEncoder.getFieldAttributes(f).ref(), I8_PTR));
      }
    }

    for (SootMethod m : sootClass.getMethods()) {
      soot.Type t = m.getReturnType();
      flags = 0;
      if (Modifier.isPublic(m.getModifiers())) {
        flags |= MI_PUBLIC;
      } else if (Modifier.isPrivate(m.getModifiers())) {
        flags |= MI_PRIVATE;
      } else if (Modifier.isProtected(m.getModifiers())) {
        flags |= MI_PROTECTED;
      }
      if (Modifier.isStatic(m.getModifiers())) {
        flags |= MI_STATIC;
      }
      if (Modifier.isFinal(m.getModifiers())) {
        flags |= MI_FINAL;
      }
      if (Modifier.isSynchronized(m.getModifiers())) {
        flags |= MI_SYNCHRONIZED;
      }
      if ((m.getModifiers() & 0x0040) > 0) {
        flags |= MI_BRIDGE;
      }
      if ((m.getModifiers() & 0x0080) > 0) {
        flags |= MI_VARARGS;
      }
      if (Modifier.isNative(m.getModifiers())) {
        if (!isStruct(sootClass) && !isStructMember(m)) {
          flags |= MI_NATIVE;
        }
      }
      if (Modifier.isAbstract(m.getModifiers())) {
        flags |= MI_ABSTRACT;
      }
      if (Modifier.isStrictFP(m.getModifiers())) {
        flags |= MI_STRICT;
      }
      if ((m.getModifiers() & 0x1000) > 0) {
        flags |= MI_SYNTHETIC;
      }
      if (attributesEncoder.methodHasAttributes(m)) {
        flags |= MI_ATTRIBUTES;
      }
      if (isBridge(m)) {
        flags |= MI_BRO_BRIDGE;
      }
      if (isCallback(m)) {
        flags |= MI_BRO_CALLBACK;
      }
      if ((t instanceof PrimType || t == VoidType.v()) && m.getParameterCount() == 0) {
        flags |= MI_COMPACT_DESC;
      }
      body.add(new IntegerConstant((short) flags));

      body.add(getString(m.getName()));

      if ((flags & MI_COMPACT_DESC) > 0) {
        int desc = 0;
        if (t.equals(BooleanType.v())) {
          desc = DESC_Z;
        } else if (t.equals(ByteType.v())) {
          desc = DESC_B;
        } else if (t.equals(ShortType.v())) {
          desc = DESC_S;
        } else if (t.equals(CharType.v())) {
          desc = DESC_C;
        } else if (t.equals(IntType.v())) {
          desc = DESC_I;
        } else if (t.equals(LongType.v())) {
          desc = DESC_J;
        } else if (t.equals(FloatType.v())) {
          desc = DESC_F;
        } else if (t.equals(DoubleType.v())) {
          desc = DESC_D;
        } else if (t.equals(VoidType.v())) {
          desc = DESC_V;
        }
        body.add(new IntegerConstant((byte) desc));
      } else {
        body.add(getString(getDescriptor(m)));
      }
      if (attributesEncoder.methodHasAttributes(m)) {
        body.add(new ConstantBitcast(attributesEncoder.getMethodAttributes(m).ref(), I8_PTR));
      }
      if (!m.isAbstract()) {
        body.add(new ConstantBitcast(new FunctionRef(mangleMethod(m), getFunctionType(m)), I8_PTR));
        body.add(
            new IntegerConstant(
                DUMMY_METHOD_SIZE)); // Size of function. This value will be modified later by
                                     // patching the .s file.
        if (m.isSynchronized()) {
          body.add(
              new ConstantBitcast(
                  new FunctionRef(mangleMethod(m) + "_synchronized", getFunctionType(m)), I8_PTR));
        }
      }
      if (isBridge(m)) {
        body.add(new GlobalRef(BridgeMethodCompiler.getTargetFnPtrName(m), I8_PTR));
      }
      if (isCallback(m)) {
        body.add(
            new ConstantBitcast(
                new FunctionRef(mangleMethod(m) + "_callback", getCallbackFunctionType(m)),
                I8_PTR));
      }
    }

    // Return the struct {header, body}. To be compatible with the C code in classinfo.c
    // it is important that the header is padded the same as in C so that the body starts
    // after sizeof(ClassInfoHeader) bytes.
    return new StructureConstantBuilder().add(header.build()).add(body.build()).build();
  }
  private StructureType getStructType(SootClass clazz, boolean checkEmpty) {
    int n = 0;
    for (SootMethod method : clazz.getMethods()) {
      n = Math.max(getStructMemberOffset(method) + 1, n);
    }

    Type[] result = new Type[n + 1];

    StructureType superType = null;
    if (clazz.hasSuperclass()) {
      SootClass superclass = clazz.getSuperclass();
      if (!superclass.getName().equals("org.robovm.rt.bro.Struct")) {
        superType = getStructType(superclass, false);
      }
    }
    result[0] = superType != null ? superType : new StructureType();

    for (SootMethod method : clazz.getMethods()) {
      int offset = getStructMemberOffset(method);
      if (offset != -1) {
        if (!method.isNative() && !method.isStatic()) {
          throw new IllegalArgumentException(
              "@StructMember annotated method " + method + " must be native and not static");
        }
        Type type = null;
        if (method.getParameterCount() == 0) {
          soot.Type sootType = method.getReturnType();
          // Possibly a getter
          if (hasPointerAnnotation(method) && !sootType.equals(LongType.v())) {
            throw new IllegalArgumentException(
                "@StructMember("
                    + offset
                    + ") annotated getter "
                    + method
                    + " must be of type long when annotated with @Pointer");
          }
          if (hasMachineSizedFloatAnnotation(method)
              && !sootType.equals(DoubleType.v())
              && !sootType.equals(FloatType.v())) {
            throw new IllegalArgumentException(
                "@StructMember("
                    + offset
                    + ") annotated getter "
                    + method
                    + " must be of type float or double when annotated with @MachineSizedFloat");
          }
          if ((hasMachineSizedSIntAnnotation(method) || hasMachineSizedUIntAnnotation(method))
              && !sootType.equals(LongType.v())) {
            throw new IllegalArgumentException(
                "@StructMember("
                    + offset
                    + ") annotated getter "
                    + method
                    + " must be of type long when annotated with @MachineSizedSInt or @MachineSizedUInt");
          }
          if (sootType instanceof soot.ArrayType && !hasArrayAnnotation(method)) {
            throw new IllegalArgumentException(
                "@Array annotation expected on struct member getter " + method);
          }
        } else if (method.getParameterCount() == 1) {
          soot.Type sootType = method.getParameterType(0);
          if (hasPointerAnnotation(method, 0) && !sootType.equals(LongType.v())) {
            throw new IllegalArgumentException(
                "@StructMember("
                    + offset
                    + ") annotated setter "
                    + method
                    + " must be of type long when annotated with @Pointer");
          }
          if (hasMachineSizedFloatAnnotation(method, 0)
              && !sootType.equals(DoubleType.v())
              && !sootType.equals(FloatType.v())) {
            throw new IllegalArgumentException(
                "@StructMember("
                    + offset
                    + ") annotated setter "
                    + method
                    + " must be of type float or double when annotated with @MachineSizedFloat");
          }
          if ((hasMachineSizedSIntAnnotation(method, 0) || hasMachineSizedUIntAnnotation(method))
              && !sootType.equals(LongType.v())) {
            throw new IllegalArgumentException(
                "@StructMember("
                    + offset
                    + ") annotated setter "
                    + method
                    + " must be of type long when annotated with @MachineSizedSInt or @MachineSizedUInt");
          }
          if (sootType instanceof soot.ArrayType && !hasArrayAnnotation(method, 0)) {
            throw new IllegalArgumentException(
                "@Array annotation expected on first parameter of struct member setter " + method);
          }
          soot.Type retType = method.getReturnType();
          // The return type of the setter must be void or this
          if (!retType.equals(VoidType.v())
              && !(retType instanceof RefType
                  && ((RefType) retType).getSootClass().equals(clazz))) {
            throw new IllegalArgumentException(
                "Setter "
                    + method
                    + " for "
                    + "@StructMember("
                    + offset
                    + ") "
                    + " must either return nothing or return a "
                    + clazz);
          }
        } else {
          throw new IllegalArgumentException(
              "@StructMember annotated method " + method + " has too many parameters");
        }

        type = getStructMemberType(method);
        int index = offset + 1;
        if (result[index] == null) {
          result[index] = type;
        } else if (type != result[index]) {
          // Two members mapped to the same offset (union). Pick
          // the type with the largest alignment and pad with bytes
          // up to the largest size.
          result[index] = mergeStructMemberTypes(config.getDataLayout(), type, result[index]);
        }
      }
    }

    for (int i = 1; i < result.length; i++) {
      if (result[i] == null) {
        throw new IllegalArgumentException("No @StructMember(" + i + ") defined in class " + clazz);
      }
    }

    if (!clazz.isAbstract() && checkEmpty && n == 0 && superType == null) {
      throw new IllegalArgumentException(
          "Struct class " + clazz + " has no @StructMember annotated methods");
    }

    return new StructureType(result);
  }
  private Type getParameterType(String anno, SootMethod method, int i) {
    soot.Type sootType = method.getParameterType(i);
    if (hasPointerAnnotation(method, i)) {
      if (!sootType.equals(LongType.v())) {
        throw new IllegalArgumentException(
            "Parameter "
                + (i + 1)
                + " of "
                + anno
                + " annotated method "
                + method
                + " must be of type long when annotated with @Pointer.");
      }
      return I8_PTR;
    }
    if (hasMachineSizedFloatAnnotation(method, i)) {
      if (!sootType.equals(DoubleType.v()) && !sootType.equals(FloatType.v())) {
        throw new IllegalArgumentException(
            "Parameter "
                + (i + 1)
                + " of "
                + anno
                + " annotated method "
                + method
                + " must be of type float or double when annotated with @MachineSizedFloat.");
      }
      return config.getArch().is32Bit() ? FLOAT : DOUBLE;
    }
    if (hasMachineSizedSIntAnnotation(method, i) || hasMachineSizedUIntAnnotation(method, i)) {
      if (!sootType.equals(LongType.v())) {
        throw new IllegalArgumentException(
            "Parameter "
                + (i + 1)
                + " of "
                + anno
                + " annotated method "
                + method
                + " must be of type long when annotated with "
                + "@MachineSizedSInt or @MachineSizedUInt");
      }
      return config.getArch().is32Bit() ? I32 : I64;
    }
    if (hasStructRetAnnotation(method, i)) {
      if (i > 0) {
        throw new IllegalArgumentException(
            "Parameter "
                + (i + 1)
                + " of "
                + anno
                + " annotated method "
                + method
                + " cannot be annotated with @StructRet. Only the first"
                + " parameter may have this annotation.");
      }
      if (!isStruct(sootType)) {
        throw new IllegalArgumentException(
            "Parameter "
                + (i + 1)
                + " of "
                + anno
                + " annotated method "
                + method
                + " must be a sub class of Struct when annotated with @StructRet.");
      }
      // @StructRet implies pass by reference
      return new PointerType(getStructType(sootType));
    }
    if (isStruct(sootType)) {
      StructureType structType = getStructType(sootType);
      if (hasByValAnnotation(method, i)) {
        return getStructType(sootType);
      }
      return new PointerType(structType);
    } else if (isNativeObject(sootType)) {
      // NativeObjects are always passed by reference.
      return I8_PTR;
    } else if (sootType instanceof PrimType) {
      return getType(sootType);
    }

    MarshalerMethod marshalerMethod =
        config.getMarshalerLookup().findMarshalerMethod(new MarshalSite(method, i));
    if (marshalerMethod instanceof ValueMarshalerMethod) {
      return ((ValueMarshalerMethod) marshalerMethod).getNativeType(config.getArch());
    } else {
      return I8_PTR;
    }
  }