/* -*- Mode: C; c-file-style: "gnu" -*-
   object.c -- native methods for java/lang/Object.
   Created: Chris Toshok <toshok@hungry.com>, 28-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 "arch.h"
#include "jniint.h"
#include "ClazzFile.h"

JNIEXPORT jobject JNICALL
Java_java_lang_Object_getClass(JNIEnv *env,
			       jobject obj)
{
  jclass clazz = (*env)->GetObjectClass(env, obj);

  return clazz;
}

/* For Classpath, not JDK */
JNIEXPORT jobject JNICALL
Java_java_lang_VMObject_getClass(JNIEnv *env,
                                 jclass this_class,
                                 jobject obj)
{
  return(Java_java_lang_Object_getClass(env, obj));
}

JNIEXPORT jint JNICALL
Java_java_lang_Object_hashCode(JNIEnv *env,
			       jobject obj)
{
  japhar_object* jobj = (japhar_object*)obj;

  return jobj->hash_code;
}

JNIEXPORT jobject JNICALL
Java_java_lang_Object_clone(JNIEnv *env,
			    jobject obj)
{
  HungryEnv *henv = HVM_ThreadGetEnv();
  jclass clonable = (*env)->FindClass(env, "java/lang/Cloneable");
  jobject cloned = NULL;
  jclass clazz = (*env)->GetObjectClass(env, obj);
  ClazzFile *cf = jclass_to_clazzfile(henv, clazz);

  if (HVM_ClassIsArray(henv, cf)
      || (*env)->IsInstanceOf(env, obj, clonable))
    {
      cloned = (jobject)HVM_ObjectClone(henv, (japhar_object*)obj);
      if (!cloned)
	HVM_ExceptionThrow(henv, "java/lang/OutOfMemoryError", NULL);
    }
  else
    {
      HVM_ExceptionThrow(henv, "java/lang/CloneNotSupportedException", NULL);
    }

  return cloned;
}

/*
 * For Classpath, not JDK
 */ 
JNIEXPORT jobject JNICALL
Java_java_lang_VMObject_clone(JNIEnv *env,
                              jclass this_class,
                              jobject obj_to_clone)
{
  return(Java_java_lang_Object_clone(env, obj_to_clone));
}
                              

JNIEXPORT void JNICALL
Java_java_lang_Object_notify(JNIEnv *env,
			     jobject obj)
{
  HungryEnv *henv = HVM_ThreadGetEnv();
  japhar_object* jobj = (japhar_object*)obj;

  if ( PR_FAILURE == HVM_MonitorNotifyOne(henv, jobj) )
    {
      HVM_ExceptionThrow(henv, "java/lang/IllegalMonitorStateException",
		      "not monitor owner!");
      return;
    }      
}

/*
 * For Classpath, not JDK
 */
JNIEXPORT void JNICALL
Java_java_lang_VMObject_notify(JNIEnv *env,
                               jclass this_class,
                               jobject obj)
{
  Java_java_lang_Object_notify(env, obj);
}

JNIEXPORT void JNICALL
Java_java_lang_Object_notifyAll(JNIEnv *env,
				jobject obj)
{
  HungryEnv *henv = HVM_ThreadGetEnv();
  japhar_object* jobj = (japhar_object*)obj;

  if ( PR_FAILURE == HVM_MonitorNotifyAll(henv, jobj) )
    {
      HVM_ExceptionThrow(henv, "java/lang/IllegalMonitorStateException",
		      "not monitor owner!");
      return;
    }      
}

/*
 * For Classpath, not JDK
 */
JNIEXPORT void JNICALL
Java_java_lang_VMObject_notifyAll(JNIEnv *env,
                                  jclass this_class,
                                  jobject obj)
{
  Java_java_lang_Object_notifyAll(env, obj);
}

/* XXX Should throw InterruptedException if interrupted */
JNIEXPORT void JNICALL
Java_java_lang_Object_wait(JNIEnv *env,
			   jobject obj,
			   jlong timeout)
{
  HungryEnv *henv = HVM_ThreadGetEnv();
  japhar_object* jobj = (japhar_object*)obj;

  if (0 > timeout)
    {
      HVM_ExceptionThrow(henv, "java/lang/IllegalArgumentException",
		      "negative timeout");
      return;
    }      

  if (timeout == 0)
    timeout = PR_INTERVAL_NO_TIMEOUT; /* wait forever */

  if ( ! HVM_MonitorWait(henv, jobj, timeout) )
    {
      HVM_ExceptionThrow(henv, "java/lang/IllegalMonitorStateException",
		      "not monitor owner!");
      return;
    }      
}

/*
 * For Classpath, not JDK
 */
JNIEXPORT void JNICALL
Java_java_lang_VMObject_wait(JNIEnv *env,
                             jclass this_class,
                             jobject obj,
                             jlong timeout,
                             jint timeout_ms)
{
  Java_java_lang_Object_wait(env, obj, timeout);
}

/* JDK 1.2 uses registration of native methods... */
static JNINativeMethod obj_native_methods[] = {
  { "hashCode",		"()I",	(void*)Java_java_lang_Object_hashCode },
  { "notify",		"()V",	(void*)Java_java_lang_Object_notify },
  { "notifyAll",	"()V",	(void*)Java_java_lang_Object_notifyAll },
  /*  { "registerNatives",	"()V",	(void*)Java_java_lang_Object_registerNatives }, XXX */
  { "wait",		"(J)V", (void*)Java_java_lang_Object_wait }
};
static int num_obj_native_methods = sizeof(obj_native_methods) / sizeof(obj_native_methods[0]);

JNIEXPORT void JNICALL
Java_java_lang_Object_registerNatives(JNIEnv *env,
				      jclass cls)
{
#ifdef HAVE_LIBFFI
  (*env)->RegisterNatives(env, cls,
			  obj_native_methods,
			  num_obj_native_methods);
#endif
}
