public void EmitToVariable(EmitContext ec) { var type = Expr.Type; if (IsByRef) { var ml = (IMemoryLocation)Expr; ml.AddressOf(ec, AddressOp.LoadStore); type = ReferenceContainer.MakeType(ec.Module, type); } else { Expr.Emit(ec); } variable = new LocalTemporary(type); variable.Store(ec); Expr = variable; }
public void EmitLoad(EmitContext ec, bool boxInstance) { var instance_type = instance.Type; // // Push the instance expression // if (addressRequired) { // // If the expression implements IMemoryLocation, then // we can optimize and use AddressOf on the // return. // // If not we have to use some temporary storage for // it. var iml = instance as IMemoryLocation; if (iml != null) { iml.AddressOf(ec, AddressOp.Load); } else { LocalTemporary temp = new LocalTemporary(instance_type); instance.Emit(ec); temp.Store(ec); temp.AddressOf(ec, AddressOp.Load); } return; } instance.Emit(ec); // Only to make verifier happy if (boxInstance && RequiresBoxing()) { ec.Emit(OpCodes.Box, instance_type); } }
public void EmitPredefined(EmitContext ec, MethodSpec method, Arguments Arguments, bool statement = false, Location?loc = null) { Expression instance_copy = null; if (!HasAwaitArguments && ec.HasSet(BuilderContext.Options.AsyncBody)) { HasAwaitArguments = Arguments != null && Arguments.ContainsEmitWithAwait(); if (HasAwaitArguments && InstanceExpressionOnStack) { throw new NotSupportedException(); } } OpCode call_op; LocalTemporary lt = null; if (method.IsStatic) { call_op = OpCodes.Call; } else { call_op = IsVirtualCallRequired(InstanceExpression, method) ? OpCodes.Callvirt : OpCodes.Call; if (HasAwaitArguments) { instance_copy = InstanceExpression.EmitToField(ec); var ie = new InstanceEmitter(instance_copy, IsAddressCall(instance_copy, call_op, method.DeclaringType)); if (Arguments == null) { ie.EmitLoad(ec, true); } } else if (!InstanceExpressionOnStack) { var ie = new InstanceEmitter(InstanceExpression, IsAddressCall(InstanceExpression, call_op, method.DeclaringType)); ie.Emit(ec, ConditionalAccess); if (DuplicateArguments) { ec.Emit(OpCodes.Dup); if (Arguments != null && Arguments.Count != 0) { lt = new LocalTemporary(ie.GetStackType(ec)); lt.Store(ec); instance_copy = lt; } } } } if (Arguments != null && !InstanceExpressionOnStack) { EmittedArguments = Arguments.Emit(ec, DuplicateArguments, HasAwaitArguments); if (EmittedArguments != null) { if (instance_copy != null) { var ie = new InstanceEmitter(instance_copy, IsAddressCall(instance_copy, call_op, method.DeclaringType)); ie.Emit(ec, ConditionalAccess); if (lt != null) { lt.Release(ec); } } EmittedArguments.Emit(ec); } } if (call_op == OpCodes.Callvirt && (InstanceExpression.Type.IsGenericParameter || InstanceExpression.Type.IsStructOrEnum)) { ec.Emit(OpCodes.Constrained, InstanceExpression.Type); } if (loc != null) { // // Emit explicit sequence point for expressions like Foo.Bar () to help debugger to // break at right place when LHS expression can be stepped-into // ec.MarkCallEntry(loc.Value); } // // Set instance expression to actual result expression. When it contains await it can be // picked up by caller // InstanceExpression = instance_copy; if (method.Parameters.HasArglist) { var varargs_types = GetVarargsTypes(method, Arguments); ec.Emit(call_op, method, varargs_types); } else { // // If you have: // this.DoFoo (); // and DoFoo is not virtual, you can omit the callvirt, // because you don't need the null checking behavior. // ec.Emit(call_op, method); } // // Pop the return value if there is one and stack should be empty // if (statement && method.ReturnType.Kind != MemberKind.Void) { ec.Emit(OpCodes.Pop); } }
// // if `dup_args' is true or any of arguments contains await. // A copy of all arguments will be returned to the caller // public virtual Arguments Emit (EmitContext ec, bool dup_args, bool prepareAwait) { List<Argument> dups; if ((dup_args && Count != 0) || prepareAwait) dups = new List<Argument> (Count); else dups = null; LocalTemporary lt; foreach (Argument a in args) { if (prepareAwait) { dups.Add (a.EmitToField (ec, true)); continue; } a.Emit (ec); if (!dup_args) { continue; } if (a.Expr.IsSideEffectFree) { // // No need to create a temporary variable for side effect free expressions. I assume // all side-effect free expressions are cheap, this has to be tweaked when we become // more aggressive on detection // dups.Add (a); } else { ec.Emit (OpCodes.Dup); // TODO: Release local temporary on next Emit // Need to add a flag to argument to indicate this lt = new LocalTemporary (a.Type); lt.Store (ec); dups.Add (new Argument (lt, a.ArgType)); } } if (dups != null) return new Arguments (dups); return null; }
public void EmitToVariable (EmitContext ec) { var type = Expr.Type; if (IsByRef) { var ml = (IMemoryLocation) Expr; ml.AddressOf (ec, AddressOp.LoadStore); type = ReferenceContainer.MakeType (ec.Module, type); } else { Expr.Emit (ec); } variable = new LocalTemporary (type); variable.Store (ec); Expr = variable; }
public void EmitLoad (EmitContext ec, bool boxInstance) { var instance_type = instance.Type; // // Push the instance expression // if (addressRequired) { // // If the expression implements IMemoryLocation, then // we can optimize and use AddressOf on the // return. // // If not we have to use some temporary storage for // it. var iml = instance as IMemoryLocation; if (iml != null) { iml.AddressOf (ec, AddressOp.Load); } else { LocalTemporary temp = new LocalTemporary (instance_type); instance.Emit (ec); temp.Store (ec); temp.AddressOf (ec, AddressOp.Load); } return; } instance.Emit (ec); // Only to make verifier happy if (boxInstance && RequiresBoxing ()) { ec.Emit (OpCodes.Box, instance_type); } }
public void EmitPredefined (EmitContext ec, MethodSpec method, Arguments Arguments, bool statement = false, Location? loc = null) { Expression instance_copy = null; if (!HasAwaitArguments && ec.HasSet (BuilderContext.Options.AsyncBody)) { HasAwaitArguments = Arguments != null && Arguments.ContainsEmitWithAwait (); if (HasAwaitArguments && InstanceExpressionOnStack) { throw new NotSupportedException (); } } OpCode call_op; LocalTemporary lt = null; if (method.IsStatic) { call_op = OpCodes.Call; } else { call_op = IsVirtualCallRequired (InstanceExpression, method) ? OpCodes.Callvirt : OpCodes.Call; if (HasAwaitArguments) { instance_copy = InstanceExpression.EmitToField (ec); var ie = new InstanceEmitter (instance_copy, IsAddressCall (instance_copy, call_op, method.DeclaringType)); if (Arguments == null) { ie.EmitLoad (ec, true); } } else if (!InstanceExpressionOnStack) { var ie = new InstanceEmitter (InstanceExpression, IsAddressCall (InstanceExpression, call_op, method.DeclaringType)); ie.Emit (ec, ConditionalAccess); if (DuplicateArguments) { ec.Emit (OpCodes.Dup); if (Arguments != null && Arguments.Count != 0) { lt = new LocalTemporary (ie.GetStackType (ec)); lt.Store (ec); instance_copy = lt; } } } } if (Arguments != null && !InstanceExpressionOnStack) { EmittedArguments = Arguments.Emit (ec, DuplicateArguments, HasAwaitArguments); if (EmittedArguments != null) { if (instance_copy != null) { var ie = new InstanceEmitter (instance_copy, IsAddressCall (instance_copy, call_op, method.DeclaringType)); ie.Emit (ec, ConditionalAccess); if (lt != null) lt.Release (ec); } EmittedArguments.Emit (ec); } } if (call_op == OpCodes.Callvirt && (InstanceExpression.Type.IsGenericParameter || InstanceExpression.Type.IsStructOrEnum)) { ec.Emit (OpCodes.Constrained, InstanceExpression.Type); } if (loc != null) { // // Emit explicit sequence point for expressions like Foo.Bar () to help debugger to // break at right place when LHS expression can be stepped-into // ec.MarkCallEntry (loc.Value); } // // Set instance expression to actual result expression. When it contains await it can be // picked up by caller // InstanceExpression = instance_copy; if (method.Parameters.HasArglist) { var varargs_types = GetVarargsTypes (method, Arguments); ec.Emit (call_op, method, varargs_types); } else { // // If you have: // this.DoFoo (); // and DoFoo is not virtual, you can omit the callvirt, // because you don't need the null checking behavior. // ec.Emit (call_op, method); } // // Pop the return value if there is one and stack should be empty // if (statement && method.ReturnType.Kind != MemberKind.Void) ec.Emit (OpCodes.Pop); }