/* src/native/vm/VMVirtualMachine.c - jdwp->jvmti interface

Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
J. Wenninger, Institut f. Computersprachen - TU Wien

This file is part of CACAO.

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

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

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.

Contact: cacao@cacaojvm.org

Authors: Martin Platter

Changes: Samuel Vinson


$Id: gnu_classpath_jdwp_VMVirtualMachine.c 6213 2006-12-18 17:36:06Z twisti $

*/

#include "toolbox/logging.h"
#include "native/jni.h"
#include "native/include/java_lang_Thread.h"
#include "native/include/java_nio_ByteBuffer.h"
#include "native/include/java_lang_Class.h"
#include "native/include/java_lang_ClassLoader.h"
#include "native/include/java_lang_reflect_Method.h"
#include "native/include/gnu_classpath_jdwp_event_EventRequest.h"
#include "native/include/gnu_classpath_jdwp_VMVirtualMachine.h"
#include "native/jvmti/jvmti.h"
#include "native/jvmti/VMjdwp.h"
#include <string.h>


/*
 * Class:     gnu_classpath_jdwp_VMVirtualMachine
 * Method:    suspendThread
 * Signature: (Ljava/lang/Thread;)V
 */
JNIEXPORT void JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_suspendThread(JNIEnv *env, jclass clazz, struct java_lang_Thread* par1)
{
	jvmtiError err; 

    err = (*jvmtienv)->SuspendThread(jvmtienv, (jthread) par1);
	printjvmtierror("VMVirtualMachine.suspendThread SuspendThread", err);
}

/*
 * Class:     gnu_classpath_jdwp_VMVirtualMachine
 * Method:    resumeThread
 * Signature: (Ljava/lang/Thread;)V
 */
JNIEXPORT void JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_resumeThread(JNIEnv *env, jclass clazz, struct java_lang_Thread* par1)
{
	jvmtiError err; 

    err = (*jvmtienv)->ResumeThread(jvmtienv, (jthread) par1);
	printjvmtierror("VMVirtualMachine.resumethread ResumeThread", err);
}


/*
 * Class:     gnu_classpath_jdwp_VMVirtualMachine
 * Method:    getSuspendCount
 * Signature: (Ljava/lang/Thread;)I
 */
JNIEXPORT s4 JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getSuspendCount(JNIEnv *env, jclass clazz, struct java_lang_Thread* par1) {
    log_text ("VMVirtualMachine_getSuspendCount: not supported");
	return 1;
}

/*
 * Class:     gnu_classpath_jdwp_VMVirtualMachine
 * Method:    getAllLoadedClassesCount
 * Signature: ()I
 */
JNIEXPORT s4 JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getAllLoadedClassesCount(JNIEnv *env, jclass clazz) {
    jint count;
    jclass* classes;
	jvmtiError err;

	if (JVMTI_ERROR_NONE != (err= (*jvmtienv)->
		GetLoadedClasses(jvmtienv, &count, &classes))) {
		printjvmtierror("VMVirtualMachine_getAllLoadedClassCount GetLoadedClasses",err);
		return 0;
	}
	(*jvmtienv)->Deallocate(jvmtienv,(unsigned char*)classes);
    return count;
}

/*
 * Class:     gnu_classpath_jdwp_VMVirtualMachine
 * Method:    getAllLoadedClasses
 * Signature: ()Ljava/util/Iterator
 */
JNIEXPORT struct java_util_Iterator* JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getAllLoadedClasses(JNIEnv *env, jclass clazz) {
	jclass *classes, *cl;
	jint classcount;
	jobjectArray joa;
/*	jthrowable e;*/
	jmethodID m;
	jobject *ol,*oi;
	int i;
	jvmtiError err;

	if (JVMTI_ERROR_NONE != (err= (*jvmtienv)->
		GetLoadedClasses(jvmtienv, &classcount, &classes))) {
		printjvmtierror("VMVirtualMachine_getAllLoadedClasses GetLoadedClasses",err);
		
		/* we should throw JDWP Exception INTERNAL = 113;*/
/*		env->ThrowNew(env,ec,"jvmti error occoured");  */
		return NULL;
	}
	
	cl = (*env)->FindClass(env,"java.lang.Class");
	if (!cl) return NULL;

	/* Arrays.asList(Object[] classes)->List.Iterator()->Iterator */
	joa = (*env)->NewObjectArray(env, (jsize)classcount, cl , NULL);
	if (!joa) return NULL;

	for (i = 0; i < classcount; i++) 
		(*env)->SetObjectArrayElement(env,joa,(jsize)i, (jobject)classes[i]);
	(*jvmtienv)->Deallocate(jvmtienv, (unsigned char*)classes);
	
	cl = (*env)->FindClass(env,"java.util.Arrays");
	if (!cl) return NULL;

	m = (*env)->GetStaticMethodID(env, cl, "asList", "([Ljava/lang/Object;)Ljava/util/List;");
	if (!m) return NULL;

	ol = (*env)->CallStaticObjectMethod(env,(jclass)cl,m,joa);
	if (!ol) return NULL;

	cl = (*env)->FindClass(env,"java.util.List");
	if (!cl) return NULL;
	m = (*env)->GetMethodID(env,cl,"iterator","()Ljava/util/Iterator;");
	if (!m) return NULL;
	oi = (*env)->CallObjectMethod(env,ol,m);
		
	return (struct java_util_Iterator*)oi;
}

