/*
 * private Object getField(Object o, Class declaringClass, Class type,
 *     int slot, boolean noAccessCheck)
 *
 * Primitive types need to be boxed.
 */
static void Dalvik_java_lang_reflect_Field_getField(const u4* args,
        JValue* pResult)
{
    // ignore thisPtr in args[0]
    Object* obj = (Object*) args[1];
    ClassObject* declaringClass = (ClassObject*) args[2];
    ClassObject* fieldType = (ClassObject*) args[3];
    int slot = args[4];
    bool noAccessCheck = (args[5] != 0);
    JValue value;
    const JValue* fieldPtr;
    DataObject* result;

    //dvmDumpClass(obj->clazz, kDumpClassFullDetail);

    /* get a pointer to the field's data; performs access checks */
    fieldPtr = getFieldDataAddr(obj, declaringClass, slot, false,noAccessCheck);
    if (fieldPtr == NULL)
        RETURN_VOID();

    /* copy 4 or 8 bytes out */
    if (fieldType->primitiveType == PRIM_LONG ||
            fieldType->primitiveType == PRIM_DOUBLE)
    {
        value.j = fieldPtr->j;
    } else {
        value.i = fieldPtr->i;
    }

    result = dvmWrapPrimitive(value, fieldType);
    dvmReleaseTrackedAlloc((Object*) result, NULL);
    RETURN_PTR(result);
}
/*
 * private void setField(Object o, Class declaringClass, Class type,
 *     int slot, boolean noAccessCheck, Object value)
 *
 * When assigning into a primitive field we will automatically extract
 * the value from box types.
 */
static void Dalvik_java_lang_reflect_Field_setField(const u4* args,
        JValue* pResult)
{
    // ignore thisPtr in args[0]
    Object* obj = (Object*) args[1];
    ClassObject* declaringClass = (ClassObject*) args[2];
    ClassObject* fieldType = (ClassObject*) args[3];
    int slot = args[4];
    bool noAccessCheck = (args[5] != 0);
    Object* valueObj = (Object*) args[6];
    JValue* fieldPtr;
    JValue value;

    /* unwrap primitive, or verify object type */
    if (!dvmUnwrapPrimitive(valueObj, fieldType, &value)) {
        dvmThrowException("Ljava/lang/IllegalArgumentException;",
                          "invalid value for field");
        RETURN_VOID();
    }

    /* get a pointer to the field's data; performs access checks */
    fieldPtr = getFieldDataAddr(obj, declaringClass, slot, true, noAccessCheck);
    if (fieldPtr == NULL)
        RETURN_VOID();

    /* store 4 or 8 bytes */
    if (fieldType->primitiveType == PRIM_LONG ||
            fieldType->primitiveType == PRIM_DOUBLE)
    {
        fieldPtr->j = value.j;
    } else if (fieldType->primitiveType == PRIM_NOT) {
        if (slot < 0) {
            StaticField *sfield;
            sfield = (StaticField *)dvmSlotToField(declaringClass, slot);
            assert(fieldPtr == &sfield->value);
            dvmSetStaticFieldObject(sfield, value.l);
        } else {
            int offset = declaringClass->ifields[slot].byteOffset;
            assert(fieldPtr == (JValue *)BYTE_OFFSET(obj, offset));
            dvmSetFieldObject(obj, offset, value.l);
        }
    } else {
        fieldPtr->i = value.i;
    }

    RETURN_VOID();
}
/*
 * Primitive field setters, e.g.:
 * private void setIField(Object o, Class declaringClass,
 *     Class type, int slot, boolean noAccessCheck, int type_no, int value)
 *
 * The "type_no" is defined by the java.lang.reflect.Field class.
 */
static void Dalvik_java_lang_reflect_Field_setPrimitiveField(const u4* args,
        JValue* pResult)
{
    // ignore thisPtr in args[0]
    Object* obj = (Object*) args[1];
    ClassObject* declaringClass = (ClassObject*) args[2];
    ClassObject* fieldType = (ClassObject*) args[3];
    int slot = args[4];
    bool noAccessCheck = (args[5] != 0);
    int typeNum = args[6];
    const s4* valuePtr = (s4*) &args[7];
    PrimitiveType srcType = convPrimType(typeNum);
    JValue* fieldPtr;
    JValue value;

    if (!dvmIsPrimitiveClass(fieldType)) {
        dvmThrowException("Ljava/lang/IllegalArgumentException;",
                          "not a primitive field");
        RETURN_VOID();
    }

    /* convert the 32/64-bit arg to a JValue matching the field type */
    if (dvmConvertPrimitiveValue(srcType, fieldType->primitiveType,
                                 valuePtr, &(value.i)) < 0)
    {
        dvmThrowException("Ljava/lang/IllegalArgumentException;",
                          "invalid primitive conversion");
        RETURN_VOID();
    }

    /* get a pointer to the field's data; performs access checks */
    fieldPtr = getFieldDataAddr(obj, declaringClass, slot, true, noAccessCheck);
    if (fieldPtr == NULL)
        RETURN_VOID();

    /* store 4 or 8 bytes */
    if (fieldType->primitiveType == PRIM_LONG ||
            fieldType->primitiveType == PRIM_DOUBLE)
    {
        fieldPtr->j = value.j;
    } else {
        fieldPtr->i = value.i;
    }

    RETURN_VOID();
}
/*
 * Primitive field getters, e.g.:
 * private double getIField(Object o, Class declaringClass,
 *     Class type, int slot, boolean noAccessCheck, int type_no)
 *
 * The "type_no" is defined by the java.lang.reflect.Field class.
 */
