/*
 * GuaraNative.c
 * Utility functions for native implementation of Guarana
 *
 * Copyright 1997,1998 Alexandre Oliva <oliva@dcc.unicamp.br>
 */

/* guarana.unicamp.br/APIguarana/lib */

#include "GuaraNative.h"

NativeOperation *guarana_new_native_operation(struct Hjava_lang_Object *object, struct Hjava_lang_Thread *thread, struct HBR_unicamp_Guarana_Operation *replaced) {
  Hjava_lang_Class *clazz = lookupClass("BR/unicamp/Guarana/Operation");
  NativeOperation *op;
  CLASS_FSIZE(clazz) = sizeof(NativeOperation);
  op = (NativeOperation*)newObjectNoMessage(clazz);
  op->object = object;
  op->thread = thread;
  op->replaced = replaced;
  return op;
}

struct HBR_unicamp_Guarana_Result *guarana_new_result_object(enum result_type kind, struct HBR_unicamp_Guarana_Operation *op, union wrapValue result) {
  Hjava_lang_Class *clazz = lookupClass("BR/unicamp/Guarana/Result");
  NativeResult *res;
  CLASS_FSIZE(clazz) = sizeof(NativeResult);
  res = (NativeResult*)newObjectNoMessage(clazz);
  res->kind = kind;
  res->op = op;
  res->res = result;
  return (struct HBR_unicamp_Guarana_Result *)res;
}

OperationFactory *guarana_new_operation_factory(struct Hjava_lang_Object *object, struct HBR_unicamp_Guarana_MetaObject *metaObject) {
  Hjava_lang_Class *clazz = lookupClass("BR/unicamp/Guarana/OperationFactoryInternal");
  OperationFactory *fact;
  CLASS_FSIZE(clazz) = sizeof(OperationFactory);
  fact = (OperationFactory*)newObjectNoMessage(clazz);
  fact->obj = object;
  fact->mobj = metaObject;
  return fact;
}

struct Hjava_lang_Object *guarana_wrap(struct Hjava_lang_Class *clazz, union wrapValue val) {
  if (!CLASS_IS_PRIMITIVE(clazz))
    return val.object_value;
  switch (CLASS_PRIM_SIG(clazz)) {
  case 'Z':
    return execute_java_constructor(0, "java.lang.Boolean", 0, "(Z)V", val.boolean_value);
  case 'B':
    return execute_java_constructor(0, "java.lang.Byte", 0, "(B)V", val.byte_value);
  case 'S':
    return execute_java_constructor(0, "java.lang.Short", 0, "(S)V", val.short_value);
  case 'I':
    return execute_java_constructor(0, "java.lang.Integer", 0, "(I)V", val.int_value);
  case 'J':
    return execute_java_constructor(0, "java.lang.Long", 0, "(J)V", val.long_value);
  case 'C':
    return execute_java_constructor(0, "java.lang.Character", 0, "(C)V", val.char_value);
  case 'F':
    return execute_java_constructor(0, "java.lang.Float", 0, "(F)V", val.float_value);
  case 'D':
    return execute_java_constructor(0, "java.lang.Double", 0, "(D)V", val.double_value);
  case 'V':
    return 0;
  default:
    ABORT();
  }
}