/* Class:     gnu/classpath/jdwp/VMVirtualMachine
 * Method:    getClassStatus
 * Signature: (Ljava/lang/Class;)I
 */
JNIEXPORT s4 JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getClassStatus(JNIEnv *env, jclass clazz, struct java_lang_Class* par1) {
	jint status;
	jvmtiError err;

	err = (*jvmtienv)->GetClassStatus(jvmtienv, (jclass) par1, &status);
	printjvmtierror("VMVirtualMachine_getClassStatus GetClassStatus", err);

	return status;
}

/*
 * Class:     gnu/classpath/jdwp/VMVirtualMachine
 * Method:    getAllClassMethods
 * Signature: (Ljava/lang/Class;)[Lgnu/classpath/jdwp/VMMethod;
 */
JNIEXPORT java_objectarray* JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getAllClassMethods(JNIEnv *env, jclass clazz, struct java_lang_Class* par1) {
    jint count;
    jmethodID* methodID, m;
   	jvmtiError err;
	
	jclass *cl;
	jobject *ol;
	jobjectArray joa;
	int i;

    if (JVMTI_ERROR_NONE != (err= (*jvmtienv)->
							 GetClassMethods(jvmtienv, (jclass) par1, 
											 &count, &methodID))) {
		printjvmtierror("VMVirtualMachine_getAllClassMethods GetClassMethods", err);
		return NULL;
	}
	
	m = (*env)->
		GetStaticMethodID(env, clazz, "getClassMethod", 
						  "(Ljava/lang/Class;J)Lgnu/classpath/jdwp/VMMethod;");
	if (!m) return NULL;
   
    cl = (*env)->FindClass(env,"gnu.classpath.jdwp.VMMethod");
	if (!cl) return NULL;
	
	joa = (*env)->NewObjectArray(env, (jsize)count, cl , NULL);
	if (!joa) return NULL;

    for (i = 0; i < count; i++) {
    	ol = (*env)->
			CallStaticObjectMethod(env,clazz,m,(jobject)par1, methodID[i]);
		if (!ol) return NULL;
    	(*env)->SetObjectArrayElement(env,joa,(jsize)i, ol);
    }
	return joa;
}


/*
 * Class:     gnu/classpath/jdwp/VMVirtualMachine
 * Method:    getClassMethod
 * Signature: (Ljava/lang/Class;J)Lgnu/classpath/jdwp/VMMethod;
 */
JNIEXPORT struct gnu_classpath_jdwp_VMMethod* JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getClassMethod(JNIEnv *env, jclass clazz, struct java_lang_Class* par1, s8 par2) {
	jclass *cl;
    jmethodID m;
    jobject *ol;
	
    cl = (*env)->FindClass(env,"gnu.classpath.jdwp.VMMethod");
	if (!cl) return NULL;
	
	m = (*env)->GetMethodID(env, cl, "<init>", "(Ljava/lang/Class;J)V");
	if (!m) return NULL;
	
    ol = (*env)->NewObject(env, cl, m, par1, par2);
	
	return (struct gnu_classpath_jdwp_VMMethod*)ol;
}


/*
 * Class:     gnu/classpath/jdwp/VMVirtualMachine
 * Method:    getFrames
 * Signature: (Ljava/lang/Thread;II)Ljava/util/ArrayList;
 */
JNIEXPORT struct java_util_ArrayList* JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getFrames(JNIEnv *env, jclass clazz, struct java_lang_Thread* par1, s4 par2, s4 par3) {
    log_text ("VMVirtualMachine_getFrames - IMPLEMENT ME!!!");
/*	jclass ec = (*env)->FindClass(env,"gnu/classpath/jdwp/JdwpInternalErrorException");
	if (JVMTI_ERROR_NONE != (*jvmtienv)->GetClassStatus(jvmtienv, par1, &status))
	env->ThrowNew(env,ec,"jvmti error occoured");*/
	return 0;
}


