/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode:nil -*-
   field.c -- field lookup.
   Created: Chris Toshok <toshok@hungry.com>, 28-Apr-1999
 */
/*
  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"
#include "ClazzFile.h"

PR_IMPLEMENT(FieldStruct*)
HVM_FieldFind(HungryEnv *henv,
              ClazzFile *clazz,
              const char *name,
              const char *sig)
{
  int field_num;
  FieldStruct *field = NULL;
  
  if (clazz == NULL)
    {
      /* XXX throw something */
      return NULL;
    }

  for (field_num = 0; field_num < clazz->num_fields; field_num++)
    {
      FieldStruct *cur_field = clazz->fields[field_num];
      
      if (!PL_strcmp(cur_field->name, name)
          && !PL_strcmp(cur_field->sig_str, sig)
          && !(cur_field->access_flags & ACC_STATIC))
        {
          field = cur_field;
          break;
        }
    }

  return field;
}

PR_IMPLEMENT(FieldStruct*)
HVM_FieldFindStatic(HungryEnv *henv,
                    ClazzFile *clazz,
                    const char *name,
                    const char *sig)
{
  int field_num;
  FieldStruct *field = NULL;

  if (clazz == NULL)
    {
      /* XXX throw something */
      return NULL;
    }

  for (field_num = 0; field_num < clazz->num_fields; field_num++)
    {
      FieldStruct *cur_field = clazz->fields[field_num];
      
      if (!PL_strcmp(cur_field->name, name)
          && !PL_strcmp(cur_field->sig_str, sig)
          && cur_field->access_flags & ACC_STATIC)
        {
          field = cur_field;
          break;
        }
    }

  return field;
}


static void
set_field(char *data,
          FieldStruct *field,
          InterpValue value)
{
  switch(*field->sig_str)
    {
    case JSIG_BOOLEAN:
      *(PRUint8*)(data + field->field_offset) = value.z;
      break;
    case JSIG_BYTE:
      *(PRInt8*)(data + field->field_offset) = value.b;
      break;
    case JSIG_CHAR:
      *(PRUint16*)(data + field->field_offset) = value.c;
      break;
    case JSIG_SHORT:
      *(PRInt16*)(data + field->field_offset) = value.s;
      break;
    case JSIG_INT:
      *(PRInt32*)(data + field->field_offset) = value.i;
      break;
    case JSIG_LONG:
      *(PRInt64*)(data + field->field_offset) = value.j;
      break;
    case JSIG_FLOAT:
      *(float*)(data + field->field_offset) = value.f;
      break;
    case JSIG_DOUBLE:
      *(PRFloat64*)(data + field->field_offset) = value.d;
      break;
    case JSIG_ARRAY:
    case JSIG_OBJECT:
      *(japhar_object**)(data + field->field_offset) = value.l;
      break;
    default:
      PR_ASSERT(0);
      break;
    }
}


static void
get_field(char *data,
          FieldStruct *field,
          InterpValue *value)
{
  if (field->has_constant_value) 
    {
      *value = field->constant_value;
    }
  else
    {
      switch(*field->sig_str)
        {
        case JSIG_BOOLEAN:
          value->z = *(PRUint8*)(data + field->field_offset);
          break;
        case JSIG_BYTE:
          value->b = *(PRInt8*)(data + field->field_offset);
          break;
        case JSIG_CHAR:
          value->c = *(PRUint16*)(data + field->field_offset);
          break;
        case JSIG_SHORT:
          value->s = *(PRInt16*)(data + field->field_offset);
          break;
        case JSIG_INT:
          value->i = *(PRInt32*)(data + field->field_offset);
          break;
        case JSIG_LONG:
          value->j = *(PRInt64*)(data + field->field_offset);
          break;
        case JSIG_FLOAT:
          value->f = *(float*)(data + field->field_offset);
          break;
        case JSIG_DOUBLE:
          value->d = *(PRFloat64*)(data + field->field_offset);
          break;
        case JSIG_ARRAY:
        case JSIG_OBJECT:
          value->l = *(japhar_object**)(data + field->field_offset);
          break;
        default:
          PR_ASSERT(0);
          break;
        }
    }
}


PR_IMPLEMENT(void)
HVM_FieldSet(japhar_object* obj,
             FieldStruct *field,
             InterpValue value)
{
  char *instance_data;

#if WITH_SPORTSMODEL
  japhar_object *_obj = obj;
  instance_data = &((japhar_object*)SM_DECRYPT_OBJECT((SMObject*)obj))->fields;
#else
  instance_data = &obj->fields;
#endif

  PR_ASSERT((field->access_flags & ACC_STATIC) == 0);

  set_field(instance_data, field, value);

#if WITH_SPORTSMODEL
  SM_DIRTY_PAGE (_obj);
#endif
}

PR_IMPLEMENT(void)
HVM_FieldGet(japhar_object* obj,
             FieldStruct *field,
             InterpValue *value)
{
  char *instance_data;

#if WITH_SPORTSMODEL
  japhar_object *_obj = obj;
  instance_data = &((japhar_object*)SM_DECRYPT_OBJECT((SMObject*)obj))->fields;
#else
  instance_data = &obj->fields;
#endif

  PR_ASSERT((field->access_flags & ACC_STATIC) == 0);

  get_field(instance_data, field, value);
}

PR_IMPLEMENT(void)
HVM_FieldSetStatic(ClazzFile *clazz,
                   FieldStruct *field,
                   InterpValue value)
{
  char *static_data;

  PR_ASSERT(field->access_flags & ACC_STATIC
            && field->clazz == clazz);

  static_data = clazz->static_fields;

  set_field(static_data, field, value);
}

PR_IMPLEMENT(void)
HVM_FieldGetStatic(ClazzFile *clazz,
                   FieldStruct *field,
                   InterpValue *value)
{
  char *static_data;

  static_data = clazz->static_fields;

  get_field(static_data, field, value);
}
