| // natFrame.cc -- native support for VMFrame.java |
| |
| /* Copyright (C) 2006, 2007 Free Software Foundation |
| |
| This file is part of libgcj. |
| |
| This software is copyrighted work licensed under the terms of the |
| Libgcj License. Please consult the file "LIBGCJ_LICENSE" for |
| details. */ |
| |
| #include <config.h> |
| #include <gcj/cni.h> |
| #include <jvm.h> |
| #include <jvmti.h> |
| #include "jvmti-int.h" |
| |
| #include <java-interp.h> |
| |
| #include <gnu/classpath/jdwp/VMFrame.h> |
| #include <gnu/classpath/jdwp/VMVirtualMachine.h> |
| #include <gnu/classpath/jdwp/exception/InvalidFrameException.h> |
| #include <gnu/classpath/jdwp/exception/InvalidSlotException.h> |
| #include <gnu/classpath/jdwp/exception/InvalidThreadException.h> |
| #include <gnu/classpath/jdwp/exception/JdwpInternalErrorException.h> |
| #include <gnu/classpath/jdwp/exception/TypeMismatchException.h> |
| #include <gnu/classpath/jdwp/util/NullObject.h> |
| #include <gnu/classpath/jdwp/value/ArrayValue.h> |
| #include <gnu/classpath/jdwp/value/ByteValue.h> |
| #include <gnu/classpath/jdwp/value/BooleanValue.h> |
| #include <gnu/classpath/jdwp/value/CharValue.h> |
| #include <gnu/classpath/jdwp/value/DoubleValue.h> |
| #include <gnu/classpath/jdwp/value/FloatValue.h> |
| #include <gnu/classpath/jdwp/value/IntValue.h> |
| #include <gnu/classpath/jdwp/value/LongValue.h> |
| #include <gnu/classpath/jdwp/value/ObjectValue.h> |
| #include <gnu/classpath/jdwp/value/ShortValue.h> |
| #include <gnu/classpath/jdwp/value/Value.h> |
| #include <gnu/classpath/jdwp/value/VoidValue.h> |
| |
| using namespace java::lang; |
| using namespace gnu::classpath::jdwp; |
| using namespace gnu::classpath::jdwp::exception; |
| |
| |
| // All the jvmti GetLocalXX and SetLocalXX functions return the same potential |
| // errors, so this function handles them all and throws the appropriate JDWP |
| // exception. |
| static void |
| checkJVMTIError (jvmtiEnv *env, jthread thread, jvmtiError jerr, jint slot, |
| jbyte sig) |
| { |
| if (jerr != JVMTI_ERROR_NONE) |
| { |
| char *error; |
| env->GetErrorName (jerr, &error); |
| String *msg = reinterpret_cast<String *> (JvNewStringUTF (error)); |
| env->Deallocate ((unsigned char *) error); |
| |
| if (jerr == JVMTI_ERROR_INVALID_THREAD) |
| throw new InvalidThreadException ((jlong) thread); |
| else if (jerr == JVMTI_ERROR_NO_MORE_FRAMES) |
| throw new InvalidFrameException (msg); |
| else if (jerr == JVMTI_ERROR_INVALID_SLOT) |
| throw new InvalidSlotException (slot); |
| else if (jerr == JVMTI_ERROR_TYPE_MISMATCH) |
| throw new TypeMismatchException (sig); |
| else |
| throw new JdwpInternalErrorException (msg); |
| } |
| } |
| |
| |
| static jobject |
| getObjectJVMTI (jvmtiEnv *env, jthread thread, jint slot, jint depth, jbyte sig) |
| { |
| jobject value; |
| jvmtiError jerr = env->GetLocalObject (thread, depth, slot, &value); |
| |
| checkJVMTIError (env, thread, jerr, slot, sig); |
| |
| return value; |
| } |
| |
| static void |
| setObjectJVMTI (jvmtiEnv *env, jthread thread, jint slot, jint depth, |
| jbyte sig, jobject value) |
| { |
| if (value->getClass ()->isAssignableFrom (&util::NullObject::class$)) |
| value = NULL; |
| |
| jvmtiError jerr = env->SetLocalObject (thread, depth, slot, value); |
| |
| checkJVMTIError (env, thread, jerr, slot, sig); |
| } |
| |
| static jint |
| getIntJVMTI (jvmtiEnv *env, jthread thread, jint slot, jint depth, jbyte sig) |
| { |
| jint value; |
| jvmtiError jerr = env->GetLocalInt (thread, depth, slot, &value); |
| |
| checkJVMTIError (env, thread, jerr, slot, sig); |
| return value; |
| } |
| |
| static void |
| setIntJVMTI (jvmtiEnv *env, jthread thread, jint slot, jint depth, jbyte sig, |
| jint value) |
| { |
| jvmtiError jerr = env->SetLocalInt (thread, depth, slot, value); |
| |
| checkJVMTIError (env, thread, jerr, slot, sig); |
| } |
| |
| static jlong |
| getLongJVMTI (jvmtiEnv *env, jthread thread, jint slot, jint depth, jbyte sig) |
| { |
| jlong value; |
| jvmtiError jerr = env->GetLocalLong (thread, depth, slot, &value); |
| |
| checkJVMTIError (env, thread, jerr, slot, sig); |
| |
| return value; |
| } |
| |
| static void |
| setLongJVMTI (jvmtiEnv *env, jthread thread, jint slot, jint depth, jbyte sig, |
| jlong value) |
| { |
| jvmtiError jerr = env->SetLocalLong (thread, depth, slot, value); |
| |
| checkJVMTIError (env, thread, jerr, slot, sig); |
| } |
| |
| static jfloat |
| getFloatJVMTI (jvmtiEnv *env, jthread thread, jint slot, jint depth, jbyte sig) |
| { |
| jfloat value; |
| jvmtiError jerr = env->GetLocalFloat (thread, depth, slot, &value); |
| |
| checkJVMTIError (env, thread, jerr, slot, sig); |
| |
| return value; |
| } |
| |
| static void |
| setFloatJVMTI (jvmtiEnv *env, jthread thread, jint slot, jint depth, jbyte sig, |
| jfloat value) |
| { |
| jvmtiError jerr = env->SetLocalFloat (thread, depth, slot, value); |
| |
| checkJVMTIError (env, thread, jerr, slot, sig); |
| } |
| |
| static jdouble |
| getDoubleJVMTI (jvmtiEnv *env, jthread thread, jint slot, jint depth, |
| jbyte sig) |
| { |
| jdouble value; |
| jvmtiError jerr = env->GetLocalDouble (thread, depth, slot, &value); |
| |
| checkJVMTIError (env, thread, jerr, slot, sig); |
| |
| return value; |
| } |
| |
| static void |
| setDoubleJVMTI (jvmtiEnv *env, jthread thread, jint slot, jint depth, |
| jbyte sig, jdouble value) |
| { |
| jvmtiError jerr = env->SetLocalDouble (thread, depth, slot, value); |
| |
| checkJVMTIError (env, thread, jerr, slot, sig); |
| } |
| |
| // This is necessary since JVMTI requires a stack depth as a parameter in all |
| // its local variable functions. Since JDWP needs frameids, we have to run |
| // through the call stack to translate these ids into the parameters JVMTI |
| // wants. |
| static jint |
| getFrameDepth (_Jv_Frame *frame) |
| { |
| jint depth = 0; |
| _Jv_Frame *top_frame = (_Jv_Frame *) frame->thread->frame; |
| jint num_frames = VMVirtualMachine::getFrameCount (frame->thread); |
| |
| while (frame != top_frame) |
| { |
| top_frame = top_frame->next; |
| depth++; |
| |
| if (depth >= num_frames || top_frame == NULL) |
| throw new InvalidFrameException ((jlong) frame); |
| } |
| |
| return depth; |
| } |
| |
| using namespace gnu::classpath::jdwp::value; |
| |
| Value * |
| gnu::classpath::jdwp::VMFrame::getValue (jint slot, jbyte sig) |
| { |
| _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (id); |
| jint depth = getFrameDepth (frame); |
| jthread thread = reinterpret_cast<jthread> (frame->thread); |
| jvmtiEnv *env = _Jv_GetJDWP_JVMTIEnv (); |
| |
| Value *value = NULL; |
| |
| switch (sig) |
| { |
| case 'B': |
| value = new ByteValue ((jbyte) getIntJVMTI (env, thread, slot, depth, |
| sig)); |
| break; |
| case 'Z': |
| value = new BooleanValue ((jboolean) getIntJVMTI (env, thread, slot, |
| depth, sig)); |
| break; |
| case 'C': |
| value = new CharValue ((jchar) getIntJVMTI (env, thread, slot, depth, |
| sig)); |
| break; |
| case 'S': |
| value = new ShortValue ((jshort) getIntJVMTI (env, thread, slot, depth, |
| sig)); |
| break; |
| case 'I': |
| value = new IntValue (getIntJVMTI (env, thread, slot, depth, sig)); |
| break; |
| case 'J': |
| value = new LongValue (getLongJVMTI (env, thread, slot, depth, sig)); |
| break; |
| case 'F': |
| value = new FloatValue (getFloatJVMTI (env, thread, slot, depth, sig)); |
| break; |
| case 'D': |
| value = new DoubleValue (getDoubleJVMTI (env, thread, slot, depth, sig)); |
| break; |
| case 'V': |
| value = new VoidValue (); |
| break; |
| case '[': |
| { |
| Object *obj = getObjectJVMTI (env, thread, slot, depth, sig); |
| if (obj == NULL) |
| obj = new util::NullObject (); |
| value = new ArrayValue (obj); |
| break; |
| } |
| default: |
| Object *obj = getObjectJVMTI (env, thread, slot, depth, sig); |
| if (obj == NULL) |
| obj = new util::NullObject (); |
| value = new ObjectValue (obj); |
| break; |
| } |
| |
| return value; |
| } |
| |
| void |
| gnu::classpath::jdwp::VMFrame::setValue (jint slot, Value* value) |
| { |
| jbyte sig = value->getTag (); |
| |
| _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (id); |
| jint depth = getFrameDepth (frame); |
| jthread thread = reinterpret_cast<jthread> (frame->thread); |
| jvmtiEnv *env = _Jv_GetJDWP_JVMTIEnv (); |
| |
| switch (sig) |
| { |
| case 'B': |
| { |
| ByteValue *val = reinterpret_cast<ByteValue *> (value); |
| setIntJVMTI (env, thread, slot, depth, sig, (jint) val->getValue ()); |
| break; |
| } |
| case 'Z': |
| { |
| BooleanValue *val = reinterpret_cast<BooleanValue *> (value); |
| setIntJVMTI (env, thread, slot, depth, sig, (jint) val->getValue ()); |
| break; |
| } |
| case 'C': |
| { |
| CharValue *val = reinterpret_cast<CharValue *> (value); |
| setIntJVMTI (env, thread, slot, depth, sig, (jint) val->getValue ()); |
| break; |
| } |
| case 'S': |
| { |
| ShortValue *val = reinterpret_cast<ShortValue *> (value); |
| setIntJVMTI (env, thread, slot, depth, sig, (jint) val->getValue ()); |
| break; |
| } |
| case 'I': |
| { |
| IntValue *val = reinterpret_cast<IntValue *> (value); |
| setIntJVMTI (env, thread, slot, depth, sig, val->getValue ()); |
| break; |
| } |
| case 'J': |
| { |
| LongValue *val = reinterpret_cast<LongValue *> (value); |
| setLongJVMTI (env, thread, slot, depth, sig, val->getValue ()); |
| break; |
| } |
| case 'F': |
| { |
| FloatValue *val = reinterpret_cast<FloatValue *> (value); |
| setFloatJVMTI (env, thread, slot, depth, sig, val->getValue ()); |
| break; |
| } |
| case 'D': |
| { |
| DoubleValue *val = reinterpret_cast<DoubleValue *> (value); |
| setDoubleJVMTI (env, thread, slot, depth, sig, val->getValue ()); |
| break; |
| } |
| case 'V': |
| break; |
| case '[': |
| { |
| ArrayValue *val = reinterpret_cast<ArrayValue *> (value); |
| setObjectJVMTI (env, thread, slot, depth, sig, val->getObject ()); |
| break; |
| } |
| default: |
| { |
| ObjectValue *val = reinterpret_cast<ObjectValue *> (value); |
| setObjectJVMTI (env, thread, slot, depth, sig, val->getObject()); |
| break; |
| } |
| } |
| } |