/* * Create an instance of the specified class. * * Returns NULL and throws an exception on failure. */ Object* dvmAllocObject(ClassObject* clazz, int flags) { Object* newObj; assert(dvmIsClassInitialized(clazz) || dvmIsClassInitializing(clazz)); if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) { flags |= ALLOC_FINALIZABLE; } /* allocate on GC heap; memory is zeroed out */ newObj = dvmMalloc(clazz->objectSize, flags); if (newObj != NULL) { DVM_OBJECT_INIT(newObj, clazz); Monitor* mon = NULL;//dvmCreateMonitor(newObj); newObj->lock = (u4)mon | LW_SHAPE_FAT; LOGVV("AllocObject: %s (%d)\n", clazz->descriptor, (int) clazz->objectSize); #if WITH_HPROF && WITH_HPROF_STACK hprofFillInStackTrace(newObj); #endif dvmTrackAllocation(clazz, clazz->objectSize); } return newObj; }
/* * Create a copy of an object, for Object.clone(). * * We use the size actually allocated, rather than obj->clazz->objectSize, * because the latter doesn't work for array objects. */ Object* dvmCloneObject(Object* obj) { Object* copy; int size; int flags; assert(dvmIsValidObject(obj)); /* Class.java shouldn't let us get here (java.lang.Class is final * and does not implement Clonable), but make extra sure. * A memcpy() clone will wreak havoc on a ClassObject's "innards". */ assert(obj->clazz != gDvm.classJavaLangClass); if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE)) flags = ALLOC_DEFAULT | ALLOC_FINALIZABLE; else flags = ALLOC_DEFAULT; //TODO: use clazz->objectSize for non-arrays size = dvmObjectSizeInHeap(obj); copy = dvmMalloc(size, flags); if (copy == NULL) return NULL; #if WITH_HPROF && WITH_HPROF_STACK hprofFillInStackTrace(copy); dvmTrackAllocation(obj->clazz, size); #endif memcpy(copy, obj, size); DVM_LOCK_INIT(©->lock); Monitor* mon = NULL;//dvmCreateMonitor(copy); copy->lock = (u4)mon | LW_SHAPE_FAT; //LOGV("CloneObject: %p->%p %s (%d)\n", obj, copy, obj->clazz->name, size); // TODO: deal with reference classes /* don't call dvmReleaseTrackedAlloc -- the caller must do that */ return copy; }
/* * Create a copy of an object, for Object.clone(). * * We use the size actually allocated, rather than obj->clazz->objectSize, * because the latter doesn't work for array objects. */ Object* dvmCloneObject(Object* obj) { Object* copy; int size; int flags; assert(dvmIsValidObject(obj)); /* Class.java shouldn't let us get here (java.lang.Class is final * and does not implement Clonable), but make extra sure. * A memcpy() clone will wreak havoc on a ClassObject's "innards". */ assert(obj->clazz != gDvm.classJavaLangClass); if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE)) flags = ALLOC_DEFAULT | ALLOC_FINALIZABLE; else flags = ALLOC_DEFAULT; if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) { size = dvmArrayObjectSize((ArrayObject *)obj); } else { size = obj->clazz->objectSize; } copy = dvmMalloc(size, flags); if (copy == NULL) return NULL; #if WITH_HPROF && WITH_HPROF_STACK hprofFillInStackTrace(copy); dvmTrackAllocation(obj->clazz, size); #endif memcpy(copy, obj, size); DVM_LOCK_INIT(©->lock); dvmWriteBarrierObject(copy); return copy; }
/* * Create an instance of the specified class. * * Returns NULL and throws an exception on failure. */ Object* dvmAllocObject(ClassObject* clazz, int flags) { Object* newObj; assert(dvmIsClassInitialized(clazz) || dvmIsClassInitializing(clazz)); if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) { flags |= ALLOC_FINALIZABLE; } /* allocate on GC heap; memory is zeroed out */ newObj = dvmMalloc(clazz->objectSize, flags); if (newObj != NULL) { DVM_OBJECT_INIT(newObj, clazz); #if WITH_HPROF && WITH_HPROF_STACK hprofFillInStackTrace(newObj); #endif dvmTrackAllocation(clazz, clazz->objectSize); } return newObj; }
/* * Generate a proxy class with the specified name, interfaces, and loader. * "interfaces" is an array of class objects. * * The interpreted code has done all of the necessary checks, e.g. we know * that "interfaces" contains only interface classes. * * On failure we leave a partially-created class object sitting around, * but the garbage collector will take care of it. */ ClassObject* dvmGenerateProxyClass(StringObject* str, ArrayObject* interfaces, Object* loader) { int result = -1; char* nameStr = NULL; Method** methods = NULL; ClassObject* newClass = NULL; int i; nameStr = dvmCreateCstrFromString(str); if (nameStr == NULL) { dvmThrowException("Ljava/lang/IllegalArgumentException;", "missing name"); goto bail; } LOGV("+++ Generate proxy class '%s' %p from %d interface classes\n", nameStr, loader, interfaces->length); /* * Characteristics of a Proxy class: * - concrete class, public and final * - superclass is java.lang.reflect.Proxy * - implements all listed interfaces (req'd for instanceof) * - has one method for each method in the interfaces (barring duplicates) * - has one constructor (takes an InvocationHandler arg) * - has overrides for hashCode, equals, and toString (these come first) * - has one field, a reference to the InvocationHandler object * * The idea here is to create a class object and fill in the details * as we would in loadClassFromDex(), and then call dvmLinkClass() to do * all the heavy lifting (notably populating the virtual and interface * method tables). */ /* * Generate a temporary list of virtual methods. */ int methodCount; if (!gatherMethods(interfaces, &methods, &methodCount)) goto bail; /* * Allocate storage for the class object and set some basic fields. */ newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT); if (newClass == NULL) return NULL; DVM_OBJECT_INIT(&newClass->obj, gDvm.unlinkedJavaLangClass); newClass->descriptorAlloc = dvmNameToDescriptor(nameStr); newClass->descriptor = newClass->descriptorAlloc; newClass->accessFlags = ACC_PUBLIC | ACC_FINAL; newClass->super = gDvm.classJavaLangReflectProxy; newClass->primitiveType = PRIM_NOT; newClass->classLoader = loader; #if WITH_HPROF && WITH_HPROF_STACK newClass->hprofSerialNumber = 0; hprofFillInStackTrace(newClass); #endif /* * Add direct method definitions. We have one (the constructor). */ newClass->directMethodCount = 1; newClass->directMethods = (Method*) dvmLinearAlloc(newClass->classLoader, 1 * sizeof(Method)); createConstructor(newClass, &newClass->directMethods[0]); dvmLinearReadOnly(newClass->classLoader, newClass->directMethods); /* * Add virtual method definitions. */ newClass->virtualMethodCount = methodCount; newClass->virtualMethods = (Method*) dvmLinearAlloc(newClass->classLoader, newClass->virtualMethodCount * sizeof(Method)); for (i = 0; i < newClass->virtualMethodCount; i++) { createHandlerMethod(newClass, &newClass->virtualMethods[i],methods[i]); } dvmLinearReadOnly(newClass->classLoader, newClass->virtualMethods); /* * Add interface list. */ int interfaceCount = interfaces->length; ClassObject** ifArray = (ClassObject**) interfaces->contents; newClass->interfaceCount = interfaceCount; newClass->interfaces = (ClassObject**)dvmLinearAlloc(newClass->classLoader, sizeof(ClassObject*) * interfaceCount); for (i = 0; i < interfaceCount; i++) newClass->interfaces[i] = ifArray[i]; dvmLinearReadOnly(newClass->classLoader, newClass->interfaces); /* * The class has one instance field, "protected InvocationHandler h", * which is filled in by the constructor. */ newClass->ifieldCount = 1; newClass->ifields = (InstField*) dvmLinearAlloc(newClass->classLoader, 1 * sizeof(InstField)); InstField* ifield = &newClass->ifields[0]; ifield->field.clazz = newClass; ifield->field.name = "h"; ifield->field.signature = "Ljava/lang/reflect/InvocationHandler;"; ifield->field.accessFlags = ACC_PROTECTED; ifield->byteOffset = -1; /* set later */ dvmLinearReadOnly(newClass->classLoader, newClass->ifields); /* * Everything is ready. See if the linker will lap it up. */ newClass->status = CLASS_LOADED; if (!dvmLinkClass(newClass, true)) { LOGI("Proxy class link failed\n"); goto bail; } /* * All good. Add it to the hash table. We should NOT see a collision * here; if we do, it means the caller has screwed up and provided us * with a duplicate name. */ if (!dvmAddClassToHash(newClass)) { LOGE("ERROR: attempted to generate %s more than once\n", newClass->descriptor); goto bail; } result = 0; bail: free(nameStr); free(methods); if (result != 0) { /* must free innards explicitly if we didn't finish linking */ dvmFreeClassInnards(newClass); newClass = NULL; dvmThrowException("Ljava/lang/RuntimeException;", NULL); } /* this allows the GC to free it */ dvmReleaseTrackedAlloc((Object*) newClass, NULL); return newClass; }