Logo Search packages:      
Sourcecode: cacao version File versions  Download package

jvmti.c

/* src/native/jvmti/jvmti.c - implementation of the Java Virtual Machine Tool 
                              Interface functions

   Copyright (C) 1996-2005 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., 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.

   Contact: cacao@complang.tuwien.ac.at

   Author: Martin Platter

   Changes:             

   
   $Id: jvmti.c,v 1.5 2005/11/06 14:01:10 motse Exp $

*/

#include <assert.h>

#include "native/jni.h"
#include "native/jvmti/jvmti.h"
#include "vm/global.h"
#include "vm/loader.h"
#include "vm/builtin.h"
#include "vm/jit/asmpart.h"
#include "vm/classcache.h"
#include "mm/boehm.h"
#include "toolbox/logging.h"
#include "vm/options.h"
#include "cacao/cacao.h"
#include "vm/stringlocal.h"
#include "mm/memory.h"
#include "threads/native/threads.h"
#include "vm/exceptions.h"
#include "native/include/java_util_Vector.h"
#include "native/include/java_io_PrintStream.h"
#include "native/include/java_io_InputStream.h"
#include "native/include/java_lang_Cloneable.h"
#include "native/include/java_lang_ThreadGroup.h"
#include "native/include/java_lang_VMObject.h"
#include "native/include/java_lang_VMSystem.h"
#include "native/include/java_lang_VMClass.h"
#include "vm/jit/stacktrace.h"

#include <string.h>
#include <linux/unistd.h>
#include <sys/time.h>
#include "toolbox/logging.h"
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <ltdl.h>

#if defined(USE_THREADS) && defined(NATIVE_THREADS)
#include "threads/native/threads.h"
#include <sched.h>
#include <pthread.h>
#endif 

#include "dbg.h"

typedef struct _environment environment;
environment *envs=NULL;

extern const struct JNIInvokeInterface JNI_JavaVMTable;

static jvmtiPhase phase; 
typedef struct _jvmtiEventModeLL jvmtiEventModeLL;
struct _jvmtiEventModeLL {
      jvmtiEventMode mode;
      jthread event_thread;
      jvmtiEventModeLL *next;
};

typedef struct _jvmtiThreadLocalStorage jvmtiThreadLocalStorage;
struct _jvmtiThreadLocalStorage{
      jthread thread;
      jvmtiThreadLocalStorage *next;
      void *data;
};

struct _environment {
    jvmtiEnv env;
    jvmtiEventCallbacks callbacks;
    /* table for enabled/disabled jvmtiEvents - first element contains global 
         behavior */
    jvmtiEventModeLL events[JVMTI_EVENT_END_ENUM - JVMTI_EVENT_START_ENUM]; 
    jvmtiCapabilities capabilities;
    void *EnvironmentLocalStorage;
      jvmtiThreadLocalStorage *tls;
      environment *next;
};


static jvmtiEnv JVMTI_EnvTable;
static jvmtiCapabilities JVMTI_Capabilities;
static lt_ptr unload;

#define CHECK_PHASE_START  if (!(0 
#define CHECK_PHASE(chkphase) || (phase == chkphase)
#define CHECK_PHASE_END  )) return JVMTI_ERROR_WRONG_PHASE
#define CHECK_CAPABILITY(env,CAP) if(((environment*)env)->capabilities.CAP == 0) \
                                     return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
#define CHECK_THREAD_IS_ALIVE(t) if((((java_lang_Thread*)t)->vmThread==NULL)&& \
                                    (((java_lang_Thread*)t)->group==NULL)) \
                                    return JVMTI_ERROR_THREAD_NOT_ALIVE;



static void execcallback(jvmtiEvent e, functionptr ec, genericEventData* data) {
      JNIEnv* jni_env = ptr_env;

      switch (e) {
      case JVMTI_EVENT_VM_INIT:
    case JVMTI_EVENT_THREAD_START:
    case JVMTI_EVENT_THREAD_END: 
            ((jvmtiEventThreadStart)ec) (data->jvmti_env, jni_env, data->thread);
            break;


    case JVMTI_EVENT_CLASS_FILE_LOAD_HOOK:
            ((jvmtiEventClassFileLoadHook)ec) (data->jvmti_env, 
                                                               jni_env, 
                                                               data->klass,
                                                               data->object,
                                                               data->name,
                                                               data->protection_domain,
                                                               data->jint1,
                                                               data->class_data,
                                                               data->new_class_data_len,
                                                               data->new_class_data);
            break;


    case JVMTI_EVENT_CLASS_PREPARE: 
    case JVMTI_EVENT_CLASS_LOAD:
            ((jvmtiEventClassLoad)ec) (data->jvmti_env, jni_env, 
                                                   data->thread, data->klass);
            break;

    case JVMTI_EVENT_VM_DEATH:
    case JVMTI_EVENT_VM_START: 
            ((jvmtiEventThreadStart)ec) (data->jvmti_env, jni_env, data->thread);
            break;

    case JVMTI_EVENT_EXCEPTION:
            ((jvmtiEventException)ec) (data->jvmti_env, jni_env, 
                                                   data->thread, 
                                                   data->method, 
                                                   data->location,
                                                   data->object,
                                                   data->catch_method,
                                                   data->catch_location);
            break;
            
    case JVMTI_EVENT_EXCEPTION_CATCH:
            ((jvmtiEventExceptionCatch)ec) (data->jvmti_env, jni_env, 
                                                            data->thread, 
                                                            data->method, 
                                                            data->location,
                                                            data->object);
            break;

    case JVMTI_EVENT_BREAKPOINT:
    case JVMTI_EVENT_SINGLE_STEP: 
            ((jvmtiEventSingleStep)ec) (data->jvmti_env, jni_env, 
                                                      data->thread, 
                                                      data->method, 
                                                      data->location);
            break;

    case JVMTI_EVENT_FRAME_POP:
            ((jvmtiEventFramePop)ec) (data->jvmti_env, jni_env, 
                                                  data->thread, 
                                                  data->method, 
                                                  data->b);
            break;

    case JVMTI_EVENT_FIELD_ACCESS: 
            ((jvmtiEventFieldAccess)ec) (data->jvmti_env, jni_env, 
                                                       data->thread, 
                                                       data->method, 
                                                       data->location,
                                                       data->klass,
                                                       data->object,
                                                       data->field);
            break;

    case JVMTI_EVENT_FIELD_MODIFICATION:
            ((jvmtiEventFieldModification)ec) (data->jvmti_env, jni_env, 
                                                               data->thread, 
                                                               data->method, 
                                                               data->location,
                                                               data->klass,
                                                               data->object,
                                                               data->field,
                                                               data->signature_type,
                                                               data->value);
            break;

    case JVMTI_EVENT_METHOD_ENTRY:
            ((jvmtiEventMethodEntry)ec) (data->jvmti_env, jni_env, 
                                                       data->thread, 
                                                       data->method);
            break;

    case JVMTI_EVENT_METHOD_EXIT: 
            ((jvmtiEventMethodExit)ec) (data->jvmti_env, jni_env, 
                                                      data->thread, 
                                                      data->method,
                                                      data->b,
                                                      data->value);
            break;

    case JVMTI_EVENT_NATIVE_METHOD_BIND:
            ((jvmtiEventNativeMethodBind)ec) (data->jvmti_env, jni_env, 
                                                              data->thread, 
                                                              data->method,
                                                              data->address,
                                                              data->new_address_ptr);
            break;

    case JVMTI_EVENT_COMPILED_METHOD_LOAD:
            ((jvmtiEventCompiledMethodLoad)ec) (data->jvmti_env, 
                                                                  data->method,
                                                                  data->jint1,
                                                                  data->address,
                                                                  data->jint2,
                                                                  data->map,
                                                                  data->compile_info);
            break;
            
    case JVMTI_EVENT_COMPILED_METHOD_UNLOAD:
            ((jvmtiEventCompiledMethodUnload)ec) (data->jvmti_env,
                                                                    data->method,
                                                                    data->address);
            break;

    case JVMTI_EVENT_DYNAMIC_CODE_GENERATED:
            ((jvmtiEventDynamicCodeGenerated)ec) (data->jvmti_env,
                                                                    data->name,
                                                                    data->address,
                                                                    data->jint1);
            break;

    case JVMTI_EVENT_GARBAGE_COLLECTION_START:
    case JVMTI_EVENT_GARBAGE_COLLECTION_FINISH:
    case JVMTI_EVENT_DATA_DUMP_REQUEST: 
            ((jvmtiEventDataDumpRequest)ec) (data->jvmti_env);
            break;

    case JVMTI_EVENT_MONITOR_WAIT:
            ((jvmtiEventMonitorWait)ec) (data->jvmti_env, jni_env, 
                                                       data->thread, 
                                                       data->object,
                                                       data->jlong);
            break;

    case JVMTI_EVENT_MONITOR_WAITED:
            ((jvmtiEventMonitorWaited)ec) (data->jvmti_env, jni_env, 
                                                         data->thread, 
                                                         data->object,
                                                         data->b);
            break;


    case JVMTI_EVENT_MONITOR_CONTENDED_ENTERED:
    case JVMTI_EVENT_MONITOR_CONTENDED_ENTER:
            ((jvmtiEventMonitorContendedEnter)ec) (data->jvmti_env, jni_env, 
                                                                     data->thread, 
                                                                     data->object);
            break;

    case JVMTI_EVENT_OBJECT_FREE: 
            ((jvmtiEventObjectFree)ec) (data->jvmti_env, data->jlong);
            break;

    case JVMTI_EVENT_VM_OBJECT_ALLOC:
            ((jvmtiEventVMObjectAlloc)ec) (data->jvmti_env, jni_env, 
                                                         data->thread, 
                                                         data->object,
                                                         data->klass,
                                                         data->jlong);
            break;


      default:
            log_text ("unknown event");
      }
}

/* fireEvent **************************************************************

   fire event callback with data arguments.

*******************************************************************************/

void fireEvent(jvmtiEvent e, genericEventData* data) {
      environment* env;
      jvmtiEventModeLL *evm;
      jthread thread;

      functionptr ec;
    /* todo : respect event order JVMTI-Spec:Multiple Co-located Events */

      thread = (jthread)THREADOBJECT;

      data->thread = thread;

      env = envs;
      while (env!=NULL) {

            if (env->events[e-JVMTI_EVENT_START_ENUM].mode == JVMTI_DISABLE) {
                  evm = env->events[e-JVMTI_EVENT_START_ENUM].next;
            /* test if the event is enable for some threads */
                  while (evm!=NULL) { 
                        if (evm->mode == JVMTI_ENABLE) {
                              data->jvmti_env=&env->env;
                              ec = ((functionptr*)(&env->callbacks))[e-JVMTI_EVENT_START_ENUM];
                              execcallback(e, ec, data);
                        }
                        evm=evm->next;
                  }
            } else { /* event enabled globally */
                  data->jvmti_env=&env->env;
                  ec = ((functionptr*)(&env->callbacks))[e-JVMTI_EVENT_START_ENUM];
                  execcallback(e, ec, data);
            }
            
            env=env->next;
      }
}



/* getchildproc ***************************************************************

   Get data from child process

*******************************************************************************/
static long getchildproc (void *ptr) {
      if (debuggee > 0) {
        /* get data from child process */
            return GETMEM(debuggee,ptr);
      } else {
            return *((long*)ptr);
      }
}



/* SetEventNotificationMode ****************************************************

   Control the generation of events

*******************************************************************************/

jvmtiError
SetEventNotificationMode (jvmtiEnv * env, jvmtiEventMode mode,
                    jvmtiEvent event_type, jthread event_thread, ...)
{
      environment* cacao_env;
      jvmtiEventModeLL *ll;

    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_ONLOAD)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;

      if((event_thread != NULL)&&
         (!builtin_instanceof(event_thread,class_java_lang_Thread))) 
            return JVMTI_ERROR_INVALID_THREAD;

      CHECK_THREAD_IS_ALIVE(event_thread);
      
      cacao_env = (environment*) env;    
      if ((mode != JVMTI_ENABLE) && (mode != JVMTI_DISABLE))
            return JVMTI_ERROR_ILLEGAL_ARGUMENT;

      if ((event_type < JVMTI_EVENT_START_ENUM) ||
            (event_type > JVMTI_EVENT_END_ENUM))
            return JVMTI_ERROR_INVALID_EVENT_TYPE;
      
      
      switch (event_type) { /* check capability */
    case JVMTI_EVENT_EXCEPTION:
      case JVMTI_EVENT_EXCEPTION_CATCH:
            CHECK_CAPABILITY(env,can_generate_exception_events)
            break;
    case JVMTI_EVENT_SINGLE_STEP:
            CHECK_CAPABILITY(env,can_generate_single_step_events)
            break;
    case JVMTI_EVENT_FRAME_POP:
            CHECK_CAPABILITY(env,can_generate_frame_pop_events)
            break;
    case JVMTI_EVENT_BREAKPOINT:
            CHECK_CAPABILITY(env,can_generate_breakpoint_events)
            break;
    case JVMTI_EVENT_FIELD_ACCESS:
            CHECK_CAPABILITY(env,can_generate_field_access_events)
            break;
    case JVMTI_EVENT_FIELD_MODIFICATION:
            CHECK_CAPABILITY(env,can_generate_field_modification_events)
            break;
    case JVMTI_EVENT_METHOD_ENTRY:
            CHECK_CAPABILITY(env,can_generate_method_entry_events)
            break;
    case JVMTI_EVENT_METHOD_EXIT:
            CHECK_CAPABILITY(env, can_generate_method_exit_events)
            break;
    case JVMTI_EVENT_NATIVE_METHOD_BIND:
            CHECK_CAPABILITY(env, can_generate_native_method_bind_events)
            break;
    case JVMTI_EVENT_COMPILED_METHOD_LOAD:
    case JVMTI_EVENT_COMPILED_METHOD_UNLOAD:
            CHECK_CAPABILITY(env,can_generate_compiled_method_load_events)
            break;
    case JVMTI_EVENT_MONITOR_WAIT:
    case JVMTI_EVENT_MONITOR_WAITED:
    case JVMTI_EVENT_MONITOR_CONTENDED_ENTER:
    case JVMTI_EVENT_MONITOR_CONTENDED_ENTERED:
            CHECK_CAPABILITY(env,can_generate_monitor_events)
            break;
    case JVMTI_EVENT_GARBAGE_COLLECTION_START:
      case JVMTI_EVENT_GARBAGE_COLLECTION_FINISH:
            CHECK_CAPABILITY(env,can_generate_garbage_collection_events)
            break;
    case JVMTI_EVENT_OBJECT_FREE:
            CHECK_CAPABILITY(env,can_generate_object_free_events)
            break;
    case JVMTI_EVENT_VM_OBJECT_ALLOC:
            CHECK_CAPABILITY(env,can_generate_vm_object_alloc_events)
            break;
      default:
            /* all other events are required */
            break;
      }

      if (event_thread != NULL) {
            /* thread level control */
            if ((JVMTI_EVENT_VM_INIT == mode) ||
                  (JVMTI_EVENT_VM_DEATH == mode) ||
                  (JVMTI_EVENT_VM_START == mode) ||
                  (JVMTI_EVENT_THREAD_START == mode) ||
                  (JVMTI_EVENT_COMPILED_METHOD_LOAD == mode) ||
                  (JVMTI_EVENT_COMPILED_METHOD_UNLOAD == mode) ||
                  (JVMTI_EVENT_DYNAMIC_CODE_GENERATED == mode) ||
                  (JVMTI_EVENT_DATA_DUMP_REQUEST == mode))
                  return JVMTI_ERROR_ILLEGAL_ARGUMENT;
            ll = &(cacao_env->events[event_type-JVMTI_EVENT_START_ENUM]);
            while (ll->next != NULL) {
                  ll = ll->next;
                  if (ll->event_thread == event_thread) {
                        ll->mode=mode;
                        return JVMTI_ERROR_NONE;
                  }
            }
            ll->next = heap_allocate(sizeof(jvmtiEventModeLL),true,NULL);
            ll->next->mode=mode;          
      } else {
            /* global control */
            cacao_env->events[event_type-JVMTI_EVENT_START_ENUM].mode=mode;
      }

      
    return JVMTI_ERROR_NONE;
}


