OSDN Git Service

am 381868f3: (-s ours) am 840d233c: am 800e4320: am 63c34b5e: am 68719a17: (-s ours...
[android-x86/dalvik.git] / vm / Jni.cpp
index 952084e..e571ad8 100644 (file)
@@ -19,6 +19,7 @@
  */
 #include "Dalvik.h"
 #include "JniInternal.h"
+#include "Misc.h"
 #include "ScopedPthreadMutexLock.h"
 #include "UniquePtr.h"
 
@@ -134,6 +135,11 @@ The GC will scan all references in the table.
 
 */
 
+static void ReportJniError() {
+    dvmDumpThread(dvmThreadSelf(), false);
+    dvmAbort();
+}
+
 #ifdef WITH_JNI_STACK_CHECK
 # define COMPUTE_STACK_SUM(_self)   computeStackSum(_self);
 # define CHECK_STACK_SUM(_self)     checkStackSum(_self);
@@ -177,7 +183,7 @@ static void checkStackSum(Thread* self) {
             ALOGD("JNI: bad stack CRC (0x%08x) -- okay during JNI_OnLoad", stackCrc);
         } else {
             ALOGW("JNI: bad stack CRC (%08x vs %08x)", crc, stackCrc);
-            dvmAbort();
+            ReportJniError();
         }
     }
     self->stackCrc = (u4) -1;       /* make logic errors more noticeable */
@@ -318,7 +324,7 @@ Object* dvmDecodeIndirectRef(Thread* self, jobject jobj) {
             Object* result = self->jniLocalRefTable.get(jobj);
             if (UNLIKELY(result == NULL)) {
                 ALOGE("JNI ERROR (app bug): use of deleted local reference (%p)", jobj);
-                dvmAbort();
+                ReportJniError();
             }
             return result;
         }
@@ -330,7 +336,7 @@ Object* dvmDecodeIndirectRef(Thread* self, jobject jobj) {
             Object* result = pRefTable->get(jobj);
             if (UNLIKELY(result == NULL)) {
                 ALOGE("JNI ERROR (app bug): use of deleted global reference (%p)", jobj);
-                dvmAbort();
+                ReportJniError();
             }
             return result;
         }
@@ -344,7 +350,7 @@ Object* dvmDecodeIndirectRef(Thread* self, jobject jobj) {
                 result = NULL;
             } else if (UNLIKELY(result == NULL)) {
                 ALOGE("JNI ERROR (app bug): use of deleted weak global reference (%p)", jobj);
-                dvmAbort();
+                ReportJniError();
             }
             return result;
         }
@@ -355,7 +361,7 @@ Object* dvmDecodeIndirectRef(Thread* self, jobject jobj) {
             return reinterpret_cast<Object*>(jobj);
         }
         ALOGW("Invalid indirect reference %p in decodeIndirectRef", jobj);
-        dvmAbort();
+        ReportJniError();
         return kInvalidIndirectRefObject;
     }
 }
