/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode:nil -*-
   jniarray.c -- Java Native Interface array operations.
   Created: Chris Toshok <toshok@hungry.com>, 26-Jul-1997
*/
/*
  This file is part of Japhar, the GNU Virtual Machine for Java Bytecodes.
  Japhar is a project of The Hungry Programmers, GNU, and OryxSoft.

  Copyright (C) 1997, 1998, 1999 The Hungry Programmers

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This library 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
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdlib.h>

#include "jniint.h"

jsize
JNIFUNC(GetArrayLength)(JNIEnv *env,
                        jarray array)
{
  InterpValue length_value;
  japhar_object* arr = array;
  FieldStruct *field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];

  HVM_FieldGet(array,
                     field,
                     &length_value);

  return length_value.i;
}

jarray
JNIFUNC(NewObjectArray)(JNIEnv *env,
                        jsize length,
                        jclass elementClass,
                        jobject initialElement)
{
  HungryEnv *henv = JNIEnvToHEnv(env);
  ClazzFile *cf = jclass_to_clazzfile(henv, elementClass);
  char *element_classname = getClassName(henv, cf);
  japhar_object* array_reference;

  /* XXX use initialElement? */

  array_reference = HVM_ArrayCreate(henv, length, element_classname);

  /* XXX Should it throw OutOfMemoryError if creation failed? */

  return (jarray)array_reference;
}

jobject
JNIFUNC(GetObjectArrayElement)(JNIEnv *env,
                               jobjectArray array,
                               jsize index)
{
  InterpValue body_value;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field = arr->clazz->fields [ ARRAY_BODY_INDEX ];

  HVM_FieldGet(array,
               field,
               &body_value);

  return ((jobject*)body_value.l)[ index ];
}

void
JNIFUNC(SetObjectArrayElement)(JNIEnv *env,
                               jobjectArray array,
                               jsize index,
                               jobject value)
{
  InterpValue body_value;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field = arr->clazz->fields [ ARRAY_BODY_INDEX ];

  HVM_FieldGet(array,
                     field,
                     &body_value);

  ((jobject*)body_value.l)[ index ] = value;
}

jbooleanArray
JNIFUNC(NewBooleanArray)(JNIEnv *env,
                         jsize length)
{
  HungryEnv *henv = JNIEnvToHEnv(env);
  ClazzFile *boolean_array_type = HVM_ClassFind(henv, "[Z");
  japhar_object* array = HVM_ArrayNew(henv, length, boolean_array_type);

  return (jobject)array;
}

jboolean*
JNIFUNC(GetBooleanArrayElements)(JNIEnv *env,
                                 jbooleanArray array,
                                 jboolean* isCopy)
{
  japhar_object* arr = (japhar_object*)array;
  InterpValue body_value, length_value;
  jboolean *the_copy = NULL;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);
  
  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);
  
#ifdef COPY_ELEMENTS
  the_copy = (jboolean*)PR_MALLOC(sizeof(jboolean) * length_value.i);
#endif

  if (the_copy == NULL)
    {
      if (isCopy) *isCopy = JNI_FALSE;
      return (jboolean*)body_value.l;
    }
  else
    {
      memcpy(the_copy, body_value.l, sizeof(jboolean) * length_value.i);
      if (isCopy) *isCopy = JNI_TRUE;
      return the_copy;
    }
}

void
JNIFUNC(ReleaseBooleanArrayElements)(JNIEnv *env,
                                     jbooleanArray array,
                                     jboolean* elems,
                                     jint mode)
{
  japhar_object* arr = (japhar_object*)array;
  InterpValue body_value, length_value;
  jboolean can_free = JNI_FALSE;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

  if (body_value.l != (void*)elems)
    can_free = JNI_TRUE;

  switch (mode)
    {
    case 0: /* commit the changes and free elems. */
      memcpy(body_value.l, elems, sizeof(jboolean) * length_value.i);
      if (can_free) PR_DELETE(elems);
      break;
    case JNI_COMMIT: /* commit the changes but don't free elems. */
      memcpy(body_value.l, elems, sizeof(jboolean) * length_value.i);
      break;
    case JNI_ABORT:  /* don't commit the changes but free elems. */
      if (can_free) PR_DELETE(elems);
      break;
    }
}