void guarana_unwrap(struct Hjava_lang_Class *clazz, union wrapValue *val, struct Hjava_lang_Object *wrapper) {
  val->word_value = 0;
  if (!CLASS_IS_PRIMITIVE(clazz)) {
    if (!instanceof(clazz, OBJECT_CLASS(wrapper)))
      SignalError(0, "java/lang/IllegalArgumentException", "object is not an instance of the requested class");
    val->object_value = wrapper;
  } else switch (CLASS_PRIM_SIG(clazz)) {
  case 'Z':
    if (strcmp(CLASS_CNAME(OBJECT_CLASS(wrapper)), "java/lang/Boolean") != 0)
      SignalError(0, "java/lang/IllegalArgumentException", "incorrect wrapper class");
    val->boolean_value = jboolean_do_execute_java_method(0, wrapper, "booleanValue", "()Z", 0, 0);
    break;
  case 'B':
    if (strcmp(CLASS_CNAME(OBJECT_CLASS(wrapper)), "java/lang/Byte") != 0)
      SignalError(0, "java/lang/IllegalArgumentException", "incorrect wrapper class");
    val->byte_value = jbyte_do_execute_java_method(0, wrapper, "byteValue", "()B", 0, 0);
    break;
  case 'S':
    if (strcmp(CLASS_CNAME(OBJECT_CLASS(wrapper)), "java/lang/Short") != 0)
      SignalError(0, "java/lang/IllegalArgumentException", "incorrect wrapper class");
    val->short_value = jshort_do_execute_java_method(0, wrapper, "shortValue", "()S", 0, 0);
    break;
  case 'I':
    if (strcmp(CLASS_CNAME(OBJECT_CLASS(wrapper)), "java/lang/Integer") != 0)
      SignalError(0, "java/lang/IllegalArgumentException", "incorrect wrapper class");
    val->int_value = jint_do_execute_java_method(0, wrapper, "intValue", "()I", 0, 0);
    break;
  case 'J':
    if (strcmp(CLASS_CNAME(OBJECT_CLASS(wrapper)), "java/lang/Long") != 0)
      SignalError(0, "java/lang/IllegalArgumentException", "incorrect wrapper class");
    val->long_value = jlong_do_execute_java_method(0, wrapper, "longValue", "()J", 0, 0);
    break;
  case 'C':
    if (strcmp(CLASS_CNAME(OBJECT_CLASS(wrapper)), "java/lang/Character") != 0)
      SignalError(0, "java/lang/IllegalArgumentException", "incorrect wrapper class");
    val->char_value = jchar_do_execute_java_method(0, wrapper, "charValue", "()C", 0, 0);
    break;
  case 'F':
    if (strcmp(CLASS_CNAME(OBJECT_CLASS(wrapper)), "java/lang/Float") != 0)
      SignalError(0, "java/lang/IllegalArgumentException", "incorrect wrapper class");
    val->float_value = jfloat_do_execute_java_method(0, wrapper, "floatValue", "()F", 0, 0);
    break;
  case 'D':
    if (strcmp(CLASS_CNAME(OBJECT_CLASS(wrapper)), "java/lang/Double") != 0)
      SignalError(0, "java/lang/IllegalArgumentException", "incorrect wrapper class");
    val->double_value = jdouble_do_execute_java_method(0, wrapper, "doubleValue", "()D", 0, 0);
    break;
  case 'V':
    break;
  default:
    ABORT();
  }
}

struct Hjava_lang_Object *guarana_wrap_from_va_list(struct Hjava_lang_Class *clazz, va_list *arg) {
  if (!CLASS_IS_PRIMITIVE(clazz))
    return va_arg(*arg, jobject);
  switch (CLASS_PRIM_SIG(clazz)) {
  case 'Z':
    return execute_java_constructor(0, "java.lang.Boolean", 0, "(Z)V", va_arg(*arg, jobject));
  case 'B':
    return execute_java_constructor(0, "java.lang.Byte", 0, "(B)V", va_arg(*arg, jbyte));
  case 'S':
    return execute_java_constructor(0, "java.lang.Short", 0, "(S)V", va_arg(*arg, jshort));
  case 'I':
    return execute_java_constructor(0, "java.lang.Integer", 0, "(I)V", va_arg(*arg, jint));
  case 'J':
    return execute_java_constructor(0, "java.lang.Long", 0, "(J)V", va_arg(*arg, jlong));
  case 'C':
    return execute_java_constructor(0, "java.lang.Character", 0, "(C)V", va_arg(*arg, jchar));
  case 'F':
    return execute_java_constructor(0, "java.lang.Float", 0, "(F)V", va_arg(*arg, jfloat));
  case 'D':
    return execute_java_constructor(0, "java.lang.Double", 0, "(D)V", va_arg(*arg, jdouble));
  case 'V':
    return 0;
  default:
    ABORT();
  }
}

