/* * Copyright (C) 2008 The Android Open Source Project * * 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. */ /* * JNI innards, common to the regular and "checked" interfaces. */ #ifndef _DALVIK_JNIINTERNAL #define _DALVIK_JNIINTERNAL #include "jni.h" /* system init/shutdown */ bool dvmJniStartup(void); void dvmJniShutdown(void); /* * Our data structures for JNIEnv and JavaVM. * * Native code thinks it has a pointer to a pointer. We know better. */ struct JavaVMExt; typedef struct JNIEnvExt { const struct JNINativeInterface* funcTable; /* must be first */ const struct JNINativeInterface* baseFuncTable; /* pointer to the VM we are a part of */ struct JavaVMExt* vm; u4 envThreadId; Thread* self; /* if nonzero, we are in a "critical" JNI call */ int critical; /* keep a copy of this here for speed */ bool forceDataCopy; struct JNIEnvExt* prev; struct JNIEnvExt* next; } JNIEnvExt; typedef struct JavaVMExt { const struct JNIInvokeInterface* funcTable; /* must be first */ const struct JNIInvokeInterface* baseFuncTable; /* if multiple VMs are desired, add doubly-linked list stuff here */ /* per-VM feature flags */ bool useChecked; bool warnError; bool forceDataCopy; /* head of list of JNIEnvs associated with this VM */ JNIEnvExt* envList; pthread_mutex_t envListLock; } JavaVMExt; /* * Native function return type; used by dvmPlatformInvoke(). * * This is part of Method.jniArgInfo, and must fit in 3 bits. * Note: Assembly code in arch/<arch>/Call<arch>.S relies on * the enum values defined here. */ typedef enum DalvikJniReturnType { DALVIK_JNI_RETURN_VOID = 0, /* must be zero */ DALVIK_JNI_RETURN_FLOAT = 1, DALVIK_JNI_RETURN_DOUBLE = 2, DALVIK_JNI_RETURN_S8 = 3, DALVIK_JNI_RETURN_S4 = 4, DALVIK_JNI_RETURN_S2 = 5, DALVIK_JNI_RETURN_U2 = 6, DALVIK_JNI_RETURN_S1 = 7 } DalvikJniReturnType; #define DALVIK_JNI_NO_ARG_INFO 0x80000000 #define DALVIK_JNI_RETURN_MASK 0x70000000 #define DALVIK_JNI_RETURN_SHIFT 28 #define DALVIK_JNI_COUNT_MASK 0x0f000000 #define DALVIK_JNI_COUNT_SHIFT 24 /* * Pop the JNI local stack when we return from a native method. "saveArea" * points to the StackSaveArea for the method we're leaving. * * (This may be implemented directly in assembly in mterp, so changes here * may only affect the portable interpreter.) */ INLINE void dvmPopJniLocals(Thread* self, StackSaveArea* saveArea) { #ifdef USE_INDIRECT_REF self->jniLocalRefTable.segmentState.all = saveArea->xtra.localRefCookie; #else self->jniLocalRefTable.nextEntry = saveArea->xtra.localRefCookie; #endif } /* * Set the envThreadId field. */ INLINE void dvmSetJniEnvThreadId(JNIEnv* pEnv, Thread* self) { ((JNIEnvExt*)pEnv)->envThreadId = self->threadId; ((JNIEnvExt*)pEnv)->self = self; } /* * JNI call bridges. Not called directly. * * The "Check" versions are used when CheckJNI is enabled. */ void dvmCallJNIMethod_general(const u4* args, JValue* pResult, const Method* method, Thread* self); void dvmCallJNIMethod_synchronized(const u4* args, JValue* pResult, const Method* method, Thread* self); void dvmCallJNIMethod_virtualNoRef(const u4* args, JValue* pResult, const Method* method, Thread* self); void dvmCallJNIMethod_staticNoRef(const u4* args, JValue* pResult, const Method* method, Thread* self); void dvmCheckCallJNIMethod_general(const u4* args, JValue* pResult, const Method* method, Thread* self); void dvmCheckCallJNIMethod_synchronized(const u4* args, JValue* pResult, const Method* method, Thread* self); void dvmCheckCallJNIMethod_virtualNoRef(const u4* args, JValue* pResult, const Method* method, Thread* self); void dvmCheckCallJNIMethod_staticNoRef(const u4* args, JValue* pResult, const Method* method, Thread* self); /* * Configure "method" to use the JNI bridge to call "func". */ void dvmUseJNIBridge(Method* method, void* func); /* * Enable the "checked" versions. */ void dvmUseCheckedJniEnv(JNIEnvExt* pEnv); void dvmUseCheckedJniVm(JavaVMExt* pVm); void dvmLateEnableCheckedJni(void); /* * Decode a local, global, or weak-global reference. */ #ifdef USE_INDIRECT_REF Object* dvmDecodeIndirectRef(JNIEnv* env, jobject jobj); #else /* use an inline to ensure this is a no-op */ INLINE Object* dvmDecodeIndirectRef(JNIEnv* env, jobject jobj) { return (Object*) jobj; } #endif /* * Verify that a reference passed in from native code is valid. Returns * an indication of local/global/invalid. */ jobjectRefType dvmGetJNIRefType(JNIEnv* env, jobject jobj); /* * Get the last method called on the interp stack. This is the method * "responsible" for calling into JNI. */ const Method* dvmGetCurrentJNIMethod(void); /* * Create/destroy a JNIEnv for the current thread. */ JNIEnv* dvmCreateJNIEnv(Thread* self); void dvmDestroyJNIEnv(JNIEnv* env); /* * Find the JNIEnv associated with the current thread. */ JNIEnvExt* dvmGetJNIEnvForThread(void); /* * Extract the return type enum from the "jniArgInfo" value. */ DalvikJniReturnType dvmGetArgInfoReturnType(int jniArgInfo); /* * Release all MonitorEnter-acquired locks that are still held. Called at * DetachCurrentThread time. */ void dvmReleaseJniMonitors(Thread* self); /* * Dump the contents of the JNI reference tables to the log file. * * The local ref tables associated with other threads are not included. */ void dvmDumpJniReferenceTables(void); /* * This mask is applied to weak global reference values returned to * native code. The goal is to create an invalid pointer that will cause * a crash if misused. The mmap region for the virtual heap is typically * around 0x40xxxxxx. * * To make weak global references easily distinguishable from other kinds * of references when !USE_INDIRECT_REF, we XOR the low bits. Assuming >= * 64-bit alignment of objects, this changes the low 3 bits from all clear * to all set. */ #define WEAK_GLOBAL_XOR 0x9e0fffff /* * "Obfuscate" a weak global reference pointer. */ INLINE jweak dvmObfuscateWeakGlobalRef(jobject jobj) { return (jweak) ((u4) jobj ^ WEAK_GLOBAL_XOR); } /* * Undo the obfuscation. */ INLINE jobject dvmNormalizeWeakGlobalRef(jweak ref) { return (jobject) ((u4) ref ^ WEAK_GLOBAL_XOR); } /* * Returns "true" if this looks like a weak global reference. * * Relies on the low 3 bits being set instead of clear (the latter is * guaranteed by 64-bit alignment of objects). */ INLINE bool dvmIsWeakGlobalRef(jobject jobj) { return (((u4) jobj & 0x07) == 0x07); } #endif /*_DALVIK_JNIINTERNAL*/