/*
 * Class:     gnu/classpath/jdwp/VMVirtualMachine
 * Method:    getFrame
 * Signature: (Ljava/lang/Thread;Ljava/nio/ByteBuffer;)Lgnu/classpath/jdwp/VMFrame;
 */
JNIEXPORT struct gnu_classpath_jdwp_VMFrame* JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getFrame(JNIEnv *env, jclass clazz, struct java_lang_Thread* par1, struct java_nio_ByteBuffer* par2) {
    log_text ("VMVirtualMachine_getFrame - IMPLEMENT ME!!!");
	return 0;
}


/*
 * Class:     gnu/classpath/jdwp/VMVirtualMachine
 * Method:    getFrameCount
 * Signature: (Ljava/lang/Thread;)I
 */
JNIEXPORT s4 JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getFrameCount(JNIEnv *env, jclass clazz, struct java_lang_Thread* par1) {
	jint count;
	jvmtiError err;
	err = (*jvmtienv)->GetFrameCount(jvmtienv, (jthread)par1, &count);
	printjvmtierror("VMVirtualMachine_getFrameCount GetFrameCount", err);
	return count;
}


/*
 * Class:     gnu/classpath/jdwp/VMVirtualMachine
 * Method:    getThreadStatus
 * Signature: (Ljava/lang/Thread;)I
 */
JNIEXPORT s4 JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getThreadStatus(JNIEnv *env, jclass clazz, struct java_lang_Thread* par1) {
	jint status;
	jvmtiError err; 
	if (JVMTI_ERROR_NONE != (err = (*jvmtienv)->GetThreadState(jvmtienv, (jthread)par1, &status))) {
		printjvmtierror("VMVirtualMachine_getThreadStatus GetThreadState", err);
		return 0;
	}
	if (status && JVMTI_THREAD_STATE_ALIVE) {
		if (status && JVMTI_THREAD_STATE_WAITING) {		
			return 4; /* WAIT - see JdwpConstants */
		}
		if (status && JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER) { 
			return 3; /* MONITOR - see JdwpConstants */
		}
		if (status && JVMTI_THREAD_STATE_SLEEPING) { 
			return 2; /* SLEEPING - see JdwpConstants */
		}
		return 1; /* RUNNING - see JdwpConstants */
	} else 
		return 0; /* ZOMBIE - see JdwpConstants */
	return -1; /* some error */
}


/*
 * Class:     gnu/classpath/jdwp/VMVirtualMachine
 * Method:    getLoadRequests
 * Signature: (Ljava/lang/ClassLoader;)Ljava/util/ArrayList;
 */
JNIEXPORT struct java_util_ArrayList* JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getLoadRequests(JNIEnv *env, jclass clazz, struct java_lang_ClassLoader* par1) {
    log_text ("VMVirtualMachine_getLoadRequests(");
	return 0;
}


/*
 * Class:     gnu/classpath/jdwp/VMVirtualMachine
 * Method:    executeMethod
 * Signature: (Ljava/lang/Object;Ljava/lang/Thread;Ljava/lang/Class;Ljava/lang/reflect/Method;[Ljava/lang/Object;Z)Lgnu/classpath/jdwp/util/MethodResult;
 */
JNIEXPORT struct gnu_classpath_jdwp_util_MethodResult* JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_executeMethod(JNIEnv *env, jclass clazz, struct java_lang_Object* par1, struct java_lang_Thread* par2, struct java_lang_Class* par3, struct java_lang_reflect_Method* par4, java_objectarray* par5, s4 par6) {
    log_text ("VMVirtualMachine_executeMethod");
	return 0;
}


/*
 * Class:     gnu/classpath/jdwp/VMVirtualMachine
 * Method:    getSourceFile
 * Signature: (Ljava/lang/Class;)Ljava/lang/String;
 */
JNIEXPORT struct java_lang_String* JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getSourceFile(JNIEnv *env, jclass clazz, struct java_lang_Class* par1) {
	char* srcname;
	jstring str;
	jvmtiError err; 

    if (JVMTI_ERROR_NONE !=(err=(*jvmtienv)->
		GetSourceFileName(jvmtienv, (jclass)par1, &srcname))) {
		printjvmtierror("VMVirtualMachine.getSourceFile GetSourceFileName", err);
		return NULL;
	}

	str = (*env)->NewString(env,(jchar*)srcname,(jsize)strlen(srcname));

	return (struct java_lang_String*)str;
}