void guarana_unwrap_to_va_list(struct Hjava_lang_Class *clazz, va_list *arg, struct Hjava_lang_Object *wrapper) {
  if (!CLASS_IS_PRIMITIVE(clazz))
     VA_ADD_ARG(*arg, struct Hjava_lang_Object*, (struct Hjava_lang_Object*)wrapper);
  else switch (CLASS_PRIM_SIG(clazz)) {
  case 'Z':
    VA_ADD_ARG(*arg, jboolean, jboolean_do_execute_java_method(0, wrapper, "booleanValue", "()Z", 0, 0));
    break;
  case 'B':
    VA_ADD_ARG(*arg, jbyte, jbyte_do_execute_java_method(0, wrapper, "byteValue", "()B", 0, 0));
    break;
  case 'S':
    VA_ADD_ARG(*arg, jshort, jshort_do_execute_java_method(0, wrapper, "shortValue", "()S", 0, 0));
    break;
  case 'I':
    VA_ADD_ARG(*arg, jint, jint_do_execute_java_method(0, wrapper, "intValue", "()I", 0, 0));
    break;
  case 'J':
    VA_ADD_ARG(*arg, jlong, jlong_do_execute_java_method(0, wrapper, "longValue", "()J", 0, 0));
    break;
  case 'C':
    VA_ADD_ARG(*arg, jchar, jchar_do_execute_java_method(0, wrapper, "charValue", "()C", 0, 0));
    break;
  case 'F':
    VA_ADD_ARG(*arg, jfloat, jfloat_do_execute_java_method(0, wrapper, "floatValue", "()F", 0, 0));
    break;
  case 'D':
    VA_ADD_ARG(*arg, jdouble, jdouble_do_execute_java_method(0, wrapper, "doubleValue", "()D", 0, 0));
    break;
  case 'V':
    break;
  default:
    ABORT();
  }
}

NativeResult *guarana_handle_operation(NativeOperation *op) {
  NativeResult *res;

  res = (NativeResult*)do_execute_java_class_method("BR/unicamp/Guarana/Guarana", "perform", "(LBR/unicamp/Guarana/Operation;)LBR/unicamp/Guarana/Result;", op);

  if (res->kind & res_thrown)
    throwException(res->res.object_value);

  return res;
}

#ifdef INTERPRETER
void
guarana_intrp_reify_method_invocation(struct Hjava_lang_Object *obj, Method *method, slots *args, slots *retval) {
  struct HBR_unicamp_Guarana_MetaObject *mo;
  if ((method->accflags & ACC_STATIC) != 0) {
    mo = method->class->head.meta_object;
  } else {
    mo = obj->meta_object;
  }
  if (mo) {
    NativeOperation *op;
    NativeResult *res;
    va_list arg;
    char *sig;

    op = guarana_new_native_operation(obj, CURRENTTHREAD(), 0);
    op->kind = op_method_invocation;
    op->op_id.method = method;
    op->op_arg.args = ALLOC_ARGLIST_FOR(METHOD_SIGNATURE(method));

    arg = ARGLIST_TO_VA_LIST(METHOD_SIGNATURE(method), op->op_arg.args);

    for(sig = op->op_id.method->signature->data+1;
	*sig != ')'; ++sig, ++args) {
      switch(*sig) {
      case 'Z':
	VA_ADD_ARG(arg, jboolean, args->v.tint);
	break;
      case 'B':
	VA_ADD_ARG(arg, jbyte, args->v.tint);
	break;
      case 'S':
	VA_ADD_ARG(arg, jshort, args->v.tint);
	break;
      case 'I':
	VA_ADD_ARG(arg, jint, args->v.tint);
	break;
      case 'J':
	VA_ADD_ARG(arg, jlong, args->v.tlong);
	++args;
	break;
      case 'C':
	VA_ADD_ARG(arg, jchar, args->v.tint);
	break;
      case 'F':
	VA_ADD_ARG(arg, jfloat, args->v.tfloat);
	break;
      case 'D':
	VA_ADD_ARG(arg, jdouble, args->v.tdouble);
	++args;
	break;
      case 'L':
	VA_ADD_ARG(arg, jobject, args->v.taddr);
	while(*++sig != ';')
	  ;
	break;
      case '[':
	va_arg(arg, jobject) = args->v.taddr;
	while(*++sig == '[')
	  ;
	if (*sig == 'L')
	  while(*++sig != ';')
	    ;
	break;
      default:
	unimp("guarana_intrp_reify_method_invocation: invalid type in signature");
	break;
      }
    }

    res = guarana_handle_operation(op);

    switch(*++sig) {
    case 'Z':
      retval->v.tint = res->res.boolean_value;
      break;
    case 'B':
      retval->v.tint = res->res.byte_value;
      break;
    case 'S':
      retval->v.tint = res->res.short_value;
      break;
    case 'I':
      retval->v.tint = res->res.int_value;
      break;
    case 'J':
      retval->v.tlong = res->res.long_value;
      break;
    case 'C':
      retval->v.tint = res->res.char_value;
      break;
    case 'F':
      retval->v.tfloat = res->res.float_value;
      break;
    case 'D':
      retval->v.tdouble = res->res.double_value;
      break;
    case 'L':
    case '[':
      retval->v.taddr = res->res.object_value;
      break;
    case 'V':
      break;
    default:
      ABORT();
    }
  } else {
    virtualMachine(method, args, retval);
  }
};
#endif

