/*
 * @(#)reflect.h	1.23 97/01/03
 * 
 * Copyright (c) 1995, 1996 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * This software is the confidential and proprietary information of Sun
 * Microsystems, Inc. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Sun.
 * 
 * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
 * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
 * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
 * THIS SOFTWARE OR ITS DERIVATIVES.
 * 
 * CopyrightVersion 1.1_beta
 * 
 */

#ifndef	_REFLECT_H
#define	_REFLECT_H

#include "oobj.h"
#include "native.h"

/*
 * Keep consistent with constants in java.lang.reflect.Member
 */
enum { MEMBER_PUBLIC, MEMBER_DECLARED };

extern HObject *	reflect_field(ClassClass *, char *, long);
extern HArrayOfObject *	reflect_fields(ClassClass *, long);

extern HObject *	reflect_method(ClassClass *, char *, HArrayOfObject *,
			    long);
extern HArrayOfObject *	reflect_methods(ClassClass *, long);

extern HObject *	reflect_constructor(ClassClass *, HArrayOfObject *,
			    long);
extern HArrayOfObject *	reflect_constructors(ClassClass *, long);

extern ClassClass *	reflect_find_class(char *, ClassClass *, char **);
extern bool_t		reflect_check_access(ExecEnv *, ClassClass *, int,
			    ClassClass *);
extern HObject *	reflect_new_array(ClassClass *, int);
extern HArrayOfObject *	reflect_new_class_array(int);
extern bool_t		reflect_is_assignable(ClassClass *, ClassClass *,
			    ExecEnv *);

/*
 * Implementation
 */

#ifdef _REFLECT_IMPL

/*
 * "Generic" accessors for Field, Method, Constructor
 */
#define	member_class(h)		(unhand(h)->clazz)
#define	member_slot(h)		(unhand(h)->slot)
#define	member_name(h)		(unhand(h)->name)
#define	member_type(h)		(unhand(h)->type)
#define	member_returnType(h)	(unhand(h)->returnType)
#define	member_parameterTypes(h)(unhand(h)->parameterTypes)
#define	member_exceptionTypes(h)(unhand(h)->exceptionTypes)


#define	REFLECT_GET(p, pCode, v, packed)				\
if (TRUE)								\
{									\
    switch (pCode) {							\
    case T_BOOLEAN:							\
    case T_BYTE:							\
	if (packed) { v.i = *(char *) (p); break; }			\
    case T_CHAR:							\
	if (packed) { v.i = *(unicode *) (p); break; }			\
    case T_SHORT:							\
	if (packed) { v.i = *(short *) (p); break; }			\
    case T_INT:								\
	v.i = *(long *) (p); break;					\
    case T_FLOAT:							\
	v.f = *(float *) (p); break;					\
    case T_LONG:							\
	v.l = GET_INT64(v, p); break;					\
    case T_DOUBLE:							\
	v.d = GET_DOUBLE(v, p); break;					\
    default:								\
	v.h = *(HObject **) (p);					\
    }									\
} else

#define	REFLECT_SET(p, pCode, v, packed)				\
if (TRUE)								\
{									\
    switch (pCode) {							\
    case T_BOOLEAN:							\
    case T_BYTE:							\
	if (packed) { *(char *) (p) = v.i; break; }			\
    case T_CHAR:							\
	if (packed) { *(unicode *) (p) = v.i; break; }			\
    case T_SHORT:							\
	if (packed) { *(short *) (p) = v.i; break; }			\
    case T_INT:								\
	*(long *) (p) = v.i ; break;					\
    case T_FLOAT:							\
	*(float *) (p) = v.f; break;					\
    case T_LONG:							\
	SET_INT64(v, p, v.l); break;					\
    case T_DOUBLE:							\
	SET_DOUBLE(v, p, v.d); break;					\
    default:								\
	*(HObject **) (p) = v.h;					\
    }									\
} else

#ifdef	WATCOM_UNIONFPBUG
/*
 * this is a copy of the REFLECT_WIDEN macro that has a work around
 * for the watcom code generation bug -- delete it when watcom gets
 * us a working compiler
 *
 * NOTE!  There are 2 (two, zwui, dos) bugs!
 *	1 - converting int -> float
 *	2 - converting int -> double
 */

#define	REFLECT_WIDEN(v, vCode, wCode, fail)				\
if (TRUE)								\
{									\
    switch(wCode) {							\
    case T_BOOLEAN:							\
    case T_BYTE:							\
    case T_CHAR:							\
	goto fail;							\
    case T_SHORT:							\
	switch (vCode) {						\
	case T_BYTE:							\
	    break;							\
	default:							\
	    goto fail;							\
	}								\
	break;								\
    case T_INT:								\
	switch (vCode) {						\
	case T_BYTE:							\
	case T_CHAR:							\
	case T_SHORT:							\
	    break;							\
	default:							\
	    goto fail;							\
	}								\
	break;								\
    case T_LONG:							\
	switch (vCode) {						\
	case T_BYTE:							\
	case T_CHAR:							\
	case T_SHORT:							\
	case T_INT:							\
	    v.l = int2ll(v.i); break;						\
	default:							\
	    goto fail;							\
	}								\
	break;								\
    case T_FLOAT:							\
	switch (vCode) {						\
	case T_BYTE:							\
	case T_CHAR:							\
	case T_SHORT:							\
	case T_INT:							\
		{							\
			int	tmpI;					\
			tmpI = v.i;					\
			v.f = (float) tmpI;				\
		}							\
		break;							\
	case T_LONG:							\
		{							\
			long	tmpL;					\
			tmpL = v.l;					\
			v.f = (float) tmpL;				\
		}							\
		break;							\
	default:							\
	    goto fail;							\
	}								\
	break;								\
    case T_DOUBLE:							\
	switch (vCode) {						\
	case T_BYTE:							\
	case T_CHAR:							\
	case T_SHORT:							\
	case T_INT:							\
	    v.d = (float) v.i; break; /* changed double cast to float -- jkm */					\
	case T_FLOAT:							\
	    v.d = (double) v.f; break;					\
	case T_LONG:							\
	    v.d = (float) v.l; break; /* changed double cast to float -- jkm */					\
	default:							\
	    goto fail;							\
	}								\
	break;								\
    default:								\
	goto fail;							\
    }									\
} else

