<commit_before>/*
 *  Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
/** 
 * @author Intel, <NAME>
 * @version $Revision: 1.1.2.2.4.5 $
 */  


#define LOG_DOMAIN "jni"
#include "cxxlog.h"

#include "platform.h"
#include "lock_manager.h"
#include "Class.h"
#include "classloader.h"
#include "environment.h"
#include "exception.h"
#include "object_handles.h"
#include "open/types.h"
#include "open/vm_util.h"
#include "vm_threads.h"
#include "open/thread.h"
#include "vm_synch.h"
#include "exceptions.h"
#include "reflection.h"
#include "ini.h"
#include "vm_arrays.h"
#include "vm_strings.h"
#include "stack_trace.h"
#include "m2n.h"
#include "nogc.h"
#include "init.h"

#include "Verifier_stub.h"

#include "jni_utils.h"

#include "jit_runtime_support.h"

#include "jvmti_direct.h"

#ifdef _IPF_
#include "stub_code_utils.h"
#endif // _IPF_

static void JNICALL UnimpStub(JNIEnv*);

struct JNINativeInterface_ jni_vtable = {
            
    (void*)UnimpStub,
    (void*)UnimpStub,
    (void*)UnimpStub,
    (void*)UnimpStub,
    GetVersion,
            
    DefineClass,
    FindClass,
    FromReflectedMethod,
    FromReflectedField,
    ToReflectedMethod,
    GetSuperclass,
    IsAssignableFrom,

    ToReflectedField,
            
    Throw,
    ThrowNew,
    ExceptionOccurred,
    ExceptionDescribe,
    ExceptionClear,
    FatalError,
    PushLocalFrame,
    PopLocalFrame,
            
    NewGlobalRef,
    DeleteGlobalRef,
    DeleteLocalRef,
    IsSameObject,
    NewLocalRef,
    EnsureLocalCapacity,
            
    AllocObject,
    NewObject,
    NewObjectV,
    NewObjectA,
            
    GetObjectClass,
    IsInstanceOf,
            
    GetMethodID,
            
    CallObjectMethod,
    CallObjectMethodV,
    CallObjectMethodA,
    CallBooleanMethod,
    CallBooleanMethodV,
    CallBooleanMethodA,
    CallByteMethod,
    CallByteMethodV,
    CallByteMethodA,
    CallCharMethod,
    CallCharMethodV,
    CallCharMethodA,
    CallShortMethod,
    CallShortMethodV,
    CallShortMethodA,
    CallIntMethod,
    CallIntMethodV,
    CallIntMethodA,
    CallLongMethod,
    CallLongMethodV,
    CallLongMethodA,
    CallFloatMethod,
    CallFloatMethodV,
    CallFloatMethodA,
    CallDoubleMethod,
    CallDoubleMethodV,
    CallDoubleMethodA,
    CallVoidMethod,
    CallVoidMethodV,
    CallVoidMethodA,
            
    CallNonvirtualObjectMethod,
    CallNonvirtualObjectMethodV,
    CallNonvirtualObjectMethodA,
    CallNonvirtualBooleanMethod,
    CallNonvirtualBooleanMethodV,
    CallNonvirtualBooleanMethodA,
    CallNonvirtualByteMethod,
    CallNonvirtualByteMethodV,
    CallNonvirtualByteMethodA,
    CallNonvirtualCharMethod,
    CallNonvirtualCharMethodV,
    CallNonvirtualCharMethodA,
    CallNonvirtualShortMethod,
    CallNonvirtualShortMethodV,
    CallNonvirtualShortMethodA,
    CallNonvirtualIntMethod,
    CallNonvirtualIntMethodV,
    CallNonvirtualIntMethodA,
    CallNonvirtualLongMethod,
    CallNonvirtualLongMethodV,
    CallNonvirtualLongMethodA,
    CallNonvirtualFloatMethod,
    CallNonvirtualFloatMethodV,
    CallNonvirtualFloatMethodA,
    CallNonvirtualDoubleMethod,
    CallNonvirtualDoubleMethodV,
    CallNonvirtualDoubleMethodA,
    CallNonvirtualVoidMethod,
    CallNonvirtualVoidMethodV,
    CallNonvirtualVoidMethodA,
            
    GetFieldID,
            
    GetObjectField,
    GetBooleanField,
    GetByteField,
    GetCharField,
    GetShortField,
    GetIntField,
    GetLongField,
    GetFloatField,
    GetDoubleField,
    SetObjectField,
    SetBooleanField,
    SetByteField,
    SetCharField,
    SetShortField,
    SetIntField,
    SetLongField,
    SetFloatField,
    SetDoubleField,
            
    GetStaticMethodID,
            
    CallStaticObjectMethod,
    CallStaticObjectMethodV,
    CallStaticObjectMethodA,
    CallStaticBooleanMethod,
    CallStaticBooleanMethodV,
    CallStaticBooleanMethodA,
    CallStaticByteMethod,
    CallStaticByteMethodV,
    CallStaticByteMethodA,
    CallStaticCharMethod,
    CallStaticCharMethodV,
    CallStaticCharMethodA,
    CallStaticShortMethod,
    CallStaticShortMethodV,
    CallStaticShortMethodA,
    CallStaticIntMethod,
    CallStaticIntMethodV,
    CallStaticIntMethodA,
    CallStaticLongMethod,
    CallStaticLongMethodV,
    CallStaticLongMethodA,
    CallStaticFloatMethod,
    CallStaticFloatMethodV,
    CallStaticFloatMethodA,
    CallStaticDoubleMethod,
    CallStaticDoubleMethodV,
    CallStaticDoubleMethodA,
    CallStaticVoidMethod,
    CallStaticVoidMethodV,
    CallStaticVoidMethodA,
            
    GetStaticFieldID,
            
    GetStaticObjectField,
    GetStaticBooleanField,
    GetStaticByteField,
    GetStaticCharField,
    GetStaticShortField,
    GetStaticIntField,
    GetStaticLongField,
    GetStaticFloatField,
    GetStaticDoubleField,
            