void
guarana_reify_method_invocation(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *obj, Method *method, va_list args, slots *retval) {
  NativeOperation *op;
  NativeResult *res;
  char *sig;

  op = guarana_new_native_operation(obj, CURRENTTHREAD(), 0);
  op->kind = op_method_invocation;
  op->op_id.method = method;
  op->op_arg.args = ALLOC_ARGLIST_FOR(METHOD_SIGNATURE(method));
  COPY_ARGLIST_FROM_TO(METHOD_SIGNATURE(method), VA_LIST_TO_ARGLIST(METHOD_SIGNATURE(method), args), op->op_arg.args);

  res = guarana_handle_operation(op);

  sig = METHOD_SIGNATURE(method);
  /* skip to return type */
  sizeofSig(&sig, true);

  switch (*sig) {
    case 'Z':
      retval->v.tint = res->res.boolean_value;
      break;
    case 'B':
      retval->v.tint = res->res.byte_value;
      break;
    case 'S':
      retval->v.tint = res->res.short_value;
      break;
    case 'I':
      retval->v.tint = res->res.int_value;
      break;
    case 'J':
      retval->v.tlong = res->res.long_value;
      break;
    case 'C':
      retval->v.tint = res->res.char_value;
      break;
    case 'F':
      retval->v.tfloat = res->res.float_value;
      break;
    case 'D':
      retval->v.tdouble = res->res.double_value;
      break;
    case 'L':
    case '[':
      retval->v.taddr = res->res.object_value;
      break;
    case 'V':
      break;
    default:
      ABORT();
  }
}

void
guarana_reify_field_load(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, Hjava_lang_Class *clazz, Field *field, union wrapValue *wrap) {
  NativeOperation *op;
  NativeResult *res;

  op = guarana_new_native_operation(o, CURRENTTHREAD(), 0);
  op->kind = op_field_read;
  op->op_id.field_id.clazz = clazz;
  op->op_id.field_id.field = field;

  res = guarana_handle_operation(op);

  *wrap = res->res;
}

jref
jref_reify_field_load(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, Hjava_lang_Class *clazz, Field *field) {
  union wrapValue wrap;
  guarana_reify_field_load(mo, o, clazz, field, &wrap);
  return wrap.object_value;
}

jword
jboolean_reify_field_load(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, Hjava_lang_Class *clazz, Field *field) {
  union wrapValue wrap;
  guarana_reify_field_load(mo, o, clazz, field, &wrap);
  return wrap.boolean_value;
}

jword
jchar_reify_field_load(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, Hjava_lang_Class *clazz, Field *field) {
  union wrapValue wrap;
  guarana_reify_field_load(mo, o, clazz, field, &wrap);
  return wrap.char_value;
}

jword
jbyte_reify_field_load(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, Hjava_lang_Class *clazz, Field *field) {
  union wrapValue wrap;
  guarana_reify_field_load(mo, o, clazz, field, &wrap);
  return wrap.byte_value;
}

jword
jshort_reify_field_load(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, Hjava_lang_Class *clazz, Field *field) {
  union wrapValue wrap;
  guarana_reify_field_load(mo, o, clazz, field, &wrap);
  return wrap.short_value;
}

jword
jint_reify_field_load(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, Hjava_lang_Class *clazz, Field *field) {
  union wrapValue wrap;
  guarana_reify_field_load(mo, o, clazz, field, &wrap);
  return wrap.int_value;
}

jlong
jlong_reify_field_load(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, Hjava_lang_Class *clazz, Field *field) {
  union wrapValue wrap;
  guarana_reify_field_load(mo, o, clazz, field, &wrap);
  return wrap.long_value;
}

jfloat
jfloat_reify_field_load(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, Hjava_lang_Class *clazz, Field *field) {
  union wrapValue wrap;
  guarana_reify_field_load(mo, o, clazz, field, &wrap);
  return wrap.float_value;
}

jdouble
jdouble_reify_field_load(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, Hjava_lang_Class *clazz, Field *field) {
  union wrapValue wrap;
  guarana_reify_field_load(mo, o, clazz, field, &wrap);
  return wrap.double_value;
}

