/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode:nil -*-
   method.c -- method lookup.
   Created: Chris Toshok <toshok@hungry.com>, 23-Aug-1998
 */
/*
  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"

extern PRLogModuleInfo* methodLm;

PR_IMPLEMENT(MethodStruct*)
HVM_MethodFind(HungryEnv *henv,
               ClazzFile *clazz,
               const char *name,
               const char *sig)
{
  int method_num;
  MethodStruct *method = NULL;
  PRBool is_ctor = (PL_strcmp(name, "<init>") == 0);

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

  if (is_ctor)
    {
      /* we need to search just this class's method pool. */
      for (method_num = 0; method_num < clazz->num_methods; method_num++)
        {
          MethodStruct *cur_method = &clazz->methods[method_num];

          if (!PL_strcmp(cur_method->name, name)
              && !PL_strcmp(cur_method->sig_str, sig)
              && (!is_ctor || cur_method->clazz == clazz)
              && !(cur_method->access_flags & ACC_STATIC))
            {
              method = cur_method;
              break;
            }
        }
    }
  else
    {
      /* we need to search just this class's virtual method table */
      for (method_num = 0; method_num < clazz->num_instance_methods; method_num++)
        {
          MethodStruct *cur_method = clazz->vmethods[method_num];

          if (!PL_strcmp(cur_method->name, name)
              && !PL_strcmp(cur_method->sig_str, sig))
            {
              method = cur_method;
              break;
            }
        }
    }

  return method;
}

PR_IMPLEMENT(MethodStruct*)
HVM_MethodFindStatic(HungryEnv *henv,
                     ClazzFile *clazz,
                     const char *name,
                     const char *sig)
{
  int method_num;
  MethodStruct *method = NULL;

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

  for (method_num = 0; method_num < clazz->num_static_methods; method_num++)
    {
      MethodStruct *cur_method = clazz->smethods[method_num];

      if (!PL_strcmp(cur_method->name, name)
          && !PL_strcmp(cur_method->sig_str, sig))
        {
          method = cur_method;
          break;
        }
    }

  return method;
}

void
do_method_call (StackFrame *this_frame,
                MethodStruct *method)
{
  HungryEnv *henv = this_frame->_env;
  if (henv->vm->_verbose_flags & VERBOSE_METHOD)
    {
      int i;
      for (i = 0; i < this_frame->depth; i ++) printf (" ");
      printf ("> %s.%s\n", getClassName(henv, method->clazz), method->name);
    }

  if (method->access_flags & ACC_NATIVE)
    {
      do_native_method_call(henv, method);
      if (henv->_exception)
        HVM_ExceptionThrowWithStackFrame(henv,
                                         henv->_exception,
                                         this_frame);
    }
  else
    {
      StackFrame *f = create_frame_for_method (henv, method);

      fill_local_vars_from_stack (f, method->num_param_words,
                                  method->access_flags & ACC_STATIC);

      f->opstack_top = henv->op_stack->stack_top;

      maybe_enter_monitor_for_method(henv, method, f->this_pointer);
    }
}

void
maybe_enter_monitor_for_method(HungryEnv *henv,
                               MethodStruct *method,
                               japhar_object* this_obj)
{
  if (method->access_flags & ACC_SYNCHRONIZED)
    {
      if (this_obj == NULL)
        this_obj = clazzfile_to_jclass(henv, method->clazz);

      HVM_MonitorEnter(henv, this_obj);

      PR_LOG(methodLm, PR_LOG_DEBUG,
             ("enter monitor for method %s.%s (this_obj = %p)\n",
              getClassName(henv, method->clazz),
              method->name, this_obj));
    }
}

void
maybe_exit_monitor_for_method(HungryEnv *henv,
                              MethodStruct *method,
                              japhar_object* this_obj)
{
  if (method->access_flags & ACC_SYNCHRONIZED)
    {
      if (this_obj == NULL)
        this_obj = clazzfile_to_jclass(henv, method->clazz);

      if ( !HVM_MonitorExit(henv, this_obj) )
        {
          HVM_ExceptionThrow(henv, java_lang_IllegalMonitorStateException,
                          "not monitor owner!");
          return;
        }

      PR_LOG(methodLm, PR_LOG_DEBUG,
             ("exit  monitor for method %s.%s (this_obj = %p)\n",
              getClassName(henv, method->clazz),
              method->name, this_obj));
    }
}