static void Dalvik_java_lang_reflect_Field_getPrimitiveField(const u4* args,
        JValue* pResult)
{
    // ignore thisPtr in args[0]
    Object* obj = (Object*) args[1];
    ClassObject* declaringClass = (ClassObject*) args[2];
    ClassObject* fieldType = (ClassObject*) args[3];
    int slot = args[4];
    bool noAccessCheck = (args[5] != 0);
    int typeNum = args[6];
    PrimitiveType targetType = convPrimType(typeNum);
    const JValue* fieldPtr;
    JValue value;

    if (!dvmIsPrimitiveClass(fieldType)) {
        dvmThrowException("Ljava/lang/IllegalArgumentException;",
                          "not a primitive field");
        RETURN_VOID();
    }

    /* get a pointer to the field's data; performs access checks */
    fieldPtr = getFieldDataAddr(obj, declaringClass, slot, false,noAccessCheck);
    if (fieldPtr == NULL)
        RETURN_VOID();

    /* copy 4 or 8 bytes out */
    if (fieldType->primitiveType == PRIM_LONG ||
            fieldType->primitiveType == PRIM_DOUBLE)
    {
        value.j = fieldPtr->j;
    } else {
        value.i = fieldPtr->i;
    }

    /* retrieve value, performing a widening conversion if necessary */
    if (dvmConvertPrimitiveValue(fieldType->primitiveType, targetType,
                                 &(value.i), &(pResult->i)) < 0)
    {
        dvmThrowException("Ljava/lang/IllegalArgumentException;",
                          "invalid primitive conversion");
        RETURN_VOID();
    }
}
/*
 * Primitive field setters, e.g.:
 * private void setIField(Object o, Class declaringClass,
 *     Class type, int slot, boolean noAccessCheck, int type_no, int value)
 *
 * The "type_no" is defined by the java.lang.reflect.Field class.
 */
static void Dalvik_java_lang_reflect_Field_setPrimitiveField(const u4* args,
    JValue* pResult)
{
    // ignore thisPtr in args[0]
    Object* obj = (Object*) args[1];
    ClassObject* declaringClass = (ClassObject*) args[2];
    ClassObject* fieldType = (ClassObject*) args[3];
    int slot = args[4];
    bool noAccessCheck = (args[5] != 0);
    int typeNum = args[6];
    const s4* valuePtr = (s4*) &args[7];
#ifdef WITH_TAINT_TRACKING
    /* rtaint = args[8]
     * thisPtr taint = args[9]
     * obj taint = args[10]
     * declaringClass taint = args[11]
     * fieldType taint = args[12]
     * slot taint = args[13]
     * noAccessCheck taint = args[14]
     * typeNum taint = args[15]
     */
    u4 valueTaint = args[16];
#endif
    PrimitiveType srcType = convPrimType(typeNum);
    JValue* fieldPtr;
    JValue value;

    if (!dvmIsPrimitiveClass(fieldType)) {
        dvmThrowException("Ljava/lang/IllegalArgumentException;",
            "not a primitive field");
        RETURN_VOID();
    }

    /* convert the 32/64-bit arg to a JValue matching the field type */
    if (dvmConvertPrimitiveValue(srcType, fieldType->primitiveType,
        valuePtr, &(value.i)) < 0)
    {
        dvmThrowException("Ljava/lang/IllegalArgumentException;",
            "invalid primitive conversion");
        RETURN_VOID();
    }

    /* get a pointer to the field's data; performs access checks */
    fieldPtr = getFieldDataAddr(obj, declaringClass, slot, true, noAccessCheck);
    if (fieldPtr == NULL)
        RETURN_VOID();

    /* store 4 or 8 bytes */
    if (fieldType->primitiveType == PRIM_LONG ||
        fieldType->primitiveType == PRIM_DOUBLE)
    {
        fieldPtr->j = value.j;
    } else {
        fieldPtr->i = value.i;
    }

#ifdef WITH_TAINT_TRACKING
    /* If we got this far, we know the fields is okay to access and there
     * will not be a problem getting the field from the slot */
    {
	Field* field = dvmSlotToField(declaringClass, slot);
	assert(field != NULL);
	if (dvmIsStaticField(field)) {
	    StaticField* sfield = (StaticField*)field;
	    dvmSetStaticFieldTaint(sfield, valueTaint);
	} else {
	    /* Note, getFieldDataAddr() already checked that
	     * obj is of type declaringClass, so no need to check here
	     */
	    InstField* ifield = (InstField*)field;
	    if (fieldType->primitiveType == PRIM_LONG ||
		fieldType->primitiveType == PRIM_DOUBLE) {
		dvmSetFieldTaintWide(obj, ifield->byteOffset, valueTaint);
	    } else {
		dvmSetFieldTaint(obj, ifield->byteOffset, valueTaint);
	    }
	}
    }
#endif

    RETURN_VOID();
}
/*
 * Primitive field getters, e.g.:
 * private double getIField(Object o, Class declaringClass,
 *     Class type, int slot, boolean noAccessCheck, int type_no)
 *
 * The "type_no" is defined by the java.lang.reflect.Field class.
 */