void
guarana_reify_field_store(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, struct Hjava_lang_Class *clazz, Field *field, union wrapValue *val) {
  NativeOperation *op;

  op = guarana_new_native_operation(o, CURRENTTHREAD(), 0);
  op->kind = op_field_write;
  op->op_id.field_id.clazz = clazz;
  op->op_id.field_id.field = field;
  op->op_arg = *val;

  guarana_handle_operation(op);
}

void
jref_reify_field_store(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, Hjava_lang_Class *clazz, Field *field, jref value) {
  union wrapValue wrap;
  wrap.object_value = value;
  guarana_reify_field_store(mo, o, clazz, field, &wrap);
}

void
jboolean_reify_field_store(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, Hjava_lang_Class *clazz, Field *field, jword value) {
  union wrapValue wrap;
  wrap.boolean_value = value;
  guarana_reify_field_store(mo, o, clazz, field, &wrap);
}

void
jchar_reify_field_store(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, Hjava_lang_Class *clazz, Field *field, jword value) {
  union wrapValue wrap;
  wrap.char_value = value;
  guarana_reify_field_store(mo, o, clazz, field, &wrap);
}

void
jbyte_reify_field_store(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, Hjava_lang_Class *clazz, Field *field, jword value) {
  union wrapValue wrap;
  wrap.byte_value = value;
  guarana_reify_field_store(mo, o, clazz, field, &wrap);
}

void
jshort_reify_field_store(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, Hjava_lang_Class *clazz, Field *field, jword value) {
  union wrapValue wrap;
  wrap.short_value = value;
  guarana_reify_field_store(mo, o, clazz, field, &wrap);
}

void
jint_reify_field_store(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, Hjava_lang_Class *clazz, Field *field, jword value) {
  union wrapValue wrap;
  wrap.int_value = value;
  guarana_reify_field_store(mo, o, clazz, field, &wrap);
}

void
jlong_reify_field_store(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, Hjava_lang_Class *clazz, Field *field, jlong value) {
  union wrapValue wrap;
  wrap.long_value = value;
  guarana_reify_field_store(mo, o, clazz, field, &wrap);
}

void
jfloat_reify_field_store(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, Hjava_lang_Class *clazz, Field *field, jfloat value) {
  union wrapValue wrap;
  wrap.float_value = value;
  guarana_reify_field_store(mo, o, clazz, field, &wrap);
}

void
jdouble_reify_field_store(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, Hjava_lang_Class *clazz, Field *field, jdouble value) {
  union wrapValue wrap;
  wrap.double_value = value;
  guarana_reify_field_store(mo, o, clazz, field, &wrap);
}

void
guarana_reify_array_load(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, int index, union wrapValue *wrap) {
  NativeOperation *op;
  NativeResult *res;

  op = guarana_new_native_operation(o, CURRENTTHREAD(), 0);
  op->kind = op_array_read;
  op->op_id.index = index;

  res = guarana_handle_operation(op);

  *wrap = res->res;
}

jref
jref_reify_array_load(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, int index) {
  union wrapValue wrap;
  guarana_reify_array_load(mo, o, index, &wrap);
  return wrap.object_value;
}

jword
jboolean_reify_array_load(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, int index) {
  union wrapValue wrap;
  guarana_reify_array_load(mo, o, index, &wrap);
  return wrap.boolean_value;
}

jword
jchar_reify_array_load(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, int index) {
  union wrapValue wrap;
  guarana_reify_array_load(mo, o, index, &wrap);
  return wrap.char_value;
}

jword
jbyte_reify_array_load(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, int index) {
  union wrapValue wrap;
  guarana_reify_array_load(mo, o, index, &wrap);
  return wrap.byte_value;
}

jword
jshort_reify_array_load(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, int index) {
  union wrapValue wrap;
  guarana_reify_array_load(mo, o, index, &wrap);
  return wrap.short_value;
}

jword
jint_reify_array_load(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, int index) {
  union wrapValue wrap;
  guarana_reify_array_load(mo, o, index, &wrap);
  return wrap.int_value;
}

jlong
jlong_reify_array_load(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, int index) {
  union wrapValue wrap;
  guarana_reify_array_load(mo, o, index, &wrap);
  return wrap.long_value;
}

