public static bool IsLdloc(this CodeInstruction instruction, LocalVar local)
 {
     if (!instruction.IsLdloc(local.builder))
     {
         return(false);
     }
     if (local.builder != null)
     {
         return(true);
     }
     return(LocalVar.OpCodeToInt[instruction.opcode] == local.index);
 }
        public static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions)
        {
            var      instructionList = instructions.ToList();
            var      GetValue        = AccessTools.Method(typeof(ToolExtensions), nameof(ToolExtensions.GetValue), new Type[] { typeof(ToolComp), typeof(ToolType), typeof(float) });
            var      NoToolWorkSpeed = AccessTools.Method(typeof(Utility), nameof(Utility.NoToolWorkSpeed));
            LocalVar currVal         = null;
            LocalVar toolType        = null;

            for (int i = 0; i < instructionList.Count; i++)
            {
                var instruction = instructionList[i];
                if (instruction.Calls(GetValue))
                {
                    if (!instructionList[i + 1].IsStloc() || !instructionList[i - 2].IsLdloc())
                    {
                        Log.Error("ST_BaseMessage".Translate() + "ST_Error_Harmony_ToolsUsedHandler".Translate());
                        break;
                    }
                    currVal  = instructionList[i + 1].ToLocalVar();
                    toolType = instructionList[i - 2].ToLocalVar();
                }
                if (currVal != null && instruction.IsLdloc(currVal) && instructionList[i + 1].LoadsConstant(1f))
                {
                    CodeInstruction loadToolType;
                    if (toolType.builder != null)
                    {
                        loadToolType = new CodeInstruction(OpCodes.Ldloc_S, toolType.builder);
                    }
                    else
                    {
                        loadToolType = new CodeInstruction(OpCodes.Ldloc_S, toolType.index);
                    }
                    instructionList.RemoveAt(i + 1);
                    instructionList.InsertRange(i + 1, new List <CodeInstruction>()
                    {
                        loadToolType,
                        new CodeInstruction(OpCodes.Call, NoToolWorkSpeed),
                    });
                    break;
                }
            }
            return(instructionList);
        }
        private MsgTypedValue VariableToTypedValue(LocalVar lvar, CoalescedFrame frame)
        {
            // TODO - lvar.Type?
            if (lvar.Name == "_")
            {
                var tv = new MsgTypedValue();
                tv.TypeId = (UInt32)Value.Type.None;
                return(tv);
            }
            else
            {
                var frameVar = frame.Variables.FirstOrDefault(v => v.Name == lvar.Name);
                if (frameVar == null)
                {
                    throw new RequestFailedException($"Variable does not exist: \"{lvar.Name}\"");
                }

                return(frameVar.TypedValue);
            }
        }
Beispiel #4
0
 private static void FindLvtEntry(LocalVar lv, ClassFile.Method method, int instructionIndex)
 {
     ClassFile.Method.LocalVariableTableEntry[] lvt = method.LocalVariableTableAttribute;
     if (lvt != null)
     {
         int  pc      = method.Instructions[instructionIndex].PC;
         int  nextPC  = method.Instructions[instructionIndex + 1].PC;
         bool isStore = IsStoreLocal(method.Instructions[instructionIndex].NormalizedOpCode);
         foreach (ClassFile.Method.LocalVariableTableEntry e in lvt)
         {
             // TODO validate the contents of the LVT entry
             if (e.index == lv.local &&
                 (e.start_pc <= pc || (e.start_pc == nextPC && isStore)) &&
                 e.start_pc + e.length > pc)
             {
                 lv.name     = e.name;
                 lv.start_pc = e.start_pc;
                 lv.end_pc   = e.start_pc + e.length;
                 break;
             }
         }
     }
 }
Beispiel #5
0
    private static LocalVar MergeLocals(List <LocalVar> locals, Dictionary <long, LocalVar> localByStoreSite, LocalVar l1, LocalVar l2)
    {
        Debug.Assert(l1 != l2);
        Debug.Assert(l1.local == l2.local);
        for (int i = 0; i < locals.Count; i++)
        {
            if (locals[i] == l2)
            {
                locals.RemoveAt(i);
                i--;
            }
        }
        Dictionary <long, LocalVar> temp = new Dictionary <long, LocalVar>(localByStoreSite);

        localByStoreSite.Clear();
        foreach (KeyValuePair <long, LocalVar> kv in temp)
        {
            localByStoreSite[kv.Key] = kv.Value == l2 ? l1 : kv.Value;
        }
        l1.isArg |= l2.isArg;
        l1.type   = InstructionState.FindCommonBaseType(l1.type, l2.type);
        Debug.Assert(l1.type != VerifierTypeWrapper.Invalid);
        return(l1);
    }
Beispiel #6
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();
    }