    SetStaticObjectField,
    SetStaticBooleanField,
    SetStaticByteField,
    SetStaticCharField,
    SetStaticShortField,
    SetStaticIntField,
    SetStaticLongField,
    SetStaticFloatField,
    SetStaticDoubleField,
            
    NewString,
    GetStringLength,
    GetStringChars,
    ReleaseStringChars,
            
    NewStringUTF,
    GetStringUTFLength,
    GetStringUTFChars,
    ReleaseStringUTFChars,
            
    GetArrayLength,
            
    NewObjectArray,
    GetObjectArrayElement,
    SetObjectArrayElement,
            
    NewBooleanArray,
    NewByteArray,
    NewCharArray,
    NewShortArray,
    NewIntArray,
    NewLongArray,
    NewFloatArray,
    NewDoubleArray,
            
    GetBooleanArrayElements,
    GetByteArrayElements,
    GetCharArrayElements,
    GetShortArrayElements,
    GetIntArrayElements,
    GetLongArrayElements,
    GetFloatArrayElements,
    GetDoubleArrayElements,
            
    ReleaseBooleanArrayElements,
    ReleaseByteArrayElements,
    ReleaseCharArrayElements,
    ReleaseShortArrayElements,
    ReleaseIntArrayElements,
    ReleaseLongArrayElements,
    ReleaseFloatArrayElements,
    ReleaseDoubleArrayElements,
            
    GetBooleanArrayRegion,
    GetByteArrayRegion,
    GetCharArrayRegion,
    GetShortArrayRegion,
    GetIntArrayRegion,
    GetLongArrayRegion,
    GetFloatArrayRegion,
    GetDoubleArrayRegion,
    SetBooleanArrayRegion,
    SetByteArrayRegion,
    SetCharArrayRegion,
    SetShortArrayRegion,
    SetIntArrayRegion,
    SetLongArrayRegion,
    SetFloatArrayRegion,
    SetDoubleArrayRegion,

    RegisterNatives,
    UnregisterNatives,
            
    MonitorEnter,
    MonitorExit,
            
    GetJavaVM,

    GetStringRegion,
    GetStringUTFRegion,

    GetPrimitiveArrayCritical,
    ReleasePrimitiveArrayCritical,
    
    GetStringCritical,
    ReleaseStringCritical,

    NewWeakGlobalRef,
    DeleteWeakGlobalRef,

    ExceptionCheck,

    NewDirectByteBuffer,
    GetDirectBufferAddress,
    GetDirectBufferCapacity
};
            
const struct JNIInvokeInterface_ java_vm_vtable = {
    (void*)UnimpStub,
    (void*)UnimpStub,
    (void*)UnimpStub,

    DestroyVM,

    AttachCurrentThread,
    DetachCurrentThread,

    GetEnv,

    AttachCurrentThreadAsDaemon,

};

static JavaVM_Internal java_vm = JavaVM_Internal(&java_vm_vtable, NULL, (void *)0x1234abcd);

static JNIEnv_Internal jni_env = JNIEnv_Internal(&jni_vtable, &java_vm, (void *)0x1234abcd);

struct JNIEnv_Internal *jni_native_intf = &jni_env;

void jni_init()
{
    java_vm.vm_env = VM_Global_State::loader_env;
} //jni_init


static void JNICALL UnimpStub(JNIEnv* UNREF env)
{
    // If we ever get here, we are in an implemented JNI function
    // By looking at the call stack and assembly it should be clear which one
    ABORT("Not implemented");
}


jint JNICALL GetVersion(JNIEnv * UNREF env)
{
    TRACE2("jni", "GetVersion called");
    return JNI_VERSION_1_4;
} //GetVersion

jclass JNICALL DefineClass(JNIEnv *jenv,
                           const char *name,
                           jobject loader,
                           const jbyte *buf,
                           jsize len)
{
    TRACE2("jni", "DefineClass called, name = " << name);
    assert(tmn_is_suspend_enabled());
    Global_Env* env = VM_Global_State::loader_env;
    ClassLoader* cl;
    if (loader != NULL)
        cl = class_loader_lookup(loader);
    else
        cl = env->bootstrap_class_loader;

    if(name)
    {
        //Replace '.' with '/'
        char *p = (char*)name;
        while(*p)
        {
            if(*p == '.')*p = '/';
            p++;
        }
    }

    const String* res_name;
    Class* clss = cl->DefineClass(env, name, (uint8 *)buf, 0, len, &res_name);

    bool ld_result;
    if(clss != NULL)
        ld_result = class_verify(env, clss) && class_prepare(env, clss);

    if(clss && ld_result)
    {
        assert(tmn_is_suspend_enabled());
        return struct_Class_to_jclass(clss);
    }
    else
    {
        jthrowable exn;
        if(exn_raised())
        {
            exn = exn_get();
            exn_clear();
        }
        else if(res_name)
            exn = (jthrowable)class_get_error(cl, res_name->bytes);
        else
            exn = exn_create("java/lang/LinkageError",
                "defineClass failed for unnamed class");

        assert(exn);
        jint UNUSED ok = Throw(jenv, exn);
        assert(ok == 0);
        return 0;
    }
} //DefineClass

jclass JNICALL FindClass(JNIEnv* env_ext,
                         const char* name)
{
    TRACE2("jni", "FindClass called, name = " << name);

    char *ch = strchr(name, '.');
    if (NULL != ch)
    {
        ThrowNew_Quick(env_ext, "java/lang/NoClassDefFoundError", name);
        return NULL;
    }

    String* cls_name = VM_Global_State::loader_env->string_pool.lookup(name);
    return FindClass(env_ext, cls_name);
} //FindClass

jclass JNICALL GetSuperclass(JNIEnv * UNREF env, jclass clazz)
{
    TRACE2("jni", "GetSuperclass called");
    assert(tmn_is_suspend_enabled());
    Class* clss = jclass_to_struct_Class(clazz);
    if(clss) {
        if(class_is_interface(clss)) {
            return 0;
        } else {
            Class *super_class = clss->super_class;
            if(super_class) {
                assert(tmn_is_suspend_enabled());
                return struct_Class_to_jclass(super_class);
            } else {
                return 0;
            }
        }
    } else {
        return 0;
    }
} //GetSuperclass

