/*
 * GuaraNative.c
 * Utility functions for native implementation of Guarana
 *
 * Copyright 1997,1998 Alexandre Oliva <oliva@dcc.unicamp.br>
 *
 * This file is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "guarana/GuaraNative.h"

char * guarana_version = GVER;

/* These are initialized by java_lang_Class_init_function_pointers, in Class.c */

HArrayOfObject* (*p_makeParameters)(Method *meth);

Hjava_lang_Class* (*p_makeReturn)(Method *meth);

struct Hjava_lang_reflect_Constructor* (*p_makeConstructor)(struct Hjava_lang_Class* clazz, int slot);

struct Hjava_lang_reflect_Method* (*p_makeMethod)(struct Hjava_lang_Class* clazz, int slot);

struct Hjava_lang_reflect_Field* (*p_makeField)(struct Hjava_lang_Class* clazz, int slot);

Hjava_lang_String* (*p_getClassName)(struct Hjava_lang_Class *clazz);

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

struct HBR_unicamp_Guarana_Result *guarana_new_result_object(enum result_type kind, struct HBR_unicamp_Guarana_Operation *op, jvalue result) {
  static Hjava_lang_Class *clazz = 0;
  NativeResult *res;
  if (!clazz) {
    clazz = lookupClass("BR/unicamp/Guarana/Result");
    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 = 0;
  OperationFactory *fact;
  if (!clazz) {
    clazz = lookupClass("BR/unicamp/Guarana/OperationFactoryInternal");
    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, jvalue val, int *size) {
  int s;
  if (!size)
    size = &s;
  if (!CLASS_IS_PRIMITIVE(clazz)) {
    *size = 1;
    return val.l;
  }
  switch (CLASS_PRIM_SIG(clazz)) {
  case 'Z':
    *size = 1;
    return execute_java_constructor(0, javaLangBooleanClass, "(Z)V", val.i);
  case 'B':
    *size = 1;
    return execute_java_constructor(0, javaLangByteClass, "(B)V", val.i);
  case 'S':
    *size = 1;
    return execute_java_constructor(0, javaLangShortClass, "(S)V", val.i);
  case 'I':
    *size = 1;
    return execute_java_constructor(0, javaLangIntegerClass, "(I)V", val.i);
  case 'J':
    *size = 2;
    return execute_java_constructor(0, javaLangLongClass, "(J)V", val.j);
  case 'C':
    *size = 1;
    return execute_java_constructor(0, javaLangCharacterClass, "(C)V", val.i);
  case 'F':
    *size = 1;
    return execute_java_constructor(0, javaLangFloatClass, "(F)V",
				    *(int*)&val.f);
    /* FIXME: a float would be promoted to double because of varargs.
     * For consistency, kaffe should always pass floats as doubles,
     * but it doesn't; this breaks native methods that take floats as
     * arguments or return them.  */
  case 'D':
    *size = 2;
    return execute_java_constructor(0, javaLangDoubleClass, "(D)V", val.d);
  case 'V':
    *size = 0;
    return 0;
  default:
    ABORT();
  }
  return 0; /* never reached */
}

int guarana_unwrap(struct Hjava_lang_Class *clazz, jvalue *val, struct Hjava_lang_Object *wrapper) {
  if (!CLASS_IS_PRIMITIVE(clazz)) {
    if (!instanceof(clazz, OBJECT_CLASS(wrapper)))
      SignalError("java/lang/IllegalArgumentException", "object is not an instance of the requested class");
    val->l = wrapper;
    return 1;
  } else switch (CLASS_PRIM_SIG(clazz)) {
  case 'Z':
    if (OBJECT_CLASS(wrapper) != javaLangBooleanClass)
      SignalError("java/lang/IllegalArgumentException", "incorrect wrapper class");
    val->i = do_execute_java_method(wrapper, "booleanValue", "()Z", 0, 0).i;
    return 1;
  case 'B':
    if (OBJECT_CLASS(wrapper) != javaLangByteClass)
      SignalError("java/lang/IllegalArgumentException", "incorrect wrapper class");
    val->i = do_execute_java_method(wrapper, "byteValue", "()B", 0, 0).i;
    return 1;
  case 'S':
    if (OBJECT_CLASS(wrapper) != javaLangShortClass)
      SignalError("java/lang/IllegalArgumentException", "incorrect wrapper class");
    val->i = do_execute_java_method(wrapper, "shortValue", "()S", 0, 0).i;
    return 1;
  case 'I':
    if (OBJECT_CLASS(wrapper) != javaLangIntegerClass)
      SignalError("java/lang/IllegalArgumentException", "incorrect wrapper class");
    val->i = do_execute_java_method(wrapper, "intValue", "()I", 0, 0).i;
    return 1;
  case 'J':
    if (OBJECT_CLASS(wrapper) != javaLangLongClass)
      SignalError("java/lang/IllegalArgumentException", "incorrect wrapper class");
    val->j = do_execute_java_method(wrapper, "longValue", "()J", 0, 0).j;
    return 2;
  case 'C':
    if (OBJECT_CLASS(wrapper) != javaLangCharacterClass)
      SignalError("java/lang/IllegalArgumentException", "incorrect wrapper class");
    val->i = do_execute_java_method(wrapper, "charValue", "()C", 0, 0).i;
    return 1;
  case 'F':
    if (OBJECT_CLASS(wrapper) != javaLangFloatClass)
      SignalError("java/lang/IllegalArgumentException", "incorrect wrapper class");
    val->f = do_execute_java_method(wrapper, "floatValue", "()F", 0, 0).f;
    return 1;
  case 'D':
    if (OBJECT_CLASS(wrapper) != javaLangDoubleClass)
      SignalError("java/lang/IllegalArgumentException", "incorrect wrapper class");
    val->d = do_execute_java_method(wrapper, "doubleValue", "()D", 0, 0).d;
    return 2;
  case 'V':
    val->l = 0;
    return 0;
  default:
    ABORT();
  }
  return 0; /* never reached */
}

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).l);

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

  return res;
}