void
JNIFUNC(GetBooleanArrayRegion)(JNIEnv *env,
                               jbooleanArray array,
                               jsize start,
                               jsize len,
                               jboolean* buf)
{
  InterpValue body_value, length_value;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);
  
  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env,
                                           java_lang_ArrayIndexOutOfBoundsException);
      (*env)->ThrowNew(env, exception, "In JNI GetBooleanArrayRegion");
      return;
    }

  memcpy(buf, ((jboolean*)body_value.l) + start, len * sizeof(jboolean));
}

void
JNIFUNC(SetBooleanArrayRegion)(JNIEnv *env,
                               jbooleanArray array,
                               jsize start,
                               jsize len,
                               jboolean* buf)
{
  InterpValue body_value, length_value;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);
  
  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env,
                                           java_lang_ArrayIndexOutOfBoundsException);
      (*env)->ThrowNew(env, exception, "In JNI GetBooleanArrayRegion");
      return;
    }

  memcpy(((jboolean*)body_value.l) + start, buf, len * sizeof(jboolean));
}

jbyteArray
JNIFUNC(NewByteArray)(JNIEnv *env,
                      jsize length)
{
  HungryEnv *henv = JNIEnvToHEnv(env);
  ClazzFile *byte_array_type = HVM_ClassFind(henv, "[B");
  japhar_object* array = HVM_ArrayNew(henv, length, byte_array_type);

  return (jbyteArray)array;
}

jbyte*
JNIFUNC(GetByteArrayElements)(JNIEnv *env,
                              jbyteArray array,
                              jboolean* isCopy)
{
  InterpValue body_value, length_value;
  jbyte *the_copy = NULL;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

#ifdef COPY_ELEMENTS
  the_copy = (jbyte*)PR_MALLOC(sizeof(jbyte) * length_value.i);
#endif

  if (the_copy == NULL)
    {
      if (isCopy) *isCopy = JNI_FALSE;
      return (jbyte*)body_value.l;
    }
  else
    {
      memcpy(the_copy, body_value.l, sizeof(jbyte) * length_value.i);
      if (isCopy) *isCopy = JNI_TRUE;
      return the_copy;
    }
}

void
JNIFUNC(ReleaseByteArrayElements)(JNIEnv *env,
                                  jbyteArray array,
                                  jbyte* elems,
                                  jint mode)
{
  InterpValue body_value, length_value;
  jboolean can_free = JNI_FALSE;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

  if (body_value.l != (void*)elems)
    can_free = JNI_TRUE;

  switch (mode)
    {
    case 0: /* commit the changes and free elems. */
      memcpy(body_value.l, elems, sizeof(jbyte) * length_value.i);
      if (can_free) PR_DELETE(elems);
      break;
    case JNI_COMMIT: /* commit the changes but don't free elems. */
      memcpy(body_value.l, elems, sizeof(jbyte) * length_value.i);
      break;
    case JNI_ABORT:  /* don't commit the changes but free elems. */
      if (can_free) PR_DELETE(elems);
      break;
    }
}

void
JNIFUNC(GetByteArrayRegion)(JNIEnv *env,
                            jbyteArray array,
                            jsize start,
                            jsize len,
                            jbyte* buf)
{
  InterpValue body_value, length_value;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env,
                                           java_lang_ArrayIndexOutOfBoundsException);
      (*env)->ThrowNew(env, exception, "In JNI GetByteArrayRegion");
      return;
    }

  memcpy(buf, ((jbyte*)body_value.l) + start, len * sizeof(jbyte));
}