jboolean JNICALL IsAssignableFrom(JNIEnv * UNREF env,
                                  jclass clazz1,
                                  jclass clazz2)
{
    TRACE2("jni", "IsAssignableFrom called");
    assert(tmn_is_suspend_enabled());
    Class* clss1 = jclass_to_struct_Class(clazz1);
    Class* clss2 = jclass_to_struct_Class(clazz2);

    Boolean isAssignable = class_is_subtype(clss1, clss2);
    if (isAssignable) {
        return JNI_TRUE;
    } else {
        return JNI_FALSE;
    }
} //IsAssignableFrom

jint JNICALL Throw(JNIEnv * UNREF env, jthrowable obj)
{
    TRACE2("jni", "Throw called");
    assert(tmn_is_suspend_enabled());
    if(obj) {
        tmn_suspend_disable();       //---------------------------------v
        set_current_thread_exception(((ObjectHandle)obj)->object);
        tmn_suspend_enable();        //---------------------------------^
        return 0;
    } else {
        return -1;
    }
} // Throw

jint JNICALL ThrowNew(JNIEnv *env, jclass clazz, const char *message)
{
    TRACE2("jni", "ThrowNew called, message = " << (message ? message : "<no message>"));
    assert(tmn_is_suspend_enabled());
    if (!clazz) return -1;

    jstring str = (jstring)0;
    if(message) {
        str = NewStringUTF(env, message);
        if(!str) {
            return -1;
        }
    }

    jmethodID init_id = GetMethodID(env, clazz, "<init>", "(Ljava/lang/String;)V");
    jvalue args[1];
    args[0].l = str;
    jobject obj = NewObjectA(env, clazz, init_id, args);
    env->DeleteLocalRef(str);
    if(obj && !ExceptionOccurred(env)) {
        tmn_suspend_disable();       //---------------------------------v

        ObjectHandle h = (ObjectHandle)obj;
        set_current_thread_exception(h->object);

        tmn_suspend_enable();        //---------------------------------^
        return 0;
    } else {
        return -1;
    }
} //ThrowNew

jint JNICALL ThrowNew_Quick(JNIEnv *env, const char *classname, const char *message)
{
    jclass exclazz = FindClass(env, classname);
    if(!exclazz) {
        return -1;
    }

    jint result = ThrowNew(env, exclazz, message);
    env->DeleteLocalRef(exclazz);
    return result;
} // ThrowNew_Quick

jthrowable JNICALL ExceptionOccurred(JNIEnv * UNREF env)
{
    TRACE2("jni", "ExceptionOccurred called");
    assert(tmn_is_suspend_enabled());
#ifdef _DEBUG
    tmn_suspend_disable();
    ManagedObject *obj = get_current_thread_exception();
    if (NULL == obj)
    {
        TRACE2("jni", "Exception occured, no exception");
    }
    else
    {
        TRACE2("jni", "Exception occured, class = " << obj->vt()->clss->name->bytes);
    }
    tmn_suspend_enable();
#endif

    if(exn_raised()) {
        return exn_get();
    } else {
        return 0;
    }
} //ExceptionOccurred

void JNICALL ExceptionDescribe(JNIEnv * UNREF env)
{
    TRACE2("jni", "ExceptionDescribe called");
    assert(tmn_is_suspend_enabled());
    if (exn_raised()) {
        tmn_suspend_disable();       //---------------------------------v
        ManagedObject* exn = get_current_thread_exception();
        const char *name = exn->vt()->clss->name->bytes;
        fprintf(stderr, "JNI.ExceptionDescribe: %s:\n", name);
        exn_print_stack_trace(stderr, exn);
        tmn_suspend_enable();        //---------------------------------^
    }
} //ExceptionDescribe

void JNICALL ExceptionClear(JNIEnv * UNREF env)
{
    TRACE2("jni", "ExceptionClear called");
    assert(tmn_is_suspend_enabled());
    tmn_suspend_disable();
#ifdef _DEBUG
    ManagedObject *obj = get_current_thread_exception();
    if (NULL == obj)
    {
        TRACE2("jni", "Exception clear, no exception");
    }
    else
    {
        TRACE2("jni", "Exception clear, class = " << obj->vt()->clss->name->bytes);
    }
#endif
    clear_current_thread_exception();
    tmn_suspend_enable();
} //ExceptionClear

void JNICALL FatalError(JNIEnv * UNREF env, const char *msg)
{
    TRACE2("jni", "FatalError called");
    assert(tmn_is_suspend_enabled());
    fprintf(stderr, "\nFATAL error occurred in a JNI native method:\n\t%s\n", msg);
    vm_exit(109);
} //FatalError

jobject JNICALL NewGlobalRef(JNIEnv * UNREF env, jobject obj)
{
    TRACE2("jni", "NewGlobalRef called");
    assert(tmn_is_suspend_enabled());
    if(!obj) {
        return 0;
    }

    assert(tmn_is_suspend_enabled());
    ObjectHandle new_handle = oh_allocate_global_handle();
    ObjectHandle old_handle = (ObjectHandle)obj;

    tmn_suspend_disable();       //---------------------------------v

    new_handle->object = old_handle->object;
    TRACE2("jni", "NewGlobalRef class = " << old_handle->object->vt()->clss);

    tmn_suspend_enable();        //---------------------------------^

    return (jobject)new_handle;
} //NewGlobalRef

void JNICALL DeleteGlobalRef(JNIEnv * UNREF env, jobject globalRef)
{
    TRACE2("jni", "DeleteGlobalRef called");
    assert(tmn_is_suspend_enabled());
#ifdef _DEBUG
    tmn_suspend_disable();
    ObjectHandle h = (ObjectHandle)globalRef;
    TRACE2("jni", "DeleteGlobalRef class = " << h->object->vt()->clss);
    tmn_suspend_enable();
#endif
    if (globalRef != NULL) {
        oh_deallocate_global_handle((ObjectHandle)globalRef);
    }
} //DeleteGlobalRef