jfloat
jfloat_reify_array_load(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, int index) {
  union wrapValue wrap;
  guarana_reify_array_load(mo, o, index, &wrap);
  return wrap.float_value;
}

jdouble
jdouble_reify_array_load(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, int index) {
  union wrapValue wrap;
  guarana_reify_array_load(mo, o, index, &wrap);
  return wrap.double_value;
}

void
guarana_reify_array_store(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, int index, union wrapValue *val) {
  NativeOperation *op;

  op = guarana_new_native_operation(o, CURRENTTHREAD(), 0);
  op->kind = op_array_write;
  op->op_id.index = index;
  op->op_arg = *val;

  guarana_handle_operation(op);
}

void
jref_reify_array_store(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, int index, jref value) {
  union wrapValue wrap;
  wrap.object_value = value;
  guarana_reify_array_store(mo, o, index, &wrap);
}

void
jboolean_reify_array_store(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, int index, jword value) {
  union wrapValue wrap;
  wrap.boolean_value = value;
  guarana_reify_array_store(mo, o, index, &wrap);
}

void
jchar_reify_array_store(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, int index, jword value) {
  union wrapValue wrap;
  wrap.char_value = value;
  guarana_reify_array_store(mo, o, index, &wrap);
}

void
jbyte_reify_array_store(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, int index, jword value) {
  union wrapValue wrap;
  wrap.byte_value = value;
  guarana_reify_array_store(mo, o, index, &wrap);
}

void
jshort_reify_array_store(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, int index, jword value) {
  union wrapValue wrap;
  wrap.short_value = value;
  guarana_reify_array_store(mo, o, index, &wrap);
}

void
jint_reify_array_store(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, int index, jword value) {
  union wrapValue wrap;
  wrap.int_value = value;
  guarana_reify_array_store(mo, o, index, &wrap);
}

void
jlong_reify_array_store(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, int index, jlong value) {
  union wrapValue wrap;
  wrap.long_value = value;
  guarana_reify_array_store(mo, o, index, &wrap);
}

void
jfloat_reify_array_store(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, int index, jfloat value) {
  union wrapValue wrap;
  wrap.float_value = value;
  guarana_reify_array_store(mo, o, index, &wrap);
}

void
jdouble_reify_array_store(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o, int index, jdouble value) {
  union wrapValue wrap;
  wrap.double_value = value;
  guarana_reify_array_store(mo, o, index, &wrap);
}

int
guarana_reify_arraylength(struct Hjava_lang_Object *o) {
  struct HBR_unicamp_Guarana_MetaObject *mo = o->meta_object;
  NativeOperation *op;
  NativeResult *res;
  union wrapValue wrap;

  if (!mo)
    return obj_length((struct Array*)o);

  op = guarana_new_native_operation(o, CURRENTTHREAD(), 0);
  op->kind = op_array_length;

  res = guarana_handle_operation(op);

  wrap = res->res;

  return wrap.int_value;
}

void
guarana_reify_monitorEnter(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o) {
  NativeOperation *op;

  op = guarana_new_native_operation(o, CURRENTTHREAD(), 0);
  op->kind = op_monitor_enter;

  guarana_handle_operation(op);
}

void
guarana_reify_monitorExit(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *o) {
  NativeOperation *op;

  op = guarana_new_native_operation(o, CURRENTTHREAD(), 0);
  op->kind = op_monitor_exit;

  guarana_handle_operation(op);
}

