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; }
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; }
// // 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; }
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); }
void DoEmitStringSwitch (LocalTemporary value, EmitContext ec) { Label l_initialized = ec.DefineLabel (); // // Skip initialization when value is null // value.EmitBranchable (ec, null_target, false); // // Check if string dictionary is initialized and initialize // switch_cache_field.EmitBranchable (ec, l_initialized, true); string_dictionary.EmitStatement (ec); ec.MarkLabel (l_initialized); LocalTemporary string_switch_variable = new LocalTemporary (TypeManager.int32_type); ResolveContext rc = new ResolveContext (ec.MemberContext); if (TypeManager.generic_ienumerable_type != null) { Arguments get_value_args = new Arguments (2); get_value_args.Add (new Argument (value)); get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out)); Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (rc); if (get_item == null) return; // // A value was not found, go to default case // get_item.EmitBranchable (ec, default_target, false); } else { Arguments get_value_args = new Arguments (1); get_value_args.Add (new Argument (value)); Expression get_item = new ElementAccess (switch_cache_field, get_value_args, loc).Resolve (rc); if (get_item == null) return; LocalTemporary get_item_object = new LocalTemporary (TypeManager.object_type); get_item_object.EmitAssign (ec, get_item, true, false); ec.Emit (OpCodes.Brfalse, default_target); ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable, new Cast (new TypeExpression (TypeManager.int32_type, loc), get_item_object, loc)).Resolve (rc); get_item_int.EmitStatement (ec); get_item_object.Release (ec); } TableSwitchEmit (ec, string_switch_variable); string_switch_variable.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); } }
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 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); }
public override bool Emit (EmitContext ec, IMemoryLocation target) { bool left_on_stack = base.Emit (ec, target); if (initializers.IsEmpty) return left_on_stack; LocalTemporary temp = target as LocalTemporary; if (temp == null) { if (!left_on_stack) { VariableReference vr = target as VariableReference; // FIXME: This still does not work correctly for pre-set variables if (vr != null && vr.IsRef) target.AddressOf (ec, AddressOp.Load); ((Expression) target).Emit (ec); left_on_stack = true; } temp = new LocalTemporary (type); } instance = temp; if (left_on_stack) temp.Store (ec); initializers.Emit (ec); if (left_on_stack) { temp.Emit (ec); temp.Release (ec); } return left_on_stack; }
// // 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 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; }
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 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; } }
public override bool Resolve (BlockContext ec) { bool is_dynamic = expr.Type == InternalType.Dynamic; if (is_dynamic) expr = Convert.ImplicitConversionRequired (ec, expr, TypeManager.ienumerable_type, loc); var get_enumerator_mg = ResolveGetEnumerator (ec); if (get_enumerator_mg == null) { return false; } var get_enumerator = get_enumerator_mg.BestCandidate; var enumerator = new TemporaryVariable (get_enumerator.ReturnType, loc); enumerator.Resolve (ec); // Prepare bool MoveNext () var move_next_mg = ResolveMoveNext (ec, get_enumerator); if (move_next_mg == null) { return false; } move_next_mg.InstanceExpression = enumerator; // Prepare ~T~ Current { get; } var current_prop = ResolveCurrent (ec, get_enumerator); if (current_prop == null) { return false; } var current_pe = new PropertyExpr (current_prop, loc) { InstanceExpression = enumerator }.Resolve (ec); if (current_pe == null) return false; VarExpr ve = var_type as VarExpr; if (ve != null) { // Infer implicitly typed local variable from foreach enumerable type var_type = new TypeExpression (current_pe.Type, var_type.Location); } var_type = var_type.ResolveAsTypeTerminal (ec, false); if (var_type == null) return false; var init = new Invocation (get_enumerator_mg, null); init.Resolve (ec); statement = new While (new BooleanExpression (new Invocation (move_next_mg, null)), new Body (var_type.Type, variable, current_pe, statement, loc), loc); var enum_type = enumerator.Type; // // Add Dispose method call when enumerator can be IDisposable // if (!enumerator.Type.ImplementsInterface (TypeManager.idisposable_type)) { if (!enum_type.IsSealed && !TypeManager.IsValueType (enum_type)) { // // Runtime Dispose check // var tv = new LocalTemporary (TypeManager.idisposable_type); statement = new Dispose (enumerator, tv, init, statement, loc); } else { // // No Dispose call needed // this.init = new SimpleAssign (enumerator, init); this.init.Resolve (ec); } } else { // // Static Dispose check // statement = new Dispose (enumerator, null, init, statement, loc); } return statement.Resolve (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) { // // 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) { 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); } } }
// // 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); }
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 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); } } }
protected void EmitConditionalAccess (EmitContext ec) { var a_expr = arguments [0].Expr; var des = a_expr as DynamicExpressionStatement; if (des != null) { des.EmitConditionalAccess (ec); } if (HasConditionalAccess ()) { var NullOperatorLabel = ec.DefineLabel (); if (ExpressionAnalyzer.IsInexpensiveLoad (a_expr)) { a_expr.Emit (ec); } else { var lt = new LocalTemporary (a_expr.Type); lt.EmitAssign (ec, a_expr, true, false); Arguments [0].Expr = lt; } ec.Emit (OpCodes.Brtrue_S, NullOperatorLabel); if (!ec.ConditionalAccess.Statement) { if (ec.ConditionalAccess.Type.IsNullableType) Nullable.LiftedNull.Create (ec.ConditionalAccess.Type, Location.Null).Emit (ec); else ec.EmitNull (); } ec.Emit (OpCodes.Br, ec.ConditionalAccess.EndLabel); ec.MarkLabel (NullOperatorLabel); return; } if (a_expr.HasConditionalAccess ()) { var lt = new LocalTemporary (a_expr.Type); lt.EmitAssign (ec, a_expr, false, false); Arguments [0].Expr = lt; } }
// // 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); } }
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); }
// // if `dup_args' is true, a copy of the arguments will be left // on the stack. If `dup_args' is true, you can specify `this_arg' // which will be duplicated before any other args. Only EmitCall // should be using this interface. // public void Emit (EmitContext ec, bool dup_args, LocalTemporary this_arg) { LocalTemporary[] temps = null; if (dup_args && Count != 0) temps = new LocalTemporary [Count]; if (reordered != null && Count > 1) { foreach (NamedArgument na in reordered) na.EmitAssign (ec); } int i = 0; foreach (Argument a in args) { a.Emit (ec); if (dup_args) { ec.Emit (OpCodes.Dup); (temps [i++] = new LocalTemporary (a.Type)).Store (ec); } } if (dup_args) { if (this_arg != null) this_arg.Emit (ec); for (i = 0; i < temps.Length; i++) { temps[i].Emit (ec); temps[i].Release (ec); } } }
public Dispose (TemporaryVariable variable, LocalTemporary dispose, Expression expr, Statement statement, Location loc) : base (expr, statement, loc) { base.local_copy = variable; this.dispose = dispose; }
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); }
protected override Expression DoResolve(ResolveContext rc) { var src = source.Resolve(rc); if (src == null) { return(null); } if (InternalType.HasNoType(src.Type)) { rc.Report.Error(8131, source.Location, "Deconstruct assignment requires an expression with a type on the right-hand-side"); return(null); } var src_type = src.Type; if (src_type.IsTupleType) { int target_count; if (targetExprs == null) { target_count = variables.Count; targetExprs = new List <Expression> (target_count); } else { target_count = targetExprs.Count; } if (src_type.Arity != target_count) { rc.Report.Error(8132, loc, "Cannot deconstruct a tuple of `{0}' elements into `{1}' variables", src_type.Arity.ToString(CultureInfo.InvariantCulture), target_count.ToString(CultureInfo.InvariantCulture)); return(null); } var tupleLiteral = src as TupleLiteral; if (tupleLiteral == null && !ExpressionAnalyzer.IsInexpensiveLoad(src)) { var expr_variable = LocalVariable.CreateCompilerGenerated(source.Type, rc.CurrentBlock, loc); source = new CompilerAssign(expr_variable.CreateReferenceExpression(rc, loc), source, loc); instance = expr_variable.CreateReferenceExpression(rc, loc); } var element_srcs = new List <Expression> (); var src_names = new List <string> (); for (int i = 0; i < target_count; ++i) { var element_src = tupleLiteral == null ? new MemberAccess(instance, NamedTupleSpec.GetElementPropertyName(i)) : tupleLiteral.Elements [i].Expr; element_srcs.Add(element_src); if (element_src is VariableReference) { src_names.Add((element_src as VariableReference)?.Name); } } for (int i = 0; i < target_count; ++i) { var tle = src_type.TypeArguments [i]; if (variables != null) { var variable = variables [i].Variable; if (variable.Type == InternalType.Discard) { variables [i] = null; targetExprs.Add(EmptyExpressionStatement.Instance); continue; } var variable_type = variables [i].TypeExpression; targetExprs.Add(new LocalVariableReference(variable, variable.Location)); if (variable_type is VarExpr) { if (InternalType.HasNoType(tle)) { rc.Report.Error(8130, Location, "Cannot infer the type of implicitly-typed deconstruction variable `{0}'", variable.Name); tle = InternalType.ErrorType; } variable.Type = tle; } else { variable.Type = variable_type.ResolveAsType(rc); } variable.PrepareAssignmentAnalysis((BlockContext)rc); } var element_target = (targetExprs [i] as SimpleName)?.LookupNameExpression(rc, MemberLookupRestrictions.None); if (element_target != null && src_names.Contains((element_target as VariableReference)?.Name)) { var tempType = element_target.Resolve(rc).Type; var temp = new LocalTemporary(tempType); tempExprs.Add(new SimpleAssign(temp, element_srcs [i]).Resolve(rc)); targetExprs [i] = new SimpleAssign(targetExprs [i], temp).Resolve(rc); } else { targetExprs [i] = new SimpleAssign(targetExprs [i], element_srcs [i]).Resolve(rc); } } eclass = ExprClass.Value; // TODO: The type is same only if there is no target element conversion // var res = (/*byte*/ b, /*short*/ s) = (2, 4); type = src.Type; return(this); } if (src_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { rc.Report.Error(8133, loc, "Cannot deconstruct dynamic objects"); return(null); } /* * var args = new Arguments (targetExprs.Count); * foreach (var t in targetExprs) { * args.Add (new Argument (t, Argument.AType.Out)); * } * * var invocation = new Invocation (new MemberAccess (src, "Deconstruct"), args); * var res = invocation.Resolve (rc); */ throw new NotImplementedException("Custom deconstruct"); }