jobject JNICALL NewLocalRef(JNIEnv *env, jobject ref)
{
    TRACE2("jni", "NewLocalRef called");
    assert(tmn_is_suspend_enabled());
    if (NULL == ref)
        return NULL;

    tmn_suspend_disable();
    ObjectHandle h = oh_allocate_local_handle();
    if (NULL == h)
    {
        tmn_suspend_enable();
        exn_raise_only(
            (jthrowable)(((JNIEnv_Internal*)env)->vm->vm_env->java_lang_OutOfMemoryError));
        return NULL;
    }

    h->object= ((ObjectHandle)ref)->object;
    TRACE2("jni", "NewLocalRef class = " << h->object->vt()->clss);
    tmn_suspend_enable();
    return (jobject)h;
}

void JNICALL DeleteLocalRef(JNIEnv * UNREF env, jobject localRef)
{
    TRACE2("jni", "DeleteLocalRef called");
    assert(tmn_is_suspend_enabled());
#ifdef _DEBUG
    tmn_suspend_disable();
    ObjectHandle h = (ObjectHandle)localRef;
    TRACE2("jni", "DeleteLocalRef class = " << h->object->vt()->clss);
    tmn_suspend_enable();
#endif
    if (localRef != NULL) {
        oh_discard_local_handle((ObjectHandle)localRef);
    }
} //DeleteLocalRef

jboolean JNICALL IsSameObject(JNIEnv * UNREF env,
                              jobject ref1,
                              jobject ref2)
{
    TRACE2("jni-same", "IsSameObject called");
    assert(tmn_is_suspend_enabled());
    if(ref1 == ref2) {
        return JNI_TRUE;
    }

    if(!(ref1 && ref2)) {
        // One reference is null and the other is not.
        return JNI_FALSE;
    }

    ObjectHandle h1 = (ObjectHandle)ref1;
    ObjectHandle h2 = (ObjectHandle)ref2;

    tmn_suspend_disable();       //---------------------------------v

    ManagedObject *java_ref1 = h1->object;
    ManagedObject *java_ref2 = h2->object;
    TRACE2("jni-same", "IsSameObject: Obj1 = " << java_ref1->vt()->clss->name->bytes <<
        " Obj2 = " << java_ref2->vt()->clss->name->bytes <<
        " objects are " << ((java_ref1 == java_ref2) ? "same" : "different"));
    jboolean result = (jboolean)((java_ref1 == java_ref2) ? JNI_TRUE : JNI_FALSE);

    tmn_suspend_enable();        //---------------------------------^

    return result;
} //IsSameObject

VMEXPORT jint JNICALL PushLocalFrame(JNIEnv * UNREF env, jint UNREF cap)
{
    TRACE2("jni", "PushLocalFrame called");
    assert(tmn_is_suspend_enabled());
    // 20020904: Not good for performance, but we can ignore local frames for now
    return 0;
}

VMEXPORT jobject JNICALL PopLocalFrame(JNIEnv * UNREF env, jobject res)
{
    TRACE2("jni", "PopLocalFrame called");
    assert(tmn_is_suspend_enabled());
    // 20020904: Not good for performance, but we can ignore local frames for now
    return res;
}


jint JNICALL EnsureLocalCapacity(JNIEnv* UNREF env, jint UNREF cap)
{
    TRACE2("jni", "EnsureLocalCapacity called");
    assert(tmn_is_suspend_enabled());
    return 0;
}


jobject JNICALL AllocObject(JNIEnv *env,
                            jclass clazz)
{
    TRACE2("jni", "AllocObject called");
    assert(tmn_is_suspend_enabled());
    assert(clazz);
    Class* clss = jclass_to_struct_Class(clazz);

    if(class_is_interface(clss) || class_is_abstract(clss)) {
        // Can't instantiate interfaces and abtract classes.
        ThrowNew_Quick(env, "java/lang/InstantiationException", clss->name->bytes);
        return 0;
    }

    tmn_suspend_disable();       //---------------------------------v
    ObjectHandle new_handle = oh_allocate_local_handle();
    ManagedObject *new_obj = (ManagedObject *)class_alloc_new_object(clss);
    if (new_obj == NULL) {
        tmn_suspend_enable();
        return 0;

    }
    new_handle->object = (ManagedObject *)new_obj;
    tmn_suspend_enable();        //---------------------------------^

    return (jobject)new_handle;
} //AllocObject



jobject JNICALL NewObject(JNIEnv *env,
                          jclass clazz,
                          jmethodID methodID,
                          ...)
{
    TRACE2("jni", "NewObject called");
    assert(tmn_is_suspend_enabled());
    va_list args;
    va_start(args, methodID);
    return NewObjectV(env, clazz, methodID, args);
} //NewObject

jobject JNICALL NewObjectV(JNIEnv *env,
                           jclass clazz,
                           jmethodID methodID,
                           va_list args)
{
    TRACE2("jni", "NewObjectV called");
    assert(tmn_is_suspend_enabled());
    jvalue *jvalue_args = get_jvalue_arg_array((Method *)methodID, args);
    jobject result = NewObjectA(env, clazz, methodID, jvalue_args);
    STD_FREE(jvalue_args);
    return result;
} //NewObjectV

jobject JNICALL NewObjectA(JNIEnv *env,
                           jclass clazz,
                           jmethodID methodID,
                           jvalue *args)
{
    TRACE2("jni", "NewObjectA called");
    assert(tmn_is_suspend_enabled());
    // Allocate the object.
    jobject new_handle = AllocObject(env, clazz);

    if(!new_handle) {
        // Couldn't allocate the object.
        return 0;
    }

    CallVoidMethodA(env, new_handle, methodID, args);
    if (ExceptionCheck(env))
        return NULL;
    else
        return new_handle;
} //NewObjectA

jclass JNICALL GetObjectClass(JNIEnv * UNREF env,
                              jobject obj)<commit_msg>HARMONY-835 <commit_after>/*
 *  Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
/** 
 * @author Intel, <NAME>
 * @version $Revision: 1.1.2.2.4.5 $
 */  