void
guarana_slots_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)
    obj = &method->class->head;
  mo = obj->meta_object;
  if (mo) {
    NativeOperation *op;
    NativeResult *res;
    char *sig;
    int argcount;

    op = guarana_new_native_operation(obj, getCurrentThread(), 0);
    if (equalUtf8Consts(method->name, init_name) ||
	equalUtf8Consts(method->name, constructor_name))
      op->kind |= op_constructor_invocation;
    else
      op->kind |= op_method_invocation;
    op->op_id.method = method;
    sig = op->op_id.method->signature->data;
    argcount = sizeofSig(&sig, true);
    op->op_arg.l = ALLOC_ARGVEC_FOR(argcount);
    memcpy(op->op_arg.l, args, argcount * sizeof(jvalue));

    res = guarana_handle_operation(op);

    switch(*sig) {
    case 'Z':
    case 'B':
    case 'S':
    case 'C':
    case 'I':
      retval->v.tint = res->res.i;
      break;
    case 'J':
      retval->v.tlong = res->res.j;
      break;
    case 'F':
      retval->v.tfloat = res->res.f;
      break;
    case 'D':
      retval->v.tdouble = res->res.d;
      break;
    case 'L':
    case '[':
      retval->v.taddr = res->res.l;
      break;
    case 'V':
      break;
    default:
      ABORT();
    }
  } else {
    callMethodA(method, METHOD_INDIRECTMETHOD(method), obj, (jvalue*)args, (jvalue*)retval);
  }
};

void
guarana_slots_resolve_method_invocation(struct Hjava_lang_Object *obj, Method *method, slots *args, slots *retval) {
  if (!METHOD_IS_STATIC(method))
      method = DMETHOD_DESC(obj->dtable->method[method->idx]);
  guarana_slots_reify_method_invocation(obj, method, args, retval);
}