Beispiel #7
0
    private static void VisitLocalLoads(CodeInfo codeInfo, ClassFile.Method method, List <LocalVar> locals, Dictionary <long, LocalVar> localByStoreSite, Dictionary <int, string> storeSites, int instructionIndex, bool debug)
    {
        Debug.Assert(IsLoadLocal(method.Instructions[instructionIndex].NormalizedOpCode));
        LocalVar    local      = null;
        TypeWrapper type       = VerifierTypeWrapper.Null;
        int         localIndex = method.Instructions[instructionIndex].NormalizedArg1;
        bool        isArg      = false;

        foreach (int store in storeSites.Keys)
        {
            if (store == -1)
            {
                // it's a method argument, it has no initial store, but the type is simply the parameter type
                type  = InstructionState.FindCommonBaseType(type, codeInfo.GetLocalTypeWrapper(0, localIndex));
                isArg = true;
            }
            else
            {
                if (method.Instructions[store].NormalizedOpCode == NormalizedByteCode.__invokespecial)
                {
                    type = InstructionState.FindCommonBaseType(type, codeInfo.GetLocalTypeWrapper(store + 1, localIndex));
                }
                else if (method.Instructions[store].NormalizedOpCode == NormalizedByteCode.__static_error)
                {
                    // it's an __invokespecial that turned into a __static_error
                    // (since a __static_error doesn't continue, we don't need to set type)
                }
                else
                {
                    Debug.Assert(IsStoreLocal(method.Instructions[store].NormalizedOpCode));
                    type = InstructionState.FindCommonBaseType(type, codeInfo.GetStackTypeWrapper(store, 0));
                }
            }
            // we can't have an invalid type, because that would have failed verification earlier
            Debug.Assert(type != VerifierTypeWrapper.Invalid);

            LocalVar l;
            if (localByStoreSite.TryGetValue(MakeKey(store, localIndex), out l))
            {
                if (local == null)
                {
                    local = l;
                }
                else if (local != l)
                {
                    // If we've already defined a LocalVar and we find another one, then we merge them
                    // together.
                    // This happens for the following code fragment:
                    //
                    // int i = -1;
                    // try { i = 0; for(; ; ) System.out.println(i); } catch(Exception x) {}
                    // try { i = 0; for(; ; ) System.out.println(i); } catch(Exception x) {}
                    // System.out.println(i);
                    //
                    local = MergeLocals(locals, localByStoreSite, local, l);
                }
            }
        }
        if (local == null)
        {
            local       = new LocalVar();
            local.local = localIndex;
            if (VerifierTypeWrapper.IsThis(type))
            {
                local.type = ((VerifierTypeWrapper)type).UnderlyingType;
            }
            else
            {
                local.type = type;
            }
            local.isArg = isArg;
            if (debug)
            {
                FindLvtEntry(local, method, instructionIndex);
            }
            locals.Add(local);
        }
        else
        {
            local.isArg |= isArg;
            local.type   = InstructionState.FindCommonBaseType(local.type, type);
            Debug.Assert(local.type != VerifierTypeWrapper.Invalid);
        }
        foreach (int store in storeSites.Keys)
        {
            LocalVar v;
            if (!localByStoreSite.TryGetValue(MakeKey(store, localIndex), out v))
            {
                localByStoreSite[MakeKey(store, localIndex)] = local;
            }
            else if (v != local)
            {
                local = MergeLocals(locals, localByStoreSite, local, v);
            }
        }
    }
Beispiel #8
0
 private LocalVar[] ReadLocalVars(Stream s)
 {
     int size = ReadInt(s);
     LocalVar[] vars = new LocalVar[size];
     for (int i = 0; i < size; ++i) {
         vars[i] = new LocalVar {
             Name = ReadString(s),
             StartPc = ReadUInt(s),
             EndPc = ReadUInt(s),
         };
     }
     return vars;
 }
Beispiel #9
0
	private static LocalVar MergeLocals(List<LocalVar> locals, Dictionary<long, LocalVar> localByStoreSite, LocalVar l1, LocalVar l2)
	{
		Debug.Assert(l1 != l2);
		Debug.Assert(l1.local == l2.local);
		for (int i = 0; i < locals.Count; i++)
		{
			if (locals[i] == l2)
			{
				locals.RemoveAt(i);
				i--;
			}
		}
		Dictionary<long, LocalVar> temp = new Dictionary<long, LocalVar>(localByStoreSite);
		localByStoreSite.Clear();
		foreach (KeyValuePair<long, LocalVar> kv in temp)
		{
			localByStoreSite[kv.Key] = kv.Value == l2 ? l1 : kv.Value;
		}
		l1.isArg |= l2.isArg;
		l1.type = InstructionState.FindCommonBaseType(l1.type, l2.type);
		Debug.Assert(l1.type != VerifierTypeWrapper.Invalid);
		return l1;
	}
Beispiel #10
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();
	}
