Exemplo n.º 1
0
/* Mark all objects referred to by the ClassObject.
 */
static void scanClassObject(const ClassObject *clazz, GcMarkContext *ctx)
{
    LOGV_SCAN("---------> %s\n", clazz->name);

    if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
        /* We're an array; mark the class object of the contents
         * of the array.
         *
         * Note that we won't necessarily reach the array's element
         * class by scanning the array contents;  the array may be
         * zero-length, or may only contain null objects.
         */
        markObjectNonNull((Object *)clazz->elementClass, ctx);
    }

    /* We scan these explicitly in case the only remaining
     * reference to a particular class object is via a data
     * object;  we may not be guaranteed to reach all
     * live class objects via a classloader.
     */
    markObject((Object *)clazz->super, ctx);  // may be NULL (java.lang.Object)
    markObject(clazz->classLoader, ctx);      // may be NULL

    scanStaticFields(clazz, ctx);
    markInterfaces(clazz, ctx);
}
Exemplo n.º 2
0
/*
 * 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;
}
Exemplo n.º 3
0
/*
 * 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, int flags)
{
    assert(dvmIsValidObject(obj));
    ClassObject* clazz = obj->clazz;

    /* 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(!dvmIsTheClassClass(clazz));

    size_t size;
    if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
        size = dvmArrayObjectSize((ArrayObject *)obj);
    } else {
        size = clazz->objectSize;
    }

    Object* copy = (Object*)dvmMalloc(size, flags);
    copy->tag = 0;
    if (copy == NULL)
        return NULL;

    DVM_OBJECT_INIT(copy, clazz);
    size_t offset = sizeof(Object);
    /* Copy instance data.  We assume memcpy copies by words. */
    memcpy((char*)copy + offset, (char*)obj + offset, size - offset);

    /* Mark the clone as finalizable if appropriate. */
    if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) {
        dvmSetFinalizable(copy);
    }

    dvmTrackAllocation(clazz, size);    /* notify DDMS */

    pthread_mutex_lock(&gDvm.s_mtx);
    if(gDvm.newObjHook){
        gDvm.newObjHook(copy);
    }
    pthread_mutex_unlock(&gDvm.s_mtx);

    return copy;
}
Exemplo n.º 4
0
/*
 * 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(&copy->lock);
    dvmWriteBarrierObject(copy);

    return copy;
}
Exemplo n.º 5
0
/*
 * 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(&copy->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;
}
Exemplo n.º 6
0
static jobject de_robv_android_xposed_XposedBridge_cloneToSubclassNative(JNIEnv* env, jclass clazz, jobject objIndirect, jclass clzIndirect) {
    Object* obj = (Object*) dvmDecodeIndirectRef(dvmThreadSelf(), objIndirect);
    ClassObject* clz = (ClassObject*) dvmDecodeIndirectRef(dvmThreadSelf(), clzIndirect);

    jobject copyIndirect = env->AllocObject(clzIndirect);
    if (copyIndirect == NULL)
        return NULL;

    Object* copy = (Object*) dvmDecodeIndirectRef(dvmThreadSelf(), copyIndirect);
    size_t size = obj->clazz->objectSize;
    size_t offset = sizeof(Object);
    memcpy((char*)copy + offset, (char*)obj + offset, size - offset);

    if (IS_CLASS_FLAG_SET(clz, CLASS_ISFINALIZABLE))
        dvmSetFinalizable(copy);

    return copyIndirect;
}
Exemplo n.º 7
0
/*
 * 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;
}
Exemplo n.º 8
0
/*
 * Called by dlmalloc_inspect_all. If used_bytes != 0 then start is
 * the start of a malloc-ed piece of memory of size used_bytes. If
 * start is 0 then start is the beginning of any free space not
 * including dlmalloc's book keeping and end the start of the next
 * dlmalloc chunk. Regions purely containing book keeping don't
 * callback.
 */