#define LOG_DOMAIN "jni"
#include "cxxlog.h"

#include "platform.h"
#include "lock_manager.h"
#include "Class.h"
#include "classloader.h"
#include "environment.h"
#include "exception.h"
#include "object_handles.h"
#include "open/types.h"
#include "open/vm_util.h"
#include "vm_threads.h"
#include "open/thread.h"
#include "vm_synch.h"
#include "exceptions.h"
#include "reflection.h"
#include "ini.h"
#include "vm_arrays.h"
#include "vm_strings.h"
#include "stack_trace.h"
#include "m2n.h"
#include "nogc.h"
#include "init.h"

#include "Verifier_stub.h"

#include "jni_utils.h"

#include "jit_runtime_support.h"

#include "jvmti_direct.h"

#ifdef _IPF_
#include "stub_code_utils.h"
#endif // _IPF_

static void JNICALL UnimpStub(JNIEnv*);

struct JNINativeInterface_ jni_vtable = {
            
    (void*)UnimpStub,
    (void*)UnimpStub,
    (void*)UnimpStub,
    (void*)UnimpStub,
    GetVersion,
            
    DefineClass,
    FindClass,
    FromReflectedMethod,
    FromReflectedField,
    ToReflectedMethod,
    GetSuperclass,
    IsAssignableFrom,

    ToReflectedField,
            
    Throw,
    ThrowNew,
    ExceptionOccurred,
    ExceptionDescribe,
    ExceptionClear,
    FatalError,
    PushLocalFrame,
    PopLocalFrame,
            
    NewGlobalRef,
    DeleteGlobalRef,
    DeleteLocalRef,
    IsSameObject,
    NewLocalRef,
    EnsureLocalCapacity,
            
    AllocObject,
    NewObject,
    NewObjectV,
    NewObjectA,
            
    GetObjectClass,
    IsInstanceOf,
            
    GetMethodID,
            
    CallObjectMethod,
    CallObjectMethodV,
    CallObjectMethodA,
    CallBooleanMethod,
    CallBooleanMethodV,
    CallBooleanMethodA,
    CallByteMethod,
    CallByteMethodV,
    CallByteMethodA,
    CallCharMethod,
    CallCharMethodV,
    CallCharMethodA,
    CallShortMethod,
    CallShortMethodV,
    CallShortMethodA,
    CallIntMethod,
    CallIntMethodV,
    CallIntMethodA,
    CallLongMethod,
    CallLongMethodV,
    CallLongMethodA,
    CallFloatMethod,
    CallFloatMethodV,
    CallFloatMethodA,
    CallDoubleMethod,
    CallDoubleMethodV,
    CallDoubleMethodA,
    CallVoidMethod,
    CallVoidMethodV,
    CallVoidMethodA,
            
    CallNonvirtualObjectMethod,
    CallNonvirtualObjectMethodV,
    CallNonvirtualObjectMethodA,
    CallNonvirtualBooleanMethod,
    CallNonvirtualBooleanMethodV,
    CallNonvirtualBooleanMethodA,
    CallNonvirtualByteMethod,
    CallNonvirtualByteMethodV,
    CallNonvirtualByteMethodA,
    CallNonvirtualCharMethod,
    CallNonvirtualCharMethodV,
    CallNonvirtualCharMethodA,
    CallNonvirtualShortMethod,
    CallNonvirtualShortMethodV,
    CallNonvirtualShortMethodA,
    CallNonvirtualIntMethod,
    CallNonvirtualIntMethodV,
    CallNonvirtualIntMethodA,
    CallNonvirtualLongMethod,
    CallNonvirtualLongMethodV,
    CallNonvirtualLongMethodA,
    CallNonvirtualFloatMethod,
    CallNonvirtualFloatMethodV,
    CallNonvirtualFloatMethodA,
    CallNonvirtualDoubleMethod,
    CallNonvirtualDoubleMethodV,
    CallNonvirtualDoubleMethodA,
    CallNonvirtualVoidMethod,
    CallNonvirtualVoidMethodV,
    CallNonvirtualVoidMethodA,
            
    GetFieldID,
            
    GetObjectField,
    GetBooleanField,
    GetByteField,
    GetCharField,
    GetShortField,
    GetIntField,
    GetLongField,
    GetFloatField,
    GetDoubleField,
    SetObjectField,
    SetBooleanField,
    SetByteField,
    SetCharField,
    SetShortField,
    SetIntField,
    SetLongField,
    SetFloatField,
    SetDoubleField,
            
    GetStaticMethodID,
            
    CallStaticObjectMethod,
    CallStaticObjectMethodV,
    CallStaticObjectMethodA,
    CallStaticBooleanMethod,
    CallStaticBooleanMethodV,
    CallStaticBooleanMethodA,
    CallStaticByteMethod,
    CallStaticByteMethodV,
    CallStaticByteMethodA,
    CallStaticCharMethod,
    CallStaticCharMethodV,
    CallStaticCharMethodA,
    CallStaticShortMethod,
    CallStaticShortMethodV,
    CallStaticShortMethodA,
    CallStaticIntMethod,
    CallStaticIntMethodV,
    CallStaticIntMethodA,
    CallStaticLongMethod,
    CallStaticLongMethodV,
    CallStaticLongMethodA,
    CallStaticFloatMethod,
    CallStaticFloatMethodV,
    CallStaticFloatMethodA,
    CallStaticDoubleMethod,
    CallStaticDoubleMethodV,
    CallStaticDoubleMethodA,
    CallStaticVoidMethod,
    CallStaticVoidMethodV,
    CallStaticVoidMethodA,
            
    GetStaticFieldID,
            
    GetStaticObjectField,
    GetStaticBooleanField,
    GetStaticByteField,
    GetStaticCharField,
    GetStaticShortField,
    GetStaticIntField,
    GetStaticLongField,
    GetStaticFloatField,
    GetStaticDoubleField,
            
    SetStaticObjectField,
    SetStaticBooleanField,
    SetStaticByteField,
    SetStaticCharField,
    SetStaticShortField,
    SetStaticIntField,
    SetStaticLongField,
    SetStaticFloatField,
    SetStaticDoubleField,
            
