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); } } }
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); } } }
private static Dictionary <int, string>[] FindLocalVariablesImpl(CodeInfo codeInfo, ClassFile classFile, ClassFile.Method method, FindLocalVarState[] state) { ClassFile.Method.Instruction[] instructions = method.Instructions; ExceptionTableEntry[] exceptions = method.ExceptionTable; int maxLocals = method.MaxLocals; Dictionary <int, string>[] localStoreReaders = new Dictionary <int, string> [instructions.Length]; bool done = false; while (!done) { done = true; for (int i = 0; i < instructions.Length; i++) { if (state[i].changed) { done = false; state[i].changed = false; FindLocalVarState curr = state[i].Copy(); for (int j = 0; j < exceptions.Length; j++) { if (exceptions[j].startIndex <= i && i < exceptions[j].endIndex) { state[exceptions[j].handlerIndex].Merge(curr); } } if (IsLoadLocal(instructions[i].NormalizedOpCode) && (instructions[i].NormalizedOpCode != NormalizedByteCode.__aload || !VerifierTypeWrapper.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(i + 1, 0)))) { if (localStoreReaders[i] == null) { localStoreReaders[i] = new Dictionary <int, string>(); } for (int j = 0; j < curr.sites[instructions[i].NormalizedArg1].Count; j++) { localStoreReaders[i][curr.sites[instructions[i].NormalizedArg1][j]] = ""; } } if (IsStoreLocal(instructions[i].NormalizedOpCode) && (instructions[i].NormalizedOpCode != NormalizedByteCode.__astore || !VerifierTypeWrapper.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(i, 0)))) { curr.Store(i, instructions[i].NormalizedArg1); // if this is a store at the end of an exception block, // we need to propagate the new state to the exception handler for (int j = 0; j < exceptions.Length; j++) { if (exceptions[j].endIndex == i + 1) { state[exceptions[j].handlerIndex].Merge(curr); } } } if (instructions[i].NormalizedOpCode == NormalizedByteCode.__invokespecial) { ClassFile.ConstantPoolItemMI cpi = classFile.GetMethodref(instructions[i].Arg1); if (ReferenceEquals(cpi.Name, StringConstants.INIT)) { TypeWrapper type = codeInfo.GetRawStackTypeWrapper(i, cpi.GetArgTypes().Length); // after we've invoked the constructor, the uninitialized references // are now initialized if (type == VerifierTypeWrapper.UninitializedThis || VerifierTypeWrapper.IsNew(type)) { for (int j = 0; j < maxLocals; j++) { if (codeInfo.GetLocalTypeWrapper(i, j) == type) { curr.Store(i, j); } } } } } else if (instructions[i].NormalizedOpCode == NormalizedByteCode.__goto_finally) { int handler = instructions[i].HandlerIndex; // Normally a store at the end of a try block doesn't affect the handler block, // but in the case of a finally handler it does, so we need to make sure that // we merge here in case the try block ended with a store. state[handler].Merge(curr); // Now we recursively analyse the handler and afterwards merge the endfault locations back to us FindLocalVarState[] handlerState = new FindLocalVarState[instructions.Length]; handlerState[handler].Merge(curr); curr = new FindLocalVarState(); FindLocalVariablesImpl(codeInfo, classFile, method, handlerState); // Merge back to the target of our __goto_finally for (int j = 0; j < handlerState.Length; j++) { if (instructions[j].NormalizedOpCode == NormalizedByteCode.__athrow && codeInfo.HasState(j) && VerifierTypeWrapper.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(j, 0)) && ((VerifierTypeWrapper)codeInfo.GetRawStackTypeWrapper(j, 0)).Index == handler) { curr.Merge(handlerState[j]); } } } switch (ByteCodeMetaData.GetFlowControl(instructions[i].NormalizedOpCode)) { case ByteCodeFlowControl.Switch: { for (int j = 0; j < instructions[i].SwitchEntryCount; j++) { state[instructions[i].GetSwitchTargetIndex(j)].Merge(curr); } state[instructions[i].DefaultTarget].Merge(curr); break; } case ByteCodeFlowControl.Branch: state[instructions[i].TargetIndex].Merge(curr); break; case ByteCodeFlowControl.CondBranch: state[instructions[i].TargetIndex].Merge(curr); state[i + 1].Merge(curr); break; case ByteCodeFlowControl.Return: case ByteCodeFlowControl.Throw: break; case ByteCodeFlowControl.Next: state[i + 1].Merge(curr); break; default: throw new InvalidOperationException(); } } } } return(localStoreReaders); }
private static Dictionary<int, string>[] FindLocalVariablesImpl(CodeInfo codeInfo, ClassFile classFile, ClassFile.Method method, FindLocalVarState[] state) { ClassFile.Method.Instruction[] instructions = method.Instructions; ExceptionTableEntry[] exceptions = method.ExceptionTable; int maxLocals = method.MaxLocals; Dictionary<int, string>[] localStoreReaders = new Dictionary<int, string>[instructions.Length]; bool done = false; while (!done) { done = true; for (int i = 0; i < instructions.Length; i++) { if (state[i].changed) { done = false; state[i].changed = false; FindLocalVarState curr = state[i].Copy(); for (int j = 0; j < exceptions.Length; j++) { if (exceptions[j].startIndex <= i && i < exceptions[j].endIndex) { state[exceptions[j].handlerIndex].Merge(curr); } } if (IsLoadLocal(instructions[i].NormalizedOpCode) && (instructions[i].NormalizedOpCode != NormalizedByteCode.__aload || !VerifierTypeWrapper.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(i + 1, 0)))) { if (localStoreReaders[i] == null) { localStoreReaders[i] = new Dictionary<int, string>(); } for (int j = 0; j < curr.sites[instructions[i].NormalizedArg1].Count; j++) { localStoreReaders[i][curr.sites[instructions[i].NormalizedArg1][j]] = ""; } } if (IsStoreLocal(instructions[i].NormalizedOpCode) && (instructions[i].NormalizedOpCode != NormalizedByteCode.__astore || !VerifierTypeWrapper.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(i, 0)))) { curr.Store(i, instructions[i].NormalizedArg1); // if this is a store at the end of an exception block, // we need to propagate the new state to the exception handler for (int j = 0; j < exceptions.Length; j++) { if (exceptions[j].endIndex == i + 1) { state[exceptions[j].handlerIndex].Merge(curr); } } } if (instructions[i].NormalizedOpCode == NormalizedByteCode.__invokespecial) { ClassFile.ConstantPoolItemMI cpi = classFile.GetMethodref(instructions[i].Arg1); if (ReferenceEquals(cpi.Name, StringConstants.INIT)) { TypeWrapper type = codeInfo.GetRawStackTypeWrapper(i, cpi.GetArgTypes().Length); // after we've invoked the constructor, the uninitialized references // are now initialized if (type == VerifierTypeWrapper.UninitializedThis || VerifierTypeWrapper.IsNew(type)) { for (int j = 0; j < maxLocals; j++) { if (codeInfo.GetLocalTypeWrapper(i, j) == type) { curr.Store(i, j); } } } } } else if (instructions[i].NormalizedOpCode == NormalizedByteCode.__goto_finally) { int handler = instructions[i].HandlerIndex; // Normally a store at the end of a try block doesn't affect the handler block, // but in the case of a finally handler it does, so we need to make sure that // we merge here in case the try block ended with a store. state[handler].Merge(curr); // Now we recursively analyse the handler and afterwards merge the endfault locations back to us FindLocalVarState[] handlerState = new FindLocalVarState[instructions.Length]; handlerState[handler].Merge(curr); curr = new FindLocalVarState(); FindLocalVariablesImpl(codeInfo, classFile, method, handlerState); // Merge back to the target of our __goto_finally for (int j = 0; j < handlerState.Length; j++) { if (instructions[j].NormalizedOpCode == NormalizedByteCode.__athrow && codeInfo.HasState(j) && VerifierTypeWrapper.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(j, 0)) && ((VerifierTypeWrapper)codeInfo.GetRawStackTypeWrapper(j, 0)).Index == handler) { curr.Merge(handlerState[j]); } } } switch (ByteCodeMetaData.GetFlowControl(instructions[i].NormalizedOpCode)) { case ByteCodeFlowControl.Switch: { for (int j = 0; j < instructions[i].SwitchEntryCount; j++) { state[instructions[i].GetSwitchTargetIndex(j)].Merge(curr); } state[instructions[i].DefaultTarget].Merge(curr); break; } case ByteCodeFlowControl.Branch: state[instructions[i].TargetIndex].Merge(curr); break; case ByteCodeFlowControl.CondBranch: state[instructions[i].TargetIndex].Merge(curr); state[i + 1].Merge(curr); break; case ByteCodeFlowControl.Return: case ByteCodeFlowControl.Throw: break; case ByteCodeFlowControl.Next: state[i + 1].Merge(curr); break; default: throw new InvalidOperationException(); } } } } return localStoreReaders; }