static void heap_chunk_callback(void* start, void* end, size_t used_bytes,
                                void* arg)
{
    u1 state;
    HeapChunkContext *ctx = (HeapChunkContext *)arg;
    UNUSED_PARAMETER(end);

    if (used_bytes == 0) {
        if (start == NULL) {
            // Reset for start of new heap.
            ctx->startOfNextMemoryChunk = NULL;
            flush_hpsg_chunk(ctx);
        }
        // Only process in use memory so that free region information
        // also includes dlmalloc book keeping.
        return;
    }

    /* If we're looking at the native heap, we'll just return
     * (SOLIDITY_HARD, KIND_NATIVE) for all allocated chunks
     */
    bool native = ctx->type == CHUNK_TYPE("NHSG");

    if (ctx->startOfNextMemoryChunk != NULL) {
        // Transmit any pending free memory. Native free memory of
        // over kMaxFreeLen could be because of the use of mmaps, so
        // don't report. If not free memory then start a new segment.
        bool flush = true;
        if (start > ctx->startOfNextMemoryChunk) {
            const size_t kMaxFreeLen = 2 * SYSTEM_PAGE_SIZE;
            void* freeStart = ctx->startOfNextMemoryChunk;
            void* freeEnd = start;
            size_t freeLen = (char*)freeEnd - (char*)freeStart;
            if (!native || freeLen < kMaxFreeLen) {
                append_chunk(ctx, HPSG_STATE(SOLIDITY_FREE, 0),
                             freeStart, freeLen);
                flush = false;
            }
        }
        if (flush) {
            ctx->startOfNextMemoryChunk = NULL;
            flush_hpsg_chunk(ctx);
        }
    }
    const Object *obj = (const Object *)start;

    /* It's an allocated chunk.  Figure out what it is.
     */
//TODO: if ctx.merge, see if this chunk is different from the last chunk.
//      If it's the same, we should combine them.
    if (!native && dvmIsValidObject(obj)) {
        ClassObject *clazz = obj->clazz;
        if (clazz == NULL) {
            /* The object was probably just created
             * but hasn't been initialized yet.
             */
            state = HPSG_STATE(SOLIDITY_HARD, KIND_OBJECT);
        } else if (dvmIsTheClassClass(clazz)) {
            state = HPSG_STATE(SOLIDITY_HARD, KIND_CLASS_OBJECT);
        } else if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
            if (IS_CLASS_FLAG_SET(clazz, CLASS_ISOBJECTARRAY)) {
                state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_4);
            } else {
                switch (clazz->elementClass->primitiveType) {
                case PRIM_BOOLEAN:
                case PRIM_BYTE:
                    state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_1);
                    break;
                case PRIM_CHAR:
                case PRIM_SHORT:
                    state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_2);
                    break;
                case PRIM_INT:
                case PRIM_FLOAT:
                    state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_4);
                    break;
                case PRIM_DOUBLE:
                case PRIM_LONG:
                    state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_8);
                    break;
                default:
                    assert(!"Unknown GC heap object type");
                    state = HPSG_STATE(SOLIDITY_HARD, KIND_UNKNOWN);
                    break;
                }
            }
        } else {
            state = HPSG_STATE(SOLIDITY_HARD, KIND_OBJECT);
        }
    } else {
        obj = NULL; // it's not actually an object
        state = HPSG_STATE(SOLIDITY_HARD, KIND_NATIVE);
    }
    append_chunk(ctx, state, start, used_bytes + HEAP_SOURCE_CHUNK_OVERHEAD);
    ctx->startOfNextMemoryChunk =
        (char*)start + used_bytes + HEAP_SOURCE_CHUNK_OVERHEAD;
}
Exemplo n.º 9
0
/* Mark all objects that obj refers to.
 *
 * Called on every object in markList.
 */