void jvoid_reify_method_invocation(Method *method, Hjava_lang_Object *obj, ...) {
  va_list arglist;
  jbool isStatic = (method->accflags & ACC_STATIC) != 0;

  va_start(arglist, obj);
  do_execute_java_method_v(isStatic ? 0 : obj, 0, 0, method,
			   isStatic, arglist);
  va_end(arglist);
}

jref jref_reify_method_invocation(Method *method, Hjava_lang_Object *obj, ...) {
  va_list arglist;
  jbool isStatic = (method->accflags & ACC_STATIC) != 0;
  jvalue result;

  va_start(arglist, obj);
  result = do_execute_java_method_v(isStatic ? 0 : obj, 0, 0, method,
				    isStatic, arglist);
  va_end(arglist);

  return result.l;
}

jword jboolean_reify_method_invocation(Method *method, Hjava_lang_Object *obj, ...) {
  va_list arglist;
  jbool isStatic = (method->accflags & ACC_STATIC) != 0;
  jvalue result;

  va_start(arglist, obj);
  result = do_execute_java_method_v(isStatic ? 0 : obj, 0, 0, method,
				    isStatic, arglist);
  va_end(arglist);

  return result.i;
}

jword jchar_reify_method_invocation(Method *method, Hjava_lang_Object *obj, ...) {
  va_list arglist;
  jbool isStatic = (method->accflags & ACC_STATIC) != 0;
  jvalue result;

  va_start(arglist, obj);
  result = do_execute_java_method_v(isStatic ? 0 : obj, 0, 0, method,
				    isStatic, arglist);
  va_end(arglist);

  return result.i;
}

jword jbyte_reify_method_invocation(Method *method, Hjava_lang_Object *obj, ...) {
  va_list arglist;
  jbool isStatic = (method->accflags & ACC_STATIC) != 0;
  jvalue result;

  va_start(arglist, obj);
  result = do_execute_java_method_v(isStatic ? 0 : obj, 0, 0, method,
				    isStatic, arglist);
  va_end(arglist);

  return result.i;
}

jword jshort_reify_method_invocation(Method *method, Hjava_lang_Object *obj, ...) {
  va_list arglist;
  jbool isStatic = (method->accflags & ACC_STATIC) != 0;
  jvalue result;

  va_start(arglist, obj);
  result = do_execute_java_method_v(isStatic ? 0 : obj, 0, 0, method,
				    isStatic, arglist);
  va_end(arglist);

  return result.i;
}

jword jint_reify_method_invocation(Method *method, Hjava_lang_Object *obj, ...) {
  va_list arglist;
  jbool isStatic = (method->accflags & ACC_STATIC) != 0;
  jvalue result;

  va_start(arglist, obj);
  result = do_execute_java_method_v(isStatic ? 0 : obj, 0, 0, method,
				    isStatic, arglist);
  va_end(arglist);

  return result.i;
}

jlong jlong_reify_method_invocation(Method *method, Hjava_lang_Object *obj, ...) {
  va_list arglist;
  jbool isStatic = (method->accflags & ACC_STATIC) != 0;
  jvalue result;

  va_start(arglist, obj);
  result = do_execute_java_method_v(isStatic ? 0 : obj, 0, 0, method,
				    isStatic, arglist);
  va_end(arglist);

  return result.j;
}

jfloat jfloat_reify_method_invocation(Method *method, Hjava_lang_Object *obj, ...) {
  va_list arglist;
  jbool isStatic = (method->accflags & ACC_STATIC) != 0;
  jvalue result;

  va_start(arglist, obj);
  result = do_execute_java_method_v(isStatic ? 0 : obj, 0, 0, method,
				    isStatic, arglist);
  va_end(arglist);

  return result.f;
}