@@ -363,8 +369,7 @@ Object* dvmDecodeIndirectRef(Thread* self, jobject jobj) {
 static void AddLocalReferenceFailure(IndirectRefTable* pRefTable) {
     pRefTable->dump("JNI local");
     ALOGE("Failed adding to JNI local ref table (has %zd entries)", pRefTable->capacity());
-    dvmDumpThread(dvmThreadSelf(), false);
-    dvmAbort();     // spec says call FatalError; this is equivalent
+    ReportJniError(); // spec says call FatalError; this is equivalent
 }
 
 /*
@@ -388,6 +393,7 @@ static inline jobject addLocalReference(Thread* self, Object* obj) {
     if (UNLIKELY(jobj == NULL)) {
         AddLocalReferenceFailure(pRefTable);
     }
+
     if (UNLIKELY(gDvmJni.workAroundAppJniBugs)) {
         // Hand out direct pointers to support broken old apps.
         return reinterpret_cast<jobject>(obj);
@@ -486,7 +492,7 @@ static jobject addGlobalReference(Object* obj) {
         gDvm.jniGlobalRefTable.dump("JNI global");
         ALOGE("Failed adding to JNI global ref table (%zd entries)",
                 gDvm.jniGlobalRefTable.capacity());
-        dvmAbort();
+        ReportJniError();
     }
 
     LOGVV("GREF add %p  (%s.%s)", obj,
@@ -509,7 +515,7 @@ static jobject addGlobalReference(Object* obj) {
                 } else {
                     gDvm.jniGlobalRefTable.dump("JNI global");
                     ALOGE("Excessive JNI global references (%d)", count);
-                    dvmAbort();
+                    ReportJniError();
                 }
             }
         }
@@ -528,7 +534,7 @@ static jobject addWeakGlobalReference(Object* obj) {
     if (jobj == NULL) {
         gDvm.jniWeakGlobalRefTable.dump("JNI weak global");
         ALOGE("Failed adding to JNI weak global ref table (%zd entries)", table->capacity());
-        dvmAbort();
+        ReportJniError();
     }
     return jobj;
 }
@@ -591,8 +597,7 @@ static void pinPrimitiveArray(ArrayObject* arrayObj) {
         dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
         ALOGE("Failed adding to JNI pinned array ref table (%d entries)",
            (int) dvmReferenceTableEntries(&gDvm.jniPinRefTable));
-        dvmDumpThread(dvmThreadSelf(), false);
-        dvmAbort();
+        ReportJniError();
     }
 
     /*
@@ -650,6 +655,31 @@ void dvmDumpJniReferenceTables() {
     dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
 }
 
+void dvmDumpJniStats(DebugOutputTarget* target) {
+    dvmPrintDebugMessage(target, "JNI: CheckJNI is %s", gDvmJni.useCheckJni ? "on" : "off");
+    if (gDvmJni.forceCopy) {
+        dvmPrintDebugMessage(target, " (with forcecopy)");
+    }
+    dvmPrintDebugMessage(target, "; workarounds are %s", gDvmJni.workAroundAppJniBugs ? "on" : "off");
+
+    dvmLockMutex(&gDvm.jniPinRefLock);
+    dvmPrintDebugMessage(target, "; pins=%d", dvmReferenceTableEntries(&gDvm.jniPinRefTable));
+    dvmUnlockMutex(&gDvm.jniPinRefLock);
+
+    dvmLockMutex(&gDvm.jniGlobalRefLock);
+    dvmPrintDebugMessage(target, "; globals=%d", gDvm.jniGlobalRefTable.capacity());
+    dvmUnlockMutex(&gDvm.jniGlobalRefLock);
+
+    dvmLockMutex(&gDvm.jniWeakGlobalRefLock);
+    size_t weaks = gDvm.jniWeakGlobalRefTable.capacity();
+    if (weaks > 0) {
+        dvmPrintDebugMessage(target, " (plus %d weak)", weaks);
+    }
+    dvmUnlockMutex(&gDvm.jniWeakGlobalRefLock);
+
+    dvmPrintDebugMessage(target, "\n\n");
+}
+
 /*
  * Verify that a reference passed in from native code is one that the
  * code is allowed to have.
@@ -958,14 +988,14 @@ static void trackMonitorEnter(Thread* self, Object* obj) {
 
         if (!dvmInitReferenceTable(refTable, kInitialSize, INT_MAX)) {
             ALOGE("Unable to initialize monitor tracking table");
-            dvmAbort();
+            ReportJniError();
         }
     }
 
     if (!dvmAddToReferenceTable(refTable, obj)) {
         /* ran out of memory? could throw exception instead */
         ALOGE("Unable to add entry to monitor tracking table");
-        dvmAbort();
+        ReportJniError();
     } else {
         LOGVV("--- added monitor %p", obj);
     }