/* GetAllThreads ***************************************************************

   Get all live threads

*******************************************************************************/

jvmtiError
GetAllThreads (jvmtiEnv * env, jint * threads_count_ptr,
             jthread ** threads_ptr)
{
    int i = 0; 
    threadobject* thread;

    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;

    if ((threads_count_ptr == NULL) || (threads_ptr == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;

#if defined(USE_THREADS) && defined(NATIVE_THREADS)
    thread = mainthreadobj;
    do {
        if((thread->o.thread->vmThread==NULL)&& (thread->o.thread->group==NULL)) 
               i++; /* count only live threads */
               thread = thread->info.prev;
      } while (thread != mainthreadobj);
    
    *threads_count_ptr = i;
      
    *threads_ptr = (jthread*) heap_allocate(sizeof(jthread) * i,true,NULL);
    i=0;
    do {
        memcpy(*threads_ptr[i],thread,sizeof(jthread));
        thread = thread->info.prev;
        i++;
    } while (thread != mainthreadobj);
#else
      return JVMTI_ERROR_NOT_AVAILABLE;
#endif

    return JVMTI_ERROR_NONE;
}


/* SuspendThread ***************************************************************

   Suspend specified thread

*******************************************************************************/

jvmtiError
SuspendThread (jvmtiEnv * env, jthread thread)
{
      CHECK_PHASE_START
      CHECK_PHASE(JVMTI_PHASE_LIVE)
      CHECK_PHASE_END;
    CHECK_CAPABILITY(env,can_suspend)
    
#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
      suspendThread((thread *) thread->thread);
#endif

    return JVMTI_ERROR_NONE;
}

/* ResumeThread ***************************************************************

   Resume a suspended thread

*******************************************************************************/

jvmtiError
ResumeThread (jvmtiEnv * env, jthread thread)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
    CHECK_CAPABILITY(env,can_suspend)

#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
      resumeThread((thread *) this->thread);
#endif

    return JVMTI_ERROR_NONE;
}

/* StopThread *****************************************************************

   Send asynchronous exception to the specified thread. Similar to 
   java.lang.Thread.stop(). Used to kill thread.

*******************************************************************************/

jvmtiError
StopThread (jvmtiEnv * env, jthread thread, jobject exception)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
    CHECK_CAPABILITY(env,can_signal_thread)
        
  log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}

/* InterruptThread ************************************************************

   Interrupt specified thread. Similar to java.lang.Thread.interrupt()

*******************************************************************************/

jvmtiError
InterruptThread (jvmtiEnv * env, jthread thread)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
    CHECK_CAPABILITY(env,can_signal_thread)

      if(!builtin_instanceof(thread,class_java_lang_Thread))
            return JVMTI_ERROR_INVALID_THREAD;

      CHECK_THREAD_IS_ALIVE(thread);        

#if defined(USE_THREADS) && defined(NATIVE_THREADS)
      interruptThread((java_lang_VMThread*)thread);
#else
      return JVMTI_ERROR_NOT_AVAILABLE;
#endif

    return JVMTI_ERROR_NONE;
}

/* GetThreadInfo ***************************************************************

   Get thread information. Details of the specified thread are stored in the 
   jvmtiThreadInfo structure.

*******************************************************************************/

jvmtiError
GetThreadInfo (jvmtiEnv * env, jthread th, jvmtiThreadInfo * info_ptr)
{
      java_lang_Thread* t = (java_lang_Thread*)th;
      int size;
      char* name;

    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      
      name = javastring_tochar((java_objectheader*)t->name);
      size = strlen(name);
      info_ptr->name=heap_allocate(size*sizeof(char),true,NULL);
      strncpy(info_ptr->name,name,size);
      info_ptr->priority=(jint)t->priority;
      info_ptr->is_daemon=(jboolean)t->daemon;
      info_ptr->thread_group=(jthreadGroup)t->group;
      info_ptr->context_class_loader=(jobject)t->contextClassLoader;

    return JVMTI_ERROR_NONE;
}

/* GetOwnedMonitorInfo *********************************************************

   Get information about the monitors owned by the specified thread

*******************************************************************************/

jvmtiError
GetOwnedMonitorInfo (jvmtiEnv * env, jthread thread,
                 jint * owned_monitor_count_ptr,
                 jobject ** owned_monitors_ptr)
{
      int i,j,size=20;
      jobject* om;
      lockRecordPool* lrp;

      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
    CHECK_CAPABILITY(env,can_get_owned_monitor_info);

      if ((owned_monitors_ptr==NULL)||(owned_monitor_count_ptr==NULL)) 
            return JVMTI_ERROR_NULL_POINTER;

      if(!builtin_instanceof(thread,class_java_lang_Thread))
            return JVMTI_ERROR_INVALID_THREAD;

      CHECK_THREAD_IS_ALIVE(thread);

#if defined(USE_THREADS) && defined(NATIVE_THREADS)

      om=MNEW(java_objectheader*,size);

      pthread_mutex_lock(&pool_lock);

      lrp=global_pool;

      while (lrp != NULL) {
            for (j=0; j<lrp->header.size; j++) {
                  if((lrp->lr[j].ownerThread==(threadobject*)thread)&&
                     (!lrp->lr[j].waiting)) {
                        if (i>=size) {
                              MREALLOC(om,java_objectheader*,size,size*2);
                              size=size*2;
                        }
                        om[i]=lrp->lr[j].o;
                        i++;
                  }
            }
            lrp=lrp->header.next;
      }

      pthread_mutex_unlock(&pool_lock);

      *owned_monitors_ptr     = heap_allocate(sizeof(java_objectheader*)*i,true,NULL);
      memcpy(*owned_monitors_ptr,om,i*sizeof(java_objectheader*));
      MFREE(om,java_objectheader*,size);

      *owned_monitor_count_ptr = i;

#endif

    return JVMTI_ERROR_NONE;
}

/* GetCurrentContendedMonitor *************************************************

   Get the object the specified thread waits for.

*******************************************************************************/

jvmtiError
GetCurrentContendedMonitor (jvmtiEnv * env, jthread thread,
                      jobject * monitor_ptr)
{
      int j;
      lockRecordPool* lrp;
      java_objectheader* monitor;

      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env, can_get_current_contended_monitor)
        
      if (monitor_ptr==NULL) return JVMTI_ERROR_NULL_POINTER;
      *monitor_ptr=NULL;

      if(!builtin_instanceof(thread,class_java_lang_Thread))
            return JVMTI_ERROR_INVALID_THREAD;

      CHECK_THREAD_IS_ALIVE(thread);


#if defined(USE_THREADS) && defined(NATIVE_THREADS)

      pthread_mutex_lock(&pool_lock);

      lrp=global_pool;

      while ((lrp != NULL)&&(monitor==NULL)) {
            for (j=0; j<lrp->header.size; j++) {
                  if((lrp->lr[j].ownerThread==(threadobject*)thread)&&(lrp->lr[j].waiting)) {
                        monitor=lrp->lr[j].o;
                        break;
                  }
            }
            lrp=lrp->header.next;
      }

      pthread_mutex_unlock(&pool_lock);

      if (monitor!=NULL) {
            *monitor_ptr = heap_allocate(sizeof(java_objectheader*),true,NULL);
            *monitor_ptr = (jobject)monitor;
      }

#endif
    return JVMTI_ERROR_NONE;
}

typedef struct {
      jvmtiStartFunction sf;
      jvmtiEnv* jvmti_env;
      void* arg;
} runagentparam;


static void *threadstartup(void *t) {
      runagentparam *rap = (runagentparam*)t;
      rap->sf(rap->jvmti_env,ptr_env,rap->arg);
      return NULL;
}

/* RunAgentThread *************************************************************

   Starts the execution of an agent thread of the specified native function 
   within the specified thread

*******************************************************************************/

jvmtiError
RunAgentThread (jvmtiEnv * env, jthread thread, jvmtiStartFunction proc,
            const void *arg, jint priority)
{
      pthread_attr_t threadattr;
      struct sched_param sp;
      runagentparam rap;

      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;

      if((thread != NULL)&&(!builtin_instanceof(thread,class_java_lang_Thread))) 
            return JVMTI_ERROR_INVALID_THREAD;
      if (proc == NULL) return JVMTI_ERROR_NULL_POINTER;
      if ((priority < JVMTI_THREAD_MIN_PRIORITY) || (priority > JVMTI_THREAD_MAX_PRIORITY)) 
            return JVMTI_ERROR_INVALID_PRIORITY;

      rap.sf = proc;
      rap.arg = (void*)arg;
      rap.jvmti_env = env;

#if defined(USE_THREADS) && defined(NATIVE_THREADS)
      pthread_attr_init(&threadattr);
      pthread_attr_setdetachstate(&threadattr, PTHREAD_CREATE_DETACHED);
      if (priority == JVMTI_THREAD_MIN_PRIORITY) {
            sp.__sched_priority = sched_get_priority_min(SCHED_FIFO);
      }
      if (priority == JVMTI_THREAD_MAX_PRIORITY) {
            sp.__sched_priority = sched_get_priority_min(SCHED_FIFO);
      }
      pthread_attr_setschedparam(&threadattr,&sp);
      if (pthread_create(&((threadobject*) thread)->info.tid, &threadattr, &threadstartup, &rap)) {
            log_text("pthread_create failed");
            assert(0);
      }
#endif

    return JVMTI_ERROR_NONE;
}


/* GetTopThreadGroups *********************************************************

   Get all top-level thread groups in the VM.

*******************************************************************************/