jdouble jdouble_reify_method_invocation(Method *method, Hjava_lang_Object *obj, ...) {
  va_list arglist;
  jbool isStatic = (method->accflags & ACC_STATIC) != 0;
  jvalue result;

  va_start(arglist, obj);
  result = do_execute_java_method_v(isStatic ? 0 : obj, 0, 0, method,
				    isStatic, arglist);
  va_end(arglist);

  return result.d;
}

void
guarana_va_list_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;
  int argcount;
  jvalue *argl;

  if ((method->accflags & ACC_STATIC) != 0)
    obj = &method->class->head;
  op = guarana_new_native_operation(obj, getCurrentThread(), 0);
  if (equalUtf8Consts(method->name, init_name) ||
      equalUtf8Consts(method->name, constructor_name))
    op->kind |= op_constructor_invocation;
  else
    op->kind |= op_method_invocation;
  op->op_id.method = method;
  sig = method->signature->data;
  argcount = sizeofSig(&sig, true);
  op->op_arg.l = ALLOC_ARGVEC_FOR(argcount);
  
  for((sig = method->signature->data + 1), (argl = (jvalue*)op->op_arg.l);
      *sig != ')'; ++sig, ++argl) {
    switch (*sig) {
    case 'Z':
    case 'B':
    case 'S':
    case 'C':
    case 'I':
      argl->i = va_arg(args, jint);
      break;
    case 'J':
      argl->j = va_arg(args, jlong);
      ++argl;
      break;
    case 'F':
      argl->f = va_arg(args, jfloat);
      break;
    case 'D':
      argl->d = va_arg(args, jdouble);
      ++argl;
      break;
    case '[':
      while (*sig == '[')
	++sig;
      if (*sig == 'L') { /* fall through */
    case 'L':
	while (*sig != ';') {
	  sig++;
	}
      }
      argl->l = va_arg(args, jref);
      break;
    default:
      ABORT();
    }
  }
    
  res = guarana_handle_operation(op);

  /* skip to return type */

  switch (*++sig) {
    case 'Z':
    case 'B':
    case 'S':
    case 'C':
    case 'I':
      retval->v.tint = res->res.i;
      break;
    case 'J':
      retval->v.tlong = res->res.j;
      break;
    case 'F':
      retval->v.tfloat = res->res.f;
      break;
    case 'D':
      retval->v.tdouble = res->res.d;
      break;
    case 'L':
    case '[':
      retval->v.taddr = res->res.l;
      break;
    case 'V':
      break;
    default:
      ABORT();
  }
}

void
guarana_va_list_resolve_method_invocation(struct HBR_unicamp_Guarana_MetaObject *mo, struct Hjava_lang_Object *obj, Method *method, va_list args, slots *retval) {
  if (!METHOD_IS_STATIC(method))
      method = DMETHOD_DESC(obj->dtable->method[method->idx]);
  guarana_va_list_reify_method_invocation(mo, obj, method, args, retval);
}

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

  op = guarana_new_native_operation(o, getCurrentThread(), 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) {
  jvalue wrap;
  guarana_reify_field_load(mo, o, clazz, field, &wrap);
  return wrap.l;
}

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

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

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

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

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

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

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

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

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

  op = guarana_new_native_operation(o, getCurrentThread(), 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) {
  jvalue wrap;
  wrap.l = 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) {
  jvalue wrap;
  wrap.i = 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) {
  jvalue wrap;
  wrap.i = 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) {
  jvalue wrap;
  wrap.i = 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) {
  jvalue wrap;
  wrap.i = 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) {
  jvalue wrap;
  wrap.i = 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) {
  jvalue wrap;
  wrap.j = 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) {
  jvalue wrap;
  wrap.f = 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) {
  jvalue wrap;
  wrap.d = 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, jvalue *wrap) {
  NativeOperation *op;
  NativeResult *res;

  op = guarana_new_native_operation(o, getCurrentThread(), 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) {
  jvalue wrap;
  guarana_reify_array_load(mo, o, index, &wrap);
  return wrap.l;
}

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

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

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

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

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

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

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

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

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

  op = guarana_new_native_operation(o, getCurrentThread(), 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) {
  jvalue wrap;
  wrap.l = 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) {
  jvalue wrap;
  wrap.i = 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) {
  jvalue wrap;
  wrap.i = 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) {
  jvalue wrap;
  wrap.i = 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) {
  jvalue wrap;
  wrap.i = 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) {
  jvalue wrap;
  wrap.i = 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) {
  jvalue wrap;
  wrap.j = 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) {
  jvalue wrap;
  wrap.f = 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) {
  jvalue wrap;
  wrap.d = value;
  guarana_reify_array_store(mo, o, index, &wrap);
}

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

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

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

  res = guarana_handle_operation(op);

  wrap = res->res;

  return wrap.i;
}