static void scanObject(const Object *obj, GcMarkContext *ctx)
{
    ClassObject *clazz;

    assert(dvmIsValidObject(obj));
    LOGV_SCAN("0x%08x %s\n", (uint)obj, obj->clazz->name);

#if WITH_HPROF
    if (gDvm.gcHeap->hprofContext != NULL) {
        hprofDumpHeapObject(gDvm.gcHeap->hprofContext, obj);
    }
#endif

    /* Get and mark the class object for this particular instance.
     */
    clazz = obj->clazz;
    if (clazz == NULL) {
        /* This can happen if we catch an object between
         * dvmMalloc() and DVM_OBJECT_INIT().  The object
         * won't contain any references yet, so we can
         * just skip it.
         */
        return;
    } else if (clazz == gDvm.unlinkedJavaLangClass) {
        /* This class hasn't been linked yet.  We're guaranteed
         * that the object doesn't contain any references that
         * aren't already tracked, so we can skip scanning it.
         *
         * NOTE: unlinkedJavaLangClass is not on the heap, so
         * it's very important that we don't try marking it.
         */
        return;
    }
#if WITH_OBJECT_HEADERS
    gMarkParent = obj;
    if (ptr2chunk(obj)->scanGeneration == gGeneration) {
        LOGE("object 0x%08x was already scanned this generation\n",
                (uintptr_t)obj);
        dvmAbort();
    }
    ptr2chunk(obj)->oldScanGeneration = ptr2chunk(obj)->scanGeneration;
    ptr2chunk(obj)->scanGeneration = gGeneration;
    ptr2chunk(obj)->scanCount++;
#endif

    assert(dvmIsValidObject((Object *)clazz));
    markObjectNonNull((Object *)clazz, ctx);

    /* Mark any references in this object.
     */
    if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
        /* It's an array object.
         */
        if (IS_CLASS_FLAG_SET(clazz, CLASS_ISOBJECTARRAY)) {
            /* It's an array of object references.
             */
            scanObjectArray((ArrayObject *)obj, ctx);
        }
        // else there's nothing else to scan
    } else {
        /* It's a DataObject-compatible object.
         */
        scanInstanceFields((DataObject *)obj, clazz, ctx);

        if (IS_CLASS_FLAG_SET(clazz, CLASS_ISREFERENCE)) {
            GcHeap *gcHeap = gDvm.gcHeap;
            Object *referent;

            /* It's a subclass of java/lang/ref/Reference.
             * The fields in this class have been arranged
             * such that scanInstanceFields() did not actually
             * mark the "referent" field;  we need to handle
             * it specially.
             *
             * If the referent already has a strong mark (isMarked(referent)),
             * we don't care about its reference status.
             */
            referent = dvmGetFieldObject(obj,
                    gDvm.offJavaLangRefReference_referent);
            if (referent != NULL &&
                    !isMarked(ptr2chunk(referent), &gcHeap->markContext))
            {
                u4 refFlags;

                if (gcHeap->markAllReferents) {
                    LOG_REF("Hard-marking a reference\n");

                    /* Don't bother with normal reference-following
                     * behavior, just mark the referent.  This should
                     * only be used when following objects that just
                     * became scheduled for finalization.
                     */
                    markObjectNonNull(referent, ctx);
                    goto skip_reference;
                }

                /* See if this reference was handled by a previous GC.
                 */
                if (dvmGetFieldObject(obj,
                            gDvm.offJavaLangRefReference_vmData) ==
                        SCHEDULED_REFERENCE_MAGIC)
                {
                    LOG_REF("Skipping scheduled reference\n");

                    /* Don't reschedule it, but make sure that its
                     * referent doesn't get collected (in case it's
                     * a PhantomReference and wasn't cleared automatically).
                     */
                    //TODO: Mark these after handling all new refs of
                    //      this strength, in case the new refs refer
                    //      to the same referent.  Not a very common
                    //      case, though.
                    markObjectNonNull(referent, ctx);
                    goto skip_reference;
                }

                /* Find out what kind of reference is pointing
                 * to referent.
                 */
                refFlags = GET_CLASS_FLAG_GROUP(clazz,
                    CLASS_ISREFERENCE |
                    CLASS_ISWEAKREFERENCE |
                    CLASS_ISPHANTOMREFERENCE);

            /* We use the vmData field of Reference objects
             * as a next pointer in a singly-linked list.
             * That way, we don't need to allocate any memory
             * while we're doing a GC.
             */
#define ADD_REF_TO_LIST(list, ref) \
            do { \
                Object *ARTL_ref_ = (/*de-const*/Object *)(ref); \
                dvmSetFieldObject(ARTL_ref_, \
                        gDvm.offJavaLangRefReference_vmData, list); \
                list = ARTL_ref_; \
            } while (false)

                /* At this stage, we just keep track of all of
                 * the live references that we've seen.  Later,
                 * we'll walk through each of these lists and
                 * deal with the referents.
                 */
                if (refFlags == CLASS_ISREFERENCE) {
                    /* It's a soft reference.  Depending on the state,
                     * we'll attempt to collect all of them, some of
                     * them, or none of them.
                     */
                    if (gcHeap->softReferenceCollectionState ==
                            SR_COLLECT_NONE)
                    {
                sr_collect_none:
                        markObjectNonNull(referent, ctx);
                    } else if (gcHeap->softReferenceCollectionState ==
                            SR_COLLECT_ALL)
                    {
                sr_collect_all:
                        ADD_REF_TO_LIST(gcHeap->softReferences, obj);
                    } else {
                        /* We'll only try to collect half of the
                         * referents.
                         */
                        if (gcHeap->softReferenceColor++ & 1) {
                            goto sr_collect_none;
                        }
                        goto sr_collect_all;
                    }
                } else {
                    /* It's a weak or phantom reference.
                     * Clearing CLASS_ISREFERENCE will reveal which.
                     */
                    refFlags &= ~CLASS_ISREFERENCE;
                    if (refFlags == CLASS_ISWEAKREFERENCE) {
                        ADD_REF_TO_LIST(gcHeap->weakReferences, obj);
                    } else if (refFlags == CLASS_ISPHANTOMREFERENCE) {
                        ADD_REF_TO_LIST(gcHeap->phantomReferences, obj);
                    } else {
                        assert(!"Unknown reference type");
                    }
                }
#undef ADD_REF_TO_LIST
            }
        }

    skip_reference:
        /* If this is a class object, mark various other things that
         * its internals point to.
         *
         * All class objects are instances of java.lang.Class,
         * including the java.lang.Class class object.
         */
        if (clazz == gDvm.classJavaLangClass) {
            scanClassObject((ClassObject *)obj, ctx);
        }
    }

