/* * Allocate storage on the GC heap. We guarantee 8-byte alignment. * * The new storage is zeroed out. * * Note that, in rare cases, this could get called while a GC is in * progress. If a non-VM thread tries to attach itself through JNI, * it will need to allocate some objects. If this becomes annoying to * deal with, we can block it at the source, but holding the allocation * mutex should be enough. * * In rare circumstances (JNI AttachCurrentThread) we can be called * from a non-VM thread. * * Use ALLOC_DONT_TRACK when we either don't want to track an allocation * (because it's being done for the interpreter "new" operation and will * be part of the root set immediately) or we can't (because this allocation * is for a brand new thread). * * Returns NULL and throws an exception on failure. * * TODO: don't do a GC if the debugger thinks all threads are suspended */ void* dvmMalloc(size_t size, int flags) { void *ptr; dvmLockHeap(); /* Try as hard as possible to allocate some memory. */ ptr = tryMalloc(size); if (ptr != NULL) { /* We've got the memory. */ if (gDvm.allocProf.enabled) { Thread* self = dvmThreadSelf(); gDvm.allocProf.allocCount++; gDvm.allocProf.allocSize += size; if (self != NULL) { self->allocProf.allocCount++; self->allocProf.allocSize += size; } } } else { /* The allocation failed. */ if (gDvm.allocProf.enabled) { Thread* self = dvmThreadSelf(); gDvm.allocProf.failedAllocCount++; gDvm.allocProf.failedAllocSize += size; if (self != NULL) { self->allocProf.failedAllocCount++; self->allocProf.failedAllocSize += size; } } } dvmUnlockHeap(); if (ptr != NULL) { /* * If caller hasn't asked us not to track it, add it to the * internal tracking list. */ if ((flags & ALLOC_DONT_TRACK) == 0) { dvmAddTrackedAlloc((Object*)ptr, NULL); } } else { /* * The allocation failed; throw an OutOfMemoryError. */ throwOOME(); } return ptr; }
/* * Find a class by name, initializing it if requested. */ ClassObject* dvmFindClassByName(StringObject* nameObj, Object* loader, bool doInit) { ClassObject* clazz = NULL; char* name = NULL; char* descriptor = NULL; if (nameObj == NULL) { dvmThrowException("Ljava/lang/NullPointerException;", NULL); goto bail; } name = dvmCreateCstrFromString(nameObj); /* * We need to validate and convert the name (from x.y.z to x/y/z). This * is especially handy for array types, since we want to avoid * auto-generating bogus array classes. */ if (!validateClassName(name)) { LOGW("dvmFindClassByName rejecting '%s'\n", name); dvmThrowException("Ljava/lang/ClassNotFoundException;", name); goto bail; } descriptor = dvmDotToDescriptor(name); if (descriptor == NULL) { goto bail; } if (doInit) clazz = dvmFindClass(descriptor, loader); else clazz = dvmFindClassNoInit(descriptor, loader); if (clazz == NULL) { LOGVV("FAIL: load %s (%d)\n", descriptor, doInit); Thread* self = dvmThreadSelf(); Object* oldExcep = dvmGetException(self); dvmAddTrackedAlloc(oldExcep, self); /* don't let this be GCed */ dvmClearException(self); dvmThrowChainedException("Ljava/lang/ClassNotFoundException;", name, oldExcep); dvmReleaseTrackedAlloc(oldExcep, self); } else { LOGVV("GOOD: load %s (%d) --> %p ldr=%p\n", descriptor, doInit, clazz, clazz->classLoader); } bail: free(name); free(descriptor); return clazz; }
/* * Wrap the now-pending exception in a different exception. This is useful * for reflection stuff that wants to hand a checked exception back from a * method that doesn't declare it. * * If something fails, an (unchecked) exception related to that failure * will be pending instead. */ void dvmWrapException(const char* newExcepStr) { Thread* self = dvmThreadSelf(); Object* origExcep; ClassObject* iteClass; origExcep = dvmGetException(self); dvmAddTrackedAlloc(origExcep, self); // don't let the GC free it dvmClearException(self); // clear before class lookup iteClass = dvmFindSystemClass(newExcepStr); if (iteClass != NULL) { Object* iteExcep; Method* initMethod; iteExcep = dvmAllocObject(iteClass, ALLOC_DEFAULT); if (iteExcep != NULL) { initMethod = dvmFindDirectMethodByDescriptor(iteClass, "<init>", "(Ljava/lang/Throwable;)V"); if (initMethod != NULL) { JValue unused; dvmCallMethod(self, initMethod, iteExcep, &unused, origExcep); /* if <init> succeeded, replace the old exception */ if (!dvmCheckException(self)) dvmSetException(self, iteExcep); } dvmReleaseTrackedAlloc(iteExcep, NULL); /* if initMethod doesn't exist, or failed... */ if (!dvmCheckException(self)) dvmSetException(self, origExcep); } else { /* leave OutOfMemoryError pending */ } } else { /* leave ClassNotFoundException pending */ } assert(dvmCheckException(self)); dvmReleaseTrackedAlloc(origExcep, self); }
/* * Create a wrapper object for a primitive data type. If "returnType" is * not primitive, this just casts "value" to an object and returns it. * * We could invoke the "toValue" method on the box types to take * advantage of pre-created values, but running that through the * interpreter is probably less efficient than just allocating storage here. * * The caller must call dvmReleaseTrackedAlloc on the result. */ DataObject* dvmBoxPrimitive(JValue value, ClassObject* returnType) { ClassObject* wrapperClass; DataObject* wrapperObj; s4* dataPtr; PrimitiveType typeIndex = returnType->primitiveType; const char* classDescriptor; if (typeIndex == PRIM_NOT) { /* add to tracking table so return value is always in table */ if (value.l != NULL) dvmAddTrackedAlloc((Object*)value.l, NULL); return (DataObject*) value.l; } classDescriptor = dexGetBoxedTypeDescriptor(typeIndex); if (classDescriptor == NULL) { return NULL; } wrapperClass = dvmFindSystemClass(classDescriptor); if (wrapperClass == NULL) { ALOGW("Unable to find '%s'", classDescriptor); assert(dvmCheckException(dvmThreadSelf())); return NULL; } wrapperObj = (DataObject*) dvmAllocObject(wrapperClass, ALLOC_DEFAULT); if (wrapperObj == NULL) return NULL; dataPtr = (s4*) wrapperObj->instanceData; /* assumes value is stored in first instance field */ /* (see dvmValidateBoxClasses) */ if (typeIndex == PRIM_LONG || typeIndex == PRIM_DOUBLE) *(s8*)dataPtr = value.j; else *dataPtr = value.i; return wrapperObj; }
void* fastiva_dvmMalloc(size_t size, int flags, ClassObject* clazz) { #endif void *ptr; dvmLockHeap(); /* Try as hard as possible to allocate some memory. */ ptr = tryMalloc(size); if (ptr != NULL) { /* We've got the memory. */ if (gDvm.allocProf.enabled) { Thread* self = dvmThreadSelf(); gDvm.allocProf.allocCount++; gDvm.allocProf.allocSize += size; if (self != NULL) { self->allocProf.allocCount++; self->allocProf.allocSize += size; } } } else { /* The allocation failed. */ if (gDvm.allocProf.enabled) { Thread* self = dvmThreadSelf(); gDvm.allocProf.failedAllocCount++; gDvm.allocProf.failedAllocSize += size; if (self != NULL) { self->allocProf.failedAllocCount++; self->allocProf.failedAllocSize += size; } } } #ifdef FASTIVA if (clazz != NULL && ptr != NULL) { // for suspend-by-signal it must be in HeapLocked scope. DVM_OBJECT_INIT((Object*)ptr, clazz); d2f_initObject((Object*)ptr, clazz); } #endif dvmUnlockHeap(); if (ptr != NULL) { /* * If caller hasn't asked us not to track it, add it to the * internal tracking list. */ if ((flags & ALLOC_DONT_TRACK) == 0) { dvmAddTrackedAlloc((Object*)ptr, NULL); } } else { /* * The allocation failed; throw an OutOfMemoryError. */ throwOOME(); } return ptr; }