Beispiel #11
0
	private static void VisitLocalLoads(CodeInfo codeInfo, ClassFile.Method method, List<LocalVar> locals, Dictionary<long, LocalVar> localByStoreSite, Dictionary<int, string> storeSites, int instructionIndex, bool debug)
	{
		Debug.Assert(IsLoadLocal(method.Instructions[instructionIndex].NormalizedOpCode));
		LocalVar local = null;
		TypeWrapper type = VerifierTypeWrapper.Null;
		int localIndex = method.Instructions[instructionIndex].NormalizedArg1;
		bool isArg = false;
		foreach (int store in storeSites.Keys)
		{
			if (store == -1)
			{
				// it's a method argument, it has no initial store, but the type is simply the parameter type
				type = InstructionState.FindCommonBaseType(type, codeInfo.GetLocalTypeWrapper(0, localIndex));
				isArg = true;
			}
			else
			{
				if (method.Instructions[store].NormalizedOpCode == NormalizedByteCode.__invokespecial)
				{
					type = InstructionState.FindCommonBaseType(type, codeInfo.GetLocalTypeWrapper(store + 1, localIndex));
				}
				else if (method.Instructions[store].NormalizedOpCode == NormalizedByteCode.__static_error)
				{
					// it's an __invokespecial that turned into a __static_error
					// (since a __static_error doesn't continue, we don't need to set type)
				}
				else
				{
					Debug.Assert(IsStoreLocal(method.Instructions[store].NormalizedOpCode));
					type = InstructionState.FindCommonBaseType(type, codeInfo.GetStackTypeWrapper(store, 0));
				}
			}
			// we can't have an invalid type, because that would have failed verification earlier
			Debug.Assert(type != VerifierTypeWrapper.Invalid);

			LocalVar l;
			if (localByStoreSite.TryGetValue(MakeKey(store, localIndex), out l))
			{
				if (local == null)
				{
					local = l;
				}
				else if (local != l)
				{
					// If we've already defined a LocalVar and we find another one, then we merge them
					// together.
					// This happens for the following code fragment:
					//
					// int i = -1;
					// try { i = 0; for(; ; ) System.out.println(i); } catch(Exception x) {}
					// try { i = 0; for(; ; ) System.out.println(i); } catch(Exception x) {}
					// System.out.println(i);
					//
					local = MergeLocals(locals, localByStoreSite, local, l);
				}
			}
		}
		if (local == null)
		{
			local = new LocalVar();
			local.local = localIndex;
			if (VerifierTypeWrapper.IsThis(type))
			{
				local.type = ((VerifierTypeWrapper)type).UnderlyingType;
			}
			else
			{
				local.type = type;
			}
			local.isArg = isArg;
			if (debug)
			{
				FindLvtEntry(local, method, instructionIndex);
			}
			locals.Add(local);
		}
		else
		{
			local.isArg |= isArg;
			local.type = InstructionState.FindCommonBaseType(local.type, type);
			Debug.Assert(local.type != VerifierTypeWrapper.Invalid);
		}
		foreach (int store in storeSites.Keys)
		{
			LocalVar v;
			if (!localByStoreSite.TryGetValue(MakeKey(store, localIndex), out v))
			{
				localByStoreSite[MakeKey(store, localIndex)] = local;
			}
			else if (v != local)
			{
				local = MergeLocals(locals, localByStoreSite, local, v);
			}
		}
	}
Beispiel #12
0
	private static void FindLvtEntry(LocalVar lv, ClassFile.Method method, int instructionIndex)
	{
		ClassFile.Method.LocalVariableTableEntry[] lvt = method.LocalVariableTableAttribute;
		if (lvt != null)
		{
			int pc = method.Instructions[instructionIndex].PC;
			int nextPC = method.Instructions[instructionIndex + 1].PC;
			bool isStore = IsStoreLocal(method.Instructions[instructionIndex].NormalizedOpCode);
			foreach (ClassFile.Method.LocalVariableTableEntry e in lvt)
			{
				// TODO validate the contents of the LVT entry
				if (e.index == lv.local &&
					(e.start_pc <= pc || (e.start_pc == nextPC && isStore)) &&
					e.start_pc + e.length > pc)
				{
					lv.name = e.name;
					lv.start_pc = e.start_pc;
					lv.end_pc = e.start_pc + e.length;
					break;
				}
			}
		}
	}
Beispiel #13
0
        private static void HandleVariables()
        {
            Token[] smt=ts.PeekNextStatement();
            SubRecord slsd;
            SubRecord scvr;
            while(smt.Length>0&&smt[0].IsType()) {
                ts.PopNextStatement();
                if(smt.Length!=2||smt[1].type!=TokenType.Unknown) {
                    AddError("Expected <type> <variable name>");
                    smt=ts.PeekNextStatement();
                    continue;
                }
                slsd=new SubRecord();
                slsd.Name="SLSD";
                byte[] data=new byte[24];
                TypeConverter.si2h(locals.Count+1, data, 0);
                if(smt[0].IsKeyword(Keywords.Int)) data[16]=1;
                slsd.SetData(data);
                r.AddRecord(slsd);
                scvr=new SubRecord();
                scvr.Name="SCVR";
                scvr.SetStrData(smt[1].utoken, true);
                r.AddRecord(scvr);

                LocalVar lv=new LocalVar(locals.Count+1, smt[0]);
                locals.Add(smt[1].token, lv);
                localList.Add(lv);
                ts.AddLocal(smt[1].token);

                smt=ts.PeekNextStatement();
            }
        }
Beispiel #14
0
 public EnumInfo(FieldInfo cur, FieldInfo sta, LocalVar localSta = null)
 {
     Current    = cur;
     State      = sta;
     localState = localSta;
 }