    NewString,
    GetStringLength,
    GetStringChars,
    ReleaseStringChars,
            
    NewStringUTF,
    GetStringUTFLength,
    GetStringUTFChars,
    ReleaseStringUTFChars,
            
    GetArrayLength,
            
    NewObjectArray,
    GetObjectArrayElement,
    SetObjectArrayElement,
            
    NewBooleanArray,
    NewByteArray,
    NewCharArray,
    NewShortArray,
    NewIntArray,
    NewLongArray,
    NewFloatArray,
    NewDoubleArray,
            
    GetBooleanArrayElements,
    GetByteArrayElements,
    GetCharArrayElements,
    GetShortArrayElements,
    GetIntArrayElements,
    GetLongArrayElements,
    GetFloatArrayElements,
    GetDoubleArrayElements,
            
    ReleaseBooleanArrayElements,
    ReleaseByteArrayElements,
    ReleaseCharArrayElements,
    ReleaseShortArrayElements,
    ReleaseIntArrayElements,
    ReleaseLongArrayElements,
    ReleaseFloatArrayElements,
    ReleaseDoubleArrayElements,
            
    GetBooleanArrayRegion,
    GetByteArrayRegion,
    GetCharArrayRegion,
    GetShortArrayRegion,
    GetIntArrayRegion,
    GetLongArrayRegion,
    GetFloatArrayRegion,
    GetDoubleArrayRegion,
    SetBooleanArrayRegion,
    SetByteArrayRegion,
    SetCharArrayRegion,
    SetShortArrayRegion,
    SetIntArrayRegion,
    SetLongArrayRegion,
    SetFloatArrayRegion,
    SetDoubleArrayRegion,

    RegisterNatives,
    UnregisterNatives,
            
    MonitorEnter,
    MonitorExit,
            
    GetJavaVM,

    GetStringRegion,
    GetStringUTFRegion,

    GetPrimitiveArrayCritical,
    ReleasePrimitiveArrayCritical,
    
    GetStringCritical,
    ReleaseStringCritical,

    NewWeakGlobalRef,
    DeleteWeakGlobalRef,

    ExceptionCheck,

    NewDirectByteBuffer,
    GetDirectBufferAddress,
    GetDirectBufferCapacity
};
            
const struct JNIInvokeInterface_ java_vm_vtable = {
    (void*)UnimpStub,
    (void*)UnimpStub,
    (void*)UnimpStub,

    DestroyVM,

    AttachCurrentThread,
    DetachCurrentThread,

    GetEnv,

    AttachCurrentThreadAsDaemon,

};

static JavaVM_Internal java_vm = JavaVM_Internal(&java_vm_vtable, NULL, (void *)0x1234abcd);

static JNIEnv_Internal jni_env = JNIEnv_Internal(&jni_vtable, &java_vm, (void *)0x1234abcd);

struct JNIEnv_Internal *jni_native_intf = &jni_env;

void jni_init()
{
    java_vm.vm_env = VM_Global_State::loader_env;
} //jni_init


static void JNICALL UnimpStub(JNIEnv* UNREF env)
{
    // If we ever get here, we are in an implemented JNI function
    // By looking at the call stack and assembly it should be clear which one
    ABORT("Not implemented");
}


jint JNICALL GetVersion(JNIEnv * UNREF env)
{
    TRACE2("jni", "GetVersion called");
    return JNI_VERSION_1_4;
} //GetVersion

jclass JNICALL DefineClass(JNIEnv *jenv,
                           const char *name,
                           jobject loader,
                           const jbyte *buf,
                           jsize len)
{
    TRACE2("jni", "DefineClass called, name = " << name);
    assert(tmn_is_suspend_enabled());
    Global_Env* env = VM_Global_State::loader_env;
    ClassLoader* cl;
    if (loader != NULL)
        cl = class_loader_lookup(loader);
    else
        cl = env->bootstrap_class_loader;

    if(name)
    {
        //Replace '.' with '/'
        char *p = (char*)name;
        while(*p)
        {
            if(*p == '.')*p = '/';
            p++;
        }
    }

    const String* res_name;
    Class* clss = cl->DefineClass(env, name, (uint8 *)buf, 0, len, &res_name);

    bool ld_result;
    if(clss != NULL)
        ld_result = class_verify(env, clss) && class_prepare(env, clss);

    if(clss && ld_result)
    {
        assert(tmn_is_suspend_enabled());
        return struct_Class_to_jclass(clss);
    }
    else
    {
        jthrowable exn;
        if(exn_raised())
        {
            exn = exn_get();
            exn_clear();
        }
        else if(res_name)
            exn = (jthrowable)class_get_error(cl, res_name->bytes);
        else
            exn = exn_create("java/lang/LinkageError",
                "defineClass failed for unnamed class");

        assert(exn);
        jint UNUSED ok = Throw(jenv, exn);
        assert(ok == 0);
        return 0;
    }
} //DefineClass

jclass JNICALL FindClass(JNIEnv* env_ext,
                         const char* name)
{
    TRACE2("jni", "FindClass called, name = " << name);

    char *ch = strchr(name, '.');
    if (NULL != ch)
    {
        ThrowNew_Quick(env_ext, "java/lang/NoClassDefFoundError", name);
        return NULL;
    }

    String* cls_name = VM_Global_State::loader_env->string_pool.lookup(name);
    return FindClass(env_ext, cls_name);
} //FindClass

jclass JNICALL GetSuperclass(JNIEnv * UNREF env, jclass clazz)
{
    TRACE2("jni", "GetSuperclass called");
    assert(tmn_is_suspend_enabled());
    Class* clss = jclass_to_struct_Class(clazz);
    if(clss) {
        if(class_is_interface(clss)) {
            return 0;
        } else {
            Class *super_class = clss->super_class;
            if(super_class) {
                assert(tmn_is_suspend_enabled());
                return struct_Class_to_jclass(super_class);
            } else {
                return 0;
            }
        }
    } else {
        return 0;
    }
} //GetSuperclass