jvmtiError
GetTopThreadGroups (jvmtiEnv * env, jint * group_count_ptr,
                jthreadGroup ** groups_ptr)
{
      jint threads_count_ptr;
      threadobject *threads_ptr;
      int i,j,x,size=20;
      jthreadGroup **tg,*ttgp;

    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;

    if ((groups_ptr == NULL) || (group_count_ptr == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;

#if defined(USE_THREADS) && defined(NATIVE_THREADS)
      tg = MNEW(jthreadGroup*,size);
      x = 0;
      if (JVMTI_ERROR_NONE!=GetAllThreads(env,&threads_count_ptr,(jthread**)&threads_ptr))
            return JVMTI_ERROR_INTERNAL;

      for (i=0;i<threads_count_ptr;i++){
            if (threads_ptr[i].o.thread->group == NULL) {
                  log_text("threadgroup not set");
                  return JVMTI_ERROR_INTERNAL;
            }
            ttgp = (jthreadGroup*)((java_lang_ThreadGroup*)threads_ptr[i].o.thread->group)->parent;
            if (ttgp == NULL) {
                  j=0;
                  while((j<x)&&(tg[j]!=ttgp)) { /* unique ? */
                        j++;
                  }

                  if (j == x) {
                        if (x >= size){
                              MREALLOC(tg,jthreadGroup*,size,size*2);
                              size=size*2;
                        }
                        tg[x]=ttgp;
                        x++;
                  }
            }
      }

      *groups_ptr = heap_allocate(sizeof(jthreadGroup*)*x,true,NULL);
      memcpy(*groups_ptr,tg,x*sizeof(jthreadGroup*));
      MFREE(tg,jthreadGroup*,size);

      *group_count_ptr = x;

#else
      return JVMTI_ERROR_NOT_AVAILABLE;
#endif
    return JVMTI_ERROR_NONE;
}


/* GetThreadGroupInfo *********************************************************

   Get information about the specified thread group.

*******************************************************************************/

jvmtiError
GetThreadGroupInfo (jvmtiEnv * env, jthreadGroup group,
                jvmtiThreadGroupInfo * info_ptr)
{
      int size;
      char* name;
      java_lang_ThreadGroup* grp;
      
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
      if (info_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;
      if (!builtin_instanceof(group,class_java_lang_ThreadGroup))
            return JVMTI_ERROR_INVALID_THREAD_GROUP;

      grp = (java_lang_ThreadGroup*)group;
      
      info_ptr->parent = (jthreadGroup) 
            Java_java_lang_VMObject_clone(NULL, 
                                                        (jclass)grp->header.vftbl->class,
                                                        (java_lang_Cloneable*) &grp->parent);

      name = javastring_tochar((java_objectheader*)grp->name);
      size = strlen(name);
      info_ptr->name=heap_allocate(size*sizeof(char),true,NULL);
      strncpy(info_ptr->name,name,size);
      info_ptr->max_priority= (jint)grp->maxpri;
      info_ptr->is_daemon= (jboolean)grp->daemon_flag;
      
    return JVMTI_ERROR_NONE;
}


/* GetThreadGroupChildren *****************************************************

   Get the live threads and active subgroups in this thread group. 

*******************************************************************************/

jvmtiError
GetThreadGroupChildren (jvmtiEnv * env, jthreadGroup group,
                  jint * thread_count_ptr, jthread ** threads_ptr,
                  jint * group_count_ptr, jthreadGroup ** groups_ptr)
{
      java_lang_ThreadGroup* tgp;

    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
      if ((thread_count_ptr == NULL) || (threads_ptr == NULL) ||
            (group_count_ptr == NULL) || (groups_ptr == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;

      if (!builtin_instanceof(group,class_java_lang_ThreadGroup))
            return JVMTI_ERROR_INVALID_THREAD_GROUP;

      tgp = (java_lang_ThreadGroup*)group;

      *thread_count_ptr = (jint)tgp->threads->elementCount;

      *threads_ptr = heap_allocate(sizeof(jthread*)*(*thread_count_ptr),true,NULL);

      memcpy(*threads_ptr, &tgp->threads->elementData, 
               (*thread_count_ptr)*sizeof(jthread*));

      *group_count_ptr = (jint) tgp->groups->elementCount;

      *groups_ptr = heap_allocate(sizeof(jthreadGroup*)*(*group_count_ptr),true,NULL);    

      memcpy(*groups_ptr, &tgp->threads->elementData,
               (*group_count_ptr)*sizeof(jthreadGroup*));

    return JVMTI_ERROR_NONE;
}


/* getcacaostacktrace *********************************************************

   Helper function that retrives stack trace for specified thread. 
   Has to take care of suspend/resume issuses

*******************************************************************************/

static jvmtiError getcacaostacktrace(stackTraceBuffer** trace, jthread thread) {

      /* todo: suspend specified thread */
/*    
      if (!cacao_stacktrace_fillInStackTrace((void**)trace,&stackTraceCollector, (threadobject*)thread)) 
            return JVMTI_ERROR_INTERNAL;
*/
      /* todo: resume specified thread */
      log_text("todo: stacktraces");
    return JVMTI_ERROR_NONE;
}


/* GetFrameCount **************************************************************

   Get the number of frames in the specified thread's stack.

*******************************************************************************/

jvmtiError
GetFrameCount (jvmtiEnv * env, jthread thread, jint * count_ptr)
{
      stackTraceBuffer* trace;
      jvmtiError er;

      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
    
      if(!builtin_instanceof(thread,class_java_lang_Thread))
            return JVMTI_ERROR_INVALID_THREAD;

      CHECK_THREAD_IS_ALIVE(thread);
      
      if(count_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;

      er = getcacaostacktrace(&trace, thread);
      if (er==JVMTI_ERROR_NONE) return er;

      *count_ptr = trace->size;

    return JVMTI_ERROR_NONE;
}


/* GetThreadState **************************************************************

   Get the state of a thread. 

*******************************************************************************/

jvmtiError
GetThreadState (jvmtiEnv * env, jthread thread, jint * thread_state_ptr)
{
      java_lang_Thread* th = (java_lang_Thread*)thread;
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
      if(!builtin_instanceof(thread,class_java_lang_Thread))
            return JVMTI_ERROR_INVALID_THREAD;

      if (thread_state_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;

      *thread_state_ptr = 0;
#if defined(USE_THREADS) && defined(NATIVE_THREADS)
      if((th->vmThread==NULL)&&(th->group==NULL)) { /* alive ? */
            /* not alive */
            if (((threadobject*)th->vmThread)->info.tid == 0)
                  *thread_state_ptr = JVMTI_THREAD_STATE_TERMINATED;
      } else {
            /* alive */
            *thread_state_ptr = JVMTI_THREAD_STATE_ALIVE;
            if (false) *thread_state_ptr |= JVMTI_THREAD_STATE_SUSPENDED; /* todo */
            /* todo */
      }
#else
      return JVMTI_ERROR_INTERNAL;
#endif

    return JVMTI_ERROR_NONE;
}


/* GetFrameLocation ************************************************************

   Get the location of the instruction currently executing

*******************************************************************************/

jvmtiError
GetFrameLocation (jvmtiEnv * env, jthread thread, jint depth,
              jmethodID * method_ptr, jlocation * location_ptr)
{
      stackframeinfo   *sfi;
      int i;
            
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
      if(!builtin_instanceof(thread,class_java_lang_Thread))
            return JVMTI_ERROR_INVALID_THREAD;

      CHECK_THREAD_IS_ALIVE(thread);

      if (depth < 0) return JVMTI_ERROR_ILLEGAL_ARGUMENT;

      if ((method_ptr == NULL)&&(location_ptr == NULL)) 
            return JVMTI_ERROR_NULL_POINTER;
      
      sfi = ((threadobject*)thread)->info._stackframeinfo;
      
      i = 0;
      while ((sfi != NULL) && (i<depth)) {
            sfi = sfi->prev;
            i++;
      }
      
      if (i>depth) return JVMTI_ERROR_NO_MORE_FRAMES;

      *method_ptr=(jmethodID)sfi->method;
      *location_ptr = 0; /* todo: location MachinePC not avilable - Linenumber not expected */
      
    return JVMTI_ERROR_NONE;
}


/* NotifyFramePop *************************************************************

   

*******************************************************************************/

jvmtiError
NotifyFramePop (jvmtiEnv * env, jthread thread, jint depth)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
    CHECK_CAPABILITY(env,can_generate_frame_pop_events)
        
  log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}

/* GetLocalObject *************************************************************

   

*******************************************************************************/

jvmtiError
GetLocalObject (jvmtiEnv * env,
            jthread thread, jint depth, jint slot, jobject * value_ptr)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_access_local_variables)

  log_text ("JVMTI-Call: TBD-OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}

/* GetLocalInt ****************************************************************

   

*******************************************************************************/

jvmtiError
GetLocalInt (jvmtiEnv * env,
           jthread thread, jint depth, jint slot, jint * value_ptr)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_access_local_variables)        
  log_text ("JVMTI-Call: TBD OPTIONAL  IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}

/* *****************************************************************************

   

*******************************************************************************/

jvmtiError
GetLocalLong (jvmtiEnv * env, jthread thread, jint depth, jint slot,
            jlong * value_ptr)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_access_local_variables)        
        
  log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* *****************************************************************************

   

*******************************************************************************/

jvmtiError
GetLocalFloat (jvmtiEnv * env, jthread thread, jint depth, jint slot,
             jfloat * value_ptr)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_access_local_variables)        
        
  log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* *****************************************************************************

   

*******************************************************************************/

jvmtiError
GetLocalDouble (jvmtiEnv * env, jthread thread, jint depth, jint slot,
            jdouble * value_ptr)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_access_local_variables)        
        
  log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* *****************************************************************************

   

*******************************************************************************/

jvmtiError
SetLocalObject (jvmtiEnv * env, jthread thread, jint depth, jint slot,
            jobject value)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_access_local_variables)
    
  log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* *****************************************************************************

   

*******************************************************************************/

jvmtiError
SetLocalInt (jvmtiEnv * env, jthread thread, jint depth, jint slot,
           jint value)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_access_local_variables)
        
  log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* *****************************************************************************

   

*******************************************************************************/

jvmtiError
SetLocalLong (jvmtiEnv * env, jthread thread, jint depth, jint slot,
            jlong value)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_access_local_variables)
        
  log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* *****************************************************************************

   

*******************************************************************************/

jvmtiError
SetLocalFloat (jvmtiEnv * env, jthread thread, jint depth, jint slot,
             jfloat value)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_access_local_variables)
        
  log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* *****************************************************************************

   

*******************************************************************************/

jvmtiError
SetLocalDouble (jvmtiEnv * env, jthread thread, jint depth, jint slot,
            jdouble value)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_access_local_variables)
    
       log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* CreateRawMonitor ***********************************************************

   This function creates a new raw monitor.

*******************************************************************************/

jvmtiError
CreateRawMonitor (jvmtiEnv * env, const char *name,
              jrawMonitorID * monitor_ptr)
{
      struct _jrawMonitorID *monitor = (struct _jrawMonitorID*) monitor_ptr;
            
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_ONLOAD)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
      if ((name == NULL) || (monitor_ptr == NULL)) 
            return JVMTI_ERROR_NULL_POINTER;

#if defined(USE_THREADS) && defined(NATIVE_THREADS)
      monitor->name=javastring_new_char(name);
#else
      log_text ("CreateRawMonitor not supported");
#endif

    return JVMTI_ERROR_NONE;
}


/* DestroyRawMonitor **********************************************************

   This function destroys a raw monitor.   

*******************************************************************************/

jvmtiError
DestroyRawMonitor (jvmtiEnv * env, jrawMonitorID monitor)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_ONLOAD)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;

      if (!builtin_instanceof((java_objectheader*)monitor->name,class_java_lang_String))
            return JVMTI_ERROR_INVALID_MONITOR;

#if defined(USE_THREADS) && defined(NATIVE_THREADS)
      if (!threadHoldsLock((threadobject*)THREADOBJECT, (java_objectheader*)monitor->name))
            return JVMTI_ERROR_NOT_MONITOR_OWNER;
      
      monitorExit((threadobject*)THREADOBJECT, (java_objectheader*)monitor->name);

      /* GC will clean monitor up */
#else
      log_text ("DestroyRawMonitor not supported");
#endif

      return JVMTI_ERROR_NONE;
}


/* RawMonitorEnter ************************************************************

  Gain exclusive ownership of a raw monitor

*******************************************************************************/

jvmtiError
RawMonitorEnter (jvmtiEnv * env, jrawMonitorID monitor)
{
      if (!builtin_instanceof((java_objectheader*)monitor->name,class_java_lang_String))
            return JVMTI_ERROR_INVALID_MONITOR;

#if defined(USE_THREADS) && defined(NATIVE_THREADS)
      builtin_monitorenter((java_objectheader*)monitor->name);        
#else
      log_text ("RawMonitorEnter not supported");
#endif

    return JVMTI_ERROR_NONE;
}


/* RawMonitorExit *************************************************************

   Release raw monitor

*******************************************************************************/

jvmtiError
RawMonitorExit (jvmtiEnv * env, jrawMonitorID monitor)
{
      if (!builtin_instanceof((java_objectheader*)monitor->name,class_java_lang_String))
            return JVMTI_ERROR_INVALID_MONITOR;

#if defined(USE_THREADS) && defined(NATIVE_THREADS)
      /* assure current thread owns this monitor */
      if (!threadHoldsLock((threadobject*)THREADOBJECT,(java_objectheader*)monitor->name))
            return JVMTI_ERROR_NOT_MONITOR_OWNER;

      builtin_monitorexit((java_objectheader*)monitor->name);
#else
      log_text ("RawMonitorExit not supported");
#endif

    return JVMTI_ERROR_NONE;
}


/* RawMonitorWait *************************************************************

   Wait for notification of the raw monitor.

*******************************************************************************/

jvmtiError
RawMonitorWait (jvmtiEnv * env, jrawMonitorID monitor, jlong millis)
{
      if (!builtin_instanceof((java_objectheader*)monitor->name,class_java_lang_String))
            return JVMTI_ERROR_INVALID_MONITOR;

#if defined(USE_THREADS) && defined(NATIVE_THREADS)
      /* assure current thread owns this monitor */
      if (!threadHoldsLock((threadobject*)THREADOBJECT,(java_objectheader*)monitor->name))
            return JVMTI_ERROR_NOT_MONITOR_OWNER;

      wait_cond_for_object(&monitor->name->header, millis,0);
      if (builtin_instanceof((java_objectheader*)exceptionptr, load_class_bootstrap(utf_new_char("java/lang/InterruptedException"))))
            return JVMTI_ERROR_INTERRUPT;

#else
      log_text ("RawMonitorWait not supported");
#endif

    return JVMTI_ERROR_NONE;
}


/* RawMonitorNotify ***********************************************************

 Notify one thread waiting on the given monitor.

*******************************************************************************/

jvmtiError
RawMonitorNotify (jvmtiEnv * env, jrawMonitorID monitor)
{
      if (!builtin_instanceof((java_objectheader*)monitor->name,class_java_lang_String))
            return JVMTI_ERROR_INVALID_MONITOR;

#if defined(USE_THREADS) && defined(NATIVE_THREADS)
      /* assure current thread owns this monitor */
      if (!threadHoldsLock((threadobject*)THREADOBJECT,(java_objectheader*)monitor->name))
            return JVMTI_ERROR_NOT_MONITOR_OWNER;

      signal_cond_for_object((java_objectheader*)&monitor->name);
#else
      log_text ("RawMonitorNotify not supported");
#endif

    return JVMTI_ERROR_NONE;
}


/* RawMonitorNotifyAll *********************************************************

 Notify all threads waiting on the given monitor.   

*******************************************************************************/

jvmtiError
RawMonitorNotifyAll (jvmtiEnv * env, jrawMonitorID monitor)
{
      if (!builtin_instanceof((java_objectheader*)monitor->name,class_java_lang_String))
            return JVMTI_ERROR_INVALID_MONITOR;

#if defined(USE_THREADS) && defined(NATIVE_THREADS)
      /* assure current thread owns this monitor */
      if (!threadHoldsLock((threadobject*)THREADOBJECT, (java_objectheader*)monitor->name))
            return JVMTI_ERROR_NOT_MONITOR_OWNER;

      broadcast_cond_for_object((java_objectheader*)&monitor->name);
#else
      log_text ("RawMonitorNotifyAll not supported");
#endif

    return JVMTI_ERROR_NONE;
}


/* SetBreakpoint **************************************************************

   

*******************************************************************************/

jvmtiError
SetBreakpoint (jvmtiEnv * env, jmethodID method, jlocation location)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_generate_breakpoint_events)
        
  log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* *****************************************************************************

   

*******************************************************************************/

jvmtiError
ClearBreakpoint (jvmtiEnv * env, jmethodID method, jlocation location)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_generate_breakpoint_events)
        
  log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* SetFieldAccessWatch ********************************************************

   

*******************************************************************************/

jvmtiError
SetFieldAccessWatch (jvmtiEnv * env, jclass klass, jfieldID field)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_generate_field_access_events)
        
  log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* *****************************************************************************

   

*******************************************************************************/

