// // 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 EmitAssign(EmitContext ec) { Expr.Emit(ec); variable = new LocalTemporary(Expr.Type); variable.Store(ec); Expr = variable; }
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); temp.Release(ec); } 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 EmitLoad(EmitContext ec) { 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 (instance_type.IsGenericParameter && !(instance is This) && TypeSpec.IsReferenceType(instance_type)) { ec.Emit(OpCodes.Box, instance_type); } else if (instance_type.IsStructOrEnum) { ec.Emit(OpCodes.Box, instance_type); } }
// // if `dup_args' is true, a copy of the arguments will be left // on the stack and return value will contain an array of access // expressions // NOTE: It's caller responsibility is to release temporary variables // public virtual Expression[] Emit(EmitContext ec, bool dup_args) { Expression[] temps; if (dup_args && Count != 0) { temps = new Expression [Count]; } else { temps = null; } int i = 0; LocalTemporary lt; foreach (Argument a in args) { a.Emit(ec); if (!dup_args) { continue; } if (a.Expr is Constant || a.Expr is This) { // // No need to create a temporary variable for constants // temps[i] = a.Expr; } else { ec.Emit(OpCodes.Dup); temps[i] = lt = new LocalTemporary(a.Type); lt.Store(ec); } ++i; } return(temps); }
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 EmitAssign (EmitContext ec) { var type = Expr.Type; if (IsByRef) { var ml = (IMemoryLocation) Expr; ml.AddressOf (ec, AddressOp.Load); type = ReferenceContainer.MakeType (type); } else { Expr.Emit (ec); } variable = new LocalTemporary (type); variable.Store (ec); Expr = variable; }
protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode) { LocalTemporary value_target = new LocalTemporary (type); if (is_type_parameter) { DoEmitTypeParameter (ec); value_target.Store (ec); value_target.AddressOf (ec, mode); return value_target; } if (!TypeManager.IsStruct (type)){ // // We throw an exception. So far, I believe we only need to support // value types: // foreach (int j in new StructType ()) // see bug 42390 // throw new Exception ("AddressOf should not be used for classes"); } value_target.AddressOf (ec, AddressOp.Store); if (method == null) { ec.ig.Emit (OpCodes.Initobj, type); } else { if (Arguments != null) Arguments.Emit (ec); ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method); } value_target.AddressOf (ec, mode); return value_target; }
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, a copy of the arguments will be left // on the stack and return value will contain an array of access // expressions // NOTE: It's caller responsibility is to release temporary variables // public virtual Expression[] Emit (EmitContext ec, bool dup_args) { Expression[] temps; if (dup_args && Count != 0) temps = new Expression [Count]; else temps = null; int i = 0; LocalTemporary lt; foreach (Argument a in args) { a.Emit (ec); if (!dup_args) continue; if (a.Expr is Constant || a.Expr is This) { // // No need to create a temporary variable for constants // temps[i] = a.Expr; } else { ec.Emit (OpCodes.Dup); temps[i] = lt = new LocalTemporary (a.Type); lt.Store (ec); } ++i; } return temps; }
static TypeSpec EmitCallInstance (EmitContext ec, Expression instance, TypeSpec declaringType, OpCode callOpcode) { var instance_type = instance.Type; // // Push the instance expression // if ((instance_type.IsStructOrEnum && (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.IsStructOrEnum) { instance.Emit (ec); ec.Emit (OpCodes.Box, instance_type); return ec.BuiltinTypes.Object; } instance.Emit (ec); return instance_type; }
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) { FieldAttributes fa = FieldInfo.Attributes; bool is_static = (fa & FieldAttributes.Static) != 0; bool is_readonly = (fa & FieldAttributes.InitOnly) != 0; ILGenerator ig = ec.ig; if (is_readonly && !ec.IsConstructor){ Report_AssignToReadonly (source); return; } prepared = prepare_for_load; EmitInstance (ec, prepared); source.Emit (ec); if (leave_copy) { ec.ig.Emit (OpCodes.Dup); if (!FieldInfo.IsStatic) { temp = new LocalTemporary (this.Type); temp.Store (ec); } } FieldBase f = TypeManager.GetField (FieldInfo); if (f != null){ if ((f.ModFlags & Modifiers.VOLATILE) != 0) ig.Emit (OpCodes.Volatile); f.SetAssigned (); } if (is_static) ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ()); else ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ()); if (temp != null) { temp.Emit (ec); temp.Release (ec); temp = null; } }
// // Initializes all hoisted variables // public void EmitStoreyInstantiation (EmitContext ec) { // There can be only one instance variable for each storey type if (Instance != null) throw new InternalErrorException (); SymbolWriter.OpenCompilerGeneratedBlock (ec); // // Create an instance of a storey // var storey_type_expr = CreateStoreyTypeExpression (ec); ResolveContext rc = new ResolveContext (ec.MemberContext); Expression e = new New (storey_type_expr, null, Location).Resolve (rc); e.Emit (ec); Instance = new LocalTemporary (storey_type_expr.Type); Instance.Store (ec); EmitHoistedFieldsInitialization (ec); SymbolWriter.DefineScopeVariable (ID, Instance.Builder); SymbolWriter.CloseCompilerGeneratedBlock (ec); }
protected void EmitInstance (EmitContext ec, bool prepare_for_load) { if (IsStatic) return; if (InstanceExpression == EmptyExpression.Null) { SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ()); return; } if (InstanceExpression.Type.IsValueType) { if (InstanceExpression is IMemoryLocation) { ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore); } else { LocalTemporary t = new LocalTemporary (InstanceExpression.Type); InstanceExpression.Emit (ec); t.Store (ec); t.AddressOf (ec, AddressOp.Store); } } else InstanceExpression.Emit (ec); if (prepare_for_load) ec.ig.Emit (OpCodes.Dup); }
public void Emit (EmitContext ec, bool leave_copy) { ILGenerator ig = ec.ig; bool is_volatile = false; FieldBase f = TypeManager.GetField (FieldInfo); if (f != null){ if ((f.ModFlags & Modifiers.VOLATILE) != 0) is_volatile = true; f.SetMemberIsUsed (); } if (FieldInfo.IsStatic){ if (is_volatile) ig.Emit (OpCodes.Volatile); ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ()); } else { if (!prepared) EmitInstance (ec, false); IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo); if (ff != null) { ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ()); ig.Emit (OpCodes.Ldflda, ff.Element); } else { if (is_volatile) ig.Emit (OpCodes.Volatile); ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ()); } } if (leave_copy) { ec.ig.Emit (OpCodes.Dup); if (!FieldInfo.IsStatic) { temp = new LocalTemporary (this.Type); temp.Store (ec); } } }
public void EmitLoad (EmitContext ec) { 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 (instance_type.IsGenericParameter && !(instance is This) && TypeSpec.IsReferenceType (instance_type)) { ec.Emit (OpCodes.Box, instance_type); } else if (instance_type.IsStructOrEnum) { ec.Emit (OpCodes.Box, instance_type); } }
// // Initializes all hoisted variables // public void EmitStoreyInstantiation (EmitContext ec) { // There can be only one instance variable for each storey type if (Instance != null) throw new InternalErrorException (); SymbolWriter.OpenCompilerGeneratedBlock (ec.ig); // // Create an instance of storey type // Expression storey_type_expr; if (is_generic) { // // Use current method type parameter (MVAR) for top level storey only. All // nested storeys use class type parameter (VAR) // TypeParameter[] tparams = ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null ? ec.CurrentAnonymousMethod.Storey.TypeParameters : ec.CurrentTypeParameters; TypeArguments targs = new TypeArguments (); if (tparams.Length < CountTypeParameters) { TypeParameter[] parent_tparams = ec.MemberContext.CurrentTypeDefinition.TypeParameters; for (int i = 0; i < parent_tparams.Length; ++i) targs.Add (new TypeParameterExpr (parent_tparams[i], Location)); } for (int i = 0; i < tparams.Length; ++i) targs.Add (new TypeParameterExpr (tparams[i], Location)); storey_type_expr = new GenericTypeExpr (TypeBuilder, targs, Location); } else { storey_type_expr = new TypeExpression (TypeBuilder, Location); } ResolveContext rc = new ResolveContext (this); Expression e = new New (storey_type_expr, null, Location).Resolve (rc); e.Emit (ec); Instance = new LocalTemporary (storey_type_expr.Type); Instance.Store (ec); EmitHoistedFieldsInitialization (ec); SymbolWriter.DefineScopeVariable (ID, Instance.Builder); SymbolWriter.CloseCompilerGeneratedBlock (ec.ig); }
// // source is ignored, because we already have a copy of it from the // LValue resolution and we have already constructed a pre-cached // version of the arguments (ea.set_arguments); // public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) { prepared = prepare_for_load; Expression value = set_expr; if (prepared) { Invocation.EmitCall (ec, is_base_indexer, instance_expr, get, arguments, loc, true, false); prepared_value = new LocalTemporary (type); prepared_value.Store (ec); source.Emit (ec); prepared_value.Release (ec); if (leave_copy) { ec.ig.Emit (OpCodes.Dup); temp = new LocalTemporary (Type); temp.Store (ec); } } else if (leave_copy) { temp = new LocalTemporary (Type); source.Emit (ec); temp.Store (ec); value = temp; } if (!prepared) arguments.Add (new Argument (value)); Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared); if (temp != null) { temp.Emit (ec); temp.Release (ec); } }
public void Emit (EmitContext ec, bool leave_copy) { if (prepared) { prepared_value.Emit (ec); } else { Invocation.EmitCall (ec, is_base_indexer, instance_expr, get, arguments, loc, false, false); } if (leave_copy) { ec.ig.Emit (OpCodes.Dup); temp = new LocalTemporary (Type); temp.Store (ec); } }
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); }
protected override void DoEmit (EmitContext ec) { if (IsGeneral) ec.BeginCatchBlock (TypeManager.object_type); else ec.BeginCatchBlock (CatchType); if (li != null) { li.CreateBuilder (ec); // // Special case hoisted catch variable, we have to use a temporary variable // to pass via anonymous storey initialization with the value still on top // of the stack // if (li.HoistedVariant != null) { LocalTemporary lt = new LocalTemporary (li.Type); SymbolWriter.OpenCompilerGeneratedBlock (ec); lt.Store (ec); SymbolWriter.CloseCompilerGeneratedBlock (ec); // switch to assigning from the temporary variable and not from top of the stack assign.UpdateSource (lt); } } else { SymbolWriter.OpenCompilerGeneratedBlock (ec); ec.Emit (OpCodes.Pop); SymbolWriter.CloseCompilerGeneratedBlock (ec); } Block.Emit (ec); }
public void Emit(EmitContext ec, bool leave_copy) { bool is_volatile = false; if ((spec.Modifiers & Modifiers.VOLATILE) != 0) is_volatile = true; spec.MemberDefinition.SetIsUsed (); if (IsStatic){ if (is_volatile) ec.Emit (OpCodes.Volatile); ec.Emit (OpCodes.Ldsfld, spec); } else { if (!prepared) EmitInstance (ec, false); // Optimization for build-in types if (TypeManager.IsStruct (type) && TypeManager.IsEqual (type, ec.MemberContext.CurrentType) && TypeManager.IsEqual (InstanceExpression.Type, type)) { ec.EmitLoadFromPtr (type); } else { var ff = spec as FixedFieldSpec; if (ff != null) { ec.Emit (OpCodes.Ldflda, spec); ec.Emit (OpCodes.Ldflda, ff.Element); } else { if (is_volatile) ec.Emit (OpCodes.Volatile); ec.Emit (OpCodes.Ldfld, spec); } } } if (leave_copy) { ec.Emit (OpCodes.Dup); if (!IsStatic) { temp = new LocalTemporary (this.Type); temp.Store (ec); } } }
public void Emit (EmitContext ec, bool leave_copy) { int rank = ea.Expr.Type.GetArrayRank (); ILGenerator ig = ec.ig; if (prepared) { LoadFromPtr (ig, this.type); } else { LoadArrayAndArguments (ec); EmitLoadOpcode (ig, type, rank); } if (leave_copy) { ig.Emit (OpCodes.Dup); temp = new LocalTemporary (this.type); temp.Store (ec); } }
public void EmitAssign(EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) { prepared = prepare_for_load; EmitInstance (ec, prepared); source.Emit (ec); if (leave_copy) { ec.Emit (OpCodes.Dup); if (!IsStatic) { temp = new LocalTemporary (this.Type); temp.Store (ec); } } if ((spec.Modifiers & Modifiers.VOLATILE) != 0) ec.Emit (OpCodes.Volatile); spec.MemberDefinition.SetIsAssigned (); if (IsStatic) ec.Emit (OpCodes.Stsfld, spec); else ec.Emit (OpCodes.Stfld, spec); if (temp != null) { temp.Emit (ec); temp.Release (ec); temp = null; } }
public void EmitPredefined (EmitContext ec, MethodSpec method, Arguments Arguments) { 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); } // // 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); }
protected void EmitInstance(EmitContext ec, bool prepare_for_load) { if (IsStatic) return; if (InstanceExpression == EmptyExpression.Null) { // FIXME: This should not be here at all SimpleName.Error_ObjectRefRequired (new ResolveContext (ec.MemberContext), loc, GetSignatureForError ()); return; } if (TypeManager.IsValueType (InstanceExpression.Type)) { if (InstanceExpression is IMemoryLocation) { ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore); } else { LocalTemporary t = new LocalTemporary (InstanceExpression.Type); InstanceExpression.Emit (ec); t.Store (ec); t.AddressOf (ec, AddressOp.Store); } } else InstanceExpression.Emit (ec); if (prepare_for_load) ec.Emit (OpCodes.Dup); }
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; InstanceEmitter ie = new InstanceEmitter(); 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); ie = new InstanceEmitter(instance_copy, IsAddressCall(instance_copy, call_op, method.DeclaringType)); if (Arguments == null) { ie.EmitLoad(ec); } } else if (!InstanceExpressionOnStack) { ie = new InstanceEmitter(InstanceExpression, IsAddressCall(InstanceExpression, call_op, method.DeclaringType)); ie.NullShortCircuit = NullShortCircuit; ie.Emit(ec); if (NullShortCircuit) { NullOperatorLabel = ie.NullOperatorLabel; } 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) { ie = new InstanceEmitter(instance_copy, IsAddressCall(instance_copy, call_op, method.DeclaringType)); ie.Emit(ec); 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 (NullShortCircuit && !DuplicateArguments) { ie.EmitResultLift(ec, method.ReturnType, statement); } }
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) { int rank = ea.Expr.Type.GetArrayRank (); ILGenerator ig = ec.ig; Type t = source.Type; prepared = prepare_for_load; if (prepared) { AddressOf (ec, AddressOp.LoadStore); ec.ig.Emit (OpCodes.Dup); } else { LoadArrayAndArguments (ec); } if (rank == 1) { bool is_stobj, has_type_arg; OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg); if (!prepared) { // // The stobj opcode used by value types will need // an address on the stack, not really an array/array // pair // if (is_stobj) ig.Emit (OpCodes.Ldelema, t); } source.Emit (ec); if (leave_copy) { ec.ig.Emit (OpCodes.Dup); temp = new LocalTemporary (this.type); temp.Store (ec); } if (prepared) StoreFromPtr (ig, t); else if (is_stobj) ig.Emit (OpCodes.Stobj, t); else if (has_type_arg) ig.Emit (op, t); else ig.Emit (op); } else { source.Emit (ec); if (leave_copy) { ec.ig.Emit (OpCodes.Dup); temp = new LocalTemporary (this.type); temp.Store (ec); } if (prepared) { StoreFromPtr (ig, t); } else { int arg_count = ea.Arguments.Count; Type [] args = new Type [arg_count + 1]; for (int i = 0; i < arg_count; i++) { //args [i++] = a.Type; args [i] = TypeManager.int32_type; } args [arg_count] = type; MethodInfo set = RootContext.ToplevelTypes.Builder.GetArrayMethod ( ea.Expr.Type, "Set", CallingConventions.HasThis | CallingConventions.Standard, TypeManager.void_type, args); ig.Emit (OpCodes.Call, set); } } if (temp != null) { temp.Emit (ec); temp.Release (ec); } }
// // 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 Emit (EmitContext ec, bool leave_copy) { Emit (ec); if (leave_copy) { ec.ig.Emit (OpCodes.Dup); temporary = new LocalTemporary (expr.Type); temporary.Store (ec); } }
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); } }
protected override void DoEmit (EmitContext ec) { if (CatchType != null) ec.BeginCatchBlock (CatchType); else ec.BeginCatchBlock (TypeManager.object_type); if (VarBlock != null) VarBlock.Emit (ec); if (Name != null) { // TODO: Move to resolve LocalVariableReference lvr = new LocalVariableReference (Block, Name, loc); lvr.Resolve (new ResolveContext (ec.MemberContext)); // Only to make verifier happy if (TypeManager.IsGenericParameter (lvr.Type)) ec.Emit (OpCodes.Unbox_Any, lvr.Type); Expression source; if (lvr.IsHoisted) { LocalTemporary lt = new LocalTemporary (lvr.Type); lt.Store (ec); source = lt; } else { // Variable is at the top of the stack source = EmptyExpression.Null; } lvr.EmitAssign (ec, source, false, false); } else ec.Emit (OpCodes.Pop); Block.Emit (ec); }
// `dup_args' leaves an extra copy of the arguments on the stack // `omit_args' does not leave any arguments at all. // So, basically, you could make one call with `dup_args' set to true, // and then another with `omit_args' set to true, and the two calls // would have the same set of arguments. However, each argument would // only have been evaluated once. public static void EmitCall (EmitContext ec, bool is_base, Expression instance_expr, MethodBase method, Arguments Arguments, Location loc, bool dup_args, bool omit_args) { ILGenerator ig = ec.ig; bool struct_call = false; bool this_call = false; LocalTemporary this_arg = null; Type decl_type = method.DeclaringType; if (IsMethodExcluded (method, loc)) return; bool is_static = method.IsStatic; if (!is_static){ this_call = instance_expr is This; if (TypeManager.IsStruct (decl_type) || TypeManager.IsEnumType (decl_type)) struct_call = true; // // If this is ourselves, push "this" // if (!omit_args) { Type t = null; Type iexpr_type = instance_expr.Type; // // Push the instance expression // if (TypeManager.IsValueType (iexpr_type) || TypeManager.IsGenericParameter (iexpr_type)) { // // Special case: calls to a function declared in a // reference-type with a value-type argument need // to have their value boxed. if (TypeManager.IsStruct (decl_type) || TypeManager.IsGenericParameter (iexpr_type)) { // // 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. if (instance_expr is IMemoryLocation) { ((IMemoryLocation)instance_expr). AddressOf (ec, AddressOp.LoadStore); } else { LocalTemporary temp = new LocalTemporary (iexpr_type); instance_expr.Emit (ec); temp.Store (ec); temp.AddressOf (ec, AddressOp.Load); } // avoid the overhead of doing this all the time. if (dup_args) t = TypeManager.GetReferenceType (iexpr_type); } else { instance_expr.Emit (ec); // FIXME: should use instance_expr is IMemoryLocation + constraint. // to help JIT to produce better code ig.Emit (OpCodes.Box, instance_expr.Type); t = TypeManager.object_type; } } else { instance_expr.Emit (ec); t = instance_expr.Type; } if (dup_args) { ig.Emit (OpCodes.Dup); if (Arguments != null && Arguments.Count != 0) { this_arg = new LocalTemporary (t); this_arg.Store (ec); } } } } if (!omit_args && Arguments != null) Arguments.Emit (ec, dup_args, this_arg); OpCode call_op; if (is_static || struct_call || is_base || (this_call && !method.IsVirtual)) { call_op = OpCodes.Call; } else { call_op = OpCodes.Callvirt; #if GMCS_SOURCE if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter)) ig.Emit (OpCodes.Constrained, instance_expr.Type); #endif } if ((method.CallingConvention & CallingConventions.VarArgs) != 0) { Type[] varargs_types = GetVarargsTypes (method, Arguments); ig.EmitCall (call_op, (MethodInfo) 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. // if (method is MethodInfo) ig.Emit (call_op, (MethodInfo) method); else ig.Emit (call_op, (ConstructorInfo) method); }
protected override void DoEmit (EmitContext ec) { // // Needed to emit anonymous storey initialization // Otherwise it does not contain any statements for now // block.Emit (ec); default_target = ec.DefineLabel (); null_target = ec.DefineLabel (); // Store variable for comparission purposes // TODO: Don't duplicate non-captured VariableReference LocalTemporary value; if (HaveUnwrap) { value = new LocalTemporary (SwitchType); unwrap.EmitCheck (ec); ec.Emit (OpCodes.Brfalse, null_target); new_expr.Emit (ec); value.Store (ec); } else if (!is_constant) { value = new LocalTemporary (SwitchType); new_expr.Emit (ec); value.Store (ec); } else value = null; // // Setup the codegen context // Label old_end = ec.LoopEnd; Switch old_switch = ec.Switch; ec.LoopEnd = ec.DefineLabel (); ec.Switch = this; // Emit Code. if (is_constant) { if (constant_section != null) constant_section.Block.Emit (ec); } else if (string_dictionary != null) { DoEmitStringSwitch (value, ec); } else { TableSwitchEmit (ec, value); } if (value != null) value.Release (ec); // Restore context state. ec.MarkLabel (ec.LoopEnd); // // Restore the previous context // ec.LoopEnd = old_end; ec.Switch = old_switch; }
public void Emit(EmitContext ec, bool leave_copy) { // // Special case: length of single dimension array property is turned into ldlen // if (IsSingleDimensionalArrayLength ()) { if (!prepared) EmitInstance (ec, false); ec.Emit (OpCodes.Ldlen); ec.Emit (OpCodes.Conv_I4); return; } Invocation.EmitCall (ec, IsBase, InstanceExpression, spec.Get, null, loc, prepared, false); if (leave_copy) { ec.Emit (OpCodes.Dup); if (!IsStatic) { temp = new LocalTemporary (this.Type); temp.Store (ec); } } }
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) { prepared = prepare_for_load; expr.Emit (ec); if (prepare_for_load) ec.ig.Emit (OpCodes.Dup); source.Emit (ec); if (leave_copy) { ec.ig.Emit (OpCodes.Dup); temporary = new LocalTemporary (expr.Type); temporary.Store (ec); } StoreFromPtr (ec.ig, type); if (temporary != null) { temporary.Emit (ec); temporary.Release (ec); } }
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.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); 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); }
// // Implements the IAssignMethod interface for assignments // public void EmitAssign(EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) { Expression my_source = source; if (prepare_for_load) { prepared = true; source.Emit (ec); if (leave_copy) { ec.Emit (OpCodes.Dup); if (!IsStatic) { temp = new LocalTemporary (this.Type); temp.Store (ec); } } } else if (leave_copy) { source.Emit (ec); temp = new LocalTemporary (this.Type); temp.Store (ec); my_source = temp; } Arguments args = new Arguments (1); args.Add (new Argument (my_source)); Invocation.EmitCall (ec, IsBase, InstanceExpression, spec.Set, args, loc, false, prepared); if (temp != null) { temp.Emit (ec); temp.Release (ec); } }