*/
#include "Dalvik.h"
#include "JniInternal.h"
+#include "Misc.h"
#include "ScopedPthreadMutexLock.h"
#include "UniquePtr.h"
*/
+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);
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 */
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;
}
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;
}
result = NULL;
} else if (UNLIKELY(result == NULL)) {
ALOGE("JNI ERROR (app bug): use of deleted weak global reference (%p)", jobj);
- dvmAbort();
+ ReportJniError();
}
return result;
}
return reinterpret_cast<Object*>(jobj);
}
ALOGW("Invalid indirect reference %p in decodeIndirectRef", jobj);
- dvmAbort();
+ ReportJniError();
return kInvalidIndirectRefObject;
}
}
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
}
/*
if (UNLIKELY(jobj == NULL)) {
AddLocalReferenceFailure(pRefTable);
}
+
if (UNLIKELY(gDvmJni.workAroundAppJniBugs)) {
// Hand out direct pointers to support broken old apps.
return reinterpret_cast<jobject>(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,
} else {
gDvm.jniGlobalRefTable.dump("JNI global");
ALOGE("Excessive JNI global references (%d)", count);
- dvmAbort();
+ ReportJniError();
}
}
}
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;
}
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();
}
/*
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.
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);
}
static void FatalError(JNIEnv* env, const char* msg) {
//dvmChangeStatus(NULL, THREAD_RUNNING);
ALOGE("JNI posting fatal error: %s", msg);
- dvmAbort();
+ ReportJniError();
}
/*
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);
}
/*
* 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;
}
/* 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;
// 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);
}
/*
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) {
/*
* 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);