private Emit <DelegateType> EmitFrom(int from, int length, string name = null, ModuleBuilder module = null) { if (from < 0 || from > Operations.Count) { throw new InvalidOperationException("from must be between 0 and " + Operations.Count + ", inclusive; found " + from); } if (length < 0) { throw new InvalidOperationException("length must be non-negative; found " + length); } if (from + length > Operations.Count) { throw new InvalidOperationException("from + length must be less than " + Operations.Count + "; found " + (from + length)); } var e1 = Emit <DelegateType> .DisassemblerDynamicMethod( LinqAlternative.Select(Parameters, p => p.ParameterType).ToArray(), name, module ); for (var i = 0; i < length; i++) { Apply(from + i, e1); } return(e1); }
/// <summary> /// Pops parameterTypes.Length arguments from the stack, invokes the constructor on the given type that matches parameterTypes, and pushes a reference to the new object onto the stack. /// </summary> public Emit <DelegateType> NewObject(Type type, params Type[] parameterTypes) { if (type == null) { throw new ArgumentNullException("type"); } if (parameterTypes == null) { throw new ArgumentNullException("parameterTypes"); } var allCons = type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance); var cons = LinqAlternative .Where( allCons, c => c.GetParameters().Length == parameterTypes.Length && LinqAlternative.Select(c.GetParameters(), (p, i) => p.ParameterType == parameterTypes[i]).Aggregate(true, (a, b) => a && b) ).SingleOrDefault(); if (cons == null) { throw new InvalidOperationException("Type " + type + " must have a constructor that matches parameters [" + BufferedILGenerator <DelegateType> .Join(", ", ((LinqArray <Type>)parameterTypes).AsEnumerable()) + "]"); } return(NewObject(cons)); }
/// <summary> /// <para>Pops a value off the stack and branches to the label at the index of that value in the given labels.</para> /// <para>If the value is out of range, execution falls through to the next instruction.</para> /// </summary> public Emit <DelegateType> Switch(params Label[] labels) { if (labels == null) { throw new ArgumentNullException("labels"); } if (labels.Length == 0) { throw new ArgumentException("labels must have at least one element"); } if (LinqAlternative.Any(labels, l => ((IOwned)l).Owner is DisassembledOperations <DelegateType>)) { return (Switch(LinqAlternative.Select(labels, l => l.Name).ToArray())); } foreach (var label in labels) { if (((IOwned)label).Owner != this) { FailOwnership(label); } } foreach (var label in labels) { UnusedLabels.Remove(label); } var transitions = new[] { new StackTransition(new [] { typeof(int) }, TypeHelpers.EmptyTypes), new StackTransition(new [] { typeof(NativeIntType) }, TypeHelpers.EmptyTypes), }; var labelsCopy = ((LinqArray <Label>)labels).Select(l => l).ToArray(); UpdateOpCodeDelegate update; UpdateState(OpCodes.Switch, labelsCopy, Wrap(transitions, "Switch"), out update); var valid = CurrentVerifiers.ConditionalBranch(labels); if (!valid.Success) { throw new SigilVerificationException("Switch", valid, IL.Instructions(AllLocals)); } foreach (var label in labels) { Branches.Add(SigilTuple.Create(OpCodes.Switch, label, IL.Index)); BranchPatches[IL.Index] = SigilTuple.Create(label, update, OpCodes.Switch); } return(this); }
/// <summary> /// Returns a string representation of this OperationResultUsage. /// </summary> public override string ToString() { var users = string.Join(", ", LinqAlternative.Select(ResultUsedBy, r => r.ToString()).OrderBy(_ => _).ToArray()); if (users.Length == 0) { return("(" + ProducesResult + ") result is unused"); } return("(" + ProducesResult + ") result is used by (" + users + ")"); }
/// <summary> /// Pops an object reference off the stack, and pushes a pointer to the given method's implementation on that object. /// /// For static or non-virtual functions, use LoadFunctionPointer /// </summary> public Emit <DelegateType> LoadVirtualFunctionPointer(MethodInfo method) { if (method == null) { throw new ArgumentNullException("method"); } if (method.IsStatic) { throw new ArgumentException("Only non-static methods can be passed to LoadVirtualFunctionPointer, found " + method); } var thisType = HasFlag(method.CallingConvention, CallingConventions.HasThis) ? method.DeclaringType : null; var parameters = method.GetParameters(); var paramList = LinqAlternative.Select(parameters, p => p.ParameterType).ToList(); var declaring = method.DeclaringType; if (TypeHelpers.IsValueType(declaring)) { declaring = declaring.MakePointerType(); } paramList.Insert(0, declaring); var type = TypeOnStack.GetKnownFunctionPointer( method.CallingConvention, thisType, method.ReturnType, paramList.ToArray() ); var transitions = new[] { new StackTransition(new [] { declaring }, new [] { typeof(NativeIntType) }) }; UpdateState(OpCodes.Ldvirtftn, method, LinqAlternative.Select(parameters, p => p.ParameterType).AsEnumerable(), Wrap(transitions, "LoadVirtualFunctionPointer")); return(this); }
/// <summary> /// Pops an object reference off the stack, and pushes a pointer to the given method's implementation on that object. /// /// For static or non-virtual functions, use LoadFunctionPointer /// </summary> public Emit <DelegateType> LoadVirtualFunctionPointer(MethodInfo method) { if (method == null) { throw new ArgumentNullException("method"); } if (method.IsStatic) { throw new ArgumentException("Only non-static methods can be passed to LoadVirtualFunctionPointer, found " + method); } var parameters = method.GetParameters(); var paramList = LinqAlternative.Select(parameters, p => p.ParameterType).ToArray(); return(InnerLoadVirtualFunctionPointer(method, paramList)); }
/// <summary> /// Creates a new Emit, suitable for building a constructor on the given TypeBuilder. /// /// The DelegateType and TypeBuilder must agree on parameter types and parameter counts. /// /// If you intend to use unveriable code, you must set allowUnverifiableCode to true. /// /// If doVerify is false (default is true) Sigil will *not* throw an exception on invalid IL. This is faster, but the benefits /// of Sigil are reduced to "a nicer ILGenerator interface". /// /// If strictBranchValidation is true (default is false) Sigil will enforce "Backward branch constraints" which are *technically* required /// for valid CIL, but in practice often ignored. The most common case to set this option is if you are generating types to write to disk. /// </summary> public static Emit <DelegateType> BuildConstructor(TypeBuilder type, MethodAttributes attributes, CallingConventions callingConvention = CallingConventions.HasThis, bool allowUnverifiableCode = false, bool doVerify = true, bool strictBranchVerification = false) { if (type == null) { throw new ArgumentNullException("type"); } CheckAttributesAndConventions(attributes, callingConvention); if (!HasFlag(callingConvention, CallingConventions.HasThis)) { throw new ArgumentException("Constructors always have a this reference"); } ValidateNewParameters <DelegateType>(); var delType = typeof(DelegateType); var invoke = delType.GetMethod("Invoke"); var returnType = invoke.ReturnType; var parameterTypes = LinqAlternative.Select(invoke.GetParameters(), s => s.ParameterType).ToArray(); if (returnType != typeof(void)) { throw new ArgumentException("DelegateType used must return void"); } var constructorBuilder = type.DefineConstructor(attributes, callingConvention, parameterTypes); // Constructors always have a `this` var pList = new List <Type>(parameterTypes); pList.Insert(0, TypeHelpers.AsType(type)); parameterTypes = pList.ToArray(); var ret = new Emit <DelegateType>(callingConvention, typeof(void), parameterTypes, allowUnverifiableCode, doVerify, strictBranchVerification) { ConstrBuilder = constructorBuilder, IsBuildingConstructor = true }; return(ret); }
internal static Emit <DelegateType> DisassemblerDynamicMethod(Type[] parameters = null, string name = null, ModuleBuilder module = null, bool doVerify = true, bool strictBranchVerification = false) { module = module ?? Module; name = name ?? AutoNamer.Next("_DynamicMethod"); ValidateNewParameters <DelegateType>(); var delType = typeof(DelegateType); var invoke = delType.GetMethod("Invoke"); var returnType = invoke.ReturnType; var parameterTypes = parameters ?? LinqAlternative.Select(invoke.GetParameters(), s => s.ParameterType).ToArray(); var dynMethod = new DynamicMethod(name, returnType, parameterTypes, module, skipVisibility: true); var ret = new Emit <DelegateType>(dynMethod.CallingConvention, returnType, parameterTypes, AllowsUnverifiableCode(module), doVerify, strictBranchVerification); ret.DynMethod = dynMethod; return(ret); }
/// <summary> /// <para>Calls the given method virtually. Pops its arguments in reverse order (left-most deepest in the stack), and pushes the return value if it is non-void.</para> /// <para>The `this` reference should appear before any arguments (deepest in the stack).</para> /// <para>The method invoked at runtime is determined by the type of the `this` reference.</para> /// <para>If the method invoked shouldn't vary (or if the method is static), use Call instead.</para> /// </summary> public Emit <DelegateType> CallVirtual(MethodInfo method, Type constrained = null, Type[] arglist = null) { if (method == null) { throw new ArgumentNullException("method"); } if (method.IsStatic) { throw new ArgumentException("Only non-static methods can be called using CallVirtual, found " + method); } if (HasFlag(method.CallingConvention, CallingConventions.VarArgs) && !HasFlag(method.CallingConvention, CallingConventions.Standard)) { if (arglist == null) { throw new InvalidOperationException("When calling a VarArgs method, arglist must be set"); } } var expectedParams = ((LinqArray <ParameterInfo>)method.GetParameters()).Select(s => TypeOnStack.Get(s.ParameterType)).ToList(); var declaring = method.DeclaringType; if (TypeHelpers.IsValueType(declaring)) { declaring = declaring.MakePointerType(); } // "this" parameter expectedParams.Insert(0, TypeOnStack.Get(declaring)); if (arglist != null) { expectedParams.AddRange(LinqAlternative.Select(arglist, t => TypeOnStack.Get(t))); } var resultType = method.ReturnType == typeof(void) ? null : TypeOnStack.Get(method.ReturnType); // Shove the constrained prefix in if it's supplied if (constrained != null) { UpdateState(OpCodes.Constrained, constrained, Wrap(StackTransition.None(), "CallVirtual")); } IEnumerable <StackTransition> transitions; if (resultType != null) { transitions = new[] { new StackTransition(expectedParams.Reverse().AsEnumerable(), new [] { resultType }) }; } else { transitions = new[] { new StackTransition(expectedParams.Reverse().AsEnumerable(), new TypeOnStack[0]) }; } UpdateState(OpCodes.Callvirt, method, ((LinqArray <ParameterInfo>)method.GetParameters()).Select(s => s.ParameterType).AsEnumerable(), Wrap(transitions, "CallVirtual"), arglist: arglist); return(this); }
/// <summary> /// A string representation of this Operation. /// </summary> public override string ToString() { if (IsExceptionBlockStart) { return("--Start Exception Block--"); } if (IsExceptionBlockEnd) { return("--End Exception Block--"); } if (IsCatchBlockStart) { return("--Start Catch Block--"); } if (IsCatchBlockEnd) { return("--End Catch Block--"); } if (IsFinallyBlockStart) { return("--Start Finally Block--"); } if (IsFinallyBlockEnd) { return("--End Finally Block--"); } if (IsMarkLabel) { return("--Mark Label " + LabelName + "--"); } var ps = string.Join( ", ", LinqAlternative.Select( Parameters, o => { if (o == null) { return("(null)"); } return(o.ToString()); } ).ToArray() ); if (ps.Length == 0) { return(OpCode.ToString()); } return(OpCode + " " + ps); }