@@ -1402,7 +1432,7 @@ static void ExceptionClear(JNIEnv* env) {
 static void FatalError(JNIEnv* env, const char* msg) {
     //dvmChangeStatus(NULL, THREAD_RUNNING);
     ALOGE("JNI posting fatal error: %s", msg);
-    dvmAbort();
+    ReportJniError();
 }
 
 /*
@@ -2301,9 +2331,18 @@ static void SetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index, j
         return;
     }
 
+    Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
+
+    if (obj != NULL && !dvmCanPutArrayElement(obj->clazz, arrayObj->clazz)) {
+      ALOGV("Can't put a '%s'(%p) into array type='%s'(%p)",
+            obj->clazz->descriptor, obj,
+            arrayObj->clazz->descriptor, arrayObj);
+      dvmThrowArrayStoreExceptionIncompatibleElement(obj->clazz, arrayObj->clazz);
+      return;
+    }
+
     //ALOGV("JNI: set element %d in array %p to %p", index, array, value);
 
-    Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
     dvmSetObjectArrayElement(arrayObj, index, obj);
 }
 
@@ -2674,15 +2713,21 @@ static jobjectRefType GetObjectRefType(JNIEnv* env, jobject jobj) {
 
 /*
  * Allocate and return a new java.nio.ByteBuffer for this block of memory.
- *
- * "address" may not be NULL, and "capacity" must be > 0.  (These are only
- * verified when CheckJNI is enabled.)
  */
 static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
     ScopedJniThreadState ts(env);
 
-    /* create an instance of java.nio.ReadWriteDirectByteBuffer */
-    ClassObject* bufferClazz = gDvm.classJavaNioReadWriteDirectByteBuffer;
+    if (capacity < 0) {
+        ALOGE("JNI ERROR (app bug): negative buffer capacity: %lld", capacity);
+        ReportJniError();
+    }
+    if (address == NULL && capacity != 0) {
+        ALOGE("JNI ERROR (app bug): non-zero capacity for NULL pointer: %lld", capacity);
+        ReportJniError();
+    }
+
+    /* create an instance of java.nio.DirectByteBuffer */
+    ClassObject* bufferClazz = gDvm.classJavaNioDirectByteBuffer;
     if (!dvmIsClassInitialized(bufferClazz) && !dvmInitClass(bufferClazz)) {
         return NULL;
     }
@@ -2693,8 +2738,8 @@ static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
     /* call the constructor */
     jobject result = addLocalReference(ts.self(), newObj);
     JValue unused;
-    dvmCallMethod(ts.self(), gDvm.methJavaNioReadWriteDirectByteBuffer_init,
-            newObj, &unused, (jint) address, (jint) capacity);
+    dvmCallMethod(ts.self(), gDvm.methJavaNioDirectByteBuffer_init,
+            newObj, &unused, (jlong) address, (jint) capacity);
     if (dvmGetException(ts.self()) != NULL) {
         deleteLocalReference(ts.self(), result);
         return NULL;
@@ -2712,7 +2757,7 @@ static void* GetDirectBufferAddress(JNIEnv* env, jobject jbuf) {
 
     // All Buffer objects have an effectiveDirectAddress field.
     Object* bufObj = dvmDecodeIndirectRef(ts.self(), jbuf);
-    return (void*) dvmGetFieldInt(bufObj, gDvm.offJavaNioBuffer_effectiveDirectAddress);
+    return (void*) dvmGetFieldLong(bufObj, gDvm.offJavaNioBuffer_effectiveDirectAddress);
 }
 
 /*
@@ -2800,8 +2845,6 @@ static jint attachThread(JavaVM* vm, JNIEnv** p_env, void* thr_args, bool isDaem
         argsCopy.name = NULL;
         argsCopy.group = (jobject) dvmGetMainThreadGroup();
     } else {
-        assert(args->version >= JNI_VERSION_1_2);
-
         argsCopy.version = args->version;
         argsCopy.name = args->name;
         if (args->group != NULL) {
@@ -3408,8 +3451,7 @@ jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
     /*
      * Set up structures for JNIEnv and VM.
      */
-    JavaVMExt* pVM = (JavaVMExt*) malloc(sizeof(JavaVMExt));
-    memset(pVM, 0, sizeof(JavaVMExt));
+    JavaVMExt* pVM = (JavaVMExt*) calloc(1, sizeof(JavaVMExt));
     pVM->funcTable = &gInvokeInterface;
     pVM->envList = NULL;
     dvmInitMutex(&pVM->envListLock);