struct Hjava_lang_Object*
guarana_meta_init(struct Hjava_lang_Object *obj, struct Hjava_lang_Class *cc, struct Hjava_lang_Object *creator) {
  struct HBR_unicamp_Guarana_MetaObject *mo = cc->head.meta_object;

  if (creator && creator->meta_object) {
      jobject newMetaObject = (jobject)do_execute_java_method(0, (jobject)creator->meta_object, "configure", "(Ljava/lang/Object;Ljava/lang/Object;)LBR/unicamp/Guarana/MetaObject;", 0, 0, obj, creator);
    do_execute_java_class_method("BR/unicamp/Guarana/Guarana", "setMetaObjectOf", "(Ljava/lang/Object;LBR/unicamp/Guarana/MetaObject;LBR/unicamp/Guarana/MetaObject;)V", obj, (jobject)obj->meta_object, newMetaObject);
  }

  if (mo) {
    /* implicit creation of NewObject messages must not be
       reified, because this would lead to infinite recursion
       whenever a MetaObject is associated with class
       NewObject */

    Method *newObjConstr;
    struct Hjava_lang_Object *newObjMsg;
    struct Hjava_lang_Class *newObjMsgClass = lookupClass("BR/unicamp/Guarana/NewObject");
    
    assert(newObjMsgClass != 0);
    assert(((newObjMsgClass->accflags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0));

    if (newObjMsgClass->state != CSTATE_OK)
      processClass(newObjMsgClass, CSTATE_OK);

    newObjConstr = findMethod(newObjMsgClass, constructor_name, makeUtf8Const("(Ljava/lang/Object;)V", -1));
    assert(newObjConstr != 0);

    newObjMsg = newObjectNoMessage(newObjMsgClass);
    do_execute_java_method(0, newObjMsg, 0, 0, newObjConstr, 0, newObjMsg);
    
    do_execute_java_class_method("BR/unicamp/Guarana/Guarana", "broadcast", "(LBR/unicamp/Guarana/Message;Ljava/lang/Object;)V", newObjMsg, (jobject)OBJECT_CLASS(obj));
  }

  return obj;
}  

struct Hjava_lang_Object*
guarana_newObject(struct Hjava_lang_Class *cc, struct Hjava_lang_Object *creator) {
  return guarana_meta_init(newObjectNoMessage(cc), cc, creator);
}

struct Hjava_lang_Object*
newObject(struct Hjava_lang_Class *cc) {
  return guarana_newObject(cc, 0);
}

struct Hjava_lang_Object*
guarana_newPrimArray(struct Hjava_lang_Class *cc, int count, struct Hjava_lang_Object *creator) {
  return guarana_meta_init(newPrimArrayNoMessage(cc, count), cc, creator);
}

struct Hjava_lang_Object*
newPrimArray(struct Hjava_lang_Class *cc, int count) {
  return guarana_newPrimArray(cc, count, 0);
}

struct Hjava_lang_Object*
guarana_newRefArray(struct Hjava_lang_Class *cc, int count, struct Hjava_lang_Object *creator) {
  return guarana_meta_init(newRefArrayNoMessage(cc, count), cc, creator);
}

struct Hjava_lang_Object*
newRefArray(struct Hjava_lang_Class *cc, int count) {
  return guarana_newRefArray(cc, count, 0);
}

/* guarana_newMultiArray defined in object.c */

Hjava_lang_Object*
newMultiArray(Hjava_lang_Class* clazz, int* dims)
{
	return guarana_newMultiArray(clazz, 0, dims);
}

/* guarana_newArray defined in object.c */

Hjava_lang_Object*
newArray(Hjava_lang_Class* eltype, int count)
{
	return guarana_newArray(eltype, 0, count);
}

/* copied from tjwassoc.co.uk/APIcore/lib/java.lang/Class.c */

HArrayOfObject*
parseSignature2Classes( char * signature, struct Hjava_lang_Class** returnType_holder )
{
	HArrayOfObject * array;
	Hjava_lang_Class ** adata;
	Hjava_lang_Class * tclass;
	const char * ptr;
	char buf[CLASSMAXSIG];	/* FIXME - size of buffer? */
	char * bufptr;
	int ins =0;
	int i = 0;
	int arraynest =0;


	ptr = signature;
	while(1)
	{
		switch( *ptr )
		{
			case '(':
				ptr++;
				break;
		    case ')':
				goto knowlength;
			case 'L':
				ins++;
				while( *ptr != ';' )
					ptr++;
				ptr++;
				break;
			case '[':
				ptr++;
				break;
			default:
				ins++;
				ptr++;
				break;
		}
	}

knowlength:

	array = (HArrayOfObject*)AllocObjectArray(ins, "Ljava/lang/Class;");
	ptr = signature;
	adata = (Hjava_lang_Class** ) ARRAY_DATA(array);

	while(1)
	{
		switch( *ptr )
		{
			case '(':
				ptr++;
				continue;
			case ')':
				ptr++;
				goto checkreturn;
			case 'I':
				tclass = &intClass;
				ptr++;
				break;
			case 'Z':
				tclass = &booleanClass;
				ptr++;
				break;
			case 'S':
				tclass = &shortClass;
				ptr++;
				break;
			case 'B':
				tclass = &byteClass;
				ptr++;
				break;
			case 'C':
				tclass = &charClass;
				ptr++;
				break;
			case 'F':
				tclass = &floatClass;
				ptr++;
				break;
			case 'D':
				tclass = &doubleClass;
				ptr++;
				break;
			case 'J':
				tclass = &longClass;
				ptr++;
				break;
			case '[':
				while ( *ptr == '[' )
				{
					ptr++;
					arraynest++;
				}
				continue;
			case 'L':
				ptr++;
				bufptr = buf;
				while ( *ptr != ';' )
					*bufptr++ = *ptr++;
				*bufptr = '\0';
				tclass = lookupClass( buf );
				ptr++;
				break;
			default:
				abort();
		
		}

		while ( arraynest )
		{
			tclass = lookupArray(tclass);
			arraynest--;
		}
		*(adata +i) = tclass;
		i++;
	}

checkreturn:

	assert(arraynest == 0);
	if (returnType_holder)
	{

arrayback:
		switch( *ptr )
		{
			case 'I':
				*returnType_holder = &intClass;
				break;
			case 'Z':
				*returnType_holder = &booleanClass;
				break;
			case 'S':
				*returnType_holder = &shortClass;
				break;
			case 'B':
				*returnType_holder= &byteClass;
				break;
			case 'C':
				*returnType_holder = &charClass;
				break;
			case 'F':
				*returnType_holder = &floatClass;
				break;
			case 'D':
				*returnType_holder = &doubleClass;
				break;
			case 'J':
				*returnType_holder = &longClass;
				break;
			case 'V':
				*returnType_holder = &voidClass;
				break;
			case '[':
				while ( *ptr == '[' )
				{
					arraynest++;
					ptr++;
				}
				goto arrayback;
			case 'L':
				ptr++;
				bufptr = buf;
				while ( *ptr != ';' )
					*bufptr++ = *ptr++;
				*bufptr = '\0';
				*returnType_holder = lookupClass( buf );
				break;
			default:
				abort();
		}

		while ( arraynest )
		{
			*returnType_holder = lookupArray(*returnType_holder);
			arraynest--;
		}
	}
	return array;
}


struct Hjava_lang_reflect_Method*
makeMethod(struct Hjava_lang_Class* clazz, int slot, HArrayOfObject* parameters,
	struct Hjava_lang_Class * returnType )
{
	Hjava_lang_reflect_Method* method;
	Method* met;

	met = CLASS_METHODS((Hjava_lang_Class*)clazz) + slot;
	method = (Hjava_lang_reflect_Method*)AllocObject("java/lang/reflect/Method");
	unhand(method)->clazz = (struct Hjava_lang_Class*) clazz;
	unhand(method)->slot = slot;
	unhand(method)->name = Utf8Const2JavaString(met->name);
	unhand(method)->returnType = returnType;
	unhand(method)->parameterTypes = parameters;
	unhand(method)->exceptionTypes = (HArrayOfObject*) AllocObjectArray(0,"Ljava/lang/Class");
	/* FIXME - check real exceptions for method - need to change main kaffe */
	return (method);
}

Hjava_lang_reflect_Field*
makeField(struct Hjava_lang_Class* clazz, int slot)
{
	Hjava_lang_reflect_Field* field;
	Field* fld;

	fld = CLASS_FIELDS((Hjava_lang_Class*)clazz) + slot;
	field = (Hjava_lang_reflect_Field*)AllocObject("java/lang/reflect/Field");
	unhand(field)->clazz = (struct Hjava_lang_Class*) clazz;
	unhand(field)->slot = slot;
	unhand(field)->type = (struct Hjava_lang_Class*) fld->type;
	unhand(field)->name = Utf8Const2JavaString(fld->name);
	return (field);
}

struct Hjava_lang_reflect_Constructor*
makeConstructor(struct Hjava_lang_Class* clazz, int slot, HArrayOfObject* parameters )
{
	Hjava_lang_reflect_Constructor* constructor;
	Method* met;

	met = CLASS_METHODS((Hjava_lang_Class*)clazz) + slot;
	constructor = (Hjava_lang_reflect_Constructor*)AllocObject("java/lang/reflect/Constructor");
	unhand(constructor)->clazz = (struct Hjava_lang_Class*) clazz;
	unhand(constructor)->slot = slot;
	unhand(constructor)->parameterTypes = parameters;
	unhand(constructor)->exceptionTypes = (HArrayOfObject*) AllocObjectArray(0,"Ljava/lang/Class");
	/* FIXME - check real exceptions for method - need to change main kaffe */
	return (constructor);
}