void
guarana_reify_monitorEnter(struct Hjava_lang_Object *o) {
  if (o->meta_object) {
    NativeOperation *op = guarana_new_native_operation(o, getCurrentThread(), 0);
    op->kind |= op_monitor_enter;

    guarana_handle_operation(op);
  } else
    _lockMutex(o);
}

void
guarana_reify_monitorExit(struct Hjava_lang_Object *o) {
  if (o->meta_object) {
    NativeOperation *op = guarana_new_native_operation(o, getCurrentThread(), 0);
    op->kind |= op_monitor_exit;

    guarana_handle_operation(op);
  } else
    _unlockMutex(o);    
}

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;

  if (creator && creator->meta_object) {
    static Method *setMetaObjectOf = 0;
    jobject newMetaObject = do_execute_java_method(creator->meta_object, "configure", "(Ljava/lang/Object;Ljava/lang/Object;)LBR/unicamp/Guarana/MetaObject;", 0, 0, obj, creator).l;
    if (!setMetaObjectOf)
      setMetaObjectOf = lookupClassMethod(lookupClass("BR/unicamp/Guarana/Guarana"), "setMetaObjectOf", "(Ljava/lang/Object;LBR/unicamp/Guarana/MetaObject;LBR/unicamp/Guarana/MetaObject;)V");
    do_execute_java_method(0, 0, 0, setMetaObjectOf, 1, obj, (jobject)obj->meta_object, newMetaObject);
  }

  mo = cc->head.meta_object;
  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 */

    static Hjava_lang_Class *newObjMsgClass = 0;
    static Method *newObjConstr = 0;
    static Method *broadcast = 0;

    struct Hjava_lang_Object *newObjMsg;

    if (!newObjMsgClass)
      newObjMsgClass = lookupClass("BR/unicamp/Guarana/NewObject");

    if (!newObjConstr)
      newObjConstr = lookupClassMethod(newObjMsgClass, constructor_name->data,
				       "(Ljava/lang/Object;)V");

    newObjMsg = newObjectNoMessage(newObjMsgClass);
    do_execute_java_method(newObjMsg, 0, 0, newObjConstr, 0, obj);
    
    if (!broadcast)
      broadcast = lookupClassMethod(lookupClass("BR/unicamp/Guarana/Guarana"),
				    "broadcast",
				    "(LBR/unicamp/Guarana/Message;Ljava/lang/Object;)V");

    do_execute_java_method(0, 0, 0, broadcast, 1,
			   newObjMsg, (jobject)OBJECT_CLASS(obj));
  }

  return obj;
}  

#ifdef GUARANA

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_newArray(struct Hjava_lang_Class *cc, int count, struct Hjava_lang_Object *creator) {
  return guarana_meta_init(newArrayNoMessage(cc, count), cc, creator);
}

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

/* guarana_newMultiArray defined in object.c */

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

#else

/* this is here for debugging purposes only */

Hjava_lang_Object*
newObjectNoMessage(Hjava_lang_Class* class) {
  return newObject(class);
}

#endif
