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(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 LOG_ERROR("JNI_GetCreatedJavaVMs failed, returned %ld", 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 #if OS(ANDROID) 94 jniError = getJavaVM()->AttachCurrentThread(&u.env, 0); 95 #else 96 jniError = getJavaVM()->AttachCurrentThread(&u.dummy, 0); 97 #endif 98 if (jniError == JNI_OK) 99 return u.env; 100 LOG_ERROR("AttachCurrentThread failed, returned %ld", static_cast<long>(jniError)); 101 return 0; 102 } 103 104 jmethodID getMethodID(jobject obj, const char* name, const char* sig) 105 { 106 JNIEnv* env = getJNIEnv(); 107 jmethodID mid = 0; 108 109 if (env) { 110 jclass cls = env->GetObjectClass(obj); 111 if (cls) { 112 mid = env->GetMethodID(cls, name, sig); 113 if (!mid) { 114 env->ExceptionClear(); 115 mid = env->GetStaticMethodID(cls, name, sig); 116 if (!mid) 117 env->ExceptionClear(); 118 } 119 } 120 env->DeleteLocalRef(cls); 121 } 122 return mid; 123 } 124 125 const char* getCharactersFromJString(jstring aJString) 126 { 127 return getCharactersFromJStringInEnv(getJNIEnv(), aJString); 128 } 129 130 void releaseCharactersForJString(jstring aJString, const char* s) 131 { 132 releaseCharactersForJStringInEnv(getJNIEnv(), aJString, s); 133 } 134 135 const char* getCharactersFromJStringInEnv(JNIEnv* env, jstring aJString) 136 { 137 jboolean isCopy; 138 const char* s = env->GetStringUTFChars(aJString, &isCopy); 139 if (!s) { 140 env->ExceptionDescribe(); 141 env->ExceptionClear(); 142 fprintf(stderr, "\n"); 143 } 144 return s; 145 } 146 147 void releaseCharactersForJStringInEnv(JNIEnv* env, jstring aJString, const char* s) 148 { 149 env->ReleaseStringUTFChars(aJString, s); 150 } 151 152 const jchar* getUCharactersFromJStringInEnv(JNIEnv* env, jstring aJString) 153 { 154 jboolean isCopy; 155 const jchar* s = env->GetStringChars(aJString, &isCopy); 156 if (!s) { 157 env->ExceptionDescribe(); 158 env->ExceptionClear(); 159 fprintf(stderr, "\n"); 160 } 161 return s; 162 } 163 164 void releaseUCharactersForJStringInEnv(JNIEnv* env, jstring aJString, const jchar* s) 165 { 166 env->ReleaseStringChars(aJString, s); 167 } 168 169 JavaType javaTypeFromClassName(const char* name) 170 { 171 JavaType type; 172 173 if (!strcmp("byte", name)) 174 type = JavaTypeByte; 175 else if (!strcmp("short", name)) 176 type = JavaTypeShort; 177 else if (!strcmp("int", name)) 178 type = JavaTypeInt; 179 else if (!strcmp("long", name)) 180 type = JavaTypeLong; 181 else if (!strcmp("float", name)) 182 type = JavaTypeFloat; 183 else if (!strcmp("double", name)) 184 type = JavaTypeDouble; 185 else if (!strcmp("char", name)) 186 type = JavaTypeChar; 187 else if (!strcmp("boolean", name)) 188 type = JavaTypeBoolean; 189 else if (!strcmp("void", name)) 190 type = JavaTypeVoid; 191 else if ('[' == name[0]) 192 type = JavaTypeArray; 193 #if USE(V8) 194 else if (!strcmp("java.lang.String", name)) 195 type = JavaTypeString; 196 #endif 197 else 198 type = JavaTypeObject; 199 200 return type; 201 } 202 203 const char* signatureFromJavaType(JavaType type) 204 { 205 switch (type) { 206 case JavaTypeVoid: 207 return "V"; 208 209 case JavaTypeArray: 210 return "["; 211 212 case JavaTypeObject: 213 #if USE(V8) 214 case JavaTypeString: 215 #endif 216 return "L"; 217 218 case JavaTypeBoolean: 219 return "Z"; 220 221 case JavaTypeByte: 222 return "B"; 223 224 case JavaTypeChar: 225 return "C"; 226 227 case JavaTypeShort: 228 return "S"; 229 230 case JavaTypeInt: 231 return "I"; 232 233 case JavaTypeLong: 234 return "J"; 235 236 case JavaTypeFloat: 237 return "F"; 238 239 case JavaTypeDouble: 240 return "D"; 241 242 case JavaTypeInvalid: 243 default: 244 break; 245 } 246 return ""; 247 } 248 249 JavaType javaTypeFromPrimitiveType(char type) 250 { 251 switch (type) { 252 case 'V': 253 return JavaTypeVoid; 254 255 case 'L': 256 return JavaTypeObject; 257 258 case '[': 259 return JavaTypeArray; 260 261 case 'Z': 262 return JavaTypeBoolean; 263 264 case 'B': 265 return JavaTypeByte; 266 267 case 'C': 268 return JavaTypeChar; 269 270 case 'S': 271 return JavaTypeShort; 272 273 case 'I': 274 return JavaTypeInt; 275 276 case 'J': 277 return JavaTypeLong; 278 279 case 'F': 280 return JavaTypeFloat; 281 282 case 'D': 283 return JavaTypeDouble; 284 285 default: 286 break; 287 } 288 return JavaTypeInvalid; 289 } 290 291 jvalue getJNIField(jobject obj, JavaType type, const char* name, const char* signature) 292 { 293 JavaVM* jvm = getJavaVM(); 294 JNIEnv* env = getJNIEnv(); 295 jvalue result; 296 297 memset(&result, 0, sizeof(jvalue)); 298 if (obj && jvm && env) { 299 jclass cls = env->GetObjectClass(obj); 300 if (cls) { 301 jfieldID field = env->GetFieldID(cls, name, signature); 302 if (field) { 303 switch (type) { 304 case JavaTypeArray: 305 case JavaTypeObject: 306 #if USE(V8) 307 case JavaTypeString: 308 #endif 309 result.l = env->functions->GetObjectField(env, obj, field); 310 break; 311 case JavaTypeBoolean: 312 result.z = env->functions->GetBooleanField(env, obj, field); 313 break; 314 case JavaTypeByte: 315 result.b = env->functions->GetByteField(env, obj, field); 316 break; 317 case JavaTypeChar: 318 result.c = env->functions->GetCharField(env, obj, field); 319 break; 320 case JavaTypeShort: 321 result.s = env->functions->GetShortField(env, obj, field); 322 break; 323 case JavaTypeInt: 324 result.i = env->functions->GetIntField(env, obj, field); 325 break; 326 case JavaTypeLong: 327 result.j = env->functions->GetLongField(env, obj, field); 328 break; 329 case JavaTypeFloat: 330 result.f = env->functions->GetFloatField(env, obj, field); 331 break; 332 case JavaTypeDouble: 333 result.d = env->functions->GetDoubleField(env, obj, field); 334 break; 335 default: 336 LOG_ERROR("Invalid field type (%d)", static_cast<int>(type)); 337 } 338 } else { 339 LOG_ERROR("Could not find field: %s", name); 340 env->ExceptionDescribe(); 341 env->ExceptionClear(); 342 fprintf(stderr, "\n"); 343 } 344 345 env->DeleteLocalRef(cls); 346 } else 347 LOG_ERROR("Could not find class for object"); 348 } 349 350 return result; 351 } 352 353 jvalue callJNIMethod(jobject object, JavaType returnType, const char* name, const char* signature, jvalue* args) 354 { 355 jmethodID methodId = getMethodID(object, name, signature); 356 jvalue result; 357 switch (returnType) { 358 case JavaTypeVoid: 359 callJNIMethodIDA<void>(object, methodId, args); 360 break; 361 case JavaTypeObject: 362 #if USE(V8) 363 case JavaTypeString: 364 #endif 365 result.l = callJNIMethodIDA<jobject>(object, methodId, args); 366 break; 367 case JavaTypeBoolean: 368 result.z = callJNIMethodIDA<jboolean>(object, methodId, args); 369 break; 370 case JavaTypeByte: 371 result.b = callJNIMethodIDA<jbyte>(object, methodId, args); 372 break; 373 case JavaTypeChar: 374 result.c = callJNIMethodIDA<jchar>(object, methodId, args); 375 break; 376 case JavaTypeShort: 377 result.s = callJNIMethodIDA<jshort>(object, methodId, args); 378 break; 379 case JavaTypeInt: 380 result.i = callJNIMethodIDA<jint>(object, methodId, args); 381 break; 382 case JavaTypeLong: 383 result.j = callJNIMethodIDA<jlong>(object, methodId, args); 384 break; 385 case JavaTypeFloat: 386 result.f = callJNIMethodIDA<jfloat>(object, methodId, args); 387 break; 388 case JavaTypeDouble: 389 result.d = callJNIMethodIDA<jdouble>(object, methodId, args); 390 break; 391 default: 392 break; 393 } 394 return result; 395 } 396 397 } // namespace Bindings 398 399 } // namespace JSC 400 401 #endif // ENABLE(JAVA_BRIDGE) 402