#else
/*
 * this is the normal code -- delete above code once we get a version
 * of Watcom that can deal with v.f = (float) v.i -- kurt
 */

#define	REFLECT_WIDEN(v, vCode, wCode, fail)				\
if (TRUE)								\
{									\
    switch(wCode) {							\
    case T_BOOLEAN:							\
    case T_BYTE:							\
    case T_CHAR:							\
	goto fail;							\
    case T_SHORT:							\
	switch (vCode) {						\
	case T_BYTE:							\
	    break;							\
	default:							\
	    goto fail;							\
	}								\
	break;								\
    case T_INT:								\
	switch (vCode) {						\
	case T_BYTE:							\
	case T_CHAR:							\
	case T_SHORT:							\
	    break;							\
	default:							\
	    goto fail;							\
	}								\
	break;								\
    case T_LONG:							\
	switch (vCode) {						\
	case T_BYTE:							\
	case T_CHAR:							\
	case T_SHORT:							\
	case T_INT:							\
	    v.l = int2ll(v.i); break;						\
	default:							\
	    goto fail;							\
	}								\
	break;								\
    case T_FLOAT:							\
	switch (vCode) {						\
	case T_BYTE:							\
	case T_CHAR:							\
	case T_SHORT:							\
	case T_INT:							\
	    v.f = (float) v.i; break;					\
	case T_LONG:							\
	    v.f = (float) ll2float(v.l); break;					\
	default:							\
	    goto fail;							\
	}								\
	break;								\
    case T_DOUBLE:							\
	switch (vCode) {						\
	case T_BYTE:							\
	case T_CHAR:							\
	case T_SHORT:							\
	case T_INT:							\
	    v.d = (double) v.i; break;					\
	case T_FLOAT:							\
	    v.d = (double) v.f; break;					\
	case T_LONG:							\
	    v.d = (double) ll2double(v.l); break;					\
	default:							\
	    goto fail;							\
	}								\
	break;								\
    default:								\
	goto fail;							\
    }									\
} else

#endif	/* !WATCOM_UNIONFPBUG */

/*
 *
 */

#define	REFLECT_ERROR(nm, det)						\
	SignalError(0, JAVAPKG #nm, det)

#define	OutOfMemoryError()						\
	REFLECT_ERROR(OutOfMemoryError, 0)

#define	NullPointerException()						\
	REFLECT_ERROR(NullPointerException, 0)

#define	InternalError(det)						\
	REFLECT_ERROR(InternalError, det)

/*
 *
 */

#define	ENSURE_RESOLVED(cb)						\
    if (!CCIs(cb, Resolved)) {						\
	char   *detail = NULL;						\
	char   *exception = ResolveClass(cb, &detail);			\
	if (exception != NULL) {					\
	    SignalError(0, exception, detail);				\
	    return NULL;						\
	}								\
    }

/*
 *
 */

#define	fbClass(fb)	(fb->clazz)
#define	fbName(fb)	(fb->name)
#define	fbSig(fb)	(fb->signature)
#define	fbAccess(fb)	(fb->access)
#define	fbID(fb)	(fb->ID)
#define	fbIsArray(fb)	(fbSig(fb)[0] == SIGNATURE_ARRAY)
#define	fbIsClass(fb)	(fbSig(fb)[0] == SIGNATURE_CLASS)
#define	fbIsPublic(fb)	((fbAccess(fb) & ACC_PUBLIC) != 0)
#define	fbIsStatic(fb)	((fbAccess(fb) & ACC_STATIC) != 0)
#define	fbIsFinal(fb)	((fbAccess(fb) & ACC_FINAL) != 0)
#define	fbOffset(fb)	(fb->u.offset)

#define	mbFb(mb)	(&mb->fb)
#define	mbClass(mb)	(mb->fb.clazz)
#define	mbName(mb)	(mb->fb.name)
#define	mbSig(mb)	(mb->fb.signature)
#define	mbAccess(mb)	(mb->fb.access)
#define	mbOffset(mb)	(mb->fb.u.offset)
#define	mbID(mb)	(mb->fb.ID)
#define	mbArgsSize(mb)	(mb->args_size)
#define	mbIsSpecial(mb)	(mbName(mb)[0] == '<')
#define	mbIsPublic(mb)	((mbAccess(mb) & ACC_PUBLIC) != 0)
#define	mbIsStatic(mb)	((mbAccess(mb) & ACC_STATIC) != 0)

#endif /* _REFLECT_IMPL */

#endif /* _REFLECT_H */