jboolean JNICALL IsAssignableFrom(JNIEnv * UNREF env,
                                  jclass clazz1,
                                  jclass clazz2)
{
    TRACE2("jni", "IsAssignableFrom called");
    assert(tmn_is_suspend_enabled());
    Class* clss1 = jclass_to_struct_Class(clazz1);
    Class* clss2 = jclass_to_struct_Class(clazz2);

    Boolean isAssignable = class_is_subtype(clss1, clss2);
    if (isAssignable) {
        return JNI_TRUE;
    } else {
        return JNI_FALSE;
    }
} //IsAssignableFrom

jint JNICALL Throw(JNIEnv * UNREF env, jthrowable obj)
{
    TRACE2("jni", "Throw called");
    assert(tmn_is_suspend_enabled());
    if(obj) {
        tmn_suspend_disable();       //---------------------------------v
        set_current_thread_exception(((ObjectHandle)obj)->object);
        tmn_suspend_enable();        //---------------------------------^
        return 0;
    } else {
        return -1;
    }
} // Throw

jint JNICALL ThrowNew(JNIEnv *env, jclass clazz, const char *message)
{
    TRACE2("jni", "ThrowNew called, message = " << (message ? message : "<no message>"));
    assert(tmn_is_suspend_enabled());
    if (!clazz) return -1;

    jstring str = (jstring)0;
    if(message) {
        str = NewStringUTF(env, message);
        if(!str) {
            return -1;
        }
    }

    jmethodID init_id = GetMethodID(env, clazz, "<init>", "(Ljava/lang/String;)V");
    jvalue args[1];
    args[0].l = str;
    jobject obj = NewObjectA(env, clazz, init_id, args);
    env->DeleteLocalRef(str);
    if(obj && !ExceptionOccurred(env)) {
        tmn_suspend_disable();       //---------------------------------v

        ObjectHandle h = (ObjectHandle)obj;
        set_current_thread_exception(h->object);

        tmn_suspend_enable();        //---------------------------------^
        return 0;
    } else {
        return -1;
    }
} //ThrowNew

jint JNICALL ThrowNew_Quick(JNIEnv *env, const char *classname, const char *message)
{
    jclass exclazz = FindClass(env, classname);
    if(!exclazz) {
        return -1;
    }

    jint result = ThrowNew(env, exclazz, message);
    env->DeleteLocalRef(exclazz);
    return result;
} // ThrowNew_Quick

jthrowable JNICALL ExceptionOccurred(JNIEnv * UNREF env)
{
    TRACE2("jni", "ExceptionOccurred called");
    assert(tmn_is_suspend_enabled());
#ifdef _DEBUG
    tmn_suspend_disable();
    ManagedObject *obj = get_current_thread_exception();
    if (NULL == obj)
    {
        TRACE2("jni", "Exception occured, no exception");
    }
    else
    {
        TRACE2("jni", "Exception occured, class = " << obj->vt()->clss->name->bytes);
    }
    tmn_suspend_enable();
#endif

    if(exn_raised()) {
        return exn_get();
    } else {
        return 0;
    }
} //ExceptionOccurred

void JNICALL ExceptionDescribe(JNIEnv * UNREF env)
{
    TRACE2("jni", "ExceptionDescribe called");
    assert(tmn_is_suspend_enabled());
    if (exn_raised()) {
        tmn_suspend_disable();       //---------------------------------v
        ManagedObject* exn = get_current_thread_exception();
        const char *name = exn->vt()->clss->name->bytes;
        fprintf(stderr, "JNI.ExceptionDescribe: %s:\n", name);
        exn_print_stack_trace(stderr, exn);
        tmn_suspend_enable();        //---------------------------------^
    }
} //ExceptionDescribe

void JNICALL ExceptionClear(JNIEnv * UNREF env)
{
    TRACE2("jni", "ExceptionClear called");
    assert(tmn_is_suspend_enabled());
    tmn_suspend_disable();
#ifdef _DEBUG
    ManagedObject *obj = get_current_thread_exception();
    if (NULL == obj)
    {
        TRACE2("jni", "Exception clear, no exception");
    }
    else
    {
        TRACE2("jni", "Exception clear, class = " << obj->vt()->clss->name->bytes);
    }
#endif
    clear_current_thread_exception();
    tmn_suspend_enable();
} //ExceptionClear

void JNICALL FatalError(JNIEnv * UNREF env, const char *msg)
{
    TRACE2("jni", "FatalError called");
    assert(tmn_is_suspend_enabled());
    fprintf(stderr, "\nFATAL error occurred in a JNI native method:\n\t%s\n", msg);
    vm_exit(109);
} //FatalError

jobject JNICALL NewGlobalRef(JNIEnv * UNREF env, jobject obj)
{
    TRACE2("jni", "NewGlobalRef called");
    assert(tmn_is_suspend_enabled());
    if(!obj) {
        return 0;
    }

    assert(tmn_is_suspend_enabled());
    ObjectHandle new_handle = oh_allocate_global_handle();
    ObjectHandle old_handle = (ObjectHandle)obj;

    tmn_suspend_disable();       //---------------------------------v

    new_handle->object = old_handle->object;
    TRACE2("jni", "NewGlobalRef class = " << old_handle->object->vt()->clss);

    tmn_suspend_enable();        //---------------------------------^

    return (jobject)new_handle;
} //NewGlobalRef

void JNICALL DeleteGlobalRef(JNIEnv * UNREF env, jobject globalRef)
{
    TRACE2("jni", "DeleteGlobalRef called");
    assert(tmn_is_suspend_enabled());
#ifdef _DEBUG
    tmn_suspend_disable();
    ObjectHandle h = (ObjectHandle)globalRef;
    TRACE2("jni", "DeleteGlobalRef class = " << h->object->vt()->clss);
    tmn_suspend_enable();
#endif
    if (globalRef != NULL) {
        oh_deallocate_global_handle((ObjectHandle)globalRef);
    }
} //DeleteGlobalRef