static void Dalvik_java_lang_reflect_Field_getPrimitiveField(const u4* args,
    JValue* pResult)
{
    // ignore thisPtr in args[0]
    Object* obj = (Object*) args[1];
    ClassObject* declaringClass = (ClassObject*) args[2];
    ClassObject* fieldType = (ClassObject*) args[3];
    int slot = args[4];
    bool noAccessCheck = (args[5] != 0);
    int typeNum = args[6];
#ifdef WITH_TAINT_TRACKING
    u4* rtaint = (u4*) &args[7]; /* return taint tag slot */
#endif
    PrimitiveType targetType = convPrimType(typeNum);
    const JValue* fieldPtr;
    JValue value;

    if (!dvmIsPrimitiveClass(fieldType)) {
        dvmThrowException("Ljava/lang/IllegalArgumentException;",
            "not a primitive field");
        RETURN_VOID();
    }

    /* get a pointer to the field's data; performs access checks */
    fieldPtr = getFieldDataAddr(obj, declaringClass, slot, false,noAccessCheck);
    if (fieldPtr == NULL)
        RETURN_VOID();

    /* copy 4 or 8 bytes out */
    if (fieldType->primitiveType == PRIM_LONG ||
        fieldType->primitiveType == PRIM_DOUBLE)
    {
        value.j = fieldPtr->j;
    } else {
        value.i = fieldPtr->i;
    }

    /* retrieve value, performing a widening conversion if necessary */
    if (dvmConvertPrimitiveValue(fieldType->primitiveType, targetType,
        &(value.i), &(pResult->i)) < 0)
    {
        dvmThrowException("Ljava/lang/IllegalArgumentException;",
            "invalid primitive conversion");
        RETURN_VOID();
    }

#ifdef WITH_TAINT_TRACKING
    /* If we got this far, we know the fields is okay to access and there
     * will not be a problem getting the field from the slot */
    {
	Field* field = dvmSlotToField(declaringClass, slot);
	assert(field != NULL);
	if (dvmIsStaticField(field)) {
	    StaticField* sfield = (StaticField*)field;
	    *rtaint = dvmGetStaticFieldTaint(sfield);
	} else {
	    /* Note, getFieldDataAddr() already checked that
	     * obj is of type declaringClass, so no need to check here
	     */
	    InstField* ifield = (InstField*)field;
	    if (fieldType->primitiveType == PRIM_LONG ||
		fieldType->primitiveType == PRIM_DOUBLE) {
		*rtaint = dvmGetFieldTaintWide(obj, ifield->byteOffset);
	    } else {
		*rtaint = dvmGetFieldTaint(obj, ifield->byteOffset);
	    }
	}
    }
#endif
}
/*
 * private void setField(Object o, Class declaringClass, Class type,
 *     int slot, boolean noAccessCheck, Object value)
 *
 * When assigning into a primitive field we will automatically extract
 * the value from box types.
 */
