The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2008 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | /* |
| 17 | * JNI innards, common to the regular and "checked" interfaces. |
| 18 | */ |
| 19 | #ifndef _DALVIK_JNIINTERNAL |
| 20 | #define _DALVIK_JNIINTERNAL |
| 21 | |
| 22 | #include "jni.h" |
| 23 | |
| 24 | /* system init/shutdown */ |
| 25 | bool dvmJniStartup(void); |
| 26 | void dvmJniShutdown(void); |
| 27 | |
| 28 | /* |
| 29 | * Our data structures for JNIEnv and JavaVM. |
| 30 | * |
| 31 | * Native code thinks it has a pointer to a pointer. We know better. |
| 32 | */ |
| 33 | struct JavaVMExt; |
| 34 | |
| 35 | typedef struct JNIEnvExt { |
| 36 | const struct JNINativeInterface* funcTable; /* must be first */ |
| 37 | |
| 38 | const struct JNINativeInterface* baseFuncTable; |
| 39 | |
| 40 | /* pointer to the VM we are a part of */ |
| 41 | struct JavaVMExt* vm; |
| 42 | |
| 43 | u4 envThreadId; |
| 44 | Thread* self; |
| 45 | |
| 46 | /* if nonzero, we are in a "critical" JNI call */ |
| 47 | int critical; |
| 48 | |
| 49 | /* keep a copy of this here for speed */ |
| 50 | bool forceDataCopy; |
| 51 | |
| 52 | struct JNIEnvExt* prev; |
| 53 | struct JNIEnvExt* next; |
| 54 | } JNIEnvExt; |
| 55 | |
| 56 | typedef struct JavaVMExt { |
| 57 | const struct JNIInvokeInterface* funcTable; /* must be first */ |
| 58 | |
| 59 | const struct JNIInvokeInterface* baseFuncTable; |
| 60 | |
| 61 | /* if multiple VMs are desired, add doubly-linked list stuff here */ |
| 62 | |
| 63 | /* per-VM feature flags */ |
| 64 | bool useChecked; |
| 65 | bool warnError; |
| 66 | bool forceDataCopy; |
| 67 | |
| 68 | /* head of list of JNIEnvs associated with this VM */ |
| 69 | JNIEnvExt* envList; |
| 70 | pthread_mutex_t envListLock; |
| 71 | } JavaVMExt; |
| 72 | |
| 73 | /* |
| 74 | * Native function return type; used by dvmPlatformInvoke(). |
Andy McFadden | 8e5c784 | 2009-07-23 17:47:18 -0700 | [diff] [blame] | 75 | * |
| 76 | * This is part of Method.jniArgInfo, and must fit in 3 bits. |
Bill Buzbee | e255751 | 2009-07-27 15:51:54 -0700 | [diff] [blame] | 77 | * Note: Assembly code in arch/<arch>/Call<arch>.S relies on |
| 78 | * the enum values defined here. |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 79 | */ |
| 80 | typedef enum DalvikJniReturnType { |
| 81 | DALVIK_JNI_RETURN_VOID = 0, /* must be zero */ |
Bill Buzbee | e255751 | 2009-07-27 15:51:54 -0700 | [diff] [blame] | 82 | DALVIK_JNI_RETURN_FLOAT = 1, |
| 83 | DALVIK_JNI_RETURN_DOUBLE = 2, |
| 84 | DALVIK_JNI_RETURN_S8 = 3, |
| 85 | DALVIK_JNI_RETURN_S4 = 4, |
| 86 | DALVIK_JNI_RETURN_S2 = 5, |
| 87 | DALVIK_JNI_RETURN_U2 = 6, |
| 88 | DALVIK_JNI_RETURN_S1 = 7 |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 89 | } DalvikJniReturnType; |
| 90 | |
| 91 | #define DALVIK_JNI_NO_ARG_INFO 0x80000000 |
| 92 | #define DALVIK_JNI_RETURN_MASK 0x70000000 |
| 93 | #define DALVIK_JNI_RETURN_SHIFT 28 |
| 94 | #define DALVIK_JNI_COUNT_MASK 0x0f000000 |
| 95 | #define DALVIK_JNI_COUNT_SHIFT 24 |
| 96 | |
| 97 | |
| 98 | /* |
| 99 | * Pop the JNI local stack when we return from a native method. "saveArea" |
| 100 | * points to the StackSaveArea for the method we're leaving. |
Andy McFadden | d5ab726 | 2009-08-25 07:19:34 -0700 | [diff] [blame] | 101 | * |
| 102 | * (This may be implemented directly in assembly in mterp, so changes here |
| 103 | * may only affect the portable interpreter.) |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 104 | */ |
| 105 | INLINE void dvmPopJniLocals(Thread* self, StackSaveArea* saveArea) |
| 106 | { |
Andy McFadden | d5ab726 | 2009-08-25 07:19:34 -0700 | [diff] [blame] | 107 | #ifdef USE_INDIRECT_REF |
| 108 | self->jniLocalRefTable.segmentState.all = saveArea->xtra.localRefCookie; |
| 109 | #else |
| 110 | self->jniLocalRefTable.nextEntry = saveArea->xtra.localRefCookie; |
| 111 | #endif |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 112 | } |
| 113 | |
| 114 | /* |
| 115 | * Set the envThreadId field. |
| 116 | */ |
| 117 | INLINE void dvmSetJniEnvThreadId(JNIEnv* pEnv, Thread* self) |
| 118 | { |
| 119 | ((JNIEnvExt*)pEnv)->envThreadId = self->threadId; |
| 120 | ((JNIEnvExt*)pEnv)->self = self; |
| 121 | } |
| 122 | |
| 123 | /* |
Andy McFadden | 0083d37 | 2009-08-21 14:44:04 -0700 | [diff] [blame] | 124 | * JNI call bridges. Not called directly. |
Andy McFadden | 59b6177 | 2009-05-13 16:44:34 -0700 | [diff] [blame] | 125 | * |
| 126 | * The "Check" versions are used when CheckJNI is enabled. |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 127 | */ |
Andy McFadden | 0083d37 | 2009-08-21 14:44:04 -0700 | [diff] [blame] | 128 | void dvmCallJNIMethod_general(const u4* args, JValue* pResult, |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 129 | const Method* method, Thread* self); |
Andy McFadden | 0083d37 | 2009-08-21 14:44:04 -0700 | [diff] [blame] | 130 | void dvmCallJNIMethod_synchronized(const u4* args, JValue* pResult, |
Andy McFadden | 59b6177 | 2009-05-13 16:44:34 -0700 | [diff] [blame] | 131 | const Method* method, Thread* self); |
Andy McFadden | 0083d37 | 2009-08-21 14:44:04 -0700 | [diff] [blame] | 132 | void dvmCallJNIMethod_virtualNoRef(const u4* args, JValue* pResult, |
| 133 | const Method* method, Thread* self); |
| 134 | void dvmCallJNIMethod_staticNoRef(const u4* args, JValue* pResult, |
| 135 | const Method* method, Thread* self); |
| 136 | void dvmCheckCallJNIMethod_general(const u4* args, JValue* pResult, |
| 137 | const Method* method, Thread* self); |
| 138 | void dvmCheckCallJNIMethod_synchronized(const u4* args, JValue* pResult, |
| 139 | const Method* method, Thread* self); |
| 140 | void dvmCheckCallJNIMethod_virtualNoRef(const u4* args, JValue* pResult, |
| 141 | const Method* method, Thread* self); |
| 142 | void dvmCheckCallJNIMethod_staticNoRef(const u4* args, JValue* pResult, |
Andy McFadden | 59b6177 | 2009-05-13 16:44:34 -0700 | [diff] [blame] | 143 | const Method* method, Thread* self); |
| 144 | |
| 145 | /* |
| 146 | * Configure "method" to use the JNI bridge to call "func". |
| 147 | */ |
| 148 | void dvmUseJNIBridge(Method* method, void* func); |
| 149 | |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 150 | |
| 151 | /* |
| 152 | * Enable the "checked" versions. |
| 153 | */ |
| 154 | void dvmUseCheckedJniEnv(JNIEnvExt* pEnv); |
| 155 | void dvmUseCheckedJniVm(JavaVMExt* pVm); |
| 156 | void dvmLateEnableCheckedJni(void); |
| 157 | |
| 158 | /* |
Andy McFadden | ab00d45 | 2009-08-19 07:21:41 -0700 | [diff] [blame] | 159 | * Decode a local, global, or weak-global reference. |
| 160 | */ |
Andy McFadden | eb9cbc3 | 2009-08-28 14:45:12 -0700 | [diff] [blame] | 161 | #ifdef USE_INDIRECT_REF |
Andy McFadden | ab00d45 | 2009-08-19 07:21:41 -0700 | [diff] [blame] | 162 | Object* dvmDecodeIndirectRef(JNIEnv* env, jobject jobj); |
Andy McFadden | eb9cbc3 | 2009-08-28 14:45:12 -0700 | [diff] [blame] | 163 | #else |
| 164 | /* use an inline to ensure this is a no-op */ |
| 165 | INLINE Object* dvmDecodeIndirectRef(JNIEnv* env, jobject jobj) { |
| 166 | return (Object*) jobj; |
| 167 | } |
| 168 | #endif |
Andy McFadden | ab00d45 | 2009-08-19 07:21:41 -0700 | [diff] [blame] | 169 | |
| 170 | /* |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 171 | * Verify that a reference passed in from native code is valid. Returns |
| 172 | * an indication of local/global/invalid. |
| 173 | */ |
Andy McFadden | ab00d45 | 2009-08-19 07:21:41 -0700 | [diff] [blame] | 174 | jobjectRefType dvmGetJNIRefType(JNIEnv* env, jobject jobj); |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 175 | |
| 176 | /* |
| 177 | * Get the last method called on the interp stack. This is the method |
| 178 | * "responsible" for calling into JNI. |
| 179 | */ |
| 180 | const Method* dvmGetCurrentJNIMethod(void); |
| 181 | |
| 182 | /* |
| 183 | * Create/destroy a JNIEnv for the current thread. |
| 184 | */ |
| 185 | JNIEnv* dvmCreateJNIEnv(Thread* self); |
| 186 | void dvmDestroyJNIEnv(JNIEnv* env); |
| 187 | |
| 188 | /* |
| 189 | * Find the JNIEnv associated with the current thread. |
| 190 | */ |
| 191 | JNIEnvExt* dvmGetJNIEnvForThread(void); |
| 192 | |
| 193 | /* |
| 194 | * Extract the return type enum from the "jniArgInfo" value. |
| 195 | */ |
| 196 | DalvikJniReturnType dvmGetArgInfoReturnType(int jniArgInfo); |
| 197 | |
| 198 | /* |
| 199 | * Release all MonitorEnter-acquired locks that are still held. Called at |
| 200 | * DetachCurrentThread time. |
| 201 | */ |
| 202 | void dvmReleaseJniMonitors(Thread* self); |
| 203 | |
Andy McFadden | b18992f | 2009-09-25 10:42:15 -0700 | [diff] [blame] | 204 | |
| 205 | /* |
| 206 | * This mask is applied to weak global reference values returned to |
| 207 | * native code. The goal is to create an invalid pointer that will cause |
| 208 | * a crash if misused. The mmap region for the virtual heap is typically |
| 209 | * around 0x40xxxxxx. |
| 210 | * |
| 211 | * To make weak global references easily distinguishable from other kinds |
| 212 | * of references when !USE_INDIRECT_REF, we XOR the low bits. Assuming >= |
| 213 | * 64-bit alignment of objects, this changes the low 3 bits from all clear |
| 214 | * to all set. |
| 215 | */ |
| 216 | #define WEAK_GLOBAL_XOR 0x9e0fffff |
| 217 | |
| 218 | /* |
| 219 | * "Obfuscate" a weak global reference pointer. |
| 220 | */ |
| 221 | INLINE jweak dvmObfuscateWeakGlobalRef(jobject jobj) { |
| 222 | return (jweak) ((u4) jobj ^ WEAK_GLOBAL_XOR); |
| 223 | } |
| 224 | |
| 225 | /* |
| 226 | * Undo the obfuscation. |
| 227 | */ |
| 228 | INLINE jobject dvmNormalizeWeakGlobalRef(jweak ref) { |
| 229 | return (jobject) ((u4) ref ^ WEAK_GLOBAL_XOR); |
| 230 | } |
| 231 | |
| 232 | /* |
| 233 | * Returns "true" if this looks like a weak global reference. |
| 234 | * |
| 235 | * Relies on the low 3 bits being set instead of clear (the latter is |
| 236 | * guaranteed by 64-bit alignment of objects). |
| 237 | */ |
| 238 | INLINE bool dvmIsWeakGlobalRef(jobject jobj) { |
| 239 | return (((u4) jobj & 0x07) == 0x07); |
| 240 | } |
| 241 | |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 242 | #endif /*_DALVIK_JNIINTERNAL*/ |