void
JNIFUNC(SetByteArrayRegion)(JNIEnv *env,
                            jbyteArray array,
                            jsize start,
                            jsize len,
                            jbyte* buf)
{
  InterpValue body_value, length_value;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
                     field,
                     &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ],
    HVM_FieldGet(array,
                       field,
                       &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env,
                                           java_lang_ArrayIndexOutOfBoundsException);
      (*env)->ThrowNew(env, exception, "In JNI GetByteArrayRegion");
      return;
    }

  memcpy(((jbyte*)body_value.l) + start, buf, len * sizeof(jbyte));
}

jcharArray
JNIFUNC(NewCharArray)(JNIEnv *env,
                      jsize length)
{
  HungryEnv *henv = JNIEnvToHEnv(env);
  ClazzFile* char_array_type = HVM_ClassFind(henv, "[C");
  japhar_object* array;

  array = HVM_ArrayNew(henv, length, char_array_type);
  /* HVM_ArrayNew() has thrown if something went wrong */

  return array;
}

jchar*
JNIFUNC(GetCharArrayElements)(JNIEnv *env,
                              jcharArray array,
                              jboolean* isCopy)
{
  InterpValue body_value, length_value;
  jchar *the_copy = NULL;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

#ifdef COPY_ELEMENTS
  the_copy = (jchar*)PR_MALLOC(sizeof(jchar) * length_value.i);
#endif

  if (the_copy == NULL)
    {
      if (isCopy) *isCopy = JNI_FALSE;
      return (jchar*)body_value.l;
    }
  else
    {
      memcpy(the_copy, body_value.l, sizeof(jchar) * length_value.i);
      if (isCopy) *isCopy = JNI_TRUE;
      return the_copy;
    }
}

void
JNIFUNC(ReleaseCharArrayElements)(JNIEnv *env,
                                  jcharArray array,
                                  jchar* elems,
                                  jint mode)
{
  InterpValue body_value, length_value;
  jboolean can_free = JNI_FALSE;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

  if (body_value.l != (void*)elems)
    can_free = JNI_TRUE;

  switch (mode)
    {
    case 0: /* commit the changes and free elems. */
      memcpy(body_value.l, elems, sizeof(jchar) * length_value.i);
      if (can_free) PR_DELETE(elems);
      break;
    case JNI_COMMIT: /* commit the changes but don't free elems. */
      memcpy(body_value.l, elems, sizeof(jchar) * length_value.i);
      break;
    case JNI_ABORT:  /* don't commit the changes but free elems. */
      if (can_free) PR_DELETE(elems);
      break;
    }
}

void
JNIFUNC(GetCharArrayRegion)(JNIEnv *env,
                            jcharArray array,
                            jsize start,
                            jsize len,
                            jchar* buf)
{
  InterpValue body_value, length_value;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env,
                                           java_lang_ArrayIndexOutOfBoundsException);
      (*env)->ThrowNew(env, exception, "In JNI GetCharArrayRegion");
      return;
    }

  memcpy(buf, ((jchar*)body_value.l) + start, len * sizeof(jchar));
}

void
JNIFUNC(SetCharArrayRegion)(JNIEnv *env,
                            jcharArray array,
                            jsize start,
                            jsize len,
                            jchar* buf)
{
  InterpValue body_value, length_value;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env,
                                           java_lang_ArrayIndexOutOfBoundsException);
      (*env)->ThrowNew(env, exception, "In JNI GetCharArrayRegion");
      return;
    }

  memcpy(((jchar*)body_value.l) + start, buf, len * sizeof(jchar));
}

jshortArray
JNIFUNC(NewShortArray)(JNIEnv *env,
                       jsize length)
{
  HungryEnv *henv = JNIEnvToHEnv(env);
  ClazzFile *short_array_type = HVM_ClassFind(henv, "[S");
  japhar_object* array = HVM_ArrayNew(henv, length, short_array_type);

  return (jshortArray)array;
}

