Exemplo n.º 1
0
    internal LocalVarInfo(CodeInfo ma, ClassFile classFile, ClassFile.Method method, UntangledExceptionTable exceptions, MethodWrapper mw, ClassLoaderWrapper classLoader)
    {
        Dictionary <int, string>[] localStoreReaders = FindLocalVariables(ma, mw, classFile, method);

        // now that we've done the code flow analysis, we can do a liveness analysis on the local variables
        ClassFile.Method.Instruction[] instructions     = method.Instructions;
        Dictionary <long, LocalVar>    localByStoreSite = new Dictionary <long, LocalVar>();
        List <LocalVar> locals = new List <LocalVar>();

        for (int i = 0; i < localStoreReaders.Length; i++)
        {
            if (localStoreReaders[i] != null)
            {
                VisitLocalLoads(ma, method, locals, localByStoreSite, localStoreReaders[i], i, classLoader.EmitDebugInfo);
            }
        }
        Dictionary <LocalVar, LocalVar> forwarders = new Dictionary <LocalVar, LocalVar>();

        if (classLoader.EmitDebugInfo)
        {
            InstructionFlags[] flags = MethodAnalyzer.ComputePartialReachability(ma, method.Instructions, exceptions, 0, false);
            // if we're emitting debug info, we need to keep dead stores as well...
            for (int i = 0; i < instructions.Length; i++)
            {
                if ((flags[i] & InstructionFlags.Reachable) != 0 &&
                    IsStoreLocal(instructions[i].NormalizedOpCode))
                {
                    if (!localByStoreSite.ContainsKey(MakeKey(i, instructions[i].NormalizedArg1)))
                    {
                        LocalVar v = new LocalVar();
                        v.local = instructions[i].NormalizedArg1;
                        v.type  = ma.GetStackTypeWrapper(i, 0);
                        FindLvtEntry(v, method, i);
                        locals.Add(v);
                        localByStoreSite.Add(MakeKey(i, v.local), v);
                    }
                }
            }
            // to make the debugging experience better, we have to trust the
            // LocalVariableTable (unless it's clearly bogus) and merge locals
            // together that are the same according to the LVT
            for (int i = 0; i < locals.Count - 1; i++)
            {
                for (int j = i + 1; j < locals.Count; j++)
                {
                    LocalVar v1 = (LocalVar)locals[i];
                    LocalVar v2 = (LocalVar)locals[j];
                    if (v1.name != null && v1.name == v2.name && v1.start_pc == v2.start_pc && v1.end_pc == v2.end_pc)
                    {
                        // we can only merge if the resulting type is valid (this protects against incorrect
                        // LVT data, but is also needed for constructors, where the uninitialized this is a different
                        // type from the initialized this)
                        TypeWrapper tw = InstructionState.FindCommonBaseType(v1.type, v2.type);
                        if (tw != VerifierTypeWrapper.Invalid)
                        {
                            v1.isArg |= v2.isArg;
                            v1.type   = tw;
                            forwarders.Add(v2, v1);
                            locals.RemoveAt(j);
                            j--;
                        }
                    }
                }
            }
        }
        else
        {
            for (int i = 0; i < locals.Count - 1; i++)
            {
                for (int j = i + 1; j < locals.Count; j++)
                {
                    LocalVar v1 = (LocalVar)locals[i];
                    LocalVar v2 = (LocalVar)locals[j];
                    // if the two locals are the same, we merge them, this is a small
                    // optimization, it should *not* be required for correctness.
                    if (v1.local == v2.local && v1.type == v2.type)
                    {
                        v1.isArg |= v2.isArg;
                        forwarders.Add(v2, v1);
                        locals.RemoveAt(j);
                        j--;
                    }
                }
            }
        }
        invokespecialLocalVars = new LocalVar[instructions.Length][];
        localVars = new LocalVar[instructions.Length];
        for (int i = 0; i < localVars.Length; i++)
        {
            LocalVar v = null;
            if (localStoreReaders[i] != null)
            {
                Debug.Assert(IsLoadLocal(instructions[i].NormalizedOpCode));
                // lame way to look up the local variable for a load
                // (by indirecting through a corresponding store)
                foreach (int store in localStoreReaders[i].Keys)
                {
                    v = localByStoreSite[MakeKey(store, instructions[i].NormalizedArg1)];
                    break;
                }
            }
            else
            {
                if (instructions[i].NormalizedOpCode == NormalizedByteCode.__invokespecial)
                {
                    invokespecialLocalVars[i] = new LocalVar[method.MaxLocals];
                    for (int j = 0; j < invokespecialLocalVars[i].Length; j++)
                    {
                        localByStoreSite.TryGetValue(MakeKey(i, j), out invokespecialLocalVars[i][j]);
                    }
                }
                else
                {
                    localByStoreSite.TryGetValue(MakeKey(i, instructions[i].NormalizedArg1), out v);
                }
            }
            if (v != null)
            {
                LocalVar fwd;
                if (forwarders.TryGetValue(v, out fwd))
                {
                    v = fwd;
                }
                localVars[i] = v;
            }
        }
        this.allLocalVars = locals.ToArray();
    }