/** @return true if we need to schedule a call to clear(). */ static bool clearReference(Object *reference) { /* This is what the default implementation of Reference.clear() * does. We're required to clear all references to a given * referent atomically, so we can't pop in and out of interp * code each time. * * Also, someone may have subclassed one of the basic Reference * types, overriding clear(). We can't trust the clear() * implementation to call super.clear(); we cannot let clear() * resurrect the referent. If we clear it here, we can safely * call any overriding implementations. */ dvmSetFieldObject(reference, gDvm.offJavaLangRefReference_referent, NULL); #if FANCY_REFERENCE_SUBCLASS /* See if clear() has actually been overridden. If so, * we need to schedule a call to it before calling enqueue(). */ if (reference->clazz->vtable[gDvm.voffJavaLangRefReference_clear]->clazz != gDvm.classJavaLangRefReference) { /* clear() has been overridden; return true to indicate * that we need to schedule a call to the real clear() * implementation. */ return true; } #endif return false; }
void ObjTracer::modify_intent( Object * obj) { //try to clear the action //action InstField *pF = &obj->clazz->ifields[0]; //dvmDumpObject(obj); ALOG(LOG_VERBOSE,"YWB", "set action null"); dvmSetFieldObject( obj, pF->byteOffset, NULL); }
/* * private void setField(Object o, Class declaringClass, Class type, * int slot, boolean noAccessCheck, Object value) * * When assigning into a primitive field we will automatically extract * the value from box types. */ static void Dalvik_java_lang_reflect_Field_setField(const u4* args, JValue* pResult) { // ignore thisPtr in args[0] Object* obj = (Object*) args[1]; ClassObject* declaringClass = (ClassObject*) args[2]; ClassObject* fieldType = (ClassObject*) args[3]; int slot = args[4]; bool noAccessCheck = (args[5] != 0); Object* valueObj = (Object*) args[6]; JValue* fieldPtr; JValue value; /* unwrap primitive, or verify object type */ if (!dvmUnwrapPrimitive(valueObj, fieldType, &value)) { dvmThrowException("Ljava/lang/IllegalArgumentException;", "invalid value for field"); RETURN_VOID(); } /* get a pointer to the field's data; performs access checks */ fieldPtr = getFieldDataAddr(obj, declaringClass, slot, true, noAccessCheck); if (fieldPtr == NULL) RETURN_VOID(); /* store 4 or 8 bytes */ if (fieldType->primitiveType == PRIM_LONG || fieldType->primitiveType == PRIM_DOUBLE) { fieldPtr->j = value.j; } else if (fieldType->primitiveType == PRIM_NOT) { if (slot < 0) { StaticField *sfield; sfield = (StaticField *)dvmSlotToField(declaringClass, slot); assert(fieldPtr == &sfield->value); dvmSetStaticFieldObject(sfield, value.l); } else { int offset = declaringClass->ifields[slot].byteOffset; assert(fieldPtr == (JValue *)BYTE_OFFSET(obj, offset)); dvmSetFieldObject(obj, offset, value.l); } } else { fieldPtr->i = value.i; } RETURN_VOID(); }
/* * This is the constructor for a generated proxy object. */ static void proxyConstructor(const u4* args, JValue* pResult, const Method* method, Thread* self) { Object* obj = (Object*) args[0]; Object* handler = (Object*) args[1]; ClassObject* clazz = obj->clazz; int fieldOffset; fieldOffset = dvmFindFieldOffset(clazz, "h", "Ljava/lang/reflect/InvocationHandler;"); if (fieldOffset < 0) { LOGE("Unable to find 'h' in Proxy object\n"); //dvmDumpClass(clazz, kDumpClassFullDetail); dvmAbort(); // this should never happen } dvmSetFieldObject(obj, fieldOffset, handler); }
/* * Allocate a new instance of the class String, performing first-use * initialization of the class if necessary. Upon success, the * returned value will have all its fields except hashCode already * filled in, including a reference to a newly-allocated char[] for * the contents, sized as given. Additionally, a reference to the * chars array is stored to the pChars pointer. Callers must * subsequently call dvmReleaseTrackedAlloc() on the result pointer. * This function returns NULL on failure. */ static StringObject* makeStringObject(u4 charsLength, ArrayObject** pChars) { /* * The String class should have already gotten found (but not * necessarily initialized) before making it here. We assert it * explicitly, since historically speaking, we have had bugs with * regard to when the class String gets set up. The assert helps * make any regressions easier to diagnose. */ assert(gDvm.classJavaLangString != NULL); if (!dvmIsClassInitialized(gDvm.classJavaLangString)) { /* Perform first-time use initialization of the class. */ if (!dvmInitClass(gDvm.classJavaLangString)) { LOGE("FATAL: Could not initialize class String"); dvmAbort(); } } Object* result = dvmAllocObject(gDvm.classJavaLangString, ALLOC_DEFAULT); if (result == NULL) { return NULL; } ArrayObject* chars = dvmAllocPrimitiveArray('C', charsLength, ALLOC_DEFAULT); if (chars == NULL) { dvmReleaseTrackedAlloc(result, NULL); return NULL; } dvmSetFieldInt(result, STRING_FIELDOFF_COUNT, charsLength); dvmSetFieldObject(result, STRING_FIELDOFF_VALUE, (Object*) chars); dvmReleaseTrackedAlloc((Object*) chars, NULL); /* Leave offset and hashCode set to zero. */ *pChars = chars; return (StringObject*) result; }
/* All objects for stronger reference levels have been * marked before this is called. */ void dvmHeapHandleReferences(Object *refListHead, enum RefType refType) { Object *reference; GcMarkContext *markContext = &gDvm.gcHeap->markContext; const int offVmData = gDvm.offJavaLangRefReference_vmData; const int offReferent = gDvm.offJavaLangRefReference_referent; bool workRequired = false; size_t numCleared = 0; size_t numEnqueued = 0; reference = refListHead; while (reference != NULL) { Object *next; Object *referent; /* Pull the interesting fields out of the Reference object. */ next = dvmGetFieldObject(reference, offVmData); referent = dvmGetFieldObject(reference, offReferent); //TODO: when handling REF_PHANTOM, unlink any references // that fail this initial if(). We need to re-walk // the list, and it would be nice to avoid the extra // work. if (referent != NULL && !isMarked(ptr2chunk(referent), markContext)) { bool schedClear, schedEnqueue; /* This is the strongest reference that refers to referent. * Do the right thing. */ switch (refType) { case REF_SOFT: case REF_WEAK: schedClear = clearReference(reference); schedEnqueue = enqueueReference(reference); break; case REF_PHANTOM: /* PhantomReferences are not cleared automatically. * Until someone clears it (or the reference itself * is collected), the referent must remain alive. * * It's necessary to fully mark the referent because * it will still be present during the next GC, and * all objects that it points to must be valid. * (The referent will be marked outside of this loop, * after handing all references of this strength, in * case multiple references point to the same object.) */ schedClear = false; /* A PhantomReference is only useful with a * queue, but since it's possible to create one * without a queue, we need to check. */ schedEnqueue = enqueueReference(reference); break; default: assert(!"Bad reference type"); schedClear = false; schedEnqueue = false; break; } numCleared += schedClear ? 1 : 0; numEnqueued += schedEnqueue ? 1 : 0; if (schedClear || schedEnqueue) { uintptr_t workBits; /* Stuff the clear/enqueue bits in the bottom of * the pointer. Assumes that objects are 8-byte * aligned. * * Note that we are adding the *Reference* (which * is by definition already marked at this point) to * this list; we're not adding the referent (which * has already been cleared). */ assert(((intptr_t)reference & 3) == 0); assert(((WORKER_CLEAR | WORKER_ENQUEUE) & ~3) == 0); workBits = (schedClear ? WORKER_CLEAR : 0) | (schedEnqueue ? WORKER_ENQUEUE : 0); if (!dvmHeapAddRefToLargeTable( &gDvm.gcHeap->referenceOperations, (Object *)((uintptr_t)reference | workBits))) { LOGE_HEAP("dvmMalloc(): no room for any more " "reference operations\n"); dvmAbort(); } workRequired = true; } if (refType != REF_PHANTOM) { /* Let later GCs know not to reschedule this reference. */ dvmSetFieldObject(reference, offVmData, SCHEDULED_REFERENCE_MAGIC); } // else this is handled later for REF_PHANTOM } // else there was a stronger reference to the referent. reference = next; } #define refType2str(r) \ ((r) == REF_SOFT ? "soft" : ( \ (r) == REF_WEAK ? "weak" : ( \ (r) == REF_PHANTOM ? "phantom" : "UNKNOWN" ))) LOGD_HEAP("dvmHeapHandleReferences(): cleared %zd, enqueued %zd %s references\n", numCleared, numEnqueued, refType2str(refType)); /* Walk though the reference list again, and mark any non-clear/marked * referents. Only PhantomReferences can have non-clear referents * at this point. */ if (refType == REF_PHANTOM) { bool scanRequired = false; HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_REFERENCE_CLEANUP, 0); reference = refListHead; while (reference != NULL) { Object *next; Object *referent; /* Pull the interesting fields out of the Reference object. */ next = dvmGetFieldObject(reference, offVmData); referent = dvmGetFieldObject(reference, offReferent); if (referent != NULL && !isMarked(ptr2chunk(referent), markContext)) { markObjectNonNull(referent, markContext); scanRequired = true; /* Let later GCs know not to reschedule this reference. */ dvmSetFieldObject(reference, offVmData, SCHEDULED_REFERENCE_MAGIC); } reference = next; } HPROF_CLEAR_GC_SCAN_STATE(); if (scanRequired) { processMarkStack(markContext); } } if (workRequired) { dvmSignalHeapWorker(false); } }
/* * private static Class defineClass(String name, ClassLoader loader, * int cookie, ProtectionDomain pd) * * Load a class from a DEX file. This is roughly equivalent to defineClass() * in a regular VM -- it's invoked by the class loader to cause the * creation of a specific class. The difference is that the search for and * reading of the bytes is done within the VM. * * The class name is a "binary name", e.g. "java.lang.String". * * Returns a null pointer with no exception if the class was not found. * Throws an exception on other failures. */ static void Dalvik_dalvik_system_DexFile_defineClass(const u4* args, JValue* pResult) { StringObject* nameObj = (StringObject*) args[0]; Object* loader = (Object*) args[1]; int cookie = args[2]; Object* pd = (Object*) args[3]; ClassObject* clazz = NULL; DexOrJar* pDexOrJar = (DexOrJar*) cookie; DvmDex* pDvmDex; char* name; char* descriptor; name = dvmCreateCstrFromString(nameObj); descriptor = dvmDotToDescriptor(name); LOGV("--- Explicit class load '%s' 0x%08x\n", descriptor, cookie); free(name); if (!validateCookie(cookie)) RETURN_VOID(); if (pDexOrJar->isDex) pDvmDex = dvmGetRawDexFileDex(pDexOrJar->pRawDexFile); else pDvmDex = dvmGetJarFileDex(pDexOrJar->pJarFile); /* once we load something, we can't unmap the storage */ pDexOrJar->okayToFree = false; clazz = dvmDefineClass(pDvmDex, descriptor, loader); Thread* self = dvmThreadSelf(); if (dvmCheckException(self)) { /* * If we threw a "class not found" exception, stifle it, since the * contract in the higher method says we simply return null if * the class is not found. */ Object* excep = dvmGetException(self); if (strcmp(excep->clazz->descriptor, "Ljava/lang/ClassNotFoundException;") == 0 || strcmp(excep->clazz->descriptor, "Ljava/lang/NoClassDefFoundError;") == 0) { dvmClearException(self); } clazz = NULL; } /* * Set the ProtectionDomain -- do we need this to happen before we * link the class and make it available? If so, we need to pass it * through dvmDefineClass (and figure out some other * stuff, like where it comes from for bootstrap classes). */ if (clazz != NULL) { //LOGI("SETTING pd '%s' to %p\n", clazz->descriptor, pd); dvmSetFieldObject((Object*) clazz, gDvm.offJavaLangClass_pd, pd); } free(descriptor); RETURN_PTR(clazz); }
/* * private void setField(Object o, Class declaringClass, Class type, * int slot, boolean noAccessCheck, Object value) * * When assigning into a primitive field we will automatically extract * the value from box types. */ static void Dalvik_java_lang_reflect_Field_setField(const u4* args, JValue* pResult) { // ignore thisPtr in args[0] Object* obj = (Object*) args[1]; ClassObject* declaringClass = (ClassObject*) args[2]; ClassObject* fieldType = (ClassObject*) args[3]; int slot = args[4]; bool noAccessCheck = (args[5] != 0); Object* valueObj = (Object*) args[6]; #ifdef WITH_TAINT_TRACKING /* rtaint = args[7] * thisPtr taint = args[8] * obj taint = args[9] * declaringClass taint = args[10] * fieldType taint = args[11] * slot taint = args[12] * noAccessCheck taint = args[13] */ u4 valueTaint = args[14]; #endif JValue* fieldPtr; JValue value; /* unwrap primitive, or verify object type */ if (!dvmUnwrapPrimitive(valueObj, fieldType, &value)) { dvmThrowException("Ljava/lang/IllegalArgumentException;", "invalid value for field"); RETURN_VOID(); } /* get a pointer to the field's data; performs access checks */ fieldPtr = getFieldDataAddr(obj, declaringClass, slot, true, noAccessCheck); if (fieldPtr == NULL) RETURN_VOID(); /* store 4 or 8 bytes */ if (fieldType->primitiveType == PRIM_LONG || fieldType->primitiveType == PRIM_DOUBLE) { fieldPtr->j = value.j; } else if (fieldType->primitiveType == PRIM_NOT) { if (slot < 0) { StaticField *sfield; sfield = (StaticField *)dvmSlotToField(declaringClass, slot); assert(fieldPtr == &sfield->value); dvmSetStaticFieldObject(sfield, value.l); } else { int offset = declaringClass->ifields[slot].byteOffset; assert(fieldPtr == (JValue *)BYTE_OFFSET(obj, offset)); dvmSetFieldObject(obj, offset, value.l); } } else { fieldPtr->i = value.i; } #ifdef WITH_TAINT_TRACKING /* If we got this far, we know the fields is okay to access and there * will not be a problem getting the field from the slot */ { Field* field = dvmSlotToField(declaringClass, slot); assert(field != NULL); if (dvmIsStaticField(field)) { StaticField* sfield = (StaticField*)field; dvmSetStaticFieldTaint(sfield, valueTaint); } else { /* Note, getFieldDataAddr() already checked that * obj is of type declaringClass, so no need to check here */ InstField* ifield = (InstField*)field; if (fieldType->primitiveType == PRIM_LONG || fieldType->primitiveType == PRIM_DOUBLE) { dvmSetFieldTaintWide(obj, ifield->byteOffset, valueTaint); } else { dvmSetFieldTaint(obj, ifield->byteOffset, valueTaint); } } } #endif RETURN_VOID(); }