/* match JdwpConstants.EventKind to jvmtiEvent constants */
static jvmtiEvent EventKind2jvmtiEvent(jbyte kind){
	switch (kind) {
	case /* SINGLE_STEP */ 1: return JVMTI_EVENT_SINGLE_STEP;
	case /* BREAKPOINT */ 2: return JVMTI_EVENT_BREAKPOINT;
    case /*  FRAME_POP */ 3: return JVMTI_EVENT_FRAME_POP;
    case /*  EXCEPTION */ 4: return JVMTI_EVENT_EXCEPTION;
    case /*  USER_DEFINED */ 5: return -1; /* can this be matched ? */
    case /*  THREAD_START */ 6: return JVMTI_EVENT_THREAD_START;
    case /*  THREAD_END */ 7: return JVMTI_EVENT_THREAD_END;
    case /*  CLASS_PREPARE */ 8: return JVMTI_EVENT_CLASS_PREPARE;
    case /*  CLASS_UNLOAD */ 9: return -1; /* can this be matched ? */
    case /*  CLASS_LOAD */ 10: return JVMTI_EVENT_CLASS_LOAD;
    case /*  FIELD_ACCESS */ 20: return JVMTI_EVENT_FIELD_ACCESS;
    case /*  FIELD_MODIFICATION */ 21: return JVMTI_EVENT_FIELD_MODIFICATION;
    case /*  EXCEPTION_CATCH */ 30: return JVMTI_EVENT_EXCEPTION_CATCH;
    case /*  METHOD_ENTRY */ 40: return JVMTI_EVENT_METHOD_ENTRY;
    case /*  METHOD_EXIT */ 41: return JVMTI_EVENT_METHOD_EXIT;
    case /*  VM_INIT */ 90: return JVMTI_EVENT_VM_INIT;
    case /*  VM_DEATH */ 99: return JVMTI_EVENT_VM_DEATH;    
    case /*  VM_DISCONNECTED */ 100: return -1; /* can this be matched ? */
	default: return -1;
	}
}

/*
 * Class:     gnu/classpath/jdwp/VMVirtualMachine
 * Method:    registerEvent
 * Signature: (Lgnu/classpath/jdwp/event/EventRequest;)V
 */
JNIEXPORT void JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_registerEvent(JNIEnv *env, jclass clazz, struct gnu_classpath_jdwp_event_EventRequest* par1) {
	jbyte kind;
	jfieldID kindid;
	jclass erc;
	jvmtiError err;

	erc = (*env)->FindClass(env,"gnu.classpath.jdwp.event.EventRequest");
	
	kindid = (*env)->GetFieldID(env, erc, "_kind", "B");
	kind = (*env)->GetByteField(env, (jobject)par1, kindid);

	if (JVMTI_ERROR_NONE != (err= (*jvmtienv)->
		SetEventNotificationMode(jvmtienv, JVMTI_ENABLE, 
								 EventKind2jvmtiEvent(kind), NULL)))
		printjvmtierror("VMVirtualMachine_registerEvent SetEventNotificationMode",err);

}


/*
 * Class:     gnu/classpath/jdwp/VMVirtualMachine
 * Method:    unregisterEvent
 * Signature: (Lgnu/classpath/jdwp/event/EventRequest;)V
 */
JNIEXPORT void JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_unregisterEvent(JNIEnv *env, jclass clazz, struct gnu_classpath_jdwp_event_EventRequest* par1) {
	jbyte kind;
	jfieldID kindid;
	jclass erc;
	jvmtiError err;

	erc = (*env)->FindClass(env,"gnu.classpath.jdwp.event.EventRequest");
	
	kindid = (*env)->GetFieldID(env, erc, "_kind", "B");
	kind = (*env)->GetByteField(env, (jobject)par1, kindid);

	if (JVMTI_ERROR_NONE != (err= (*jvmtienv)->
		SetEventNotificationMode(jvmtienv, JVMTI_DISABLE, 
								 EventKind2jvmtiEvent(kind), NULL)))
		printjvmtierror("VMVirtualMachine_registerEvent SetEventNotificationMode",err);

}


/*
 * Class:     gnu/classpath/jdwp/VMVirtualMachine
 * Method:    clearEvents
 * Signature: (B)V
 */
JNIEXPORT void JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_clearEvents(JNIEnv *env, jclass clazz, s4 par1) {
	/* jvmti events are not saved - there is nothing to clear */
}


/*
 * These are local overrides for various environment variables in Emacs.
 * Please do not remove this and leave it at the end of the file, where
 * Emacs will automagically detect them.
 * ---------------------------------------------------------------------
 * Local variables:
 * mode: c
 * indent-tabs-mode: t
 * c-basic-offset: 4
 * tab-width: 4
 * End:
 */