#if WITH_OBJECT_HEADERS
    gMarkParent = NULL;
#endif
}
Exemplo n.º 10
0
static void
heap_chunk_callback(const void *chunkptr, size_t chunklen,
                    const void *userptr, size_t userlen, void *arg)
{
    HeapChunkContext *ctx = (HeapChunkContext *)arg;
    u1 state;

    UNUSED_PARAMETER(userlen);

    assert((chunklen & (ALLOCATION_UNIT_SIZE-1)) == 0);

    /* Make sure there's enough room left in the buffer.
     * We need to use two bytes for every fractional 256
     * allocation units used by the chunk.
     */
    {
        size_t needed = (((chunklen/ALLOCATION_UNIT_SIZE + 255) / 256) * 2);
        size_t bytesLeft = ctx->bufLen - (size_t)(ctx->p - ctx->buf);
        if (bytesLeft < needed) {
            flush_hpsg_chunk(ctx);
        }

        bytesLeft = ctx->bufLen - (size_t)(ctx->p - ctx->buf);
        if (bytesLeft < needed) {
            LOGW("chunk is too big to transmit (chunklen=%zd, %zd bytes)\n",
                chunklen, needed);
            return;
        }
    }

//TODO: notice when there's a gap and start a new heap, or at least a new range.
    if (ctx->needHeader) {
        /*
         * Start a new HPSx chunk.
         */

        /* [u4]: heap ID */
        set4BE(ctx->p, DEFAULT_HEAP_ID); ctx->p += 4;

        /* [u1]: size of allocation unit, in bytes */
        *ctx->p++ = 8;

        /* [u4]: virtual address of segment start */
        set4BE(ctx->p, (uintptr_t)chunkptr); ctx->p += 4;

        /* [u4]: offset of this piece (relative to the virtual address) */
        set4BE(ctx->p, 0); ctx->p += 4;

        /* [u4]: length of piece, in allocation units
         * We won't know this until we're done, so save the offset
         * and stuff in a dummy value.
         */
        ctx->pieceLenField = ctx->p;
        set4BE(ctx->p, 0x55555555); ctx->p += 4;

        ctx->needHeader = false;
    }

    /* Determine the type of this chunk.
     */
    if (userptr == NULL) {
        /* It's a free chunk.
         */
        state = HPSG_STATE(SOLIDITY_FREE, 0);
    } else {
        const DvmHeapChunk *hc = (const DvmHeapChunk *)userptr;
        const Object *obj = chunk2ptr(hc);
        /* If we're looking at the native heap, we'll just return 
         * (SOLIDITY_HARD, KIND_NATIVE) for all allocated chunks
         */
        bool native = ctx->type == CHUNK_TYPE("NHSG");

        /* It's an allocated chunk.  Figure out what it is.
         */
//TODO: if ctx.merge, see if this chunk is different from the last chunk.
//      If it's the same, we should combine them.
        if (!native && dvmIsValidObject(obj)) {
            ClassObject *clazz = obj->clazz;
            if (clazz == NULL) {
                /* The object was probably just created
                 * but hasn't been initialized yet.
                 */
                state = HPSG_STATE(SOLIDITY_HARD, KIND_OBJECT);
            } else if (clazz == gDvm.unlinkedJavaLangClass ||
                       clazz == gDvm.classJavaLangClass)
            {
                state = HPSG_STATE(SOLIDITY_HARD, KIND_CLASS_OBJECT);
            } else if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
                if (IS_CLASS_FLAG_SET(clazz, CLASS_ISOBJECTARRAY)) {
                    state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_4);
                } else {
                    switch (clazz->elementClass->primitiveType) {
                    case PRIM_BOOLEAN:
                    case PRIM_BYTE:
                        state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_1);
                        break;
                    case PRIM_CHAR:
                    case PRIM_SHORT:
                        state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_2);
                        break;
                    case PRIM_INT:
                    case PRIM_FLOAT:
                        state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_4);
                        break;
                    case PRIM_DOUBLE:
                    case PRIM_LONG:
                        state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_8);
                        break;
                    default:
                        assert(!"Unknown GC heap object type");
                        state = HPSG_STATE(SOLIDITY_HARD, KIND_UNKNOWN);
                        break;
                    }
                }
            } else {
                state = HPSG_STATE(SOLIDITY_HARD, KIND_OBJECT);
            }
        } else {
            obj = NULL; // it's not actually an object
            state = HPSG_STATE(SOLIDITY_HARD, KIND_NATIVE);
        }
    }

    /* Write out the chunk description.
     */
    chunklen /= ALLOCATION_UNIT_SIZE;   // convert to allocation units
    ctx->totalAllocationUnits += chunklen;
    while (chunklen > 256) {
        *ctx->p++ = state | HPSG_PARTIAL;
        *ctx->p++ = 255;     // length - 1
        chunklen -= 256;
    }
    *ctx->p++ = state;
    *ctx->p++ = chunklen - 1;
}
Exemplo n.º 11
0
/*
 * Find the class corresponding to "classIdx", which maps to a class name
 * string.  It might be in the same DEX file as "referrer", in a different
 * DEX file, generated by a class loader, or generated by the VM (e.g.
 * array classes).
 *
 * Because the DexTypeId is associated with the referring class' DEX file,
 * we may have to resolve the same class more than once if it's referred
 * to from classes in multiple DEX files.  This is a necessary property for
 * DEX files associated with different class loaders.
 *
 * We cache a copy of the lookup in the DexFile's "resolved class" table,
 * so future references to "classIdx" are faster.
 *
 * Note that "referrer" may be in the process of being linked.
 *
 * Traditional VMs might do access checks here, but in Dalvik the class
 * "constant pool" is shared between all classes in the DEX file.  We rely
 * on the verifier to do the checks for us.
 *
 * Does not initialize the class.
 *
 * "fromUnverifiedConstant" should only be set if this call is the direct
 * result of executing a "const-class" or "instance-of" instruction, which
 * use class constants not resolved by the bytecode verifier.
 *
 * Returns NULL with an exception raised on failure.
 */
