public StringLiteralDictionary(ReferenceResolver resolver) { m_dict = new Dictionary <string, FieldReference>(); m_resolver = resolver; m_usedNames = new HashSet <string>(); m_typedef = new TypeDefinition("", ARRAY_CLASS_NAME, TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Abstract /*static*/); // make sure other parts of the system don't get confused m_resolver.GetTypeReference(typeof(ESharp.EObject)).Module.Types.Add(m_typedef); }
public void TransformIL(IEnumerable <TypeDefinition> types) { m_resolver = new ReferenceResolver(types); var mod = ModuleDefinition.CreateModule("t", ModuleKind.Dll); foreach (var t in types) { foreach (var m in t.Methods) { if (!m.HasBody) { continue; } var exceptionVariable = new VariableDefinition(m_resolver.GetTypeReference(typeof(EException))); m.Body.Variables.Add(exceptionVariable); var ilp = m.Body.GetILProcessor(); var insts = m.Body.Instructions; for (int idx = 0; idx < m.Body.Instructions.Count; idx++) { var i = m.Body.Instructions[idx]; var next = i.Next; //store thrown exceptions in variable, this is how the rest of this function expects it if (i.OpCode == OpCodes.Throw) { ilp.InsertBefore(i, ilp.Create(OpCodes.Stloc, exceptionVariable)); idx++; } } RethrowCallException(m, exceptionVariable); // remember that this method might throw. // todo, base this on the outcome of this routine?? if (m_helper.CanThrow(m)) { m.CustomAttributes.Add(new CustomAttribute(mod.ImportReference(typeof(Throws).GetConstructor(new Type[] { })), new byte[] { 1, 0, 0, 0 })); } if (m.Body.Instructions.Any(x => x.OpCode == OpCodes.Throw)) { AddUncaugtCatch(m, exceptionVariable); } foreach (var handlerGroup in m.Body.ExceptionHandlers.GroupBy(x => Tuple.Create(x.TryStart, x.TryEnd)).ToArray()) //x.TryStart.Offset << 16 + x.TryEnd.Offset // todo support multiple catch handlers { var catchHandler = handlerGroup.SingleOrDefault(x => x.HandlerType == ExceptionHandlerType.Catch); var finallyHandler = handlerGroup.SingleOrDefault(x => x.HandlerType == ExceptionHandlerType.Finally); if (catchHandler != null) // catch handler { ReplaceCatch(ilp, catchHandler, exceptionVariable); // remove old catch var block = insts.SkipWhile(x => x != catchHandler.HandlerStart).TakeWhile(x => x != catchHandler.HandlerEnd).ToArray(); foreach (var bi in block) { ilp.Remove(bi); } m.Body.ExceptionHandlers.Remove(catchHandler); // todo remove handler } //{ // finally handler //} } Debug.Assert(!m.Body.Instructions.Any(x => x.OpCode == OpCodes.Throw), "No throw insturction should be remaining"); Debug.Assert(!m.Body.HasExceptionHandlers, "No Exception Handlers should be remaining"); } } }
// This logic will catch uncaught exceptions when leaving a function public void AddUncaugtCatch(MethodDefinition m, VariableDefinition excpetionVariable) { if (!m.HasBody || m.Body.Instructions.Count == 0) { return; } var insts = m.Body.Instructions; var ilp = m.Body.GetILProcessor(); var retType = m.ReturnType.Resolve(); var useRetType = retType.Name != "Void"; var catchLabel = ilp.Create(OpCodes.Nop); var retunLabel = ilp.Create(OpCodes.Nop); if (!insts.Any(x => x.OpCode == OpCodes.Ret)) { // no ret, eg because the function throws; need dummy ret if (retType.Name != "Void") { if (retType.IsValueType) { var variable = new VariableDefinition(retType); m.Body.Variables.Add(variable); ilp.Emit(OpCodes.Ldloca, variable); ilp.Emit(OpCodes.Initobj, retType); ilp.Emit(OpCodes.Ldloc, variable); } else { ilp.Emit(OpCodes.Ldnull); } } ilp.Emit(OpCodes.Ret); } var old_ret = insts.Last(); Debug.Assert(old_ret.OpCode == OpCodes.Ret, "Ret instruction expected at the end of each function"); // No need for leave here as stack is always correct. // Actually don't use leave as a return code might be on the stack. ilp.InsertBefore(old_ret, ilp.Create(OpCodes.Br, retunLabel)); ilp.InsertBefore(old_ret, catchLabel); ilp.InsertBefore(old_ret, retunLabel); // create catch block (store exception, exception should be on the top of the stack) var fieldref = m_resolver.GetField("ESharp.EException", "S_EException_LastException"); ilp.InsertBefore(retunLabel, ilp.Create(OpCodes.Stsfld, fieldref)); // load default return value if (useRetType) { if (retType.IsValueType) { var variable = new VariableDefinition(retType); m.Body.Variables.Add(variable); ilp.InsertBefore(retunLabel, ilp.Create(OpCodes.Ldloca, variable)); ilp.InsertBefore(retunLabel, ilp.Create(OpCodes.Initobj, retType)); ilp.InsertBefore(retunLabel, ilp.Create(OpCodes.Ldloc, variable)); } else { ilp.InsertBefore(retunLabel, ilp.Create(OpCodes.Ldnull)); } // fall through to return label } var handler = new ExceptionHandler(ExceptionHandlerType.Catch) { TryStart = insts.First(), TryEnd = catchLabel, HandlerStart = catchLabel, HandlerEnd = retunLabel, CatchType = m_resolver.GetTypeReference("EException") }; m.Body.ExceptionHandlers.Add(handler); }
public FieldReference AddArray_1(byte[] data) { return(AddGeneric("array" + m_counter++, m_resolver.GetTypeReference("Array_1"), "Array_1", data.Cast <object>())); }