// // 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 EmitAwaitOnCompletedDynamic(EmitContext ec, FieldExpr awaiter) { var critical = Module.PredefinedTypes.ICriticalNotifyCompletion; if (!critical.Define()) { throw new NotImplementedException(); } var temp_critical = new LocalTemporary(critical.TypeSpec); var label_critical = ec.DefineLabel(); var label_end = ec.DefineLabel(); // // Special path for dynamic awaiters // // var awaiter = this.$awaiter as ICriticalNotifyCompletion; // if (awaiter == null) { // var completion = (INotifyCompletion) this.$awaiter; // this.$builder.AwaitOnCompleted (ref completion, ref this); // } else { // this.$builder.AwaitUnsafeOnCompleted (ref awaiter, ref this); // } // awaiter.Emit(ec); ec.Emit(OpCodes.Isinst, critical.TypeSpec); temp_critical.Store(ec); temp_critical.Emit(ec); ec.Emit(OpCodes.Brtrue_S, label_critical); var temp = new LocalTemporary(Module.PredefinedTypes.INotifyCompletion.TypeSpec); awaiter.Emit(ec); ec.Emit(OpCodes.Castclass, temp.Type); temp.Store(ec); EmitOnCompleted(ec, temp, false); temp.Release(ec); ec.Emit(OpCodes.Br_S, label_end); ec.MarkLabel(label_critical); EmitOnCompleted(ec, temp_critical, true); ec.MarkLabel(label_end); temp_critical.Release(ec); }
static TypeSpec EmitCallInstance(EmitContext ec, Expression instance, TypeSpec declaringType, OpCode callOpcode) { var instance_type = instance.Type; // // Push the instance expression // if ((instance_type.IsStruct && (callOpcode == OpCodes.Callvirt || (callOpcode == OpCodes.Call && declaringType.IsStruct))) || instance_type.IsGenericParameter || declaringType.IsNullableType) { // // 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(ReferenceContainer.MakeType(ec.Module, instance_type)); } if (instance_type.IsEnum || instance_type.IsStruct) { instance.Emit(ec); ec.Emit(OpCodes.Box, instance_type); return(ec.BuiltinTypes.Object); } instance.Emit(ec); return(instance_type); }
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; }
// // 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 EmitPredefined (EmitContext ec, MethodSpec method, Arguments Arguments, 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 { if (IsVirtualCallRequired (InstanceExpression, method)) { call_op = OpCodes.Callvirt; } else { call_op = OpCodes.Call; } if (HasAwaitArguments) { instance_copy = InstanceExpression.EmitToField (ec); if (Arguments == null) EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op); } else if (!InstanceExpressionOnStack) { var instance_on_stack_type = EmitCallInstance (ec, InstanceExpression, method.DeclaringType, call_op); if (DuplicateArguments) { ec.Emit (OpCodes.Dup); if (Arguments != null && Arguments.Count != 0) { lt = new LocalTemporary (instance_on_stack_type); lt.Store (ec); instance_copy = lt; } } } } if (Arguments != null && !InstanceExpressionOnStack) { EmittedArguments = Arguments.Emit (ec, DuplicateArguments, HasAwaitArguments); if (EmittedArguments != null) { if (instance_copy != null) { EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op); if (lt != null) lt.Release (ec); } EmittedArguments.Emit (ec); } } if (call_op == OpCodes.Callvirt && (InstanceExpression.Type.IsGenericParameter || InstanceExpression.Type.IsStruct)) { 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 // // TODO: The list is probably not comprehensive, need to do more testing // if (InstanceExpression is PropertyExpr || InstanceExpression is Invocation || InstanceExpression is IndexerExpr || InstanceExpression is New || InstanceExpression is DelegateInvocation) ec.Mark (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); return; } // // 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); }
static TypeSpec EmitCallInstance (EmitContext ec, Expression instance, TypeSpec declaringType, OpCode callOpcode) { var instance_type = instance.Type; // // Push the instance expression // if ((instance_type.IsStruct && (callOpcode == OpCodes.Callvirt || (callOpcode == OpCodes.Call && declaringType.IsStruct))) || instance_type.IsGenericParameter || declaringType.IsNullableType) { // // 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 ReferenceContainer.MakeType (ec.Module, instance_type); } if (instance_type.IsEnum || instance_type.IsStruct) { instance.Emit (ec); ec.Emit (OpCodes.Box, instance_type); return ec.BuiltinTypes.Object; } instance.Emit (ec); return instance_type; }
public void EmitPredefined(EmitContext ec, MethodSpec method, Arguments Arguments, 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 { if (IsVirtualCallRequired(InstanceExpression, method)) { call_op = OpCodes.Callvirt; } else { call_op = OpCodes.Call; } if (HasAwaitArguments) { instance_copy = InstanceExpression.EmitToField(ec); if (Arguments == null) { EmitCallInstance(ec, instance_copy, method.DeclaringType, call_op); } } else if (!InstanceExpressionOnStack) { var instance_on_stack_type = EmitCallInstance(ec, InstanceExpression, method.DeclaringType, call_op); if (DuplicateArguments) { ec.Emit(OpCodes.Dup); if (Arguments != null && Arguments.Count != 0) { lt = new LocalTemporary(instance_on_stack_type); lt.Store(ec); instance_copy = lt; } } } } if (Arguments != null && !InstanceExpressionOnStack) { EmittedArguments = Arguments.Emit(ec, DuplicateArguments, HasAwaitArguments); if (EmittedArguments != null) { if (instance_copy != null) { EmitCallInstance(ec, instance_copy, method.DeclaringType, call_op); if (lt != null) { lt.Release(ec); } } EmittedArguments.Emit(ec); } } if (call_op == OpCodes.Callvirt && (InstanceExpression.Type.IsGenericParameter || InstanceExpression.Type.IsStruct)) { 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 // // TODO: The list is probably not comprehensive, need to do more testing // if (InstanceExpression is PropertyExpr || InstanceExpression is Invocation || InstanceExpression is IndexerExpr || InstanceExpression is New || InstanceExpression is DelegateInvocation) { ec.Mark(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); return; } // // 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); }