jshort*
JNIFUNC(GetShortArrayElements)(JNIEnv *env,
                               jshortArray array,
                               jboolean* isCopy)
{
  InterpValue body_value, length_value;
  jshort *the_copy = NULL;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

#ifdef COPY_ELEMENTS
  the_copy = (jshort*)PR_MALLOC(sizeof(jshort) * length_value.i);
#endif

  if (the_copy == NULL)
    {
      if (isCopy) *isCopy = JNI_FALSE;
      return (jshort*)body_value.l;
    }
  else
    {
      memcpy(the_copy, body_value.l, sizeof(jshort) * length_value.i);
      if (isCopy) *isCopy = JNI_TRUE;
      return the_copy;
    }
}

void
JNIFUNC(ReleaseShortArrayElements)(JNIEnv *env,
                                   jshortArray array,
                                   jshort* elems,
                                   jint mode)
{
  InterpValue body_value, length_value;
  jboolean can_free = JNI_FALSE;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
                     field,
                     &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ],
    HVM_FieldGet(array,
                       field,
                       &length_value);

  if (body_value.l != (void*)elems)
    can_free = JNI_TRUE;

  switch (mode)
    {
    case 0: /* commit the changes and free elems. */
      memcpy(body_value.l, elems, sizeof(jshort) * length_value.i);
      if (can_free) PR_DELETE(elems);
      break;
    case JNI_COMMIT: /* commit the changes but don't free elems. */
      memcpy(body_value.l, elems, sizeof(jshort) * length_value.i);
      break;
    case JNI_ABORT:  /* don't commit the changes but free elems. */
      if (can_free) PR_DELETE(elems);
      break;
    }
}

void
JNIFUNC(GetShortArrayRegion)(JNIEnv *env,
                             jshortArray array,
                             jsize start,
                             jsize len,
                             jshort* buf)
{
  InterpValue body_value, length_value;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env,
                                           java_lang_ArrayIndexOutOfBoundsException);
      (*env)->ThrowNew(env, exception, "In JNI GetShortArrayRegion");
      return;
    }

  memcpy(buf, ((jshort*)body_value.l) + start, len * sizeof(jshort));
}

void
JNIFUNC(SetShortArrayRegion)(JNIEnv *env,
                             jshortArray array,
                             jsize start,
                             jsize len,
                             jshort* buf)
{
  InterpValue body_value, length_value;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env,
                                           java_lang_ArrayIndexOutOfBoundsException);
      (*env)->ThrowNew(env, exception, "In JNI GetShortArrayRegion");
      return;
    }

  memcpy(((jshort*)body_value.l) + start, buf, len * sizeof(jshort));
}

jintArray
JNIFUNC(NewIntArray)(JNIEnv *env,
                     jsize length)
{
  HungryEnv *henv = JNIEnvToHEnv(env);
  ClazzFile *int_array_type = HVM_ClassFind(henv, "[I");
  japhar_object* array = HVM_ArrayNew(henv, length, int_array_type);

  return (jintArray)array;
}

jint*
JNIFUNC(GetIntArrayElements)(JNIEnv *env,
                             jintArray array,
                             jboolean* isCopy)
{
  InterpValue body_value, length_value;
  jint *the_copy = NULL;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

#ifdef COPY_ELEMENTS
  the_copy = (jint*)PR_MALLOC(sizeof(jint) * length_value.i);
#endif

  if (the_copy == NULL)
    {
      if (isCopy) *isCopy = JNI_FALSE;
      return (jint*)body_value.l;
    }
  else
    {
      memcpy(the_copy, body_value.l, sizeof(jint) * length_value.i);
      if (isCopy) *isCopy = JNI_TRUE;
      return the_copy;
    }
}

