1 /* 2 * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "JNIUtility.h" 28 29 #if ENABLE(MAC_JAVA_BRIDGE) 30 31 #include <dlfcn.h> 32 33 namespace JSC { 34 35 namespace Bindings { 36 37 static jint KJSGetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs) 38 { 39 static void* javaVMFramework = 0; 40 if (!javaVMFramework) 41 javaVMFramework = dlopen("/System/Library/Frameworks/JavaVM.framework/JavaVM", RTLD_LAZY); 42 if (!javaVMFramework) 43 return JNI_ERR; 44 45 typedef jint(*FunctionPointerType)(JavaVM**, jsize, jsize*); 46 static FunctionPointerType functionPointer = 0; 47 if (!functionPointer) 48 functionPointer = reinterpret_cast<FunctionPointerType>(dlsym(javaVMFramework, "JNI_GetCreatedJavaVMs")); 49 if (!functionPointer) 50 return JNI_ERR; 51 return functionPointer(vmBuf, bufLen, nVMs); 52 } 53 54 static JavaVM* jvm = 0; 55 56 // Provide the ability for an outside component to specify the JavaVM to use 57 // If the jvm value is set, the getJavaVM function below will just return. 58 // In getJNIEnv(), if AttachCurrentThread is called to a VM that is already 59 // attached, the result is a no-op. 60 void setJavaVM(JavaVM* javaVM) 61 { 62 jvm = javaVM; 63 } 64 65 JavaVM* getJavaVM() 66 { 67 if (jvm) 68 return jvm; 69 70 JavaVM* jvmArray[1]; 71 jsize bufLen = 1; 72 jsize nJVMs = 0; 73 jint jniError = 0; 74 75 // Assumes JVM is already running ..., one per process 76 jniError = KJSGetCreatedJavaVMs(jvmArray, bufLen, &nJVMs); 77 if (jniError == JNI_OK && nJVMs > 0) 78 jvm = jvmArray[0]; 79 else 80 fprintf(stderr, "%s: JNI_GetCreatedJavaVMs failed, returned %ld\n", __PRETTY_FUNCTION__, static_cast<long>(jniError)); 81 82 return jvm; 83 } 84 85 JNIEnv* getJNIEnv() 86 { 87 union { 88 JNIEnv* env; 89 void* dummy; 90 } u; 91 jint jniError = 0; 92 93 jniError = getJavaVM()->AttachCurrentThread(&u.dummy, 0); 94 if (jniError == JNI_OK) 95 return u.env; 96 fprintf(stderr, "%s: AttachCurrentThread failed, returned %ld\n", __PRETTY_FUNCTION__, static_cast<long>(jniError)); 97 return 0; 98 } 99 100 jmethodID getMethodID(jobject obj, const char* name, const char* sig) 101 { 102 JNIEnv* env = getJNIEnv(); 103 jmethodID mid = 0; 104 105 if (env) { 106 jclass cls = env->GetObjectClass(obj); 107 if (cls) { 108 mid = env->GetMethodID(cls, name, sig); 109 if (!mid) { 110 env->ExceptionClear(); 111 mid = env->GetStaticMethodID(cls, name, sig); 112 if (!mid) 113 env->ExceptionClear(); 114 } 115 } 116 env->DeleteLocalRef(cls); 117 } 118 return mid; 119 } 120 121 const char* getCharactersFromJString(jstring aJString) 122 { 123 return getCharactersFromJStringInEnv(getJNIEnv(), aJString); 124 } 125 126 void releaseCharactersForJString(jstring aJString, const char* s) 127 { 128 releaseCharactersForJStringInEnv(getJNIEnv(), aJString, s); 129 } 130 131 const char* getCharactersFromJStringInEnv(JNIEnv* env, jstring aJString) 132 { 133 jboolean isCopy; 134 const char* s = env->GetStringUTFChars(aJString, &isCopy); 135 if (!s) { 136 env->ExceptionDescribe(); 137 env->ExceptionClear(); 138 fprintf(stderr, "\n"); 139 } 140 return s; 141 } 142 143 void releaseCharactersForJStringInEnv(JNIEnv* env, jstring aJString, const char* s) 144 { 145 env->ReleaseStringUTFChars(aJString, s); 146 } 147 148 const jchar* getUCharactersFromJStringInEnv(JNIEnv* env, jstring aJString) 149 { 150 jboolean isCopy; 151 const jchar* s = env->GetStringChars(aJString, &isCopy); 152 if (!s) { 153 env->ExceptionDescribe(); 154 env->ExceptionClear(); 155 fprintf(stderr, "\n"); 156 } 157 return s; 158 } 159 160 void releaseUCharactersForJStringInEnv(JNIEnv* env, jstring aJString, const jchar* s) 161 { 162 env->ReleaseStringChars(aJString, s); 163 } 164 165 JNIType JNITypeFromClassName(const char* name) 166 { 167 JNIType type; 168 169 if (!strcmp("byte", name)) 170 type = byte_type; 171 else if (!strcmp("short", name)) 172 type = short_type; 173 else if (!strcmp("int", name)) 174 type = int_type; 175 else if (!strcmp("long", name)) 176 type = long_type; 177 else if (!strcmp("float", name)) 178 type = float_type; 179 else if (!strcmp("double", name)) 180 type = double_type; 181 else if (!strcmp("char", name)) 182 type = char_type; 183 else if (!strcmp("boolean", name)) 184 type = boolean_type; 185 else if (!strcmp("void", name)) 186 type = void_type; 187 else if ('[' == name[0]) 188 type = array_type; 189 else 190 type = object_type; 191 192 return type; 193 } 194 195 const char* signatureFromPrimitiveType(JNIType type) 196 { 197 switch (type) { 198 case void_type: 199 return "V"; 200 201 case array_type: 202 return "["; 203 204 case object_type: 205 return "L"; 206 207 case boolean_type: 208 return "Z"; 209 210 case byte_type: 211 return "B"; 212 213 case char_type: 214 return "C"; 215 216 case short_type: 217 return "S"; 218 219 case int_type: 220 return "I"; 221 222 case long_type: 223 return "J"; 224 225 case float_type: 226 return "F"; 227 228 case double_type: 229 return "D"; 230 231 case invalid_type: 232 default: 233 break; 234 } 235 return ""; 236 } 237 238 JNIType JNITypeFromPrimitiveType(char type) 239 { 240 switch (type) { 241 case 'V': 242 return void_type; 243 244 case 'L': 245 return object_type; 246 247 case '[': 248 return array_type; 249 250 case 'Z': 251 return boolean_type; 252 253 case 'B': 254 return byte_type; 255 256 case 'C': 257 return char_type; 258 259 case 'S': 260 return short_type; 261 262 case 'I': 263 return int_type; 264 265 case 'J': 266 return long_type; 267 268 case 'F': 269 return float_type; 270 271 case 'D': 272 return double_type; 273 274 default: 275 break; 276 } 277 return invalid_type; 278 } 279 280 jvalue getJNIField(jobject obj, JNIType type, const char* name, const char* signature) 281 { 282 JavaVM* jvm = getJavaVM(); 283 JNIEnv* env = getJNIEnv(); 284 jvalue result; 285 286 memset(&result, 0, sizeof(jvalue)); 287 if (obj && jvm && env) { 288 jclass cls = env->GetObjectClass(obj); 289 if (cls) { 290 jfieldID field = env->GetFieldID(cls, name, signature); 291 if (field) { 292 switch (type) { 293 case array_type: 294 case object_type: 295 result.l = env->functions->GetObjectField(env, obj, field); 296 break; 297 case boolean_type: 298 result.z = env->functions->GetBooleanField(env, obj, field); 299 break; 300 case byte_type: 301 result.b = env->functions->GetByteField(env, obj, field); 302 break; 303 case char_type: 304 result.c = env->functions->GetCharField(env, obj, field); 305 break; 306 case short_type: 307 result.s = env->functions->GetShortField(env, obj, field); 308 break; 309 case int_type: 310 result.i = env->functions->GetIntField(env, obj, field); 311 break; 312 case long_type: 313 result.j = env->functions->GetLongField(env, obj, field); 314 break; 315 case float_type: 316 result.f = env->functions->GetFloatField(env, obj, field); 317 break; 318 case double_type: 319 result.d = env->functions->GetDoubleField(env, obj, field); 320 break; 321 default: 322 fprintf(stderr, "%s: invalid field type (%d)\n", __PRETTY_FUNCTION__, static_cast<int>(type)); 323 } 324 } else { 325 fprintf(stderr, "%s: Could not find field: %s\n", __PRETTY_FUNCTION__, name); 326 env->ExceptionDescribe(); 327 env->ExceptionClear(); 328 fprintf(stderr, "\n"); 329 } 330 331 env->DeleteLocalRef(cls); 332 } else 333 fprintf(stderr, "%s: Could not find class for object\n", __PRETTY_FUNCTION__); 334 } 335 336 return result; 337 } 338 339 } // namespace Bindings 340 341 } // namespace JSC 342 343 #endif // ENABLE(MAC_JAVA_BRIDGE) 344