jobject JNICALL NewLocalRef(JNIEnv *env, jobject ref)
{
    TRACE2("jni", "NewLocalRef called");
    assert(tmn_is_suspend_enabled());
    if (NULL == ref)
        return NULL;

    tmn_suspend_disable();
    ObjectHandle h = oh_allocate_local_handle();
    if (NULL == h)
    {
        tmn_suspend_enable();
        exn_raise_only(
            (jthrowable)(((JNIEnv_Internal*)env)->vm->vm_env->java_lang_OutOfMemoryError));
        return NULL;
    }

    h->object= ((ObjectHandle)ref)->object;
    TRACE2("jni", "NewLocalRef class = " << h->object->vt()->clss);
    tmn_suspend_enable();
    return (jobject)h;
}

void JNICALL DeleteLocalRef(JNIEnv * UNREF env, jobject localRef)
{
    TRACE2("jni", "DeleteLocalRef called");
    assert(tmn_is_suspend_enabled());
#ifdef _DEBUG
    tmn_suspend_disable();
    ObjectHandle h = (ObjectHandle)localRef;
    TRACE2("jni", "DeleteLocalRef class = " << h->object->vt()->clss);
    tmn_suspend_enable();
#endif
    if (localRef != NULL) {
        oh_discard_local_handle((ObjectHandle)localRef);
    }
} //DeleteLocalRef

jboolean JNICALL IsSameObject(JNIEnv * UNREF env,
                              jobject ref1,
                              jobject ref2)
{
    TRACE2("jni-same", "IsSameObject called");
    assert(tmn_is_suspend_enabled());
    if(ref1 == ref2) {
        return JNI_TRUE;
    }

    if(!(ref1 && ref2)) {
        // One reference is null and the other is not.
        return JNI_FALSE;
    }

    ObjectHandle h1 = (ObjectHandle)ref1;
    ObjectHandle h2 = (ObjectHandle)ref2;

    tmn_suspend_disable();       //---------------------------------v

    ManagedObject *java_ref1 = h1->object;
    ManagedObject *java_ref2 = h2->object;
    TRACE2("jni-same", "IsSameObject: Obj1 = " << java_ref1->vt()->clss->name->bytes <<
        " Obj2 = " << java_ref2->vt()->clss->name->bytes <<
        " objects are " << ((java_ref1 == java_ref2) ? "same" : "different"));
    jboolean result = (jboolean)((java_ref1 == java_ref2) ? JNI_TRUE : JNI_FALSE);

    tmn_suspend_enable();        //---------------------------------^

    return result;
} //IsSameObject

VMEXPORT jint JNICALL PushLocalFrame(JNIEnv * UNREF env, jint UNREF cap)
{
    TRACE2("jni", "PushLocalFrame called");
    assert(tmn_is_suspend_enabled());
    // 20020904: Not good for performance, but we can ignore local frames for now
    return 0;
}

VMEXPORT jobject JNICALL PopLocalFrame(JNIEnv * UNREF env, jobject res)
{
    TRACE2("jni", "PopLocalFrame called");
    assert(tmn_is_suspend_enabled());
    // 20020904: Not good for performance, but we can ignore local frames for now
    return res;
}


jint JNICALL EnsureLocalCapacity(JNIEnv* UNREF env, jint UNREF cap)
{
    TRACE2("jni", "EnsureLocalCapacity called");
    assert(tmn_is_suspend_enabled());
    return 0;
}


jobject JNICALL AllocObject(JNIEnv *env,
                            jclass clazz)
{
    TRACE2("jni", "AllocObject called");
    assert(tmn_is_suspend_enabled());
    assert(clazz);
    Class* clss = jclass_to_struct_Class(clazz);

    if(class_is_interface(clss) || class_is_abstract(clss)) {
        // Can't instantiate interfaces and abtract classes.
        ThrowNew_Quick(env, "java/lang/InstantiationException", clss->name->bytes);
        return 0;
    }

    tmn_suspend_disable();       //---------------------------------v
    ObjectHandle new_handle = oh_allocate_local_handle();
    ManagedObject *new_obj = (ManagedObject *)class_alloc_new_object(clss);
    if (new_obj == NULL) {
        tmn_suspend_enable();
        return 0;

    }
    new_handle->object = (ManagedObject *)new_obj;
    tmn_suspend_enable();        //---------------------------------^

    return (jobject)new_handle;
} //AllocObject



jobject JNICALL NewObject(JNIEnv *env,
                          jclass clazz,
                          jmethodID methodID,
                          ...)
{
    TRACE2("jni", "NewObject called");
    assert(tmn_is_suspend_enabled());
    va_list args;
    va_start(args, methodID);
    return NewObjectV(env, clazz, methodID, args);
} //NewObject

jobject JNICALL NewObjectV(JNIEnv *env,
                           jclass clazz,
                           jmethodID methodID,
                           va_list args)
{
    TRACE2("jni", "NewObjectV called");
    assert(tmn_is_suspend_enabled());
    jvalue *jvalue_args = get_jvalue_arg_array((Method *)methodID, args);
    jobject result = NewObjectA(env, clazz, methodID, jvalue_args);
    STD_FREE(jvalue_args);
    return result;
} //NewObjectV

jobject JNICALL NewObjectA(JNIEnv *env,
                           jclass clazz,
                           jmethodID methodID,
                           jvalue *args)
{
    TRACE2("jni", "NewObjectA called");
    assert(tmn_is_suspend_enabled());
    // Allocate the object.
    jobject new_handle = AllocObject(env, clazz);

    if(!new_handle) {
        // Couldn't allocate the object.
        return 0;
    }

    CallNonvirtualVoidMethodA(env, new_handle, clazz, methodID, args);
    if (ExceptionCheck(env))
        return NULL;
    else
        return new_handle;
} //NewObjectA

jclass JNICALL GetObjectClass(JNIEnv * UNREF env,
                              jobject obj)
{'fraction_non_alphanumeric': 0.11717728376611246, 'fraction_numerical': 0.006421632729310667, 'mean_word_length': 2.588486676721971, 'pattern_counts': {'":': 0, '<': 65, '<?xml version=': 0, '>': 115, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5906933', 'n_tokens_mistral': 13769, 'n_tokens_neox': 13556, 'n_words': 2625}