void
JNIFUNC(ReleaseIntArrayElements)(JNIEnv *env,
                                 jintArray array,
                                 jint* elems,
                                 jint mode)
{
  InterpValue body_value, length_value;
  jboolean can_free = JNI_FALSE;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

  if (body_value.l != (void*)elems)
    can_free = JNI_TRUE;

  switch (mode)
    {
    case 0: /* commit the changes and free elems. */
      memcpy(body_value.l, elems, sizeof(jint) * length_value.i);
      if (can_free) PR_DELETE(elems);
      break;
    case JNI_COMMIT: /* commit the changes but don't free elems. */
      memcpy(body_value.l, elems, sizeof(jint) * length_value.i);
      break;
    case JNI_ABORT:  /* don't commit the changes but free elems. */
      if (can_free) PR_DELETE(elems);
      break;
    }
}

void
JNIFUNC(GetIntArrayRegion)(JNIEnv *env,
                           jintArray array,
                           jsize start,
                           jsize len,
                           jint* buf)
{
  InterpValue body_value, length_value;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env,
                                           java_lang_ArrayIndexOutOfBoundsException);
      (*env)->ThrowNew(env, exception, "In JNI GetIntArrayRegion");
      return;
    }

  memcpy(buf, ((jint*)body_value.l) + start, len * sizeof(jint));
}

void
JNIFUNC(SetIntArrayRegion)(JNIEnv *env,
                           jintArray array,
                           jsize start,
                           jsize len,
                           jint* buf)
{
  InterpValue body_value, length_value;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env,
                                           java_lang_ArrayIndexOutOfBoundsException);
      (*env)->ThrowNew(env, exception, "In JNI GetIntArrayRegion");
      return;
    }

  memcpy(((jint*)body_value.l) + start, buf, len * sizeof(jint));
}

jlongArray
JNIFUNC(NewLongArray)(JNIEnv *env,
                      jsize length)
{
  HungryEnv *henv = JNIEnvToHEnv(env);
  ClazzFile *long_array_type = HVM_ClassFind(henv, "[J");
  japhar_object* array = HVM_ArrayNew(henv, length, long_array_type);

  return (jlongArray)array;
}

jlong*
JNIFUNC(GetLongArrayElements)(JNIEnv *env,
                              jlongArray array,
                              jboolean* isCopy)
{
  InterpValue body_value, length_value;
  jlong *the_copy = NULL;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

#ifdef COPY_ELEMENTS
  the_copy = (jlong*)PR_MALLOC(sizeof(jlong) * length_value.i);
#endif

  if (the_copy == NULL)
    {
      if (isCopy) *isCopy = JNI_FALSE;
      return (jlong*)body_value.l;
    }
  else
    {
      memcpy(the_copy, body_value.l, sizeof(jlong) * length_value.i);
      if (isCopy) *isCopy = JNI_TRUE;
      return the_copy;
    }
}

void
JNIFUNC(ReleaseLongArrayElements)(JNIEnv *env,
                                  jlongArray array,
                                  jlong* elems,
                                  jint mode)
{
  InterpValue body_value, length_value;
  jboolean can_free = JNI_FALSE;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

  if (body_value.l != (void*)elems)
    can_free = JNI_TRUE;

  switch (mode)
    {
    case 0: /* commit the changes and free elems. */
      memcpy(body_value.l, elems, sizeof(jlong) * length_value.i);
      if (can_free) PR_DELETE(elems);
      break;
    case JNI_COMMIT: /* commit the changes but don't free elems. */
      memcpy(body_value.l, elems, sizeof(jlong) * length_value.i);
      break;
    case JNI_ABORT:  /* don't commit the changes but free elems. */
      if (can_free) PR_DELETE(elems);
      break;
    }
}

void
JNIFUNC(GetLongArrayRegion)(JNIEnv *env,
                            jlongArray array,
                            jsize start,
                            jsize len,
                            jlong* buf)
{
  InterpValue body_value, length_value;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env,
                                           java_lang_ArrayIndexOutOfBoundsException);
      (*env)->ThrowNew(env, exception, "In JNI GetLongArrayRegion");
      return;
    }

  memcpy(buf, ((jlong*)body_value.l) + start, len * sizeof(jlong));
}

