示例#1
0
static bool is_valid_object(jvmtiEnv* env, jobject handle)
{
    SuspendEnabledChecker sec;

    if (NULL == handle)
        return true;

    tmn_suspend_disable();

    ManagedObject *obj = ((ObjectHandle) handle)->object;

    if (obj < (ManagedObject *)VM_Global_State::loader_env->heap_base ||
        obj > (ManagedObject *)VM_Global_State::loader_env->heap_end)
    {
        tmn_suspend_enable();
        return false;
    }

    Class *clss = obj->vt()->clss;
    ManagedObject *clsObj = struct_Class_to_java_lang_Class(clss);
    // ppervov: FIXME: there is an assertion in the above function which
    // is exactly the same as in the following if. So, this code will only
    // work in release and just assert in debug.
    if (clsObj->vt()->clss != VM_Global_State::loader_env->JavaLangClass_Class) {
        tmn_suspend_enable();
        return false;
    }

    tmn_suspend_enable();
    return true;
}
示例#2
0
/**
 * Returns all monitors owned by the specific thread.
 *
 * @param[in] java_thread thread which owns monitors
 * @param[out] monitor_count_ptr number of owned monitors 
 * @param[out] monitors_ptr array of owned monitors
 */
IDATA VMCALL
jthread_get_owned_monitors(jthread java_thread,
                           jint *monitor_count_ptr,
                           jobject **monitors_ptr)
{
    assert(java_thread);
    assert(monitors_ptr);
    assert(monitor_count_ptr);

    IDATA status = hythread_global_lock();
    if (status != TM_ERROR_NONE) {
        return status;
    }
    vm_thread_t vm_thread = jthread_get_vm_thread_from_java(java_thread);
    if (!vm_thread) {
        status = hythread_global_unlock();
        return status;
    }
    jvmti_thread_t jvmti_thread = &vm_thread->jvmti_thread;
    if (!jvmti_thread)
	{
        status = hythread_global_unlock();
        return status;
	}

    jobject *monitors =
        (jobject *) malloc(sizeof(jobject *) *
                           jvmti_thread->owned_monitors_nmb);
    if (!monitors) {
        hythread_global_unlock();
        return TM_ERROR_OUT_OF_MEMORY;
    }

    tmn_suspend_disable();
    for (int i = 0; i < jvmti_thread->owned_monitors_nmb; i++) {
        jobject new_ref = oh_allocate_local_handle_from_jni();

        if (NULL != new_ref)
            new_ref->object = jvmti_thread->owned_monitors[i]->object;
        else
        {
            tmn_suspend_enable();   
            hythread_global_unlock();
            return TM_ERROR_OUT_OF_MEMORY;
        }
        // change the order of reported monitors to be compliant with RI
        monitors[jvmti_thread->owned_monitors_nmb - 1 - i] = new_ref;
    }
    tmn_suspend_enable();   

    *monitors_ptr = monitors;
    *monitor_count_ptr = jvmti_thread->owned_monitors_nmb;

    status = hythread_global_unlock();
    return status;
} // jthread_get_owned_monitors
示例#3
0
// Note: Function runs from unwindable area before exception throwing
// function can be safe point & should be called with disable recursion = 1
static ManagedObject *create_lazy_exception(
    Class_Handle exn_class,
    Method_Handle exn_constr,
    U_8 * exn_constr_args,
    jvalue* vm_exn_constr_args)
{
    assert(!hythread_is_suspend_enabled());

    bool unwindable = set_unwindable(false);
    ManagedObject* result;
    if (NULL == vm_exn_constr_args) {
        result = class_alloc_new_object_and_run_constructor(
            (Class*) exn_class, (Method*) exn_constr, exn_constr_args);
    } else {
        // exception is throwing, so suspend can be enabled safely
        tmn_suspend_enable();
        jthrowable exc_object = create_exception(
            (Class*) exn_class, (Method*) exn_constr, vm_exn_constr_args);

        if (exc_object) {
            result = exc_object->object;
        } else {
            result = NULL;
        }
        tmn_suspend_disable();
    }
    set_unwindable(unwindable);
    exn_rethrow_if_pending();
    return result;
}   //create_object_lazily
//FIXME LAZY EXCEPTION (2006.05.06)
//Find all usage and change to lazy use
jthrowable exn_get()
{
    assert(hythread_is_suspend_enabled());

    // we can check heap references for equality to NULL
    // without disabling gc, because GC wouldn't change 
    // null to non-null and vice versa.
    vm_thread_t vm_thread = p_TLS_vmthread;
    if ((NULL == vm_thread->thread_exception.exc_object)
        && (NULL == vm_thread->thread_exception.exc_class)) {
        return NULL;
    }

    // returned value which will contains jthrowable value of
    // curent thread exception
    jobject exc;

    if (NULL != vm_thread->thread_exception.exc_object) {
        tmn_suspend_disable();
        exc = oh_allocate_local_handle();
        exc->object = (ManagedObject *) vm_thread->thread_exception.exc_object;
        tmn_suspend_enable();
    } else if (NULL != vm_thread->thread_exception.exc_class) {
        exc = exn_create((Exception*)&(vm_thread->thread_exception));
    } else {
        LDIE(59, "It's impossible internal error in exception handling.");
    }
    return exc;
} // exn_get
示例#5
0
VMEXPORT // temporary solution for interpreter unplug
Vector_Handle vm_new_vector_primitive(Class *vector_class, int length) {
    ASSERT_RAISE_AREA;
    assert(!hythread_is_suspend_enabled());
    assert(vector_class->is_array_of_primitives());
    unsigned sz = vector_class->calculate_array_size(length);

    if (sz == 0) {
        tmn_suspend_enable();
        if (length < 0) {
            exn_raise_by_name("java/lang/NegativeArraySizeException");
        } else {
            exn_raise_by_name("java/lang/OutOfMemoryError",
                    "VM doesn't support arrays of the requested size");
        }
        tmn_suspend_disable();
        return NULL;
    }

    Vector_Handle vector = (Vector_Handle)gc_alloc(sz, 
        vector_class->get_allocation_handle(), vm_get_gc_thread_local());
#ifdef VM_STATS
    vector_class->instance_allocated(sz);
#endif //VM_STATS

    if (NULL == vector) {
        exn_raise_object(
            VM_Global_State::loader_env->java_lang_OutOfMemoryError);
        return 0;
    }

    set_vector_length(vector, length);
    assert(get_vector_vtable(vector) == vector_class->get_vtable());
    return vector;
}
示例#6
0
void class_throw_linking_error(Class_Handle ch, unsigned index, unsigned opcode)
{
    ASSERT_RAISE_AREA;
    tmn_suspend_enable();

    ConstantPool& cp = ch->get_constant_pool();
    if(cp.is_entry_in_error(index)) {
        exn_raise_object(cp.get_error_cause(index));
        tmn_suspend_disable();
        return; // will return in interpreter mode
    }

    switch(opcode) {
        case OPCODE_NEW:
            class_can_instantiate(cp.get_class_class(index), LINK_THROW_ERRORS);
            break;
        case OPCODE_PUTFIELD:
            field_can_link(ch, cp.get_ref_field(index),
                CAN_LINK_FROM_FIELD, LINK_WRITE_ACCESS, LINK_THROW_ERRORS);
            break;
        case OPCODE_GETFIELD:
            field_can_link(ch, cp.get_ref_field(index),
                CAN_LINK_FROM_FIELD, LINK_READ_ACCESS, LINK_THROW_ERRORS);
            break;
        case OPCODE_PUTSTATIC:
            field_can_link(ch, cp.get_ref_field(index),
                CAN_LINK_FROM_STATIC, LINK_WRITE_ACCESS, LINK_THROW_ERRORS);
            break;
        case OPCODE_GETSTATIC:
            field_can_link(ch, cp.get_ref_field(index),
                CAN_LINK_FROM_STATIC, LINK_READ_ACCESS, LINK_THROW_ERRORS);
            break;
        case OPCODE_INVOKEINTERFACE:
            method_can_link_interface(ch, index, cp.get_ref_method(index),
                LINK_THROW_ERRORS);
            break;
        case OPCODE_INVOKESPECIAL:
            method_can_link_special(ch, index, cp.get_ref_method(index),
                LINK_THROW_ERRORS);
            break;
        case OPCODE_INVOKESTATIC:
            method_can_link_static(ch, index, cp.get_ref_method(index),
                LINK_THROW_ERRORS);
            break;
        case OPCODE_INVOKEVIRTUAL:
            method_can_link_virtual(ch, index, cp.get_ref_method(index),
                LINK_THROW_ERRORS);
            break;
        default:
            // FIXME Potentially this can be any RuntimeException or Error
            // The most probable case is OutOfMemoryError.
            LWARN(5, "**Java exception occured during resolution under compilation");
            exn_raise_object(VM_Global_State::loader_env->java_lang_OutOfMemoryError);
            //ASSERT(0, "Unexpected opcode: " << opcode);
            break;
    }
    tmn_suspend_disable();
}
static Method* prepare_exc_creating(Class* exc_class, jvalue* args,
    const char* exc_message) {
    ASSERT_RAISE_AREA;
    assert(hythread_is_suspend_enabled());

    // Checks that it's corresponding method
    if (NULL == exc_message) {
        return prepare_exc_creating(exc_class, args);
    }

    // Finds corresponding constructor
    Method* exc_init = lookup_exc_constructor(exc_class, "(Ljava/lang/String;)V");

    // Check that constructor is found
    if (NULL == exc_init){
        return NULL;
    }

    // Creates string object
    tmn_suspend_disable();

    ManagedObject *arg_obj =
        string_create_from_utf8(exc_message, (unsigned) strlen(exc_message));

    if (!arg_obj) {
        exn_raise_object(VM_Global_State::loader_env->java_lang_OutOfMemoryError);
        tmn_suspend_enable();
        return NULL;
    }
    jobject arg = oh_allocate_local_handle();
    arg->object = arg_obj;

    tmn_suspend_enable();

    // Fills arguments for constructor
    args[1].l = arg;

    // Returns found constructor
    return exc_init;
}
jthrowable create_exception(Class* exc_class, Method* exc_init, jvalue* args) {
    ASSERT_RAISE_AREA;
    assert(hythread_is_suspend_enabled());

    bool suspended_enabled = hythread_is_suspend_enabled();

    if (suspended_enabled) {
        tmn_suspend_disable();
    }

    ManagedObject *man_obj = class_alloc_new_object(exc_class);

    if (!man_obj) {
        exn_raise_object(VM_Global_State::loader_env->java_lang_OutOfMemoryError);
        if (suspended_enabled) {
            tmn_suspend_enable();
        }
        return NULL;
    }

    jthrowable exc_object = oh_allocate_local_handle();
    exc_object->object = man_obj;
    args[0].l = exc_object;

    if (exn_raised()) { //if RuntimeException or Error
        if (suspended_enabled) {
            tmn_suspend_enable();
        }
        return NULL;
    }

    vm_execute_java_method_array((jmethodID) exc_init, 0, args);

    if (suspended_enabled) {
        tmn_suspend_enable();
    }

    return exc_object;
}
示例#9
0
文件: compile.cpp 项目: dacut/juliet
NativeCodePtr compile_me(Method* method)
{
    ASSERT_RAISE_AREA;
    ASSERT_NO_INTERPRETER;
    TRACE("compile_me " << method);

    GcFrame gc;
    compile_protect_arguments(method, &gc);

    if (exn_raised()) {
        return NULL;
     }

    tmn_suspend_enable();
    if (method->is_abstract()) { 
        compile_raise_exception("java/lang/AbstractMethodError", "", method); 
        tmn_suspend_disable(); 
        return NULL; 
    }

    DebugUtilsTI *ti = VM_Global_State::loader_env->TI;
    JIT_Result res = compile_do_compilation(method);

    if (res != JIT_SUCCESS) {
        INFO2("compile", "Cannot compile " << method);
        if (!exn_raised()) {
            compile_raise_exception("java/lang/InternalError", "Cannot compile ", method);
        }
        tmn_suspend_disable();
        return NULL;
    }
    tmn_suspend_disable();

    NativeCodePtr entry_point = method->get_code_addr();
    INFO2("compile.code", "Compiled method " << method
            << ", entry " << entry_point);

    if (method->get_pending_breakpoints() != 0)
        jvmti_set_pending_breakpoints(method);
    if(ti->isEnabled() && ti->is_single_step_enabled()
        && !method->is_native())
    {
        jvmti_thread_t jvmti_thread = jthread_self_jvmti();
        assert(jvmti_thread);
        jvmti_set_single_step_breakpoints_for_method(ti, jvmti_thread, method);
    }

    return entry_point;
} // compile_me
示例#10
0
static void class_report_failure(Class* target, uint16 cp_index, jthrowable exn)
{
    ConstantPool& cp = target->get_constant_pool();
    assert(cp.is_valid_index(cp_index));
    assert(hythread_is_suspend_enabled());
    assert(exn);

    tmn_suspend_disable();
    target->lock();
    if (!cp.is_entry_in_error(cp_index)) {
        // vvv - This should be atomic change
        cp.resolve_as_error(cp_index, exn);
        // ^^^
    }
    target->unlock();
    tmn_suspend_enable();
}
// function is safe point & should be called in disable mode in safe enviroment
ManagedObject* __stdcall get_exception_object_internal()
{
    assert(!hythread_is_suspend_enabled());
    if (NULL != p_TLS_vmthread->thread_exception.exc_object) {
        return p_TLS_vmthread->thread_exception.exc_object;
    } else if (NULL != p_TLS_vmthread->thread_exception.exc_class) {
        Exception* exception = (Exception*)&(p_TLS_vmthread->thread_exception);

        // suspend can be enabeled in safe enviroment
        tmn_suspend_enable();
        jthrowable exc_object = create_exception(exception);
        tmn_suspend_disable();

        return exc_object->object;
    } else {
        return NULL;
    }
} // get_exc_object_internal
示例#12
0
static bool method_can_link_special(Class* clss, unsigned index, Method* method, bool _throw)
{
    ASSERT_RAISE_AREA;

    ConstantPool& cp = clss->get_constant_pool();
    unsigned class_idx = cp.get_ref_class_index(index);
    unsigned class_name_idx = cp.get_class_name_index(class_idx);
    String* ref_class_name = cp.get_utf8_string(class_name_idx);

    if(method->get_name() == VM_Global_State::loader_env->Init_String
        && method->get_class()->get_name() != ref_class_name)
    {
        if(_throw) {
            exn_raise_by_name("java/lang/NoSuchMethodError",
                method->get_name()->bytes);
        }
        return false;
    }
    if(method->is_static())
    {
        if(_throw) {
            exn_raise_by_name("java/lang/IncompatibleClassChangeError",
                method->get_class()->get_name()->bytes);
        }
        return false;
    }
    if(method->is_abstract())
    {
        if(_throw) {
            tmn_suspend_enable();
            unsigned buf_size = clss->get_name()->len +
                method->get_name()->len + method->get_descriptor()->len + 5;
            char* buf = (char*)STD_ALLOCA(buf_size);
            memset(buf, 0, buf_size);
            sprintf(buf, "%s.%s%s", clss->get_name()->bytes,
                method->get_name()->bytes, method->get_descriptor()->bytes);
            jthrowable exc_object = exn_create("java/lang/AbstractMethodError", buf);
            exn_raise_object(exc_object);
            tmn_suspend_disable();
        }
        return false;
    }
    return true;
}
示例#13
0
static Vector_Handle vm_anewarray_resolved_array_type(Class *arr_clss, int length)
{
#ifdef VM_STATS
    UNSAFE_REGION_START
    VM_Statistics::get_vm_stats().num_anewarray++;  
    UNSAFE_REGION_END
#endif
    ASSERT_RAISE_AREA;
    assert(!hythread_is_suspend_enabled());
    assert(!arr_clss->is_array_of_primitives());

    unsigned sz = arr_clss->calculate_array_size(length);
    if (sz == 0) {
        tmn_suspend_enable();

        if (length < 0) {
            exn_raise_by_name("java/lang/NegativeArraySizeException");
        } else {
            exn_raise_by_name("java/lang/OutOfMemoryError",
                    "VM doesn't support arrays of the requested size");
        }
        tmn_suspend_disable();
        return NULL;
    }

    assert((sz & NEXT_TO_HIGH_BIT_SET_MASK) == 0);

    Vector_Handle object_array = (Vector_Handle )gc_alloc(sz,
        arr_clss->get_allocation_handle(), vm_get_gc_thread_local());
#ifdef VM_STATS
    arr_clss->instance_allocated(sz);
#endif //VM_STATS

    if (NULL == object_array) {
        exn_raise_object(
            VM_Global_State::loader_env->java_lang_OutOfMemoryError);
        return NULL;
    }

    set_vector_length(object_array, length);
    assert(get_vector_vtable(object_array) == arr_clss->get_vtable());
    return object_array;
} //vm_anewarray_resolved_array_type
void init_cause(jthrowable exc_object, jthrowable exc_cause) {
    ASSERT_RAISE_AREA;
    assert(exc_cause);
    assert(hythread_is_suspend_enabled());

    tmn_suspend_disable();

    Class* exc_class = exc_object->object->vt()->clss;
    Method *init_cause_method = class_lookup_method_recursive(exc_class,
        "initCause", "(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
    assert(init_cause_method);
    jvalue args[2];
    args[0].l = exc_object;
    args[1].l = exc_cause;
    jvalue ret_val;
    vm_execute_java_method_array((jmethodID) init_cause_method, &ret_val,
        args);
    tmn_suspend_enable();
}
示例#15
0
文件: compile.cpp 项目: dacut/juliet
static JIT_Result compile_do_compilation(Method* method)
{
    ASSERT_RAISE_AREA;
    assert(hythread_is_suspend_enabled());
    tmn_suspend_disable();
    class_initialize(method->get_class());
    tmn_suspend_enable();
   
    method->lock();
    if (exn_raised()) {
        method->unlock();
        return JIT_FAILURE;
    } else if (method->get_state() == Method::ST_Compiled) {
        method->unlock();
        return JIT_SUCCESS;
    } else if (method->get_state()==Method::ST_NotCompiled && exn_raised()) {
        method->unlock();
        return JIT_FAILURE;
    } else if(!check_available_stack_size(0x8000)) {
        method->unlock();
        return JIT_FAILURE;
    }

    if (method->is_native()) {
        JIT_Result res = compile_prepare_native_method(method);            
        if (res == JIT_SUCCESS) {
            compile_flush_generated_code();
            method->set_state(Method::ST_Compiled);
            method->do_jit_recompiled_method_callbacks();
            method->apply_vtable_patches();
        } else {
            method->set_state(Method::ST_NotCompiled);
            compile_raise_exception("java/lang/UnsatisfiedLinkError", "Cannot load native ", method);
        }
        method->unlock();
        return res;
    } else {
        // Call an execution manager to compile the method.
        // An execution manager is safe to call from multiple threads.
        method->unlock();
        return VM_Global_State::loader_env->em_interface->CompileMethod(method);
    }
}
void exn_throw_by_name_internal(const char* exc_name, const char* exc_message,
    jthrowable exc_cause)
{
    BEGIN_RAISE_AREA;
    // functions can be invoked in suspend disabled and enabled state
    if (!hythread_is_suspend_enabled()) {
        // exception is throwing, so suspend can be enabled safely
        tmn_suspend_enable();
    }
    assert(hythread_is_suspend_enabled());
    Class *exc_class = get_exc_class(exc_name);

    if (exc_class == NULL) {
        assert(exn_raised());
        exn_rethrow();
        return; // unreachable code
    }
    exn_throw_by_class_internal(exc_class, exc_message, exc_cause);
    END_RAISE_AREA;
}
void exn_throw_by_class_internal(Class* exc_class, const char* exc_message,
    jthrowable exc_cause)
{
    BEGIN_RAISE_AREA;
    // functions can be invoked in suspend disabled and enabled state
    if (!hythread_is_suspend_enabled()) {
        // exception is throwing, so suspend can be enabled safely
        tmn_suspend_enable();
    }
    assert(hythread_is_suspend_enabled());
#ifdef VM_LAZY_EXCEPTION
    //set_unwindable(false);

    jvalue args[3];
    Method* exc_init = prepare_exc_creating(
            exc_class, args, exc_message, exc_cause);

    if (NULL == exc_init) {
        CTRACE(("%s",
            "exn_throw_by_class(),create exception and delegating to exn_throw_for_JIT()"));
        jthrowable exc_object = exn_create(exc_class, exc_message, exc_cause);
        exn_rethrow_if_pending();
        //set_unwindable(true);
        exn_throw_object_internal(exc_object);
    } else {
        CTRACE(("%s", "exn_throw_by_class(), lazy delegating to exn_throw_for_JIT()"));
        //set_unwindable(true);

        // no return, so enable isn't required
        tmn_suspend_disable();
        exn_throw_for_JIT(NULL, exc_class, exc_init, NULL, args);
        //tmn_suspend_enable();
    }
#else
    jthrowable exc_object = exn_create(exc_class, exc_message, exc_cause);
    exn_rethrow_if_pending();
    exn_throw_object_internal(exc_object);
#endif
    END_RAISE_AREA;
}
Class *get_exc_class(const char *exception_name)
{
    ASSERT_RAISE_AREA;
    assert(hythread_is_suspend_enabled());
    Global_Env *env = VM_Global_State::loader_env;
    String *exc_str = env->string_pool.lookup(exception_name);
    Class *exc_class =
        env->bootstrap_class_loader->LoadVerifyAndPrepareClass(env, exc_str);

    if (exc_class == NULL) {
        return NULL;
    }

    tmn_suspend_disable();
    class_initialize(exc_class);
    tmn_suspend_enable();

    if (exn_raised()) {
        return NULL;
    }

    return exc_class;
}
示例#19
0
jvmtiError JNICALL
jvmtiGetLocalLong(jvmtiEnv* env,
                  jthread thread,
                  jint depth,
                  jint slot,
                  jlong* value_ptr)
{
    TRACE("GetLocalLong called");
    SuspendEnabledChecker sec;
    /*
     * Check given env & current phase.
     */
    jvmtiPhase phases[] = {JVMTI_PHASE_LIVE};

    CHECK_EVERYTHING();

    CHECK_CAPABILITY(can_access_local_variables);

    // check error condition: JVMTI_ERROR_INVALID_THREAD
    // check error condition: JVMTI_ERROR_THREAD_NOT_ALIVE
    // check error condition: JVMTI_ERROR_ILLEGAL_ARGUMENT
    // check error condition: JVMTI_ERROR_NULL_POINTER
    jvmtiError err = GetLocal_checkArgs(env, &thread, depth, slot, value_ptr);
    if (err != JVMTI_ERROR_NONE)
        return err;

    bool thread_suspended = false;
    // Suspend thread before getting stacks
    vm_thread_t vm_thread;
    if (NULL != thread)
    {
        // Check that this thread is not current
        vm_thread = jthread_get_vm_thread_ptr_safe(thread);
        if (vm_thread != p_TLS_vmthread)
        {
            IDATA UNREF status = hythread_suspend_other((hythread_t)vm_thread);
            assert(TM_ERROR_NONE == status);
            thread_suspended = true;
        }
    }
    else
        vm_thread = p_TLS_vmthread;

    if (interpreter_enabled())
        // check error condition: JVMTI_ERROR_INVALID_SLOT
        // check error condition: JVMTI_ERROR_OPAQUE_FRAME
        // check error condition: JVMTI_ERROR_NO_MORE_FRAMES
        // TODO: check error condition: JVMTI_ERROR_TYPE_MISMATCH
        err = interpreter.interpreter_ti_getLocal64(env,
            vm_thread, depth, slot, value_ptr);
    else
    {
        GET_JIT_FRAME_CONTEXT;

        tmn_suspend_disable();
        OpenExeJpdaError result = jit->get_local_var(method, jfc, slot,
            VM_DATA_TYPE_INT64, value_ptr);
        si_free(si);
        tmn_suspend_enable();

        err = jvmti_translate_jit_error(result);
    }

    if (thread_suspended)
        hythread_resume((hythread_t)vm_thread);

    return err;
}
示例#20
0
/**
 * General function to set value of local variable.
 * @param var_type  type of the local variable
 * @param p_value   pointer to the new variable value
 */
static jvmtiError set_local(jvmtiEnv* env,
                            jthread thread,
                            jint depth,
                            jint slot,
                            VM_Data_Type var_type,
                            void* p_value)
{
    SuspendEnabledChecker sec;
    /*
     * Check given env & current phase.
     */
    jvmtiPhase phases[] = {JVMTI_PHASE_LIVE};

    CHECK_EVERYTHING();

    CHECK_CAPABILITY(can_access_local_variables);

    // check error condition: JVMTI_ERROR_INVALID_THREAD
    // check error condition: JVMTI_ERROR_THREAD_NOT_ALIVE
    // check error condition: JVMTI_ERROR_ILLEGAL_ARGUMENT
    jvmtiError err = GetLocal_checkArgs(env, &thread, depth, slot, p_value);
    if (err != JVMTI_ERROR_NONE)
        return err;

    // check error condition: JVMTI_ERROR_INVALID_OBJECT
    if (VM_DATA_TYPE_CLASS == var_type && ! is_valid_object(env, *(jobject*) p_value))
        return JVMTI_ERROR_INVALID_OBJECT;

    bool thread_suspended = false;
    // Suspend thread before getting stacks
    vm_thread_t vm_thread;
    if (NULL != thread)
    {
        // Check that this thread is not current
        vm_thread = jthread_get_vm_thread_ptr_safe(thread);
        if (vm_thread != p_TLS_vmthread)
        {
            IDATA UNREF status = hythread_suspend_other((hythread_t)vm_thread);
            assert(TM_ERROR_NONE == status);
            thread_suspended = true;
        }
    }
    else
        vm_thread = p_TLS_vmthread;

    if (interpreter_enabled())
    {
        // TODO: check error condition: JVMTI_ERROR_INVALID_SLOT
        // TODO: check error condition: JVMTI_ERROR_TYPE_MISMATCH
        // TODO: check error condition: JVMTI_ERROR_OPAQUE_FRAME
        // TODO: check error condition: JVMTI_ERROR_NO_MORE_FRAMES

        switch (var_type) {
            case VM_DATA_TYPE_CLASS:
                err = interpreter.interpreter_ti_setObject(env, vm_thread,
                        depth, slot, *(jobject*) p_value);
                break;
            case VM_DATA_TYPE_INT32:
            case VM_DATA_TYPE_F4:
                err = interpreter.interpreter_ti_setLocal32(env, vm_thread,
                        depth, slot, *(int*) p_value);
                break;
            case VM_DATA_TYPE_INT64:
            case VM_DATA_TYPE_F8:
                err = interpreter.interpreter_ti_setLocal64(env, vm_thread,
                        depth, slot, *(int64*) p_value);
                break;
            default:
                DIE(("Error: unrecognized local variable type"));
        }
    }
    else
    {
        GET_JIT_FRAME_CONTEXT;

        tmn_suspend_disable();
        OpenExeJpdaError result;

        switch (var_type) {
            case VM_DATA_TYPE_CLASS:
                if (NULL != *(jobject*) p_value)
                    result = jit->set_local_var(method, jfc, slot,
                        VM_DATA_TYPE_CLASS, &(*(ObjectHandle*) p_value)->object);
                else
                {
                    ManagedObject *n = (ManagedObject *)VM_Global_State::loader_env->managed_null;
                    result = jit->set_local_var(method, jfc, slot,
                        VM_DATA_TYPE_CLASS, &n);
                }

                break;
            case VM_DATA_TYPE_INT32:
            case VM_DATA_TYPE_F4:
            case VM_DATA_TYPE_INT64:
            case VM_DATA_TYPE_F8:
                result = jit->set_local_var(method, jfc, slot, var_type,
                        p_value);
                break;
            default:
                DIE(("Error: unrecognized local variable type"));
        }

        si_free(si);
        tmn_suspend_enable();

        err = jvmti_translate_jit_error(result);
    }

    if (thread_suspended)
        hythread_resume((hythread_t)vm_thread);

    return err;
}