/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
/*
 * This file contains the code necessary to fake out the rest
 * of the runtime into thinking that we actually do have array
 * classes.
 */
/*
  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 "runtimeint.h"

extern PRLogModuleInfo *arrayClassLm;

static ClassConstant superclass_constant = {
  CONSTANT_Class,
  2
};

static Utf8Constant object_name_constant = {
  CONSTANT_Utf8,
  16, /* strlen("java/lang/Object") */
  NULL
};

ClazzFile*
createFakeArrayClass(HungryEnv *henv, const char *class_name)
{
  ClazzFile *clazz = HVM_ClassFindLoaded(henv, class_name);
  int field_index;
  int method_index;

  /* we've already created it. */
  if (clazz)
    return clazz;

  PR_LOG(arrayClassLm, PR_LOG_DEBUG, ("creating array class %s\n",
                                      class_name));

  clazz = (ClazzFile*)HVM_Calloc(1, sizeof(ClazzFile));
  if (NULL == clazz)
    return NULL;

  clazz->access_flags = ACC_ARRAY | ACC_PUBLIC;
  clazz->constant_pool_count = 4;
  clazz->superclass_index = 1;
  clazz->superclass = (ClazzFile*)HVM_ClassFind(henv, java_lang_Object);
  clazz->class_name = HVM_Strdup(class_name);
  if (NULL == clazz->class_name)
    {
      HVM_Free (clazz);
      return NULL;
    }

  clazz->initialization_state = CLASS_INIT_FINISHED;

  clazz->constants = (ConstantPoolEntry*)HVM_Calloc(3, sizeof(ConstantPoolEntry));
  if (NULL == clazz->constants)
    {
      HVM_Free (clazz->class_name);
      HVM_Free (clazz);
      return NULL;
    }

  clazz->constants[1].clazz_info = superclass_constant;
  clazz->constants[2].utf8_info = object_name_constant;
  clazz->constants[2].utf8_info.bytes =
    (PRUint8*)HVM_Strdup(java_lang_Object);
  if (NULL == clazz->constants[2].utf8_info.bytes)
    {
      HVM_Free (clazz->constants);
      HVM_Free (clazz->class_name);
      HVM_Free (clazz);
      return NULL;
    }

  clazz->num_fields = 4 + clazz->superclass->num_fields;
  clazz->num_instance_fields = 4;

  clazz->fields = (FieldStruct**)HVM_Calloc(clazz->num_fields
                                            + clazz->superclass->num_fields,
                                            sizeof(FieldStruct*));

  clazz->field_pool = (FieldStruct*)HVM_Calloc(clazz->num_fields,
                                               sizeof(FieldStruct));

  if (NULL == clazz->fields
      || NULL == clazz->field_pool)
    {
      HVM_Free (clazz->constants[2].utf8_info.bytes);
      HVM_Free (clazz->constants);
      HVM_Free (clazz->class_name);
      HVM_Free (clazz);
      if (clazz->fields)
        HVM_Free (clazz->fields);
      if (clazz->field_pool)
        HVM_Free (clazz->field_pool);
      return NULL;
    }

  clazz->fields[ ARRAY_LENGTH_INDEX ] = &clazz->field_pool[ARRAY_LENGTH_INDEX ];
  clazz->fields[ ARRAY_LENGTH_INDEX ]->clazz = clazz;
  clazz->fields[ ARRAY_LENGTH_INDEX ]->name = "length";
  clazz->fields[ ARRAY_LENGTH_INDEX ]->sig_str = "I";
  clazz->fields[ ARRAY_LENGTH_INDEX ]->access_flags = ACC_PRIVATE;
  clazz->fields[ ARRAY_LENGTH_INDEX ]->field_offset = VALUE_UNRESOLVED;

  clazz->fields[ ARRAY_TYPE_INDEX ] = &clazz->field_pool[ ARRAY_TYPE_INDEX ];
  clazz->fields[ ARRAY_TYPE_INDEX ]->clazz = clazz;
  clazz->fields[ ARRAY_TYPE_INDEX ]->name = "type";
  clazz->fields[ ARRAY_TYPE_INDEX ]->sig_str = "I";
  clazz->fields[ ARRAY_TYPE_INDEX ]->access_flags = ACC_PRIVATE;
  clazz->fields[ ARRAY_TYPE_INDEX ]->field_offset = VALUE_UNRESOLVED;

  clazz->fields[ ARRAY_BODY_INDEX ] = &clazz->field_pool[ ARRAY_BODY_INDEX ];
  clazz->fields[ ARRAY_BODY_INDEX ]->clazz = clazz;
  clazz->fields[ ARRAY_BODY_INDEX ]->name = "body";
  clazz->fields[ ARRAY_BODY_INDEX ]->sig_str = "I";
  clazz->fields[ ARRAY_BODY_INDEX ]->access_flags = ACC_PRIVATE;
  /** XXX can't make it SIG_JOBJECT or the garbage collector
      will try to traverse to it... badness. */
  clazz->fields[ ARRAY_BODY_INDEX ]->field_offset = VALUE_UNRESOLVED;

  clazz->fields[ ARRAY_ELSIZE_INDEX ] = &clazz->field_pool[ ARRAY_ELSIZE_INDEX ];
  clazz->fields[ ARRAY_ELSIZE_INDEX ]->clazz = clazz;
  clazz->fields[ ARRAY_ELSIZE_INDEX ]->name = "elsize";
  clazz->fields[ ARRAY_ELSIZE_INDEX ]->sig_str = "I";
  clazz->fields[ ARRAY_ELSIZE_INDEX ]->access_flags = ACC_PRIVATE;
  clazz->fields[ ARRAY_ELSIZE_INDEX ]->field_offset = VALUE_UNRESOLVED;

  for (field_index = 0;
       field_index < clazz->superclass->num_fields;
       field_index ++)
    {
      clazz->fields[ 4 + field_index ] = clazz->superclass->fields[ field_index ];
    }

  clazz->num_instance_methods = clazz->superclass->num_instance_methods;
  clazz->vmethods = (MethodStruct**)HVM_Malloc(clazz->num_instance_methods
                                               * sizeof(MethodStruct*));
  clazz->smethods = NULL;

  for (method_index = 0;
       method_index < clazz->superclass->num_instance_methods;
       method_index ++)
    {
      clazz->vmethods[ method_index ] = clazz->superclass->vmethods[ method_index ];
    }


  PR_LOG(arrayClassLm, PR_LOG_DEBUG,
         ("  adding array class to repository\n"));

  clazz->nesting_level = 1;

  calculate_instance_field_offsets(henv, clazz);

  add_loaded_class(henv, clazz);

  return clazz;
}

ClazzFile*
createFakeArrayRemoveDimension(HungryEnv *henv, ClazzFile* array)
{
  char *arrayclass_name = getClassName(henv, array);

  return createFakeArrayClass(henv, arrayclass_name + 1);
}