void
JNIFUNC(SetLongArrayRegion)(JNIEnv *env,
                            jlongArray array,
                            jsize start,
                            jsize len,
                            jlong* buf)
{
  InterpValue body_value, length_value;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env,
                                           java_lang_ArrayIndexOutOfBoundsException);
      (*env)->ThrowNew(env, exception, "In JNI GetLongArrayRegion");
      return;
    }

  memcpy(((jlong*)body_value.l) + start, buf, len * sizeof(jlong));
}

jfloatArray
JNIFUNC(NewFloatArray)(JNIEnv *env,
                       jsize length)
{
  HungryEnv *henv = JNIEnvToHEnv(env);
  ClazzFile *float_array_type = HVM_ClassFind(henv, "[F");
  japhar_object* array = HVM_ArrayNew(henv, length, float_array_type);

  return (jfloatArray)array;
}

jfloat*
JNIFUNC(GetFloatArrayElements)(JNIEnv *env,
                               jfloatArray array,
                               jboolean* isCopy)
{
  InterpValue body_value, length_value;
  jfloat *the_copy = NULL;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

#ifdef COPY_ELEMENTS
  the_copy = (jfloat*)PR_MALLOC(sizeof(jfloat) * length_value.i);
#endif

  if (the_copy == NULL)
    {
      if (isCopy) *isCopy = JNI_FALSE;
      return (jfloat*)body_value.l;
    }
  else
    {
      memcpy(the_copy, body_value.l, sizeof(jfloat) * length_value.i);
      if (isCopy) *isCopy = JNI_TRUE;
      return the_copy;
    }
}

void
JNIFUNC(ReleaseFloatArrayElements)(JNIEnv *env,
                                   jfloatArray array,
                                   jfloat* elems,
                                   jint mode)
{
  InterpValue body_value, length_value;
  jboolean can_free = JNI_FALSE;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

  if (body_value.l != (void*)elems)
    can_free = JNI_TRUE;

  switch (mode)
    {
    case 0: /* commit the changes and free elems. */
      memcpy(body_value.l, elems, sizeof(jfloat) * length_value.i);
      if (can_free) PR_DELETE(elems);
      break;
    case JNI_COMMIT: /* commit the changes but don't free elems. */
      memcpy(body_value.l, elems, sizeof(jfloat) * length_value.i);
      break;
    case JNI_ABORT:  /* don't commit the changes but free elems. */
      if (can_free) PR_DELETE(elems);
      break;
    }
}

void
JNIFUNC(GetFloatArrayRegion)(JNIEnv *env,
                             jfloatArray array,
                             jsize start,
                             jsize len,
                             jfloat* buf)
{
  InterpValue body_value, length_value;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env,
                                           java_lang_ArrayIndexOutOfBoundsException);
      (*env)->ThrowNew(env, exception, "In JNI GetFloatArrayRegion");
      return;
    }

  memcpy(buf, ((jfloat*)body_value.l) + start, len * sizeof(jfloat));
}

void
JNIFUNC(SetFloatArrayRegion)(JNIEnv *env,
                             jfloatArray array,
                             jsize start,
                             jsize len,
                             jfloat* buf)
{
  InterpValue body_value, length_value;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
                     field,
                     &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ],
    HVM_FieldGet(array,
                       field,
                       &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env,
                                           java_lang_ArrayIndexOutOfBoundsException);
      (*env)->ThrowNew(env, exception, "In JNI GetFloatArrayRegion");
      return;
    }

  memcpy(((jfloat*)body_value.l) + start, buf, len * sizeof(jfloat));
}