static void Dalvik_java_lang_reflect_Field_setField(const u4* args,
    JValue* pResult)
{
    // ignore thisPtr in args[0]
    Object* obj = (Object*) args[1];
    ClassObject* declaringClass = (ClassObject*) args[2];
    ClassObject* fieldType = (ClassObject*) args[3];
    int slot = args[4];
    bool noAccessCheck = (args[5] != 0);
    Object* valueObj = (Object*) args[6];
#ifdef WITH_TAINT_TRACKING
    /* rtaint = args[7]
     * thisPtr taint = args[8]
     * obj taint = args[9]
     * declaringClass taint = args[10]
     * fieldType taint = args[11]
     * slot taint = args[12]
     * noAccessCheck taint = args[13]
     */
    u4 valueTaint = args[14];
#endif
    JValue* fieldPtr;
    JValue value;

    /* unwrap primitive, or verify object type */
    if (!dvmUnwrapPrimitive(valueObj, fieldType, &value)) {
        dvmThrowException("Ljava/lang/IllegalArgumentException;",
            "invalid value for field");
        RETURN_VOID();
    }

    /* get a pointer to the field's data; performs access checks */
    fieldPtr = getFieldDataAddr(obj, declaringClass, slot, true, noAccessCheck);
    if (fieldPtr == NULL)
        RETURN_VOID();

    /* store 4 or 8 bytes */
    if (fieldType->primitiveType == PRIM_LONG ||
        fieldType->primitiveType == PRIM_DOUBLE)
    {
        fieldPtr->j = value.j;
    } else if (fieldType->primitiveType == PRIM_NOT) {
        if (slot < 0) {
            StaticField *sfield;
            sfield = (StaticField *)dvmSlotToField(declaringClass, slot);
            assert(fieldPtr == &sfield->value);
            dvmSetStaticFieldObject(sfield, value.l);
        } else {
            int offset = declaringClass->ifields[slot].byteOffset;
            assert(fieldPtr == (JValue *)BYTE_OFFSET(obj, offset));
            dvmSetFieldObject(obj, offset, value.l);
        }
    } else {
        fieldPtr->i = value.i;
    }

#ifdef WITH_TAINT_TRACKING
    /* If we got this far, we know the fields is okay to access and there
     * will not be a problem getting the field from the slot */
    {
	Field* field = dvmSlotToField(declaringClass, slot);
	assert(field != NULL);
	if (dvmIsStaticField(field)) {
	    StaticField* sfield = (StaticField*)field;
	    dvmSetStaticFieldTaint(sfield, valueTaint);
	} else {
	    /* Note, getFieldDataAddr() already checked that
	     * obj is of type declaringClass, so no need to check here
	     */
	    InstField* ifield = (InstField*)field;
	    if (fieldType->primitiveType == PRIM_LONG ||
		fieldType->primitiveType == PRIM_DOUBLE) {
		dvmSetFieldTaintWide(obj, ifield->byteOffset, valueTaint);
	    } else {
		dvmSetFieldTaint(obj, ifield->byteOffset, valueTaint);
	    }
	}
    }
#endif

    RETURN_VOID();
}
/*
 * private Object getField(Object o, Class declaringClass, Class type,
 *     int slot, boolean noAccessCheck)
 *
 * Primitive types need to be boxed.
 */
static void Dalvik_java_lang_reflect_Field_getField(const u4* args,
    JValue* pResult)
{
    // ignore thisPtr in args[0]
    Object* obj = (Object*) args[1];
    ClassObject* declaringClass = (ClassObject*) args[2];
    ClassObject* fieldType = (ClassObject*) args[3];
    int slot = args[4];
    bool noAccessCheck = (args[5] != 0);
#ifdef WITH_TAINT_TRACKING
    u4* rtaint = (u4*) &args[6]; /* return taint tag slot */
#endif
    JValue value;
    const JValue* fieldPtr;
    DataObject* result;

    //dvmDumpClass(obj->clazz, kDumpClassFullDetail);

    /* get a pointer to the field's data; performs access checks */
    fieldPtr = getFieldDataAddr(obj, declaringClass, slot, false,noAccessCheck);
    if (fieldPtr == NULL)
        RETURN_VOID();

    /* copy 4 or 8 bytes out */
    if (fieldType->primitiveType == PRIM_LONG ||
        fieldType->primitiveType == PRIM_DOUBLE)
    {
        value.j = fieldPtr->j;
    } else {
        value.i = fieldPtr->i;
    }

    result = dvmWrapPrimitive(value, fieldType);
    dvmReleaseTrackedAlloc((Object*) result, NULL);

#ifdef WITH_TAINT_TRACKING
    /* If we got this far, we know the fields is okay to access and there
     * will not be a problem getting the field from the slot */
    {
	Field* field = dvmSlotToField(declaringClass, slot);
	assert(field != NULL);
	if (dvmIsStaticField(field)) {
	    StaticField* sfield = (StaticField*)field;
	    *rtaint = dvmGetStaticFieldTaint(sfield);
	} else {
	    /* Note, getFieldDataAddr() already checked that
	     * obj is of type declaringClass, so no need to check here
	     */
	    InstField* ifield = (InstField*)field;
	    if (fieldType->primitiveType == PRIM_LONG ||
		fieldType->primitiveType == PRIM_DOUBLE) {
		*rtaint = dvmGetFieldTaintWide(obj, ifield->byteOffset);
	    } else {
		*rtaint = dvmGetFieldTaint(obj, ifield->byteOffset);
	    }
	}
    }
#endif

    RETURN_PTR(result);
}