jvmtiError
ClearFieldAccessWatch (jvmtiEnv * env, jclass klass, jfieldID field)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_generate_field_access_events)
        
  log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* *****************************************************************************

   

*******************************************************************************/

jvmtiError
SetFieldModificationWatch (jvmtiEnv * env, jclass klass, jfieldID field)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_generate_field_modification_events)
        
  log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* *****************************************************************************

   

*******************************************************************************/

jvmtiError
ClearFieldModificationWatch (jvmtiEnv * env, jclass klass, jfieldID field)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_generate_field_modification_events)
        
  log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* Allocate ********************************************************************

   Allocate an area of memory through the JVM TI allocator. The allocated 
   memory should be freed with Deallocate

*******************************************************************************/

jvmtiError
Allocate (jvmtiEnv * env, jlong size, unsigned char **mem_ptr)
{
    
    if (mem_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;
    if (size < 0) return JVMTI_ERROR_ILLEGAL_ARGUMENT;

    *mem_ptr = heap_allocate(sizeof(size),true,NULL);
    if (*mem_ptr == NULL) 
        return JVMTI_ERROR_OUT_OF_MEMORY;
    else
        return JVMTI_ERROR_NONE;
    
}


/* Deallocate ******************************************************************

   Deallocate mem using the JVM TI allocator.

*******************************************************************************/

jvmtiError
Deallocate (jvmtiEnv * env, unsigned char *mem)
{
    /* let Boehm GC do the job */
    return JVMTI_ERROR_NONE;
}


/* GetClassSignature ************************************************************

   For the class indicated by klass, return the JNI type signature and the 
   generic signature of the class.

*******************************************************************************/

jvmtiError
GetClassSignature (jvmtiEnv * env, jclass klass, char **signature_ptr,
               char **generic_ptr)
{
    int nsize,psize;

    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
       
    if ((generic_ptr== NULL)||(signature_ptr == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;

    nsize=((classinfo*)klass)->name->blength;
    psize=((classinfo*)klass)->packagename->blength;

    *signature_ptr = (char*) 
        heap_allocate(sizeof(char)* nsize+psize+4,true,NULL);

    *signature_ptr[0]='L';
    memcpy(&(*signature_ptr[1]),((classinfo*)klass)->packagename->text, psize);
    *signature_ptr[psize+2]='/';
    memcpy(&(*signature_ptr[psize+3]),((classinfo*)klass)->name->text, nsize);
    *signature_ptr[nsize+psize+3]=';';
    *signature_ptr[nsize+psize+4]='\0';

    *generic_ptr = NULL;

    return JVMTI_ERROR_NONE;
}

/* GetClassStatus *************************************************************

   Get status of the class.

*******************************************************************************/

jvmtiError
GetClassStatus (jvmtiEnv * env, jclass klass, jint * status_ptr)
{
      classinfo *c;
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;

      if (!builtin_instanceof((java_objectheader*)klass,class_java_lang_Class))
            return JVMTI_ERROR_INVALID_CLASS; 

    if (status_ptr == NULL) 
        return JVMTI_ERROR_NULL_POINTER;

      c = (classinfo*)klass;
      *status_ptr = 0;  

/*    if (c) *status_ptr = *status_ptr | JVMTI_CLASS_STATUS_VERIFIED; ? */
/*    if () *status_ptr = *status_ptr | JVMTI_CLASS_STATUS_PREPARED;  ? */

      if (c->initialized) 
            *status_ptr = *status_ptr | JVMTI_CLASS_STATUS_INITIALIZED;

      if (c->erroneous_state) 
            *status_ptr = *status_ptr | JVMTI_CLASS_STATUS_ERROR;

      if (c->vftbl->arraydesc != NULL) 
            *status_ptr = *status_ptr | JVMTI_CLASS_STATUS_ARRAY;

      if (Java_java_lang_VMClass_isPrimitive(NULL,NULL,(struct java_lang_Class*)c)) 
            *status_ptr = *status_ptr | JVMTI_CLASS_STATUS_PRIMITIVE; 

    return JVMTI_ERROR_NONE;
}


/* GetSourceFileName **********************************************************

   For the class indicated by klass, return the source file name.

*******************************************************************************/

jvmtiError
GetSourceFileName (jvmtiEnv * env, jclass klass, char **source_name_ptr)
{
    int size; 

    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_get_source_file_name)
        
    if ((klass == NULL)||(source_name_ptr == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;
    
    size = (((classinfo*)klass)->sourcefile->blength);

    *source_name_ptr = (char*) heap_allocate(sizeof(char)* size,true,NULL);
    
    memcpy(*source_name_ptr,((classinfo*)klass)->sourcefile->text, size);

    return JVMTI_ERROR_NONE;
}


/* GetClassModifiers **********************************************************

   For class klass return the access flags

*******************************************************************************/

jvmtiError
GetClassModifiers (jvmtiEnv * env, jclass klass, jint * modifiers_ptr)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
      if (modifiers_ptr == NULL)
            return JVMTI_ERROR_NULL_POINTER;    

      if (!builtin_instanceof((java_objectheader*)klass,class_java_lang_Class))
            return JVMTI_ERROR_INVALID_CLASS;

      *modifiers_ptr = (jint) ((classinfo*)klass)->flags;
      
    return JVMTI_ERROR_NONE;
}


/* GetClassMethods *************************************************************

   For class klass return a count of methods and a list of method IDs

*******************************************************************************/

jvmtiError
GetClassMethods (jvmtiEnv * env, jclass klass, jint * method_count_ptr,
             jmethodID ** methods_ptr)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
    if ((klass == NULL)||(methods_ptr == NULL)||(method_count_ptr == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;

      if (!builtin_instanceof((java_objectheader*)klass,class_java_lang_Class))
            return JVMTI_ERROR_INVALID_CLASS;

    *method_count_ptr = (jint)((classinfo*)klass)->methodscount;
    *methods_ptr = (jmethodID*) 
        heap_allocate(sizeof(jmethodID) * (*method_count_ptr),true,NULL);
    
    memcpy (*methods_ptr, ((classinfo*)klass)->methods, 
            sizeof(jmethodID) * (*method_count_ptr));
    
    return JVMTI_ERROR_NONE;
}


/* GetClassFields *************************************************************

   For the class indicated by klass, return a count of fields and a list of 
   field IDs.

*******************************************************************************/

jvmtiError
GetClassFields (jvmtiEnv * env, jclass klass, jint * field_count_ptr,
            jfieldID ** fields_ptr)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
    if ((klass == NULL)||(fields_ptr == NULL)||(field_count_ptr == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;

    *field_count_ptr = (jint)((classinfo*)klass)->fieldscount;
    *fields_ptr = (jfieldID*) 
        heap_allocate(sizeof(jfieldID) * (*field_count_ptr),true,NULL);
    
    memcpy (*fields_ptr, ((classinfo*)klass)->fields, 
            sizeof(jfieldID) * (*field_count_ptr));
    
    return JVMTI_ERROR_NONE;
}


/* GetImplementedInterfaces ***************************************************

   Return the direct super-interfaces of this class.

*******************************************************************************/

jvmtiError
GetImplementedInterfaces (jvmtiEnv * env, jclass klass,
                    jint * interface_count_ptr,
                    jclass ** interfaces_ptr)
{
      int i;
      classref_or_classinfo *interfaces;
      classinfo *tmp;

      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;

      if ((interfaces_ptr == NULL) || (interface_count_ptr == NULL))
            return JVMTI_ERROR_NULL_POINTER;    

      if (!builtin_instanceof((java_objectheader*)klass,class_java_lang_Class))
            return JVMTI_ERROR_INVALID_CLASS;

            
    *interface_count_ptr = (jint)((classinfo*)klass)->interfacescount;
    *interfaces_ptr = 
            heap_allocate(sizeof(jclass*) * (*interface_count_ptr),true,NULL);

      interfaces = ((classinfo*)klass)->interfaces;
      for (i=0; i<*interface_count_ptr; i++) {
            if (IS_CLASSREF(interfaces[i]))
                  tmp = load_class_bootstrap(interfaces[i].ref->name);
            else
                  tmp = interfaces[i].cls;
            
            *interfaces_ptr[i]=tmp;
      }

    return JVMTI_ERROR_NONE;
}


/* IsInterface ****************************************************************

   Determines whether a class object reference represents an interface.

*******************************************************************************/

jvmtiError
IsInterface (jvmtiEnv * env, jclass klass, jboolean * is_interface_ptr)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
    if ((klass == NULL)||(is_interface_ptr == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;
    
    *is_interface_ptr = (((classinfo*)klass)->flags & ACC_INTERFACE);

    return JVMTI_ERROR_NONE;
}

/* IsArrayClass ***************************************************************

   Determines whether a class object reference represents an array.

*******************************************************************************/

jvmtiError
IsArrayClass (jvmtiEnv * env, jclass klass, jboolean * is_array_class_ptr)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
    if (is_array_class_ptr == NULL) 
        return JVMTI_ERROR_NULL_POINTER;

    *is_array_class_ptr = ((classinfo*)klass)->vftbl->arraydesc != NULL;

    return JVMTI_ERROR_NONE;
}


/* GetClassLoader *************************************************************

   For the class indicated by klass, return via classloader_ptr a reference to 
   the class loader for the class.

*******************************************************************************/

jvmtiError
GetClassLoader (jvmtiEnv * env, jclass klass, jobject * classloader_ptr)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
    if ((klass == NULL)||(classloader_ptr == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;

    *classloader_ptr = (jobject)((classinfo*)klass)->classloader;
 
    return JVMTI_ERROR_NONE;
}


/* GetObjectHashCode **********************************************************

   Return hash code for object object

*******************************************************************************/

jvmtiError
GetObjectHashCode (jvmtiEnv * env, jobject object, jint * hash_code_ptr)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
   
      if (hash_code_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;
      if (!builtin_instanceof(object,class_java_lang_Object))
            return JVMTI_ERROR_INVALID_OBJECT;
     
      *hash_code_ptr = Java_java_lang_VMSystem_identityHashCode(NULL,NULL,(struct java_lang_Object*)object);

    return JVMTI_ERROR_NONE;
}


/* *****************************************************************************

   

*******************************************************************************/

jvmtiError
GetObjectMonitorUsage (jvmtiEnv * env, jobject object,
                   jvmtiMonitorUsage * info_ptr)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
    CHECK_CAPABILITY(env,can_get_monitor_info)
        
  log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* GetFieldName ***************************************************************

   For the field indicated by klass and field, return the field name and 
   signature.

*******************************************************************************/

jvmtiError
GetFieldName (jvmtiEnv * env, jclass klass, jfieldID field,
            char **name_ptr, char **signature_ptr, char **generic_ptr)
{
    int size; 

    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
    if ((field == NULL)||(name_ptr == NULL)||(signature_ptr == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;
    
    size = (((fieldinfo*)field)->name->blength);
    *name_ptr = (char*) heap_allocate(sizeof(char)* size,true,NULL);    
    memcpy(*name_ptr,((fieldinfo*)field)->name->text, size);

    size = (((fieldinfo*)field)->descriptor->blength);
    *signature_ptr = (char*) heap_allocate(sizeof(char)* size,true,NULL);    
    memcpy(*signature_ptr,((fieldinfo*)field)->descriptor->text, size);

    *generic_ptr = NULL;

    return JVMTI_ERROR_NONE;
}


/* GetFieldDeclaringClass *****************************************************

   For the field indicated by klass and field return the class that defined it 
   The declaring class will either be klass, a superclass, or an implemented 
   interface.

*******************************************************************************/

jvmtiError
GetFieldDeclaringClass (jvmtiEnv * env, jclass klass, jfieldID field,
                  jclass * declaring_class_ptr)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
    /* todo: how do I find declaring class other then iterate over all fields in all classes ?*/
  log_text ("JVMTI-Call: IMPLEMENT ME!!!");
 
    return JVMTI_ERROR_NONE;
}


/* GetFieldModifiers **********************************************************

   Return access flags of field field 

*******************************************************************************/

jvmtiError
GetFieldModifiers (jvmtiEnv * env, jclass klass, jfieldID field,
               jint * modifiers_ptr)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
      if (!builtin_instanceof((java_objectheader*)klass, class_java_lang_Class))
            return JVMTI_ERROR_INVALID_OBJECT;

      if (modifiers_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;
 
      /* todo: JVMTI_ERROR_INVALID_FIELDID; */
      
      *modifiers_ptr = ((fieldinfo*)field)->flags;
      
    return JVMTI_ERROR_NONE;
}


/* IsFieldSynthetic ***********************************************************

   

*******************************************************************************/

jvmtiError
IsFieldSynthetic (jvmtiEnv * env, jclass klass, jfieldID field,
              jboolean * is_synthetic_ptr)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
    CHECK_CAPABILITY(env,can_get_synthetic_attribute)
        
  log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* GetMethodName ***************************************************************

   For the method indicated by method, return the method name via name_ptr and 
   method signature via signature_ptr.

*******************************************************************************/

jvmtiError
GetMethodName (jvmtiEnv * env, jmethodID method, char **name_ptr,
             char **signature_ptr, char **generic_ptr)
{
    methodinfo* m = (methodinfo*)method;

    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;

    if ((method == NULL) || (name_ptr == NULL) || (signature_ptr == NULL)
        || (generic_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER;

    *name_ptr = (char*)heap_allocate(m->name->blength,true,NULL);
    memcpy(*name_ptr, m->name->text, m->name->blength);

    *signature_ptr = (char*)heap_allocate(m->descriptor->blength,true,NULL);
    memcpy(*signature_ptr, m->descriptor->text, m->descriptor->blength);
    
    /* there is no generic signature attribute */
    *generic_ptr = NULL;

    return JVMTI_ERROR_NONE;
}


/* GetMethodDeclaringClass *****************************************************

  For the method indicated by method, return the class that defined it.

*******************************************************************************/

jvmtiError
GetMethodDeclaringClass (jvmtiEnv * env, jmethodID method,
                   jclass * declaring_class_ptr)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
     
    if ((method == NULL) || (declaring_class_ptr == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;
    
    *declaring_class_ptr = (jclass)((methodinfo*)method)->class;
    
    return JVMTI_ERROR_NONE;
}


/* GetMethodModifiers **********************************************************

   For the method indicated by method, return the access flags.

*******************************************************************************/

jvmtiError
GetMethodModifiers (jvmtiEnv * env, jmethodID method, jint * modifiers_ptr)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
    if ((method == NULL) || (modifiers_ptr == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;

    *modifiers_ptr = (jint) (((methodinfo*)method)->flags);

    return JVMTI_ERROR_NONE;
}


/* GetMaxLocals ****************************************************************

   For the method indicated by method, return the number of local variable slots 
   used by the method, including the local variables used to pass parameters to 
   the method on its invocation.

*******************************************************************************/

jvmtiError
GetMaxLocals (jvmtiEnv * env, jmethodID method, jint * max_ptr)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
    if ((method == NULL)||(max_ptr == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;    
    
    if (((methodinfo*)method)->flags & ACC_NATIVE)  
        return JVMTI_ERROR_NATIVE_METHOD;
   
    *max_ptr = (jint) ((methodinfo*)method)->maxlocals;

    return JVMTI_ERROR_NONE;
}



/* GetArgumentsSize ************************************************************

   Return the number of local variable slots used by the method's arguments.

*******************************************************************************/

jvmtiError
GetArgumentsSize (jvmtiEnv * env, jmethodID method, jint * size_ptr)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;

    if ((method == NULL)||(size_ptr == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;    
    
    if (((methodinfo*)method)->flags & ACC_NATIVE)  
        return JVMTI_ERROR_NATIVE_METHOD;

    *size_ptr = (jint)((methodinfo*)method)->paramcount;
    return JVMTI_ERROR_NONE;
}



/* GetLineNumberTable ***********************************************************

   Return table of source line number entries for a given method

*******************************************************************************/

jvmtiError
GetLineNumberTable (jvmtiEnv * env, jmethodID method,
                jint * entry_count_ptr, jvmtiLineNumberEntry ** table_ptr)
{
    int i;

    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
    CHECK_CAPABILITY(env,can_get_line_numbers)
   
    if ((method == NULL) || (entry_count_ptr == NULL) || (table_ptr == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;    
    if (((methodinfo*)method)->flags & ACC_NATIVE)  
        return JVMTI_ERROR_NATIVE_METHOD;
    if (((methodinfo*)method)->linenumbers == NULL) 
        return JVMTI_ERROR_ABSENT_INFORMATION;

    *entry_count_ptr= (jint)((methodinfo*)method)->linenumbercount;
    *table_ptr = (jvmtiLineNumberEntry*) heap_allocate(
        sizeof(jvmtiLineNumberEntry) * (*entry_count_ptr),true,NULL);


    for (i=0; i < *entry_count_ptr; i++) {
        (*table_ptr[i]).start_location = 
            (jlocation) method->linenumbers[i].start_pc;
        (*table_ptr[i]).line_number = 
            (jint) ((methodinfo*)method)->linenumbers[i].line_number;
    }
    
    return JVMTI_ERROR_NONE;
}


/* GetMethodLocation ***********************************************************

   For the method indicated by method, return the beginning and ending addresses 
   through start_location_ptr and end_location_ptr. In cacao this points to 
   entry point in machine code and length of machine code

*******************************************************************************/

jvmtiError
GetMethodLocation (jvmtiEnv * env, jmethodID method,
               jlocation * start_location_ptr,
               jlocation * end_location_ptr)
{
    methodinfo* m = (methodinfo*)method;

    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;

    if ((method == NULL) || (start_location_ptr == NULL) || 
        (end_location_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER;
    
    *start_location_ptr = (jlocation)m->mcode;
    *end_location_ptr = (jlocation)(m->mcode)+m->mcodelength;
    return JVMTI_ERROR_NONE;
}


/* GetLocalVariableTable *******************************************************

   Return local variable information.

*******************************************************************************/

jvmtiError
GetLocalVariableTable (jvmtiEnv * env, jmethodID method,
                   jint * entry_count_ptr,
                   jvmtiLocalVariableEntry ** table_ptr)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
    CHECK_CAPABILITY(env,can_access_local_variables)
        
  log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!");

    return JVMTI_ERROR_NONE;
}


/* GetBytecode *****************************************************************

   For the method indicated by method, return the byte codes that implement the 
   method.

*******************************************************************************/

jvmtiError
GetBytecodes (jvmtiEnv * env, jmethodID method,
            jint * bytecode_count_ptr, unsigned char **bytecodes_ptr)
{
    methodinfo* m = (methodinfo*)method;;

    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
    CHECK_CAPABILITY(env,can_get_bytecodes)
        
    if ((method == NULL) || (bytecode_count_ptr == NULL) || 
        (bytecodes_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER;

    *bytecode_count_ptr = m->jcodelength;
    *bytecodes_ptr = (unsigned char*)heap_allocate(m->jcodelength,true,NULL);
    memcpy(*bytecodes_ptr, m->jcode, m->jcodelength);

    return JVMTI_ERROR_NONE;
}


/* IsMethodNative **************************************************************

   For the method indicated by method, return a value indicating whether the 
   method is a native function

*******************************************************************************/

jvmtiError
IsMethodNative (jvmtiEnv * env, jmethodID method, jboolean * is_native_ptr)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
    
    if ((method == NULL)||(is_native_ptr == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;    

    if (((methodinfo*)method)->flags & ACC_NATIVE) 
        *is_native_ptr = JNI_TRUE;
    else
        *is_native_ptr = JNI_FALSE;

    return JVMTI_ERROR_NONE;
}


/* IsMethodSynthetic ***********************************************************

   return a value indicating whether the method is synthetic. Synthetic methods 
   are generated by the compiler but not present in the original source code.

*******************************************************************************/

jvmtiError
IsMethodSynthetic (jvmtiEnv * env, jmethodID method,
               jboolean * is_synthetic_ptr)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_get_synthetic_attribute)

  log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* GetLoadedClasses ************************************************************

   Return an array of all classes loaded in the virtual machine.

*******************************************************************************/

jvmtiError
GetLoadedClasses (jvmtiEnv * env, jint * class_count_ptr,
              jclass ** classes_ptr)
{
      int i,j;
      classcache_name_entry *cne;
      classcache_class_entry *cce;
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;

    if (class_count_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;
    if (classes_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;

      tables_lock();

      *classes_ptr = heap_allocate(sizeof(jclass*)*classcache_hash.entries,true,NULL);
      *class_count_ptr = classcache_hash.entries;
      j=0;
    /* look in every slot of the hashtable */
      for (i=0; i<classcache_hash.size; i++) { 
            cne =(classcache_name_entry*) classcache_hash.ptr[i];
            while (cne != NULL) { /* iterate over hashlink */
                  cce = cne->classes;
                  while (cce != NULL){ /* iterate over classes with same name */
                        if (cce->classobj != NULL) { /* get only loaded classes */
                              assert(j<classcache_hash.entries);
                              *classes_ptr[j]=cce->classobj;
                              j++;
                        }
                        cce = cce->next;
                  }
                  cne = cne->hashlink;
            }
      }

      tables_unlock();

    return JVMTI_ERROR_NONE;
}


/* GetClassLoaderClasses *******************************************************

   Returns an array of those classes for which this class loader has been 
   recorded as an initiating loader.

*******************************************************************************/

jvmtiError
GetClassLoaderClasses (jvmtiEnv * env, jobject initiating_loader,
                   jint * class_count_ptr, jclass ** classes_ptr)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;

/*    if (class_count_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;
        if (classes_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;*/
        
      /* behave like jdk 1.1 and make no distinction between initiating and 
         defining class loaders */
      
    return GetLoadedClasses(env, class_count_ptr, classes_ptr);
}


/* PopFrame *******************************************************************

   

*******************************************************************************/

jvmtiError
PopFrame (jvmtiEnv * env, jthread thread)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
    CHECK_CAPABILITY(env,can_pop_frame)
        
            log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* RedefineClasses ************************************************************

   

*******************************************************************************/

jvmtiError
RedefineClasses (jvmtiEnv * env, jint class_count,
             const jvmtiClassDefinition * class_definitions)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_redefine_classes)    
      CHECK_CAPABILITY(env,can_redefine_any_class)
  log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* GetVersionNumber ***********************************************************

   Return the JVM TI version identifier.   

*******************************************************************************/

jvmtiError
GetVersionNumber (jvmtiEnv * env, jint * version_ptr)
{
    if (version_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;

    *version_ptr = JVMTI_VERSION_1_0;
    
    return JVMTI_ERROR_NONE;
}


/* GetCapabilities ************************************************************

   Returns the optional JVM TI features which this environment currently 
   possesses.

*******************************************************************************/

jvmtiError
GetCapabilities (jvmtiEnv * env, jvmtiCapabilities * capabilities_ptr)
{
    if (capabilities_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;

    memcpy(capabilities_ptr, &(((environment*) env)->capabilities), sizeof(JVMTI_Capabilities));

    return JVMTI_ERROR_NONE;
}


/* *****************************************************************************

   

*******************************************************************************/

jvmtiError
GetSourceDebugExtension (jvmtiEnv * env, jclass klass,
                   char **source_debug_extension_ptr)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_get_source_debug_extension)
        
    log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* IsMethodObsolete ************************************************************

   Determine if a method ID refers to an obsolete method version. 

*******************************************************************************/

jvmtiError
IsMethodObsolete (jvmtiEnv * env, jmethodID method,
              jboolean * is_obsolete_ptr)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_redefine_classes)        

    log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* *****************************************************************************

   

*******************************************************************************/

jvmtiError
SuspendThreadList (jvmtiEnv * env, jint request_count,
               const jthread * request_list, jvmtiError * results)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
    CHECK_CAPABILITY(env,can_suspend)
        
  log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* *****************************************************************************

   

*******************************************************************************/

jvmtiError
ResumeThreadList (jvmtiEnv * env, jint request_count,
              const jthread * request_list, jvmtiError * results)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
    CHECK_CAPABILITY(env,can_suspend)
        
  log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* GetStackTrace **************************************************************

   Get information about the stack of a thread

*******************************************************************************/

jvmtiError
GetStackTrace (jvmtiEnv * env, jthread thread, jint start_depth,
             jint max_frame_count, jvmtiFrameInfo * frame_buffer,
             jint * count_ptr)
{
      stackTraceBuffer* trace;
      jvmtiError er;
      int i,j;

      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
    
      if(!builtin_instanceof(thread,class_java_lang_Thread))
            return JVMTI_ERROR_INVALID_THREAD;

      CHECK_THREAD_IS_ALIVE(thread);

      if((count_ptr == NULL)||(frame_buffer == NULL)) 
            return JVMTI_ERROR_NULL_POINTER;

      if (max_frame_count <0) return JVMTI_ERROR_ILLEGAL_ARGUMENT;

      er = getcacaostacktrace(&trace, thread);
      if (er==JVMTI_ERROR_NONE) return er;

      if ((trace->size >= start_depth) || ((trace->size * -1) > start_depth)) 
            return JVMTI_ERROR_ILLEGAL_ARGUMENT;
      
      for (i=start_depth, j=0;i<trace->size;i++,j++) {
            frame_buffer[j].method = (jmethodID)trace[i].start->method;
        /* todo: location MachinePC not avilable - Linenumber not expected */
            frame_buffer[j].location = 0;
      }
      
    return JVMTI_ERROR_NONE;
}


/* GetThreadListStackTraces ***************************************************

   Get information about the stacks of the supplied threads.

*******************************************************************************/

jvmtiError
GetThreadListStackTraces (jvmtiEnv * env, jint thread_count,
                    const jthread * thread_list,
                    jint max_frame_count,
                    jvmtiStackInfo ** stack_info_ptr)
{
      int i;
      jvmtiError er;
      
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
      if ((stack_info_ptr == NULL)||(thread_list == NULL)) 
            return JVMTI_ERROR_NULL_POINTER;

      if (thread_count < 0) return JVMTI_ERROR_ILLEGAL_ARGUMENT;

      if (max_frame_count < 0) return JVMTI_ERROR_ILLEGAL_ARGUMENT;

      *stack_info_ptr = (jvmtiStackInfo*) 
            heap_allocate(sizeof(jvmtiStackInfo) * thread_count, true, NULL);

      for(i=0; i<thread_count; i++) { /* fill in stack info sturcture array */
            (*stack_info_ptr)[i].thread=thread_list[i];
            GetThreadState(env,thread_list[i],&((*stack_info_ptr)[i].state));
            (*stack_info_ptr)[i].frame_buffer = 
                  heap_allocate(sizeof(jvmtiFrameInfo) * max_frame_count,true,NULL);
            er = GetStackTrace(env,thread_list[i],0,max_frame_count,
                                       (*stack_info_ptr)[i].frame_buffer,
                                       &((*stack_info_ptr)[i].frame_count));

            if (er != JVMTI_ERROR_NONE) return er;
      }

    return JVMTI_ERROR_NONE;
}


/* GetAllStackTraces **********************************************************

   Get stack traces of all live threads

*******************************************************************************/

jvmtiError
GetAllStackTraces (jvmtiEnv * env, jint max_frame_count,
               jvmtiStackInfo ** stack_info_ptr, jint * thread_count_ptr)
{
      jthread *threads_ptr;
      jvmtiError er;

      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
    
      if (thread_count_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;
    
      /* todo: all threads have to be suspended */ 

      if (JVMTI_ERROR_NONE!=GetAllThreads(env,thread_count_ptr,&threads_ptr))
            return JVMTI_ERROR_INTERNAL;

      GetThreadListStackTraces(env, *thread_count_ptr, threads_ptr,
                                           max_frame_count, stack_info_ptr);

      /* todo: resume all threads have to be suspended */ 
      if (er != JVMTI_ERROR_NONE) return er;

    return JVMTI_ERROR_NONE;
}


/* GetThreadLocalStorage ******************************************************

   Get the value of the JVM TI thread-local storage.

*******************************************************************************/

jvmtiError
GetThreadLocalStorage (jvmtiEnv * env, jthread thread, void **data_ptr)
{
      jvmtiThreadLocalStorage *tls;

      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;

      if(thread == NULL)
            thread = (jthread) THREADOBJECT;
      else {
            if (!builtin_instanceof(thread,class_java_lang_Thread)) 
                  return JVMTI_ERROR_INVALID_THREAD;
            CHECK_THREAD_IS_ALIVE(thread);
      }

      if(data_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;

      tls = ((environment*)env)->tls;
      while ((tls->thread != thread) && (tls != NULL)) {
            tls = tls->next;
      }
      
      if (tls == NULL) return JVMTI_ERROR_INTERNAL; /* env/thread pair not found */
      
      *data_ptr = tls->data;
      
    return JVMTI_ERROR_NONE;
}


/* SetThreadLocalStorage *******************************************************

   Stores a pointer value associated with each environment-thread pair. The 
   value is NULL unless set with this function. Agents can allocate memory in 
   which they store thread specific information

*******************************************************************************/

jvmtiError
SetThreadLocalStorage (jvmtiEnv * jenv, jthread thread, const void *data)
{
      jvmtiThreadLocalStorage *tls, *pre;
      environment* env = (environment*)jenv;

      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
      if(thread == NULL)
            thread = (jthread) THREADOBJECT;
      else {
            if (!builtin_instanceof(thread,class_java_lang_Thread)) 
                  return JVMTI_ERROR_INVALID_THREAD;
            CHECK_THREAD_IS_ALIVE(thread);
      }
      
      if (env->tls == NULL) {
            tls = env->tls = heap_allocate(sizeof(jvmtiThreadLocalStorage),true,NULL);
      } else {
            tls = env->tls;
            while ((tls->thread != thread) && (tls->next != NULL)) {
                  tls = tls->next;
            }
            if (tls->thread != thread) {
                  tls->next = heap_allocate(sizeof(jvmtiThreadLocalStorage),true,NULL);
                  tls = tls->next;
            }
      }
      
      if (data != NULL) {
            tls->data = (void*)data;
      } else { 
            /* remove current tls */
            pre = env->tls;
            while (pre->next == tls) pre = pre->next;
            pre->next = tls->next;
      }
    return JVMTI_ERROR_NONE;
}


/* *****************************************************************************

   

*******************************************************************************/

jvmtiError
GetTag (jvmtiEnv * env, jobject object, jlong * tag_ptr)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_tag_objects)
    
  log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}

/* *****************************************************************************

   

*******************************************************************************/

jvmtiError
SetTag (jvmtiEnv * env, jobject object, jlong tag)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_tag_objects)
        
  log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* ForceGarbageCollection *****************************************************

   Force boehm-gc to perform a garbage collection

*******************************************************************************/

jvmtiError
ForceGarbageCollection (jvmtiEnv * env)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;

      gc_call();        

    return JVMTI_ERROR_NONE;
}


/* IterateOverObjectsReachableFromObject **************************************

   

*******************************************************************************/

jvmtiError
IterateOverObjectsReachableFromObject (jvmtiEnv * env, jobject object,
                               jvmtiObjectReferenceCallback
                               object_reference_callback,
                               void *user_data)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_tag_objects)
        
  log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* IterateOverReachableObjects ************************************************

   

*******************************************************************************/

jvmtiError
IterateOverReachableObjects (jvmtiEnv * env, jvmtiHeapRootCallback
                       heap_root_callback,
                       jvmtiStackReferenceCallback
                       stack_ref_callback,
                       jvmtiObjectReferenceCallback
                       object_ref_callback, void *user_data)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_tag_objects)
    
  log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* IterateOverHeap ************************************************************

   

*******************************************************************************/

jvmtiError
IterateOverHeap (jvmtiEnv * env, jvmtiHeapObjectFilter object_filter,
             jvmtiHeapObjectCallback heap_object_callback,
             void *user_data)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_tag_objects)
    
  log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* IterateOverInstancesOfClass ************************************************

   

*******************************************************************************/

jvmtiError
IterateOverInstancesOfClass (jvmtiEnv * env, jclass klass,
                       jvmtiHeapObjectFilter object_filter,
                       jvmtiHeapObjectCallback
                       heap_object_callback, void *user_data)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_tag_objects)
   
  log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* *****************************************************************************

   

*******************************************************************************/

jvmtiError
GetObjectsWithTags (jvmtiEnv * env, jint tag_count, const jlong * tags,
                jint * count_ptr, jobject ** object_result_ptr,
                jlong ** tag_result_ptr)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_tag_objects)
        
  log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* SetJNIFunctionTable **********************************************************

   Set the JNI function table in all current and future JNI environments

*******************************************************************************/

jvmtiError
SetJNIFunctionTable (jvmtiEnv * env,
                 const jniNativeInterface * function_table)
{ 
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;;
    
    if (function_table == NULL) return JVMTI_ERROR_NULL_POINTER;
    ptr_env = (void*)heap_allocate(sizeof(jniNativeInterface),true,NULL);
    memcpy(ptr_env, function_table, sizeof(jniNativeInterface));
    return JVMTI_ERROR_NONE;
}


/* GetJNIFunctionTable *********************************************************

   Get the JNI function table. The JNI function table is copied into allocated 
   memory.

*******************************************************************************/

jvmtiError
GetJNIFunctionTable (jvmtiEnv * env, jniNativeInterface ** function_table)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;

    if (function_table == NULL) return JVMTI_ERROR_NULL_POINTER;
    *function_table = (jniNativeInterface*)
        heap_allocate(sizeof(jniNativeInterface),true,NULL);
    memcpy(*function_table, ptr_env, sizeof(jniNativeInterface));
    return JVMTI_ERROR_NONE;
}


/* SetEventCallbacks **********************************************************

   Set the functions to be called for each event. The callbacks are specified 
   by supplying a replacement function table.

*******************************************************************************/

jvmtiError
SetEventCallbacks (jvmtiEnv * env,
               const jvmtiEventCallbacks * callbacks,
               jint size_of_callbacks)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_ONLOAD)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;

    if (size_of_callbacks < 0) return JVMTI_ERROR_ILLEGAL_ARGUMENT;
    
    if (callbacks == NULL) { /* remove the existing callbacks */
        memset(&(((environment* )env)->callbacks), 0, 
                     sizeof(jvmtiEventCallbacks));
    }

    memcpy (&(((environment* )env)->callbacks),callbacks,size_of_callbacks);

    return JVMTI_ERROR_NONE;
}


/* GenerateEvents *************************************************************

   Generate events (CompiledMethodLoad and DynamicCodeGenerated) to represent 
   the current state of the VM.

*******************************************************************************/

jvmtiError
GenerateEvents (jvmtiEnv * env, jvmtiEvent event_type)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
  log_text ("JVMTI-Call: IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}


/* GetExtensionFunctions ******************************************************

   Returns the set of extension functions.

*******************************************************************************/

jvmtiError
GetExtensionFunctions (jvmtiEnv * env, jint * extension_count_ptr,
                   jvmtiExtensionFunctionInfo ** extensions)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_ONLOAD)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
    if ((extension_count_ptr== NULL)||(extensions == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;

    /* cacao has no extended functions yet */
    *extension_count_ptr = 0;

    return JVMTI_ERROR_NONE;
}


/* GetExtensionEvents *********************************************************

   Returns the set of extension events.

*******************************************************************************/

jvmtiError
GetExtensionEvents (jvmtiEnv * env, jint * extension_count_ptr,
                jvmtiExtensionEventInfo ** extensions)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_ONLOAD)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
    if ((extension_count_ptr== NULL)||(extensions == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;

    /* cacao has no extended events yet */
    *extension_count_ptr = 0;

    return JVMTI_ERROR_NONE;
}


/* SetExtensionEventCallback **************************************************

   Sets the callback function for an extension event and enables the event.

*******************************************************************************/

jvmtiError
SetExtensionEventCallback (jvmtiEnv * env, jint extension_event_index,
                     jvmtiExtensionEvent callback)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_ONLOAD)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;

    /* cacao has no extended events yet */
    return JVMTI_ERROR_ILLEGAL_ARGUMENT;
}


/* DisposeEnvironment **********************************************************

   Shutdown a JVM TI connection created with JNI GetEnv.

*******************************************************************************/

jvmtiError
DisposeEnvironment (jvmtiEnv * env)
{
      environment* cacao_env = (environment*)env;
      environment* tenvs = envs;
    memset(&((cacao_env)->events[0]),0,sizeof(jvmtiEventModeLL)*
               (JVMTI_EVENT_END_ENUM-JVMTI_EVENT_START_ENUM));
    (cacao_env)->EnvironmentLocalStorage = NULL;
      
      if (tenvs!=cacao_env) {
            while (tenvs->next != cacao_env) {
                  tenvs = tenvs->next;
            }
            tenvs->next = cacao_env->next;
      } else
            envs = NULL;

    /* let Boehm GC do the rest */
    return JVMTI_ERROR_NONE;
}


/* GetErrorName ***************************************************************

   Return the symbolic name for an error code.

*******************************************************************************/

#define COPY_RESPONSE(name_ptr,str) *name_ptr = (char*) heap_allocate(sizeof(str),true,NULL); \
                                    memcpy(*name_ptr, &str, sizeof(str)); \
                                    break

jvmtiError
GetErrorName (jvmtiEnv * env, jvmtiError error, char **name_ptr)
{
    if (name_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;

    switch (error) {
    case JVMTI_ERROR_NONE : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_NONE");
    case JVMTI_ERROR_NULL_POINTER : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_NULL_POINTER"); 
    case JVMTI_ERROR_OUT_OF_MEMORY : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_OUT_OF_MEMORY");
    case JVMTI_ERROR_ACCESS_DENIED : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_ACCESS_DENIED");
    case JVMTI_ERROR_UNATTACHED_THREAD : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_UNATTACHED_THREAD");
    case JVMTI_ERROR_INVALID_ENVIRONMENT : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_ENVIRONMENT"); 
    case JVMTI_ERROR_WRONG_PHASE : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_WRONG_PHASE");
    case JVMTI_ERROR_INTERNAL : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INTERNAL");
    case JVMTI_ERROR_INVALID_PRIORITY : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_PRIORITY");
    case JVMTI_ERROR_THREAD_NOT_SUSPENDED : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_THREAD_NOT_SUSPENDED");
    case JVMTI_ERROR_THREAD_SUSPENDED : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_THREAD_SUSPENDED");
    case JVMTI_ERROR_THREAD_NOT_ALIVE : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_THREAD_NOT_ALIVE");
    case JVMTI_ERROR_CLASS_NOT_PREPARED : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_CLASS_NOT_PREPARED");
    case JVMTI_ERROR_NO_MORE_FRAMES : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_NO_MORE_FRAMES");
    case JVMTI_ERROR_OPAQUE_FRAME : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_OPAQUE_FRAME");
    case JVMTI_ERROR_DUPLICATE : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_DUPLICATE");
    case JVMTI_ERROR_NOT_FOUND : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_NOT_FOUND");
    case JVMTI_ERROR_NOT_MONITOR_OWNER : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_NOT_MONITOR_OWNER");
    case JVMTI_ERROR_INTERRUPT : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INTERRUPT");
    case JVMTI_ERROR_UNMODIFIABLE_CLASS : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_UNMODIFIABLE_CLASS");
    case JVMTI_ERROR_NOT_AVAILABLE : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_NOT_AVAILABLE");
    case JVMTI_ERROR_ABSENT_INFORMATION : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_ABSENT_INFORMATION");
    case JVMTI_ERROR_INVALID_EVENT_TYPE : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_EVENT_TYPE");
    case JVMTI_ERROR_NATIVE_METHOD : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_NATIVE_METHOD");
    case JVMTI_ERROR_INVALID_THREAD : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_THREAD");
    case JVMTI_ERROR_INVALID_FIELDID : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_FIELDID");
    case JVMTI_ERROR_INVALID_METHODID : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_METHODID");
    case JVMTI_ERROR_INVALID_LOCATION : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_LOCATION");
    case JVMTI_ERROR_INVALID_OBJECT : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_OBJECT");
    case JVMTI_ERROR_INVALID_CLASS : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_CLASS");
    case JVMTI_ERROR_TYPE_MISMATCH : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_TYPE_MISMATCH");
    case JVMTI_ERROR_INVALID_SLOT : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_SLOT");
    case JVMTI_ERROR_MUST_POSSESS_CAPABILITY : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_MUST_POSSESS_CAPABILITY");
    case JVMTI_ERROR_INVALID_THREAD_GROUP : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_THREAD_GROUP");
    case JVMTI_ERROR_INVALID_MONITOR : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_MONITOR");
    case JVMTI_ERROR_ILLEGAL_ARGUMENT : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_ILLEGAL_ARGUMENT");
    case JVMTI_ERROR_INVALID_TYPESTATE : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_TYPESTATE");
    case JVMTI_ERROR_UNSUPPORTED_VERSION : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_UNSUPPORTED_VERSION");
    case JVMTI_ERROR_INVALID_CLASS_FORMAT : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_CLASS_FORMAT");
    case JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION");
    case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED");
    case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED");
    case JVMTI_ERROR_FAILS_VERIFICATION : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_FAILS_VERIFICATION");
    case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED");
    case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED");
    case JVMTI_ERROR_NAMES_DONT_MATCH : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_NAMES_DONT_MATCH");
    case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED");
    case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED : 
        COPY_RESPONSE (name_ptr, "JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED");
    default:
        return JVMTI_ERROR_ILLEGAL_ARGUMENT;
    }
    return JVMTI_ERROR_NONE;
}

/* GetJLocationFormat **********************************************************

   This function describes the representation of jlocation used in this VM.

*******************************************************************************/

jvmtiError
GetJLocationFormat (jvmtiEnv * env, jvmtiJlocationFormat * format_ptr)
{
    *format_ptr = JVMTI_JLOCATION_MACHINEPC;
    return JVMTI_ERROR_NONE;
}


/* GetSystemProperties ********************************************************

   The list of VM system property keys which may be used with GetSystemProperty 
   is returned.

*******************************************************************************/

jvmtiError
GetSystemProperties (jvmtiEnv * env, jint * count_ptr, char ***property_ptr)
{
    jmethodID mid;
    jmethodID moremid;
    classinfo *sysclass, *propclass, *enumclass;
    java_objectheader *sysprop, *keys, *obj;
    char* ch;
    int i;

    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_ONLOAD)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;

    if ((count_ptr == NULL) || (property_ptr == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;

    sysclass = load_class_from_sysloader(
        utf_new_char_classname ("java/lang/System"));

    if (!sysclass) throw_main_exception_exit();

    mid = class_resolvemethod(sysclass, 
                              utf_new_char("getProperties"),
                              utf_new_char("()Ljava/util/Properties;"));
    if (!mid) throw_main_exception_exit();


    sysprop = asm_calljavafunction(mid, sysclass, NULL, NULL, NULL);
    if (!sysprop) throw_main_exception_exit();

    propclass = sysprop->vftbl->class;

    mid = class_resolvemethod(propclass, 
                              utf_new_char("size"),
                              utf_new_char("()I"));
    if (!mid) throw_main_exception_exit();

    *count_ptr = 
        JNI_JNIEnvTable.CallIntMethod(NULL, sysprop, mid);
    *property_ptr = heap_allocate(sizeof(char*) * (*count_ptr) ,true,NULL);

    mid = class_resolvemethod(propclass, 
                              utf_new_char("keys"),
                              utf_new_char("()Ljava/util/Enumeration;"));
    if (!mid) throw_main_exception_exit();

    keys = JNI_JNIEnvTable.CallObjectMethod(NULL, sysprop, mid);
    enumclass = keys->vftbl->class;
        
    moremid = class_resolvemethod(enumclass, 
                                  utf_new_char("hasMoreElements"),
                                  utf_new_char("()Z"));
    if (!moremid) throw_main_exception_exit();

    mid = class_resolvemethod(propclass, 
                              utf_new_char("nextElement"),
                              utf_new_char("()Ljava/lang/Object;"));
    if (!mid) throw_main_exception_exit();

    i = 0;
    while (JNI_JNIEnvTable.CallBooleanMethod(NULL,keys,(jmethodID)moremid)) {
        obj = JNI_JNIEnvTable.CallObjectMethod(NULL, keys, mid);
        ch = javastring_tochar(obj);
        *property_ptr[i] = heap_allocate(sizeof(char*) * strlen (ch),true,NULL);
        memcpy(*property_ptr[i], ch, strlen (ch));
        MFREE(ch,char,strlen(ch)+1);
        i++;
    }

    return JVMTI_ERROR_NONE;
}


/* GetSystemProperty **********************************************************

   Return a VM system property value given the property key.

*******************************************************************************/

jvmtiError
GetSystemProperty (jvmtiEnv * env, const char *property, char **value_ptr)
{
    jmethodID mid;
    classinfo *sysclass, *propclass;
    java_objectheader *sysprop, *obj;
    char* ch;

    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_ONLOAD)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;

    if ((value_ptr == NULL) || (property == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;

    sysclass = load_class_from_sysloader(utf_new_char("java/lang/System"));
    if (!sysclass) throw_main_exception_exit();

    mid = class_resolvemethod(sysclass, 
                              utf_new_char("getProperties"),
                              utf_new_char("()Ljava/util/Properties;"));
    if (!mid) throw_main_exception_exit();

    sysprop = JNI_JNIEnvTable.CallStaticObjectMethod(NULL, (jclass)sysclass, mid);

    propclass = sysprop->vftbl->class;

    mid = class_resolvemethod(propclass, 
                              utf_new_char("getProperty"),
                              utf_new_char("(Ljava/lang/String;)Ljava/lang/String;"));
    if (!mid) throw_main_exception_exit();

    obj = (java_objectheader*)JNI_JNIEnvTable.CallObjectMethod(
        NULL, sysprop, mid, javastring_new_char(property));
    if (!obj) return JVMTI_ERROR_NOT_AVAILABLE;

    ch = javastring_tochar(obj);
    *value_ptr = heap_allocate(sizeof(char*) * strlen (ch),true,NULL);
    memcpy(*value_ptr, ch, strlen (ch));
    MFREE(ch,char,strlen(ch)+1);       

    return JVMTI_ERROR_NONE;
}


/* SetSystemProperty **********************************************************

   Set a VM system property value.

*******************************************************************************/

jvmtiError
SetSystemProperty (jvmtiEnv * env, const char *property, const char *value)
{
    jmethodID mid;
    classinfo *sysclass, *propclass;
    java_objectheader *sysprop;

    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE_END;
        
    if (property == NULL) return JVMTI_ERROR_NULL_POINTER;
    if (value == NULL) return JVMTI_ERROR_NOT_AVAILABLE;

    sysclass = load_class_from_sysloader(utf_new_char("java/lang/System"));
    if (!sysclass) throw_main_exception_exit();

    mid = class_resolvemethod(sysclass, 
                              utf_new_char("getProperties"),
                              utf_new_char("()Ljava/util/Properties;"));
    if (!mid) throw_main_exception_exit();

    sysprop = JNI_JNIEnvTable.CallStaticObjectMethod(NULL, (jclass)sysclass, mid);

    propclass = sysprop->vftbl->class;

    mid = class_resolvemethod(propclass, 
                              utf_new_char("setProperty"),
                              utf_new_char("(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"));
    if (!mid) throw_main_exception_exit();

    JNI_JNIEnvTable.CallObjectMethod(
        NULL, sysprop, mid, javastring_new_char(property),javastring_new_char(value));
    
    return JVMTI_ERROR_NONE;
}

/* GetPhase ********************************************************************

   Return the current phase of VM execution

*******************************************************************************/

jvmtiError
GetPhase (jvmtiEnv * env, jvmtiPhase * phase_ptr)
{
    if (phase_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;
    
    *phase_ptr = phase;

    return JVMTI_ERROR_NONE;
}

/* GetCurrentThreadCpuTimerInfo ************************************************

   

*******************************************************************************/

jvmtiError
GetCurrentThreadCpuTimerInfo (jvmtiEnv * env, jvmtiTimerInfo * info_ptr)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_get_current_thread_cpu_time)     

  log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!");

    return JVMTI_ERROR_NONE;
}

/* GetCurrentThreadCpuTime ****************************************************

   

*******************************************************************************/

jvmtiError
GetCurrentThreadCpuTime (jvmtiEnv * env, jlong * nanos_ptr)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_get_current_thread_cpu_time)     
        
  log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}

/* GetThreadCpuTimerInfo ******************************************************

   

*******************************************************************************/

jvmtiError
GetThreadCpuTimerInfo (jvmtiEnv * env, jvmtiTimerInfo * info_ptr)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_get_thread_cpu_time)
    
  log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}

/* GetThreadCpuTime ***********************************************************

   

*******************************************************************************/

jvmtiError
GetThreadCpuTime (jvmtiEnv * env, jthread thread, jlong * nanos_ptr)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
      CHECK_CAPABILITY(env,can_get_thread_cpu_time)        
  log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!");
    return JVMTI_ERROR_NONE;
}

/* GetTimerInfo ***************************************************************

   Get information about the GetTime timer.    

*******************************************************************************/

jvmtiError
GetTimerInfo (jvmtiEnv * env, jvmtiTimerInfo * info_ptr)
{
    if (info_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;

    info_ptr->max_value = !0x0;
      info_ptr->may_skip_forward = true;
      info_ptr->may_skip_backward = true;
      info_ptr->kind = JVMTI_TIMER_TOTAL_CPU;
   
    return JVMTI_ERROR_NONE;
}

/* GetTime ********************************************************************

   Return the current value of the system timer, in nanoseconds

*******************************************************************************/

jvmtiError
GetTime (jvmtiEnv * env, jlong * nanos_ptr)
{
    /* Note: this implementation copied directly from Japhar's, by Chris Toshok. */
    struct timeval tp;
    
    if (nanos_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;

    if (gettimeofday (&tp, NULL) == -1)
        JNI_JNIEnvTable.FatalError (NULL, "gettimeofday call failed.");
    
    *nanos_ptr = (jlong) tp.tv_sec;
    *nanos_ptr *= 1000;
    *nanos_ptr += (tp.tv_usec / 1000);

    return JVMTI_ERROR_NONE;
}

/* GetPotentialCapabilities ***************************************************

   Returns the JVM TI features that can potentially be possessed by this 
   environment at this time.

*******************************************************************************/

jvmtiError
GetPotentialCapabilities (jvmtiEnv * env,
                    jvmtiCapabilities * capabilities_ptr)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_ONLOAD)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
    if (capabilities_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;

    memcpy(capabilities_ptr, &JVMTI_Capabilities, sizeof(JVMTI_Capabilities));

    return JVMTI_ERROR_NONE;
}


#define CHECK_ADD_CAPABILITY(env,CAN)      \
        if ((capabilities_ptr->CAN == 1) && \
           (JVMTI_Capabilities.CAN == 0))   \
           return JVMTI_ERROR_NOT_AVAILABLE; \
        env->capabilities.CAN = 1;

/* AddCapabilities ************************************************************

   Set new capabilities by adding the capabilities pointed to by 
   capabilities_ptr. All previous capabilities are retained.

*******************************************************************************/

jvmtiError
AddCapabilities (jvmtiEnv * env, const jvmtiCapabilities * capabilities_ptr)
{
    environment* cacao_env;

    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_ONLOAD)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
    if ((env == NULL) || (capabilities_ptr == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;
    
    cacao_env = (environment*)env;
    
    CHECK_ADD_CAPABILITY(cacao_env,can_tag_objects)
    CHECK_ADD_CAPABILITY(cacao_env,can_generate_field_modification_events)
    CHECK_ADD_CAPABILITY(cacao_env,can_generate_field_access_events)
    CHECK_ADD_CAPABILITY(cacao_env,can_get_bytecodes)
    CHECK_ADD_CAPABILITY(cacao_env,can_get_synthetic_attribute)
    CHECK_ADD_CAPABILITY(cacao_env,can_get_owned_monitor_info)
    CHECK_ADD_CAPABILITY(cacao_env,can_get_current_contended_monitor)
    CHECK_ADD_CAPABILITY(cacao_env,can_get_monitor_info)
    CHECK_ADD_CAPABILITY(cacao_env,can_pop_frame)
    CHECK_ADD_CAPABILITY(cacao_env,can_redefine_classes)
    CHECK_ADD_CAPABILITY(cacao_env,can_signal_thread)
    CHECK_ADD_CAPABILITY(cacao_env,can_get_source_file_name)
    CHECK_ADD_CAPABILITY(cacao_env,can_get_line_numbers)
    CHECK_ADD_CAPABILITY(cacao_env,can_get_source_debug_extension)
    CHECK_ADD_CAPABILITY(cacao_env,can_access_local_variables)
    CHECK_ADD_CAPABILITY(cacao_env,can_maintain_original_method_order)
    CHECK_ADD_CAPABILITY(cacao_env,can_generate_single_step_events)
    CHECK_ADD_CAPABILITY(cacao_env,can_generate_exception_events)
    CHECK_ADD_CAPABILITY(cacao_env,can_generate_frame_pop_events)
    CHECK_ADD_CAPABILITY(cacao_env,can_generate_breakpoint_events)
    CHECK_ADD_CAPABILITY(cacao_env,can_suspend)
    CHECK_ADD_CAPABILITY(cacao_env,can_redefine_any_class)
    CHECK_ADD_CAPABILITY(cacao_env,can_get_current_thread_cpu_time)
    CHECK_ADD_CAPABILITY(cacao_env,can_get_thread_cpu_time)
    CHECK_ADD_CAPABILITY(cacao_env,can_generate_method_entry_events)
    CHECK_ADD_CAPABILITY(cacao_env,can_generate_method_exit_events)
    CHECK_ADD_CAPABILITY(cacao_env,can_generate_all_class_hook_events)
    CHECK_ADD_CAPABILITY(cacao_env,can_generate_compiled_method_load_events)
    CHECK_ADD_CAPABILITY(cacao_env,can_generate_monitor_events)
    CHECK_ADD_CAPABILITY(cacao_env,can_generate_vm_object_alloc_events)
    CHECK_ADD_CAPABILITY(cacao_env,can_generate_native_method_bind_events)
    CHECK_ADD_CAPABILITY(cacao_env,can_generate_garbage_collection_events)
    CHECK_ADD_CAPABILITY(cacao_env,can_generate_object_free_events)


    return JVMTI_ERROR_NONE;    
}


#define CHECK_DEL_CAPABILITY(env,CAN)      \
        if (capabilities_ptr->CAN == 1) \
           env->capabilities.CAN = 0;

/* RelinquishCapabilities *****************************************************

   Relinquish the capabilities pointed to by capabilities_ptr.

*******************************************************************************/

jvmtiError
RelinquishCapabilities (jvmtiEnv * env,
                  const jvmtiCapabilities * capabilities_ptr)
{
    environment* cacao_env;
    
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_ONLOAD)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
        
    if ((env == NULL) || (capabilities_ptr == NULL)) 
        return JVMTI_ERROR_NULL_POINTER;

    cacao_env = (environment*)env;

    CHECK_DEL_CAPABILITY(cacao_env,can_tag_objects)
    CHECK_DEL_CAPABILITY(cacao_env,can_generate_field_modification_events)
    CHECK_DEL_CAPABILITY(cacao_env,can_generate_field_access_events)
    CHECK_DEL_CAPABILITY(cacao_env,can_get_bytecodes)
    CHECK_DEL_CAPABILITY(cacao_env,can_get_synthetic_attribute)
    CHECK_DEL_CAPABILITY(cacao_env,can_get_owned_monitor_info)
    CHECK_DEL_CAPABILITY(cacao_env,can_get_current_contended_monitor)
    CHECK_DEL_CAPABILITY(cacao_env,can_get_monitor_info)
    CHECK_DEL_CAPABILITY(cacao_env,can_pop_frame)
    CHECK_DEL_CAPABILITY(cacao_env,can_redefine_classes)
    CHECK_DEL_CAPABILITY(cacao_env,can_signal_thread)
    CHECK_DEL_CAPABILITY(cacao_env,can_get_source_file_name)
    CHECK_DEL_CAPABILITY(cacao_env,can_get_line_numbers)
    CHECK_DEL_CAPABILITY(cacao_env,can_get_source_debug_extension)
    CHECK_DEL_CAPABILITY(cacao_env,can_access_local_variables)
    CHECK_DEL_CAPABILITY(cacao_env,can_maintain_original_method_order)
    CHECK_DEL_CAPABILITY(cacao_env,can_generate_single_step_events)
    CHECK_DEL_CAPABILITY(cacao_env,can_generate_exception_events)
    CHECK_DEL_CAPABILITY(cacao_env,can_generate_frame_pop_events)
    CHECK_DEL_CAPABILITY(cacao_env,can_generate_breakpoint_events)
    CHECK_DEL_CAPABILITY(cacao_env,can_suspend)
    CHECK_DEL_CAPABILITY(cacao_env,can_redefine_any_class)
    CHECK_DEL_CAPABILITY(cacao_env,can_get_current_thread_cpu_time)
    CHECK_DEL_CAPABILITY(cacao_env,can_get_thread_cpu_time)
    CHECK_DEL_CAPABILITY(cacao_env,can_generate_method_entry_events)
    CHECK_DEL_CAPABILITY(cacao_env,can_generate_method_exit_events)
    CHECK_DEL_CAPABILITY(cacao_env,can_generate_all_class_hook_events)
    CHECK_DEL_CAPABILITY(cacao_env,can_generate_compiled_method_load_events)
    CHECK_DEL_CAPABILITY(cacao_env,can_generate_monitor_events)
    CHECK_DEL_CAPABILITY(cacao_env,can_generate_vm_object_alloc_events)
    CHECK_DEL_CAPABILITY(cacao_env,can_generate_native_method_bind_events)
    CHECK_DEL_CAPABILITY(cacao_env,can_generate_garbage_collection_events)
    CHECK_DEL_CAPABILITY(cacao_env,can_generate_object_free_events)

    return JVMTI_ERROR_NONE;
}

/* *****************************************************************************

   

*******************************************************************************/

jvmtiError
GetAvailableProcessors (jvmtiEnv * env, jint * processor_count_ptr)
{
      CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;
    
      if (processor_count_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;

      log_text ("GetAvailableProcessors IMPLEMENT ME!!!");
      
      *processor_count_ptr = 1; /* where do I get this ?*/
      
    return JVMTI_ERROR_NONE;
}

/* GetEnvironmentLocalStorage **************************************************

   Called by the agent to get the value of the JVM TI environment-local storage.

*******************************************************************************/

jvmtiError
GetEnvironmentLocalStorage (jvmtiEnv * env, void **data_ptr)
{
    if ((env == NULL) || (data_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER;

    *data_ptr = ((environment*)env)->EnvironmentLocalStorage;

    return JVMTI_ERROR_NONE;
}

/* SetEnvironmentLocalStorage **************************************************

   The VM stores a pointer value associated with each environment. Agents can 
   allocate memory in which they store environment specific information.

*******************************************************************************/

jvmtiError
SetEnvironmentLocalStorage (jvmtiEnv * env, const void *data)
{
    if (env == NULL) return JVMTI_ERROR_NULL_POINTER;

    ((environment*)env)->EnvironmentLocalStorage = (void*) data;

    return JVMTI_ERROR_NONE;
}

/* AddToBootstrapClassLoaderSearch ********************************************

   After the bootstrap class loader unsuccessfully searches for a class, the 
   specified platform-dependent search path segment will be searched as well.

*******************************************************************************/

jvmtiError
AddToBootstrapClassLoaderSearch (jvmtiEnv * env, const char *segment)
{
    char* tmp_bcp;
    int ln;

    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_ONLOAD)
    CHECK_PHASE_END;

    if (segment == NULL) return JVMTI_ERROR_NULL_POINTER;

    ln = strlen(bootclasspath) + strlen(":") + strlen(segment);
    tmp_bcp = MNEW(char, ln);
    strcat(tmp_bcp, bootclasspath);
    strcat(tmp_bcp, ":");
    strcat(tmp_bcp, segment);
    MFREE(bootclasspath,char,ln);
    bootclasspath = tmp_bcp;

    return JVMTI_ERROR_NONE;
}

/* SetVerboseFlag *************************************************************

   Control verbose output. This is the output which typically is sent to stderr

*******************************************************************************/

jvmtiError
SetVerboseFlag (jvmtiEnv * env, jvmtiVerboseFlag flag, jboolean value)
{
    switch (flag) {
    case JVMTI_VERBOSE_OTHER: 
        runverbose = value;
        break;
    case JVMTI_VERBOSE_GC: 
        opt_verbosegc = value;
        break;
    case JVMTI_VERBOSE_CLASS: 
        loadverbose = value;
        break;
    case JVMTI_VERBOSE_JNI: 
        break;
    default:
        return JVMTI_ERROR_ILLEGAL_ARGUMENT;            
    }
    return JVMTI_ERROR_NONE;
}

/* GetObjectSize **************************************************************

   For the object object return the size.

*******************************************************************************/

jvmtiError
GetObjectSize (jvmtiEnv * env, jobject object, jlong * size_ptr)
{
    CHECK_PHASE_START
    CHECK_PHASE(JVMTI_PHASE_START)
    CHECK_PHASE(JVMTI_PHASE_LIVE)
    CHECK_PHASE_END;

      if (size_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;
      if (!builtin_instanceof(object,class_java_lang_Object))
            return JVMTI_ERROR_INVALID_OBJECT;

      *size_ptr = ((java_objectheader*)object)->vftbl->class->instancesize;

    return JVMTI_ERROR_NONE;
}


/* *****************************************************************************

   Environment variables

*******************************************************************************/

static jvmtiCapabilities JVMTI_Capabilities = {
  0,                    /* can_tag_objects */
  0,                    /* can_generate_field_modification_events */
  0,                    /* can_generate_field_access_events */
  1,                    /* can_get_bytecodes */
  0,                    /* can_get_synthetic_attribute */

#if defined(USE_THREADS) && defined(NATIVE_THREADS)
  1,                    /* can_get_owned_monitor_info */
  1,                    /* can_get_current_contended_monitor */
#else
  0,                    /* can_get_owned_monitor_info */
  0,                    /* can_get_current_contended_monitor */
#endif

  0,                    /* can_get_monitor_info */
  0,                    /* can_pop_frame */
  0,                    /* can_redefine_classes */
#if defined(USE_THREADS) && defined(NATIVE_THREADS)
  1,                    /* can_signal_thread */
#else
  0,                    /* can_signal_thread */
#endif
  1,                    /* can_get_source_file_name */
  1,                    /* can_get_line_numbers */
  0,                    /* can_get_source_debug_extension */
  0,                    /* can_access_local_variables */
  0,                    /* can_maintain_original_method_order */
  0,                    /* can_generate_single_step_events */
  0,                    /* can_generate_exception_events */
  0,                    /* can_generate_frame_pop_events */
  0,                    /* can_generate_breakpoint_events */
#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
  1,                    /* can_suspend */
#else
  0,                    /* can_suspend */
#endif
  0,                    /* can_redefine_any_class */
  0,                    /* can_get_current_thread_cpu_time */
  0,                    /* can_get_thread_cpu_time */
  0,                    /* can_generate_method_entry_events */
  0,                    /* can_generate_method_exit_events */
  0,                    /* can_generate_all_class_hook_events */
  0,                    /* can_generate_compiled_method_load_events */
  0,                    /* can_generate_monitor_events */
  0,                    /* can_generate_vm_object_alloc_events */
  0,                    /* can_generate_native_method_bind_events */
  0,                    /* can_generate_garbage_collection_events */
  0,                    /* can_generate_object_free_events */
};

static jvmtiEnv JVMTI_EnvTable = {
    NULL,
    &SetEventNotificationMode,
    NULL,
    &GetAllThreads,
    &SuspendThread,
    &ResumeThread,
    &StopThread,
    &InterruptThread,
    &GetThreadInfo,
    &GetOwnedMonitorInfo,
    &GetCurrentContendedMonitor,
    &RunAgentThread,
    &GetTopThreadGroups,
    &GetThreadGroupInfo,
    &GetThreadGroupChildren,
    &GetFrameCount,
    &GetThreadState,
    NULL,
    &GetFrameLocation,
    &NotifyFramePop,
    &GetLocalObject,
    &GetLocalInt,
    &GetLocalLong,
    &GetLocalFloat,
    &GetLocalDouble,
    &SetLocalObject,
    &SetLocalInt,
    &SetLocalLong,
    &SetLocalFloat,
    &SetLocalDouble,
    &CreateRawMonitor,
    &DestroyRawMonitor,
    &RawMonitorEnter,
    &RawMonitorExit,
    &RawMonitorWait,
    &RawMonitorNotify,
    &RawMonitorNotifyAll,
    &SetBreakpoint,
    &ClearBreakpoint,
    NULL,
    &SetFieldAccessWatch,
    &ClearFieldAccessWatch,
    &SetFieldModificationWatch,
    &ClearFieldModificationWatch,
    NULL,
    &Allocate,
    &Deallocate,
    &GetClassSignature,
    &GetClassStatus,
    &GetSourceFileName,
    &GetClassModifiers,
    &GetClassMethods,
    &GetClassFields,
    &GetImplementedInterfaces,
    &IsInterface,
    &IsArrayClass,
    &GetClassLoader, 
    &GetObjectHashCode, 
    &GetObjectMonitorUsage, 
    &GetFieldName, 
    &GetFieldDeclaringClass, 
    &GetFieldModifiers, 
    &IsFieldSynthetic, 
    &GetMethodName, 
    &GetMethodDeclaringClass, 
    &GetMethodModifiers, 
    NULL,
    &GetMaxLocals, 
    &GetArgumentsSize, 
    &GetLineNumberTable, 
    &GetMethodLocation, 
    &GetLocalVariableTable, 
    NULL,
    NULL,
    &GetBytecodes, 
    &IsMethodNative, 
    &IsMethodSynthetic, 
    &GetLoadedClasses, 
    &GetClassLoaderClasses, 
    &PopFrame, 
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    &RedefineClasses, 
    &GetVersionNumber, 
    &GetCapabilities, 
    &GetSourceDebugExtension, 
    &IsMethodObsolete, 
    &SuspendThreadList, 
    &ResumeThreadList, 
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    &GetAllStackTraces, 
    &GetThreadListStackTraces, 
    &GetThreadLocalStorage, 
    &SetThreadLocalStorage, 
    &GetStackTrace, 
    NULL,
    &GetTag, 
    &SetTag, 
    &ForceGarbageCollection,
    &IterateOverObjectsReachableFromObject, 
    &IterateOverReachableObjects, 
    &IterateOverHeap, 
    &IterateOverInstancesOfClass, 
    NULL,
    &GetObjectsWithTags, 
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    &SetJNIFunctionTable, 
    &GetJNIFunctionTable, 
    &SetEventCallbacks, 
    &GenerateEvents, 
    &GetExtensionFunctions, 
    &GetExtensionEvents, 
    &SetExtensionEventCallback, 
    &DisposeEnvironment,
    &GetErrorName, 
    &GetJLocationFormat, 
    &GetSystemProperties, 
    &GetSystemProperty, 
    &SetSystemProperty, 
    &GetPhase, 
    &GetCurrentThreadCpuTimerInfo, 
    &GetCurrentThreadCpuTime, 
    &GetThreadCpuTimerInfo, 
    &GetThreadCpuTime, 
    &GetTimerInfo, 
    &GetTime, 
    &GetPotentialCapabilities, 
    NULL,
    &AddCapabilities,
    &RelinquishCapabilities,
    &GetAvailableProcessors,
    NULL,
    NULL,
    &GetEnvironmentLocalStorage,
    &SetEnvironmentLocalStorage,
    &AddToBootstrapClassLoaderSearch,
    &SetVerboseFlag,
    NULL,
    NULL,
    NULL,
    &GetObjectSize
};

void set_jvmti_phase(jvmtiPhase p) {
      genericEventData d;
      jvmtiEvent e;

    phase = p;
    switch (p) {
    case JVMTI_PHASE_ONLOAD:
        /* nothing to be done */
        return;
    case JVMTI_PHASE_PRIMORDIAL:
        /* nothing to be done */
        return;
    case JVMTI_PHASE_START: 
            e = JVMTI_EVENT_VM_START;
        break;
    case JVMTI_PHASE_LIVE: 
            e = JVMTI_EVENT_VM_INIT;
        break;
    case JVMTI_PHASE_DEAD:
            e = JVMTI_EVENT_VM_DEATH;
        break;
    }

      fireEvent(e,&d);
}

jvmtiEnv* new_jvmtienv() {
    environment* env;

      env = envs;
      if (env != NULL) 
            while (env->next!=NULL) {
                  env=env->next;
            }
      env = heap_allocate(sizeof(environment),true,NULL);
    memcpy(&(env->env),&JVMTI_EnvTable,sizeof(jvmtiEnv));
      memset(&(env->events),JVMTI_DISABLE,(JVMTI_EVENT_END_ENUM - JVMTI_EVENT_START_ENUM)*
               sizeof(jvmtiEventModeLL));
    /* To possess a capability, the agent must add the capability.*/
    memset(&(env->capabilities), 1, sizeof(jvmtiCapabilities));
    RelinquishCapabilities(&(env->env),&(env->capabilities));
    env->EnvironmentLocalStorage = NULL;
      env->tls = NULL;
      return &(env->env);
}

void agentload(char* opt_arg) {
      lt_dlhandle  handle;
      lt_ptr       onload;
      char *libname, *arg;
      int i=0,len;
      jint retval;
      
      len = strlen(opt_arg);
      
      while ((opt_arg[i]!='=')&&(i<len)) i++;
      
      libname=MNEW(char,i);
      strncpy(libname,opt_arg,i-1);
      libname[i-1]='\0';

      arg=MNEW(char, len-i);
      strcpy(arg,&opt_arg[i+1]);

      /* try to open the library */

      if (!(handle = lt_dlopen(libname)))
            return;

      /* resolve Agent_OnLoad function */
      onload = lt_dlsym(handle, "Agent_OnLoad");
      if (onload == NULL) {
            fprintf(stderr, "unable to load Agent_OnLoad function in %s\n", libname);
            exit(1);
      }

      /* resolve Agent_UnLoad function */
      unload = lt_dlsym(handle, "Agent_Unload");

      retval = 
            ((JNIEXPORT jint JNICALL (*) (JavaVM *vm, char *options, void *reserved))
             onload) ((JavaVM*) &JNI_JavaVMTable, arg, NULL);
      
      MFREE(libname,char,i);
      MFREE(arg,char,len-i);
      
      if (retval != 0) exit (retval);

      /* todo: native_library_hash_add(name, (java_objectheader *) loader, handle); */
}

void agentunload() {
      if (unload != NULL) {
            ((JNIEXPORT void JNICALL (*) (JavaVM *vm)) unload) 
                  ((JavaVM*) &JNI_JavaVMTable);
      }
}

/*
 * 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:
 */

Generated by  Doxygen 1.6.0   Back to index