jdoubleArray
JNIFUNC(NewDoubleArray)(JNIEnv *env,
                        jsize length)
{
  HungryEnv *henv = JNIEnvToHEnv(env);
  ClazzFile *double_array_type = HVM_ClassFind(henv, "[D");
  japhar_object* array = HVM_ArrayNew(henv, length, double_array_type);

  return (jdoubleArray)array;
}

jdouble*
JNIFUNC(GetDoubleArrayElements)(JNIEnv *env,
                                jdoubleArray array,
                                jboolean* isCopy)
{
  InterpValue body_value, length_value;
  jdouble *the_copy = NULL;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

#ifdef COPY_ELEMENTS
  the_copy = (jdouble*)PR_MALLOC(sizeof(jdouble) * length_value.i);
#endif

  if (the_copy == NULL)
    {
      if (isCopy) *isCopy = JNI_FALSE;
      return (jdouble*)body_value.l;
    }
  else
    {
      memcpy(the_copy, body_value.l, sizeof(jdouble) * length_value.i);
      if (isCopy) *isCopy = JNI_TRUE;
      return the_copy;
    }
}

void
JNIFUNC(ReleaseDoubleArrayElements)(JNIEnv *env,
                                    jdoubleArray array,
                                    jdouble* elems,
                                    jint mode)
{
  InterpValue body_value, length_value;
  jboolean can_free = JNI_FALSE;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

  if (body_value.l != (void*)elems)
    can_free = JNI_TRUE;

  switch (mode)
    {
    case 0: /* commit the changes and free elems. */
      memcpy(body_value.l, elems, sizeof(jdouble) * length_value.i);
      if (can_free) PR_DELETE(elems);
      break;
    case JNI_COMMIT: /* commit the changes but don't free elems. */
      memcpy(body_value.l, elems, sizeof(jdouble) * length_value.i);
      break;
    case JNI_ABORT:  /* don't commit the changes but free elems. */
      if (can_free) PR_DELETE(elems);
      break;
    }
}

void
JNIFUNC(GetDoubleArrayRegion)(JNIEnv *env,
                              jdoubleArray array,
                              jsize start,
                              jsize len,
                              jdouble* buf)
{
  InterpValue body_value, length_value;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env,
                                           java_lang_ArrayIndexOutOfBoundsException);
      (*env)->ThrowNew(env, exception, "In JNI GetDoubleArrayRegion");
      return;
    }

  memcpy(buf, ((jdouble*)body_value.l) + start, len * sizeof(jdouble));
}

void
JNIFUNC(SetDoubleArrayRegion)(JNIEnv *env,
                              jdoubleArray array,
                              jsize start,
                              jsize len,
                              jdouble* buf)
{
  InterpValue body_value, length_value;
  japhar_object* arr = (japhar_object*)array;
  FieldStruct *field;

  field = arr->clazz->fields [ ARRAY_BODY_INDEX ];
  HVM_FieldGet(array,
               field,
               &body_value);

  field = arr->clazz->fields [ ARRAY_LENGTH_INDEX ];
  HVM_FieldGet(array,
               field,
               &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env,
                                           java_lang_ArrayIndexOutOfBoundsException);
      (*env)->ThrowNew(env, exception, "In JNI GetDoubleArrayRegion");
      return;
    }

  memcpy(((jdouble*)body_value.l) + start, buf, len * sizeof(jdouble));
}


/* new for JDK 1.2 */

void*
JNIFUNC(GetPrimitiveArrayCritical)(JNIEnv *env, jarray array,
                                   jboolean *isCopy)
{
  (*env)->FatalError(env, "JNI GetPrimitiveArrayCritical not implemented yet.\n");

  return NULL;
}

void
JNIFUNC(ReleasePrimitiveArrayCritical)(JNIEnv *env,
                                       jarray array,
                                       void *carray,
                                       jint mode)
{
  (*env)->FatalError(env, "JNI ReleasePrimitiveArrayCritical not implemented yet.\n");
}