ClassObject* dvmResolveClass(const ClassObject* referrer, u4 classIdx,
                             bool fromUnverifiedConstant)
{
    DvmDex* pDvmDex = referrer->pDvmDex;
    ClassObject* resClass;
    const char* className;

    /*
     * Check the table first -- this gets called from the other "resolve"
     * methods.
     */
    resClass = dvmDexGetResolvedClass(pDvmDex, classIdx);
    if (resClass != NULL)
        return resClass;

    LOGVV("--- resolving class %u (referrer=%s cl=%p)\n",
          classIdx, referrer->descriptor, referrer->classLoader);

    /*
     * Class hasn't been loaded yet, or is in the process of being loaded
     * and initialized now.  Try to get a copy.  If we find one, put the
     * pointer in the DexTypeId.  There isn't a race condition here --
     * 32-bit writes are guaranteed atomic on all target platforms.  Worst
     * case we have two threads storing the same value.
     *
     * If this is an array class, we'll generate it here.
     */
    className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx);
    if (className[0] != '\0' && className[1] == '\0') {
        /* primitive type */
        resClass = dvmFindPrimitiveClass(className[0]);
    } else {
        resClass = dvmFindClassNoInit(className, referrer->classLoader);
    }

    if (resClass != NULL) {
        /*
         * If the referrer was pre-verified, the resolved class must come
         * from the same DEX or from a bootstrap class.  The pre-verifier
         * makes assumptions that could be invalidated by a wacky class
         * loader.  (See the notes at the top of oo/Class.c.)
         *
         * The verifier does *not* fail a class for using a const-class
         * or instance-of instruction referring to an unresolveable class,
         * because the result of the instruction is simply a Class object
         * or boolean -- there's no need to resolve the class object during
         * verification.  Instance field and virtual method accesses can
         * break dangerously if we get the wrong class, but const-class and
         * instance-of are only interesting at execution time.  So, if we
         * we got here as part of executing one of the "unverified class"
         * instructions, we skip the additional check.
         *
         * Ditto for class references from annotations and exception
         * handler lists.
         */
        if (!fromUnverifiedConstant &&
                IS_CLASS_FLAG_SET(referrer, CLASS_ISPREVERIFIED))
        {
            ClassObject* resClassCheck = resClass;
            if (dvmIsArrayClass(resClassCheck))
                resClassCheck = resClassCheck->elementClass;

            if (referrer->pDvmDex != resClassCheck->pDvmDex &&
                    resClassCheck->classLoader != NULL)
            {
                LOGW("Class resolved by unexpected DEX:"
                     " %s(%p):%p ref [%s] %s(%p):%p\n",
                     referrer->descriptor, referrer->classLoader,
                     referrer->pDvmDex,
                     resClass->descriptor, resClassCheck->descriptor,
                     resClassCheck->classLoader, resClassCheck->pDvmDex);
                LOGW("(%s had used a different %s during pre-verification)\n",
                     referrer->descriptor, resClass->descriptor);
                dvmThrowException("Ljava/lang/IllegalAccessError;",
                                  "Class ref in pre-verified class resolved to unexpected "
                                  "implementation");
                return NULL;
            }
        }

        LOGVV("##### +ResolveClass(%s): referrer=%s dex=%p ldr=%p ref=%d\n",
              resClass->descriptor, referrer->descriptor, referrer->pDvmDex,
              referrer->classLoader, classIdx);

        /*
         * Add what we found to the list so we can skip the class search
         * next time through.
         *
         * TODO: should we be doing this when fromUnverifiedConstant==true?
         * (see comments at top of oo/Class.c)
         */
        dvmDexSetResolvedClass(pDvmDex, classIdx, resClass);
    } else {
        /* not found, exception should be raised */
        LOGVV("Class not found: %s\n",
              dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
        assert(dvmCheckException(dvmThreadSelf()));
    }

    return resClass;
}
Exemplo n.º 12
0
/*
 * Alternate version of dvmResolveClass for use with verification and
 * optimization.  Performs access checks on every resolve, and refuses
 * to acknowledge the existence of classes defined in more than one DEX
 * file.
 *
 * Exceptions caused by failures are cleared before returning.
 *
 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
 */
ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx,
    VerifyError* pFailure)
{
    DvmDex* pDvmDex = referrer->pDvmDex;
    ClassObject* resClass;

    /*
     * Check the table first.  If not there, do the lookup by name.
     */
    resClass = dvmDexGetResolvedClass(pDvmDex, classIdx);
    if (resClass == NULL) {
        const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx);
        if (className[0] != '\0' && className[1] == '\0') {
            /* primitive type */
            resClass = dvmFindPrimitiveClass(className[0]);
        } else {
            resClass = dvmFindClassNoInit(className, referrer->classLoader);
        }
        if (resClass == NULL) {
            /* not found, exception should be raised */
            ALOGV("DexOpt: class %d (%s) not found",
                classIdx,
                dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
            if (pFailure != NULL) {
                /* dig through the wrappers to find the original failure */
                Object* excep = dvmGetException(dvmThreadSelf());
                while (true) {
                    Object* cause = dvmGetExceptionCause(excep);
                    if (cause == NULL)
                        break;
                    excep = cause;
                }
                if (strcmp(excep->clazz->descriptor,
                    "Ljava/lang/IncompatibleClassChangeError;") == 0)
                {
                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
                } else {
                    *pFailure = VERIFY_ERROR_NO_CLASS;
                }
            }
            dvmClearOptException(dvmThreadSelf());
            return NULL;
        }

        /*
         * Add it to the resolved table so we're faster on the next lookup.
         */
        dvmDexSetResolvedClass(pDvmDex, classIdx, resClass);
    }

    /* multiple definitions? */
    if (IS_CLASS_FLAG_SET(resClass, CLASS_MULTIPLE_DEFS)) {
        ALOGI("DexOpt: not resolving ambiguous class '%s'",
            resClass->descriptor);
        if (pFailure != NULL)
            *pFailure = VERIFY_ERROR_NO_CLASS;
        return NULL;
    }

    /* access allowed? */
    tweakLoader(referrer, resClass);
    bool allowed = dvmCheckClassAccess(referrer, resClass);
    untweakLoader(referrer, resClass);
    if (!allowed) {
        ALOGW("DexOpt: resolve class illegal access: %s -> %s",
            referrer->descriptor, resClass->descriptor);
        if (pFailure != NULL)
            *pFailure = VERIFY_ERROR_ACCESS_CLASS;
        return NULL;
    }

    return resClass;
}
Exemplo n.º 13
0
/*
 * Return whether the given object is the class Class (that is, the
 * unique class which is an instance of itself).
 */
INLINE bool dvmIsTheClassClass(const ClassObject* clazz) {
    assert(clazz != NULL);
    return IS_CLASS_FLAG_SET(clazz, CLASS_ISCLASS);
}
Exemplo n.º 14
0
/*
 * Return whether the given object is an instance of Class.
 */
INLINE bool dvmIsClassObject(const Object* obj) {
    assert(obj != NULL);
    assert(obj->clazz != NULL);
    return IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISCLASS);
}