public override void InjectYield(EmitContext ec, Expression expr, int resume_pc, bool unwind_protect, Label resume_point) { // Store the new value into current var fe = new FieldExpr(((IteratorStorey)storey).CurrentField, loc); fe.InstanceExpression = new CompilerGeneratedThis(storey.CurrentType, loc); fe.EmitAssign(ec, expr, false, false); base.InjectYield(ec, expr, resume_pc, unwind_protect, resume_point); EmitLeave(ec, unwind_protect); ec.MarkLabel(resume_point); }
protected override void DoEmit(EmitContext ec) { var fe_awaiter = new FieldExpr(awaiter, loc); fe_awaiter.InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, loc); // // result = awaiter.GetResult (); // var mg_result = MethodGroupExpr.CreatePredefined(get_result, fe_awaiter.Type, loc); mg_result.InstanceExpression = fe_awaiter; mg_result.EmitCall(ec, new Arguments(0)); }
void EmitCall(EmitContext ec, bool isStatement) { int dyn_args_count = arguments == null ? 0 : arguments.Count; TypeExpr site_type = CreateSiteType(RootContext.ToplevelTypes.Compiler, isStatement, dyn_args_count); FieldExpr site_field_expr = new FieldExpr(CreateSiteField(site_type).FieldBuilder, loc); SymbolWriter.OpenCompilerGeneratedBlock(ec.ig); Arguments args = new Arguments(1); args.Add(new Argument(binder_expr)); StatementExpression s = new StatementExpression(new SimpleAssign(site_field_expr, new Invocation(new MemberAccess(site_type, "Create"), args))); BlockContext bc = new BlockContext(ec.MemberContext, null, TypeManager.void_type); if (s.Resolve(bc)) { Statement init = new If(new Binary(Binary.Operator.Equality, site_field_expr, new NullLiteral(loc)), s, loc); init.Emit(ec); } args = new Arguments(1 + dyn_args_count); args.Add(new Argument(site_field_expr)); if (arguments != null) { foreach (Argument a in arguments) { if (a is NamedArgument) { // Name is not valid in this context args.Add(new Argument(a.Expr, a.ArgType)); continue; } args.Add(a); } } ResolveContext rc = new ResolveContext(ec.MemberContext); Expression target = new DelegateInvocation(new MemberAccess(site_field_expr, "Target", loc).Resolve(rc), args, loc).Resolve(rc); if (target != null) { target.Emit(ec); } SymbolWriter.CloseCompilerGeneratedBlock(ec.ig); }
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); }
public static bool EmitStack(EmitContext ec, FieldExpr field, string name, bool isadr = false) { if (field.Spec == null) { ec.Report.Error(3664, "Asm code : the field " + name + " does not have a get accessor or does not exist"); return(false); } if (!isadr) { ec.Emit(OpCodes.Ldsfld, field.Spec); } else { ec.Emit(OpCodes.Ldsflda, field.Spec); } return(true); }
public Expression EmitContinuationInitialization(EmitContext ec) { // // When more than 1 awaiter has been used in the block we // introduce class scope field to cache continuation delegate // if (awaiters > 1) { if (continuation == null) { continuation = AddCompilerGeneratedField("$continuation", new TypeExpression(action, Location), true); continuation.Define(); } var fexpr = new FieldExpr(continuation, Location); fexpr.InstanceExpression = new CompilerGeneratedThis(CurrentType, Location); // // if ($continuation == null) // $continuation = new Action (MoveNext); // fexpr.Emit(ec); var skip_cont_init = ec.DefineLabel(); ec.Emit(OpCodes.Brtrue_S, skip_cont_init); ec.EmitThis(); EmitActionLoad(ec); ec.Emit(OpCodes.Stfld, continuation.Spec); ec.MarkLabel(skip_cont_init); return(fexpr); } // // Otherwise simply use temporary local variable // var field = LocalVariable.CreateCompilerGenerated(action, OriginalSourceBlock, Location); EmitActionLoad(ec); field.EmitAssign(ec); return(new LocalVariableReference(field, Location)); }
public Expression GetResultExpression(EmitContext ec) { var fe_awaiter = new FieldExpr(awaiter, loc); fe_awaiter.InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, loc); // // result = awaiter.GetResult (); // if (IsDynamic) { var rc = new ResolveContext(ec.MemberContext); return(new Invocation(new MemberAccess(fe_awaiter, "GetResult"), new Arguments(0)).Resolve(rc)); } var mg_result = MethodGroupExpr.CreatePredefined(awaiter_definition.GetResult, fe_awaiter.Type, loc); mg_result.InstanceExpression = fe_awaiter; return(new GetResultInvocation(mg_result, new Arguments(0))); }
public override bool Resolve(EmitContext ec) { TypeExpression storey_type_expr = new TypeExpression(host.TypeBuilder, loc); ArrayList init = null; if (host.hoisted_this != null) { init = new ArrayList(host.hoisted_params == null ? 1 : host.HoistedParameters.Count + 1); HoistedThis ht = host.hoisted_this; FieldExpr from = new FieldExpr(ht.Field.FieldBuilder, loc); from.InstanceExpression = CompilerGeneratedThis.Instance; init.Add(new ElementInitializer(ht.Field.Name, from, loc)); } if (host.hoisted_params != null) { if (init == null) { init = new ArrayList(host.HoistedParameters.Count); } for (int i = 0; i < host.hoisted_params.Count; ++i) { HoistedParameter hp = (HoistedParameter)host.hoisted_params [i]; HoistedParameter hp_cp = (HoistedParameter)host.hoisted_params_copy [i]; FieldExpr from = new FieldExpr(hp_cp.Field.FieldBuilder, loc); from.InstanceExpression = CompilerGeneratedThis.Instance; init.Add(new ElementInitializer(hp.Field.Name, from, loc)); } } if (init != null) { new_storey = new NewInitialize(storey_type_expr, new ArrayList(0), new CollectionOrObjectInitializers(init, loc), loc); } else { new_storey = new New(storey_type_expr, new ArrayList(0), loc); } new_storey = new_storey.Resolve(ec); if (new_storey != null) { new_storey = Convert.ImplicitConversionRequired(ec, new_storey, host_method.MemberType, loc); } if (TypeManager.int_interlocked_compare_exchange == null) { Type t = TypeManager.CoreLookupType("System.Threading", "Interlocked", Kind.Class, true); if (t != null) { TypeManager.int_interlocked_compare_exchange = TypeManager.GetPredefinedMethod( t, "CompareExchange", loc, TypeManager.int32_type, TypeManager.int32_type, TypeManager.int32_type); } } ec.CurrentBranching.CurrentUsageVector.Goto(); return(true); }
protected void EmitCall(EmitContext ec, Expression binder, Arguments arguments, bool isStatement) { int dyn_args_count = arguments == null ? 0 : arguments.Count; TypeExpr site_type = CreateSiteType (RootContext.ToplevelTypes.Compiler, arguments, dyn_args_count, isStatement); FieldExpr site_field_expr = new FieldExpr (CreateSiteField (site_type), loc); SymbolWriter.OpenCompilerGeneratedBlock (ec); Arguments args = new Arguments (1); args.Add (new Argument (binder)); StatementExpression s = new StatementExpression (new SimpleAssign (site_field_expr, new Invocation (new MemberAccess (site_type, "Create"), args))); BlockContext bc = new BlockContext (ec.MemberContext, null, TypeManager.void_type); if (s.Resolve (bc)) { Statement init = new If (new Binary (Binary.Operator.Equality, site_field_expr, new NullLiteral (loc), loc), s, loc); init.Emit (ec); } args = new Arguments (1 + dyn_args_count); args.Add (new Argument (site_field_expr)); if (arguments != null) { foreach (Argument a in arguments) { if (a is NamedArgument) { // Name is not valid in this context args.Add (new Argument (a.Expr, a.ArgType)); continue; } args.Add (a); } } Expression target = new DelegateInvocation (new MemberAccess (site_field_expr, "Target", loc).Resolve (bc), args, loc).Resolve (bc); if (target != null) target.Emit (ec); SymbolWriter.CloseCompilerGeneratedBlock (ec); }
void FabricateBodyStatement () { // // Delegate obj1 = backing_field // do { // Delegate obj2 = obj1; // obj1 = Interlocked.CompareExchange (ref backing_field, Delegate.Combine|Remove(obj2, value), obj1); // } while ((object)obj1 != (object)obj2) // var field_info = ((EventField) method).backing_field; FieldExpr f_expr = new FieldExpr (field_info, Location); if (!IsStatic) f_expr.InstanceExpression = new CompilerGeneratedThis (Parent.CurrentType, Location); var obj1 = LocalVariable.CreateCompilerGenerated (field_info.MemberType, block, Location); var obj2 = LocalVariable.CreateCompilerGenerated (field_info.MemberType, block, Location); block.AddStatement (new StatementExpression (new SimpleAssign (new LocalVariableReference (obj1, Location), f_expr))); var cond = new BooleanExpression (new Binary (Binary.Operator.Inequality, new Cast (new TypeExpression (Module.Compiler.BuiltinTypes.Object, Location), new LocalVariableReference (obj1, Location), Location), new Cast (new TypeExpression (Module.Compiler.BuiltinTypes.Object, Location), new LocalVariableReference (obj2, Location), Location))); var body = new ExplicitBlock (block, Location, Location); block.AddStatement (new Do (body, cond, Location, Location)); body.AddStatement (new StatementExpression ( new SimpleAssign (new LocalVariableReference (obj2, Location), new LocalVariableReference (obj1, Location)))); var args_oper = new Arguments (2); args_oper.Add (new Argument (new LocalVariableReference (obj2, Location))); args_oper.Add (new Argument (block.GetParameterReference (0, Location))); var op_method = GetOperation (Location); var args = new Arguments (3); args.Add (new Argument (f_expr, Argument.AType.Ref)); args.Add (new Argument (new Cast ( new TypeExpression (field_info.MemberType, Location), new Invocation (MethodGroupExpr.CreatePredefined (op_method, op_method.DeclaringType, Location), args_oper), Location))); args.Add (new Argument (new LocalVariableReference (obj1, Location))); var cas = Module.PredefinedMembers.InterlockedCompareExchange_T.Resolve (Location); if (cas == null) return; body.AddStatement (new StatementExpression (new SimpleAssign ( new LocalVariableReference (obj1, Location), new Invocation (MethodGroupExpr.CreatePredefined (cas, cas.DeclaringType, Location), args)))); }
protected override Expression DoResolve (ResolveContext rc) { target = new FieldExpr (field, loc); source = rc.CurrentBlock.ParametersBlock.GetParameterInfo (parameter).CreateReferenceExpression (rc, loc); return base.DoResolve (rc); }
void ResolveStringSwitchMap (EmitContext ec) { FullNamedExpression string_dictionary_type; #if GMCS_SOURCE MemberAccess system_collections_generic = new MemberAccess (new MemberAccess ( new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc), "Generic", loc); string_dictionary_type = new MemberAccess (system_collections_generic, "Dictionary", new TypeArguments ( new TypeExpression (TypeManager.string_type, loc), new TypeExpression (TypeManager.int32_type, loc)), loc); #else MemberAccess system_collections_generic = new MemberAccess ( new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc); string_dictionary_type = new MemberAccess (system_collections_generic, "Hashtable", loc); #endif Field field = new Field (ec.TypeContainer, string_dictionary_type, Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, new MemberName (CompilerGeneratedClass.MakeName (null, "f", "switch$map", unique_counter++), loc), null); if (!field.Define ()) return; ec.TypeContainer.PartialContainer.AddField (field); ArrayList init = new ArrayList (); int counter = 0; Elements.Clear (); string value = null; foreach (SwitchSection section in Sections) { foreach (SwitchLabel sl in section.Labels) { if (sl.Label == null || sl.Converted == SwitchLabel.NullStringCase) { value = null; continue; } value = (string) sl.Converted; ArrayList init_args = new ArrayList (2); init_args.Add (new StringLiteral (value, sl.Location)); init_args.Add (new IntConstant (counter, loc)); init.Add (new CollectionElementInitializer (init_args, loc)); } if (value == null) continue; Elements.Add (counter, section.Labels [0]); ++counter; } ArrayList args = new ArrayList (1); args.Add (new Argument (new IntConstant (Sections.Count, loc))); Expression initializer = new NewInitialize (string_dictionary_type, args, new CollectionOrObjectInitializers (init, loc), loc); switch_cache_field = new FieldExpr (field.FieldBuilder, loc); string_dictionary = new SimpleAssign (switch_cache_field, initializer.Resolve (ec)); }
void CreateAutomaticProperty () { // Create backing field Field field = new BackingField (this); if (!field.Define ()) return; Parent.PartialContainer.AddField (field); FieldExpr fe = new FieldExpr (field, Location); if ((field.ModFlags & Modifiers.STATIC) == 0) fe.InstanceExpression = new CompilerGeneratedThis (fe.Type, Location); // Create get block Get.Block = new ToplevelBlock (Compiler, ParametersCompiled.EmptyReadOnlyParameters, Location); Return r = new Return (fe, Location); Get.Block.AddStatement (r); // Create set block Set.Block = new ToplevelBlock (Compiler, Set.ParameterInfo, Location); Assign a = new SimpleAssign (fe, new SimpleName ("value", Location)); Set.Block.AddStatement (new StatementExpression (a)); }
protected void EmitCall (EmitContext ec, Expression binder, Arguments arguments, bool isStatement) { // // This method generates all internal infrastructure for a dynamic call. The // reason why it's quite complicated is the mixture of dynamic and anonymous // methods. Dynamic itself requires a temporary class (ContainerX) and anonymous // methods can generate temporary storey as well (AnonStorey). Handling MVAR // type parameters rewrite is non-trivial in such case as there are various // combinations possible therefore the mutator is not straightforward. Secondly // we need to keep both MVAR(possibly VAR for anon storey) and type VAR to emit // correct Site field type and its access from EmitContext. // int dyn_args_count = arguments == null ? 0 : arguments.Count; int default_args = isStatement ? 1 : 2; var module = ec.Module; bool has_ref_out_argument = false; var targs = new TypeExpression[dyn_args_count + default_args]; targs[0] = new TypeExpression (module.PredefinedTypes.CallSite.TypeSpec, loc); TypeExpression[] targs_for_instance = null; TypeParameterMutator mutator; var site_container = ec.CreateDynamicSite (); if (context_mvars != null) { TypeParameters tparam; TypeContainer sc = site_container; do { tparam = sc.CurrentTypeParameters; sc = sc.Parent; } while (tparam == null); mutator = new TypeParameterMutator (context_mvars, tparam); if (!ec.IsAnonymousStoreyMutateRequired) { targs_for_instance = new TypeExpression[targs.Length]; targs_for_instance[0] = targs[0]; } } else { mutator = null; } for (int i = 0; i < dyn_args_count; ++i) { Argument a = arguments[i]; if (a.ArgType == Argument.AType.Out || a.ArgType == Argument.AType.Ref) has_ref_out_argument = true; var t = a.Type; // Convert any internal type like dynamic or null to object if (t.Kind == MemberKind.InternalCompilerType) t = ec.BuiltinTypes.Object; if (targs_for_instance != null) targs_for_instance[i + 1] = new TypeExpression (t, loc); if (mutator != null) t = t.Mutate (mutator); targs[i + 1] = new TypeExpression (t, loc); } TypeExpr del_type = null; TypeExpr del_type_instance_access = null; if (!has_ref_out_argument) { string d_name = isStatement ? "Action" : "Func"; TypeSpec te = null; Namespace type_ns = module.GlobalRootNamespace.GetNamespace ("System", true); if (type_ns != null) { te = type_ns.LookupType (module, d_name, dyn_args_count + default_args, LookupMode.Normal, loc); } if (te != null) { if (!isStatement) { var t = type; if (t.Kind == MemberKind.InternalCompilerType) t = ec.BuiltinTypes.Object; if (targs_for_instance != null) targs_for_instance[targs_for_instance.Length - 1] = new TypeExpression (t, loc); if (mutator != null) t = t.Mutate (mutator); targs[targs.Length - 1] = new TypeExpression (t, loc); } del_type = new GenericTypeExpr (te, new TypeArguments (targs), loc); if (targs_for_instance != null) del_type_instance_access = new GenericTypeExpr (te, new TypeArguments (targs_for_instance), loc); else del_type_instance_access = del_type; } } // // Create custom delegate when no appropriate predefined delegate has been found // Delegate d; if (del_type == null) { TypeSpec rt = isStatement ? ec.BuiltinTypes.Void : type; Parameter[] p = new Parameter[dyn_args_count + 1]; p[0] = new Parameter (targs[0], "p0", Parameter.Modifier.NONE, null, loc); var site = ec.CreateDynamicSite (); int index = site.Containers == null ? 0 : site.Containers.Count; if (mutator != null) rt = mutator.Mutate (rt); for (int i = 1; i < dyn_args_count + 1; ++i) { p[i] = new Parameter (targs[i], "p" + i.ToString ("X"), arguments[i - 1].Modifier, null, loc); } d = new Delegate (site, new TypeExpression (rt, loc), Modifiers.INTERNAL | Modifiers.COMPILER_GENERATED, new MemberName ("Container" + index.ToString ("X")), new ParametersCompiled (p), null); d.CreateContainer (); d.DefineContainer (); d.Define (); d.PrepareEmit (); site.AddTypeContainer (d); // // Add new container to inflated site container when the // member cache already exists // if (site.CurrentType is InflatedTypeSpec && index > 0) site.CurrentType.MemberCache.AddMember (d.CurrentType); del_type = new TypeExpression (d.CurrentType, loc); if (targs_for_instance != null) { del_type_instance_access = null; } else { del_type_instance_access = del_type; } } else { d = null; } var site_type_decl = new GenericTypeExpr (module.PredefinedTypes.CallSiteGeneric.TypeSpec, new TypeArguments (del_type), loc); var field = site_container.CreateCallSiteField (site_type_decl, loc); if (field == null) return; if (del_type_instance_access == null) { var dt = d.CurrentType.DeclaringType.MakeGenericType (module, context_mvars.Types); del_type_instance_access = new TypeExpression (MemberCache.GetMember (dt, d.CurrentType), loc); } var instanceAccessExprType = new GenericTypeExpr (module.PredefinedTypes.CallSiteGeneric.TypeSpec, new TypeArguments (del_type_instance_access), loc); if (instanceAccessExprType.ResolveAsType (ec.MemberContext) == null) return; bool inflate_using_mvar = context_mvars != null && ec.IsAnonymousStoreyMutateRequired; TypeSpec gt; if (inflate_using_mvar || context_mvars == null) { gt = site_container.CurrentType; } else { gt = site_container.CurrentType.MakeGenericType (module, context_mvars.Types); } // When site container already exists the inflated version has to be // updated manually to contain newly created field if (gt is InflatedTypeSpec && site_container.AnonymousMethodsCounter > 1) { var tparams = gt.MemberDefinition.TypeParametersCount > 0 ? gt.MemberDefinition.TypeParameters : TypeParameterSpec.EmptyTypes; var inflator = new TypeParameterInflator (module, gt, tparams, gt.TypeArguments); gt.MemberCache.AddMember (field.InflateMember (inflator)); } FieldExpr site_field_expr = new FieldExpr (MemberCache.GetMember (gt, field), loc); BlockContext bc = new BlockContext (ec.MemberContext, null, ec.BuiltinTypes.Void); Arguments args = new Arguments (1); args.Add (new Argument (binder)); StatementExpression s = new StatementExpression (new SimpleAssign (site_field_expr, new Invocation (new MemberAccess (instanceAccessExprType, "Create"), args))); using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) { var conditionalAccessReceiver = IsConditionalAccessReceiver; var ca = ec.ConditionalAccess; if (conditionalAccessReceiver) { ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ()) { Statement = isStatement }; // // Emit conditional access expressions before dynamic call // is initialized. It pushes site_field_expr on stack before // the actual instance argument is emited which would cause // jump from non-empty stack. // EmitConditionalAccess (ec); } if (s.Resolve (bc)) { Statement init = new If (new Binary (Binary.Operator.Equality, site_field_expr, new NullLiteral (loc)), s, loc); init.Emit (ec); } args = new Arguments (1 + dyn_args_count); args.Add (new Argument (site_field_expr)); if (arguments != null) { int arg_pos = 1; foreach (Argument a in arguments) { if (a is NamedArgument) { // Name is not valid in this context args.Add (new Argument (a.Expr, a.ArgType)); } else { args.Add (a); } if (inflate_using_mvar && a.Type != targs[arg_pos].Type) a.Expr.Type = targs[arg_pos].Type; ++arg_pos; } } var target = new DelegateInvocation (new MemberAccess (site_field_expr, "Target", loc).Resolve (bc), args, false, loc).Resolve (bc); if (target != null) { target.Emit (ec); } if (conditionalAccessReceiver) { ec.CloseConditionalAccess (!isStatement && type.IsNullableType ? type : null); ec.ConditionalAccess = ca; } } }
protected void EmitCallWithInvoke (EmitContext ec, Expression binder, Arguments arguments, bool isStatement) { var module = ec.Module; var site_container = ec.CreateDynamicSite (); BlockContext bc = new BlockContext (ec.MemberContext, null, ec.BuiltinTypes.Void); FieldExpr site_field_expr = null; StatementExpression s = null; // create call site var call_site = binder; if (call_site != null) { // resolve call site call_site = call_site.Resolve(bc); // create field for call site var site_type_decl = call_site.Type; var field = site_container.CreateCallSiteField (new TypeExpression(site_type_decl, loc), loc); if (field == null) { throw new InvalidOperationException("Could not create call site field"); } // ??? bool inflate_using_mvar = context_mvars != null && ec.IsAnonymousStoreyMutateRequired; // ??? TypeSpec gt; if (inflate_using_mvar || context_mvars == null) { gt = site_container.CurrentType; } else { gt = site_container.CurrentType.MakeGenericType (module, context_mvars.Types); } // When site container already exists the inflated version has to be // updated manually to contain newly created field if (gt is InflatedTypeSpec && site_container.AnonymousMethodsCounter > 1) { var tparams = gt.MemberDefinition.TypeParametersCount > 0 ? gt.MemberDefinition.TypeParameters : TypeParameterSpec.EmptyTypes; var inflator = new TypeParameterInflator (module, gt, tparams, gt.TypeArguments); gt.MemberCache.AddMember (field.InflateMember (inflator)); } site_field_expr = new FieldExpr (MemberCache.GetMember (gt, field), loc); s = new StatementExpression (new SimpleAssign (site_field_expr, call_site)); } using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) { if (s!= null && s.Resolve (bc)) { Statement init = new If (new Binary (Binary.Operator.Equality, site_field_expr, new NullLiteral (loc)), s, loc); init.Emit (ec); } // remove dynamics from argument list arguments.CastDynamicArgs(bc); IDynamicCallSite dynamicCallSite = (IDynamicCallSite)this.binder; Expression target = dynamicCallSite.InvokeCallSite(bc, site_field_expr, arguments, type, isStatement); if (target != null) target = target.Resolve(bc); if (target != null) { var statement = target as ExpressionStatement; if (isStatement && statement != null) { statement.EmitStatement(ec); } else { if (!isStatement && (target.Type != type)) { // PlayScript: If doing an invoke, we have to cast the return type to the type expected by the expression.. target = new Cast(new TypeExpression(type, loc), target, loc).Resolve (bc); } target.Emit(ec); } } } }
void EmitHoistedFieldsInitialization (ResolveContext rc, EmitContext ec) { // // Initialize all storey reference fields by using local or hoisted variables // if (used_parent_storeys != null) { foreach (StoreyFieldPair sf in used_parent_storeys) { // // Get instance expression of storey field // Expression instace_expr = GetStoreyInstanceExpression (ec); var fs = sf.Field.Spec; if (TypeManager.IsGenericType (instace_expr.Type)) fs = MemberCache.GetMember (instace_expr.Type, fs); FieldExpr f_set_expr = new FieldExpr (fs, Location); f_set_expr.InstanceExpression = instace_expr; // TODO: CompilerAssign expression SimpleAssign a = new SimpleAssign (f_set_expr, sf.Storey.GetStoreyInstanceExpression (ec)); if (a.Resolve (rc) != null) a.EmitStatement (ec); } } // // Initialize hoisted `this' only once, everywhere else will be // referenced indirectly // if (initialize_hoisted_this) { rc.CurrentBlock.AddScopeStatement (new ThisInitializer (hoisted_this)); } // // Setting currect anonymous method to null blocks any further variable hoisting // AnonymousExpression ae = ec.CurrentAnonymousMethod; ec.CurrentAnonymousMethod = null; if (hoisted_params != null) { EmitHoistedParameters (ec, hoisted_params); } ec.CurrentAnonymousMethod = ae; }
void FabricateBodyStatement() { var cas = TypeManager.gen_interlocked_compare_exchange; if (cas == null) { var t = Module.PredefinedTypes.Interlocked.Resolve (Location); if (t == null) return; var p = new ParametersImported ( new[] { new ParameterData (null, Parameter.Modifier.REF), new ParameterData (null, Parameter.Modifier.NONE), new ParameterData (null, Parameter.Modifier.NONE) }, new[] { new TypeParameterSpec (0, null, SpecialConstraint.None, Variance.None, null), new TypeParameterSpec (0, null, SpecialConstraint.None, Variance.None, null), new TypeParameterSpec (0, null, SpecialConstraint.None, Variance.None, null), }, false); var filter = new MemberFilter ("CompareExchange", 1, MemberKind.Method, p, null); cas = TypeManager.gen_interlocked_compare_exchange = TypeManager.GetPredefinedMethod (t, filter, Location); } // // Delegate obj1 = backing_field // do { // Delegate obj2 = obj1; // obj1 = Interlocked.CompareExchange (ref backing_field, Delegate.Combine|Remove(obj2, value), obj1); // } while (obj1 != obj2) // var field_info = ((EventField) method).backing_field; FieldExpr f_expr = new FieldExpr (field_info, Location); if (!IsStatic) f_expr.InstanceExpression = new CompilerGeneratedThis (Parent.CurrentType, Location); var obj1 = LocalVariable.CreateCompilerGenerated (field_info.MemberType, block, Location); var obj2 = LocalVariable.CreateCompilerGenerated (field_info.MemberType, block, Location); block.AddStatement (new StatementExpression (new SimpleAssign (new LocalVariableReference (obj1, Location), f_expr))); var cond = new BooleanExpression (new Binary (Binary.Operator.Inequality, new LocalVariableReference (obj1, Location), new LocalVariableReference (obj2, Location), Location)); var body = new ExplicitBlock (block, Location, Location); block.AddStatement (new Do (body, cond, Location)); body.AddStatement (new StatementExpression ( new SimpleAssign (new LocalVariableReference (obj2, Location), new LocalVariableReference (obj1, Location)))); var args_oper = new Arguments (2); args_oper.Add (new Argument (new LocalVariableReference (obj2, Location))); args_oper.Add (new Argument (block.GetParameterReference (0, Location))); var args = new Arguments (3); args.Add (new Argument (f_expr, Argument.AType.Ref)); args.Add (new Argument (new Cast ( new TypeExpression (field_info.MemberType, Location), new Invocation (MethodGroupExpr.CreatePredefined (Operation, Operation.DeclaringType, Location), args_oper), Location))); args.Add (new Argument (new LocalVariableReference (obj1, Location))); body.AddStatement (new StatementExpression (new SimpleAssign ( new LocalVariableReference (obj1, Location), new Invocation (MethodGroupExpr.CreatePredefined (cas, cas.DeclaringType, Location), args)))); }
// // Emits the instance field initializers // public bool EmitFieldInitializers (EmitContext ec) { ArrayList fields; ILGenerator ig = ec.ig; Expression instance_expr; if (ec.IsStatic){ fields = initialized_static_fields; instance_expr = null; } else { fields = initialized_fields; instance_expr = new This (Location.Null).Resolve (ec); } if (fields == null) return true; foreach (Field f in fields){ Expression e = f.GetInitializerExpression (ec); if (e == null) return false; Location l = f.Location; FieldExpr fe = new FieldExpr (f.FieldBuilder, l); fe.InstanceExpression = instance_expr; Expression a = new Assign (fe, e, l); a = a.Resolve (ec); if (a == null) return false; if (a is ExpressionStatement) ((ExpressionStatement) a).EmitStatement (ec); else { throw new Exception ("Assign.Resolve returned a non ExpressionStatement"); } } return true; }
public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original) { // // If the event is local to this class, we transform ourselves into a FieldExpr // if (EventInfo.DeclaringType == ec.ContainerType || TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) { EventField mi = TypeManager.GetEventField (EventInfo); if (mi != null) { if (!ec.IsInObsoleteScope) mi.CheckObsoleteness (loc); if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment) Error_AssignmentEventOnly (); FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc); InstanceExpression = null; return ml.ResolveMemberAccess (ec, left, loc, original); } } if (left is This && !ec.IsInCompoundAssignment) Error_AssignmentEventOnly (); return base.ResolveMemberAccess (ec, left, loc, original); }
public override bool Resolve (BlockContext ec) { TypeExpression storey_type_expr = new TypeExpression (host.Definition, loc); List<Expression> init = null; if (host.hoisted_this != null) { init = new List<Expression> (host.hoisted_params == null ? 1 : host.HoistedParameters.Count + 1); HoistedThis ht = host.hoisted_this; FieldExpr from = new FieldExpr (ht.Field, loc); from.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc); init.Add (new ElementInitializer (ht.Field.Name, from, loc)); } if (host.hoisted_params != null) { if (init == null) init = new List<Expression> (host.HoistedParameters.Count); for (int i = 0; i < host.hoisted_params.Count; ++i) { HoistedParameter hp = (HoistedParameter) host.hoisted_params [i]; HoistedParameter hp_cp = (HoistedParameter) host.hoisted_params_copy [i]; FieldExpr from = new FieldExpr (hp_cp.Field, loc); from.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc); init.Add (new ElementInitializer (hp.Field.Name, from, loc)); } } if (init != null) { new_storey = new NewInitialize (storey_type_expr, null, new CollectionOrObjectInitializers (init, loc), loc); } else { new_storey = new New (storey_type_expr, null, loc); } new_storey = new_storey.Resolve (ec); if (new_storey != null) new_storey = Convert.ImplicitConversionRequired (ec, new_storey, host_method.MemberType, loc); ec.CurrentBranching.CurrentUsageVector.Goto (); return true; }
// // Creates field access expression for hoisted variable // protected FieldExpr GetFieldExpression (EmitContext ec) { if (ec.CurrentAnonymousMethod == null || ec.CurrentAnonymousMethod.Storey == null) { if (cached_outer_access != null) return cached_outer_access; // // When setting top-level hoisted variable in generic storey // change storey generic types to method generic types (VAR -> MVAR) // cached_outer_access = storey.MemberName.IsGeneric ? new FieldExpr (field.FieldBuilder, storey.Instance.Type, field.Location) : new FieldExpr (field.FieldBuilder, field.Location); cached_outer_access.InstanceExpression = storey.GetStoreyInstanceExpression (ec); return cached_outer_access; } FieldExpr inner_access; if (cached_inner_access != null) { inner_access = (FieldExpr) cached_inner_access [ec.CurrentAnonymousMethod]; } else { inner_access = null; cached_inner_access = new Hashtable (4); } if (inner_access == null) { inner_access = field.Parent.MemberName.IsGeneric ? new FieldExpr (field.FieldBuilder, field.Parent.CurrentType, field.Location) : new FieldExpr (field.FieldBuilder, field.Location); inner_access.InstanceExpression = storey.GetStoreyInstanceExpression (ec); cached_inner_access.Add (ec.CurrentAnonymousMethod, inner_access); } return inner_access; }
public override bool Resolve (BlockContext ec) { TypeExpression storey_type_expr = new TypeExpression (host.TypeBuilder, loc); ArrayList init = null; if (host.hoisted_this != null) { init = new ArrayList (host.hoisted_params == null ? 1 : host.HoistedParameters.Count + 1); HoistedThis ht = host.hoisted_this; FieldExpr from = new FieldExpr (ht.Field.FieldBuilder, loc); from.InstanceExpression = CompilerGeneratedThis.Instance; init.Add (new ElementInitializer (ht.Field.Name, from, loc)); } if (host.hoisted_params != null) { if (init == null) init = new ArrayList (host.HoistedParameters.Count); for (int i = 0; i < host.hoisted_params.Count; ++i) { HoistedParameter hp = (HoistedParameter) host.hoisted_params [i]; HoistedParameter hp_cp = (HoistedParameter) host.hoisted_params_copy [i]; FieldExpr from = new FieldExpr (hp_cp.Field.FieldBuilder, loc); from.InstanceExpression = CompilerGeneratedThis.Instance; init.Add (new ElementInitializer (hp.Field.Name, from, loc)); } } if (init != null) { new_storey = new NewInitialize (storey_type_expr, null, new CollectionOrObjectInitializers (init, loc), loc); } else { new_storey = new New (storey_type_expr, null, loc); } new_storey = new_storey.Resolve (ec); if (new_storey != null) new_storey = Convert.ImplicitConversionRequired (ec, new_storey, host_method.MemberType, loc); if (TypeManager.int_interlocked_compare_exchange == null) { Type t = TypeManager.CoreLookupType (ec.Compiler, "System.Threading", "Interlocked", Kind.Class, true); if (t != null) { TypeManager.int_interlocked_compare_exchange = TypeManager.GetPredefinedMethod ( t, "CompareExchange", loc, TypeManager.int32_type, TypeManager.int32_type, TypeManager.int32_type); } } ec.CurrentBranching.CurrentUsageVector.Goto (); return true; }
public override MemberExpr ResolveMemberAccess(ResolveContext ec, Expression left, Location loc, SimpleName original) { // // If the event is local to this class, we transform ourselves into a FieldExpr // if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf(ec.CurrentType, spec.DeclaringType)) { // TODO: Breaks dynamic binder as currect context fields are imported and not compiled EventField mi = spec.MemberDefinition as EventField; if (mi != null && mi.HasBackingField) { mi.SetIsUsed (); if (!ec.IsObsolete) mi.CheckObsoleteness (loc); if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) Error_AssignmentEventOnly (ec); FieldExpr ml = new FieldExpr (mi.BackingField, loc); InstanceExpression = null; return ml.ResolveMemberAccess (ec, left, loc, original); } } if (left is This && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) Error_AssignmentEventOnly (ec); return base.ResolveMemberAccess (ec, left, loc, original); }
public override void Emit (DeclSpace parent) { if ((method.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) == 0) { if (parent is Class) { MethodBuilder mb = method_data.MethodBuilder; mb.SetImplementationFlags (mb.GetMethodImplementationFlags () | MethodImplAttributes.Synchronized); } var field_info = ((EventField) method).backing_field; FieldExpr f_expr = new FieldExpr (field_info, Location); if ((method.ModFlags & Modifiers.STATIC) == 0) f_expr.InstanceExpression = new CompilerGeneratedThis (field_info.Spec.MemberType, Location); block = new ToplevelBlock (Compiler, ParameterInfo, Location); block.AddStatement (new StatementExpression ( new CompoundAssign (Operation, f_expr, block.GetParameterReference (ParameterInfo[0].Name, Location), Location))); } base.Emit (parent); }
public void EmitPrologue(EmitContext ec) { var fe_awaiter = new FieldExpr(awaiter, loc); fe_awaiter.InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, loc); // // awaiter = expr.GetAwaiter (); // fe_awaiter.EmitAssign(ec, expr, false, false); Label skip_continuation = ec.DefineLabel(); Expression completed_expr; if (IsDynamic) { var rc = new ResolveContext(ec.MemberContext); Arguments dargs = new Arguments(1); dargs.Add(new Argument(fe_awaiter)); completed_expr = new DynamicMemberBinder("IsCompleted", dargs, loc).Resolve(rc); } else { var pe = PropertyExpr.CreatePredefined(is_completed, loc); pe.InstanceExpression = fe_awaiter; completed_expr = pe; } completed_expr.EmitBranchable(ec, skip_continuation, true); base.DoEmit(ec); // // The stack has to be empty before calling await continuation. We handle this // by lifting values which would be left on stack into class fields. The process // is quite complicated and quite hard to test because any expression can possibly // leave a value on the stack. // // Following assert fails when some of expression called before is missing EmitToField // or parent expression fails to find await in children expressions // ec.AssertEmptyStack(); var args = new Arguments(1); var storey = (AsyncTaskStorey)machine_initializer.Storey; var fe_cont = new FieldExpr(storey.Continuation, loc); fe_cont.InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, loc); args.Add(new Argument(fe_cont)); if (IsDynamic) { var rc = new ResolveContext(ec.MemberContext); var mg_expr = new Invocation(new MemberAccess(fe_awaiter, "OnCompleted"), args).Resolve(rc); ExpressionStatement es = (ExpressionStatement)mg_expr; es.EmitStatement(ec); } else { var mg_completed = MethodGroupExpr.CreatePredefined(on_completed, fe_awaiter.Type, loc); mg_completed.InstanceExpression = fe_awaiter; // // awaiter.OnCompleted (continuation); // mg_completed.EmitCall(ec, args); } // Return ok machine_initializer.EmitLeave(ec, unwind_protect); ec.MarkLabel(resume_point); ec.MarkLabel(skip_continuation); }
protected void EmitCall(EmitContext ec, Expression binder, Arguments arguments, bool isStatement) { // // This method generates all internal infrastructure for a dynamic call. The // reason why it's quite complicated is the mixture of dynamic and anonymous // methods. Dynamic itself requires a temporary class (ContainerX) and anonymous // methods can generate temporary storey as well (AnonStorey). Handling MVAR // type parameters rewrite is non-trivial in such case as there are various // combinations possible therefore the mutator is not straightforward. Secondly // we need to keep both MVAR(possibly VAR for anon storey) and type VAR to emit // correct Site field type and its access from EmitContext. // int dyn_args_count = arguments == null ? 0 : arguments.Count; int default_args = isStatement ? 1 : 2; var module = ec.Module; bool has_ref_out_argument = false; var targs = new TypeExpression[dyn_args_count + default_args]; targs[0] = new TypeExpression(module.PredefinedTypes.CallSite.TypeSpec, loc); TypeExpression[] targs_for_instance = null; TypeParameterMutator mutator; var site_container = ec.CreateDynamicSite(); if (context_mvars != null) { TypeParameters tparam; TypeContainer sc = site_container; do { tparam = sc.CurrentTypeParameters; sc = sc.Parent; } while (tparam == null); mutator = new TypeParameterMutator(context_mvars, tparam); if (!ec.IsAnonymousStoreyMutateRequired) { targs_for_instance = new TypeExpression[targs.Length]; targs_for_instance[0] = targs[0]; } } else { mutator = null; } for (int i = 0; i < dyn_args_count; ++i) { Argument a = arguments[i]; if (a.ArgType == Argument.AType.Out || a.ArgType == Argument.AType.Ref) { has_ref_out_argument = true; } var t = a.Type; // Convert any internal type like dynamic or null to object if (t.Kind == MemberKind.InternalCompilerType) { t = ec.BuiltinTypes.Object; } if (targs_for_instance != null) { targs_for_instance[i + 1] = new TypeExpression(t, loc); } if (mutator != null) { t = t.Mutate(mutator); } targs[i + 1] = new TypeExpression(t, loc); } TypeExpr del_type = null; TypeExpr del_type_instance_access = null; if (!has_ref_out_argument) { string d_name = isStatement ? "Action" : "Func"; TypeSpec te = null; Namespace type_ns = module.GlobalRootNamespace.GetNamespace("System", true); if (type_ns != null) { te = type_ns.LookupType(module, d_name, dyn_args_count + default_args, LookupMode.Normal, loc); } if (te != null) { if (!isStatement) { var t = type; if (t.Kind == MemberKind.InternalCompilerType) { t = ec.BuiltinTypes.Object; } if (targs_for_instance != null) { targs_for_instance[targs_for_instance.Length - 1] = new TypeExpression(t, loc); } if (mutator != null) { t = t.Mutate(mutator); } targs[targs.Length - 1] = new TypeExpression(t, loc); } del_type = new GenericTypeExpr(te, new TypeArguments(targs), loc); if (targs_for_instance != null) { del_type_instance_access = new GenericTypeExpr(te, new TypeArguments(targs_for_instance), loc); } else { del_type_instance_access = del_type; } } } // // Create custom delegate when no appropriate predefined delegate has been found // Delegate d; if (del_type == null) { TypeSpec rt = isStatement ? ec.BuiltinTypes.Void : type; Parameter[] p = new Parameter[dyn_args_count + 1]; p[0] = new Parameter(targs[0], "p0", Parameter.Modifier.NONE, null, loc); var site = ec.CreateDynamicSite(); int index = site.Containers == null ? 0 : site.Containers.Count; if (mutator != null) { rt = mutator.Mutate(rt); } for (int i = 1; i < dyn_args_count + 1; ++i) { p[i] = new Parameter(targs[i], "p" + i.ToString("X"), arguments[i - 1].Modifier, null, loc); } d = new Delegate(site, new TypeExpression(rt, loc), Modifiers.INTERNAL | Modifiers.COMPILER_GENERATED, new MemberName("Container" + index.ToString("X")), new ParametersCompiled(p), null); d.CreateContainer(); d.DefineContainer(); d.Define(); d.PrepareEmit(); site.AddTypeContainer(d); // // Add new container to inflated site container when the // member cache already exists // if (site.CurrentType is InflatedTypeSpec && index > 0) { site.CurrentType.MemberCache.AddMember(d.CurrentType); } del_type = new TypeExpression(d.CurrentType, loc); if (targs_for_instance != null) { del_type_instance_access = null; } else { del_type_instance_access = del_type; } } else { d = null; } var site_type_decl = new GenericTypeExpr(module.PredefinedTypes.CallSiteGeneric.TypeSpec, new TypeArguments(del_type), loc); var field = site_container.CreateCallSiteField(site_type_decl, loc); if (field == null) { return; } if (del_type_instance_access == null) { var dt = d.CurrentType.DeclaringType.MakeGenericType(module, context_mvars.Types); del_type_instance_access = new TypeExpression(MemberCache.GetMember(dt, d.CurrentType), loc); } var instanceAccessExprType = new GenericTypeExpr(module.PredefinedTypes.CallSiteGeneric.TypeSpec, new TypeArguments(del_type_instance_access), loc); if (instanceAccessExprType.ResolveAsType(ec.MemberContext) == null) { return; } bool inflate_using_mvar = context_mvars != null && ec.IsAnonymousStoreyMutateRequired; TypeSpec gt; if (inflate_using_mvar || context_mvars == null) { gt = site_container.CurrentType; } else { gt = site_container.CurrentType.MakeGenericType(module, context_mvars.Types); } // When site container already exists the inflated version has to be // updated manually to contain newly created field if (gt is InflatedTypeSpec && site_container.AnonymousMethodsCounter > 1) { var tparams = gt.MemberDefinition.TypeParametersCount > 0 ? gt.MemberDefinition.TypeParameters : TypeParameterSpec.EmptyTypes; var inflator = new TypeParameterInflator(module, gt, tparams, gt.TypeArguments); gt.MemberCache.AddMember(field.InflateMember(inflator)); } FieldExpr site_field_expr = new FieldExpr(MemberCache.GetMember(gt, field), loc); BlockContext bc = new BlockContext(ec.MemberContext, null, ec.BuiltinTypes.Void); Arguments args = new Arguments(1); args.Add(new Argument(binder)); StatementExpression s = new StatementExpression(new SimpleAssign(site_field_expr, new Invocation(new MemberAccess(instanceAccessExprType, "Create"), args))); using (ec.With(BuilderContext.Options.OmitDebugInfo, true)) { if (s.Resolve(bc)) { Statement init = new If(new Binary(Binary.Operator.Equality, site_field_expr, new NullLiteral(loc)), s, loc); init.Emit(ec); } args = new Arguments(1 + dyn_args_count); args.Add(new Argument(site_field_expr)); if (arguments != null) { int arg_pos = 1; foreach (Argument a in arguments) { if (a is NamedArgument) { // Name is not valid in this context args.Add(new Argument(a.Expr, a.ArgType)); } else { args.Add(a); } if (inflate_using_mvar && a.Type != targs[arg_pos].Type) { a.Expr.Type = targs[arg_pos].Type; } ++arg_pos; } } Expression target = new DelegateInvocation(new MemberAccess(site_field_expr, "Target", loc).Resolve(bc), args, loc).Resolve(bc); if (target != null) { target.Emit(ec); } } }
protected override Expression DoResolve(ResolveContext rc) { target = new FieldExpr(field, loc); source = rc.CurrentBlock.ParametersBlock.GetParameterInfo(parameter).CreateReferenceExpression(rc, loc); return(base.DoResolve(rc)); }
protected override void DoEmit (EmitContext ec) { Expression source; if (parent == null) source = new CompilerGeneratedThis (ec.CurrentType, loc); else { source = new FieldExpr (parent.HoistedThis.Field, Location.Null) { InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, Location.Null) }; } hoisted_this.EmitAssign (ec, source, false, false); }
public override bool Resolve(BlockContext ec) { TypeExpression storey_type_expr = new TypeExpression(host.Definition, loc); List <Expression> init = null; if (host.hoisted_this != null) { init = new List <Expression> (host.hoisted_params == null ? 1 : host.HoistedParameters.Count + 1); HoistedThis ht = host.hoisted_this; FieldExpr from = new FieldExpr(ht.Field, loc); from.InstanceExpression = CompilerGeneratedThis.Instance; init.Add(new ElementInitializer(ht.Field.Name, from, loc)); } if (host.hoisted_params != null) { if (init == null) { init = new List <Expression> (host.HoistedParameters.Count); } for (int i = 0; i < host.hoisted_params.Count; ++i) { HoistedParameter hp = (HoistedParameter)host.hoisted_params [i]; HoistedParameter hp_cp = (HoistedParameter)host.hoisted_params_copy [i]; FieldExpr from = new FieldExpr(hp_cp.Field, loc); from.InstanceExpression = CompilerGeneratedThis.Instance; init.Add(new ElementInitializer(hp.Field.Name, from, loc)); } } if (init != null) { new_storey = new NewInitialize(storey_type_expr, null, new CollectionOrObjectInitializers(init, loc), loc); } else { new_storey = new New(storey_type_expr, null, loc); } new_storey = new_storey.Resolve(ec); if (new_storey != null) { new_storey = Convert.ImplicitConversionRequired(ec, new_storey, host_method.MemberType, loc); } var t = ec.Module.PredefinedTypes.Interlocked.Resolve(loc); if (t != null) { var p = new ParametersImported( new[] { new ParameterData(null, Parameter.Modifier.REF), new ParameterData(null, Parameter.Modifier.NONE), new ParameterData(null, Parameter.Modifier.NONE) }, new[] { TypeManager.int32_type, TypeManager.int32_type, TypeManager.int32_type }, false); var f = new MemberFilter("CompareExchange", 0, MemberKind.Method, p, TypeManager.int32_type); TypeManager.int_interlocked_compare_exchange = TypeManager.GetPredefinedMethod(t, f, loc); } ec.CurrentBranching.CurrentUsageVector.Goto(); return(true); }
public override bool Resolve(BlockContext ec) { TypeExpression storey_type_expr = new TypeExpression (host.Definition, loc); List<Expression> init = null; if (host.hoisted_this != null) { init = new List<Expression> (host.hoisted_params == null ? 1 : host.HoistedParameters.Count + 1); HoistedThis ht = host.hoisted_this; FieldExpr from = new FieldExpr (ht.Field, loc); from.InstanceExpression = CompilerGeneratedThis.Instance; init.Add (new ElementInitializer (ht.Field.Name, from, loc)); } if (host.hoisted_params != null) { if (init == null) init = new List<Expression> (host.HoistedParameters.Count); for (int i = 0; i < host.hoisted_params.Count; ++i) { HoistedParameter hp = (HoistedParameter) host.hoisted_params [i]; HoistedParameter hp_cp = (HoistedParameter) host.hoisted_params_copy [i]; FieldExpr from = new FieldExpr (hp_cp.Field, loc); from.InstanceExpression = CompilerGeneratedThis.Instance; init.Add (new ElementInitializer (hp.Field.Name, from, loc)); } } if (init != null) { new_storey = new NewInitialize (storey_type_expr, null, new CollectionOrObjectInitializers (init, loc), loc); } else { new_storey = new New (storey_type_expr, null, loc); } new_storey = new_storey.Resolve (ec); if (new_storey != null) new_storey = Convert.ImplicitConversionRequired (ec, new_storey, host_method.MemberType, loc); if (TypeManager.int_interlocked_compare_exchange == null) { TypeSpec t = TypeManager.CoreLookupType (ec.Compiler, "System.Threading", "Interlocked", MemberKind.Class, true); if (t != null) { var p = ParametersCompiled.CreateFullyResolved ( new[] { new ParameterData (null, Parameter.Modifier.REF), new ParameterData (null, Parameter.Modifier.NONE), new ParameterData (null, Parameter.Modifier.NONE) }, new[] { TypeManager.int32_type, TypeManager.int32_type, TypeManager.int32_type } ); var f = new MemberFilter ("CompareExchange", 0, MemberKind.Method, p, TypeManager.int32_type); TypeManager.int_interlocked_compare_exchange = TypeManager.GetPredefinedMethod (t, f, loc); } } ec.CurrentBranching.CurrentUsageVector.Goto (); return true; }
protected override bool DoDefineMembers() { PredefinedType builder_type; PredefinedMember <MethodSpec> bf; PredefinedMember <MethodSpec> bs; PredefinedMember <MethodSpec> sr; PredefinedMember <MethodSpec> se; PredefinedMember <MethodSpec> sm; bool has_task_return_type = false; var pred_members = Module.PredefinedMembers; if (return_type.Kind == MemberKind.Void) { builder_type = Module.PredefinedTypes.AsyncVoidMethodBuilder; bf = pred_members.AsyncVoidMethodBuilderCreate; bs = pred_members.AsyncVoidMethodBuilderStart; sr = pred_members.AsyncVoidMethodBuilderSetResult; se = pred_members.AsyncVoidMethodBuilderSetException; sm = pred_members.AsyncVoidMethodBuilderSetStateMachine; } else if (return_type == Module.PredefinedTypes.Task.TypeSpec) { builder_type = Module.PredefinedTypes.AsyncTaskMethodBuilder; bf = pred_members.AsyncTaskMethodBuilderCreate; bs = pred_members.AsyncTaskMethodBuilderStart; sr = pred_members.AsyncTaskMethodBuilderSetResult; se = pred_members.AsyncTaskMethodBuilderSetException; sm = pred_members.AsyncTaskMethodBuilderSetStateMachine; task = pred_members.AsyncTaskMethodBuilderTask.Get(); } else { builder_type = Module.PredefinedTypes.AsyncTaskMethodBuilderGeneric; bf = pred_members.AsyncTaskMethodBuilderGenericCreate; bs = pred_members.AsyncTaskMethodBuilderGenericStart; sr = pred_members.AsyncTaskMethodBuilderGenericSetResult; se = pred_members.AsyncTaskMethodBuilderGenericSetException; sm = pred_members.AsyncTaskMethodBuilderGenericSetStateMachine; task = pred_members.AsyncTaskMethodBuilderGenericTask.Get(); has_task_return_type = true; } set_result = sr.Get(); set_exception = se.Get(); builder_factory = bf.Get(); builder_start = bs.Get(); var istate_machine = Module.PredefinedTypes.IAsyncStateMachine; var set_statemachine = sm.Get(); if (!builder_type.Define() || !istate_machine.Define() || set_result == null || builder_factory == null || set_exception == null || set_statemachine == null || builder_start == null || !Module.PredefinedTypes.INotifyCompletion.Define()) { Report.Error(1993, Location, "Cannot find compiler required types for asynchronous functions support. Are you targeting the wrong framework version?"); return(base.DoDefineMembers()); } var bt = builder_type.TypeSpec; // // Inflate generic Task types // if (has_task_return_type) { var task_return_type = return_type.TypeArguments; if (mutator != null) { task_return_type = mutator.Mutate(task_return_type); } bt = bt.MakeGenericType(Module, task_return_type); set_result = MemberCache.GetMember(bt, set_result); set_exception = MemberCache.GetMember(bt, set_exception); set_statemachine = MemberCache.GetMember(bt, set_statemachine); if (task != null) { task = MemberCache.GetMember(bt, task); } } builder = AddCompilerGeneratedField("$builder", new TypeExpression(bt, Location)); Field rfield; if (has_task_return_type && HasAwaitInsideFinally) { // // Special case async block with return value from finally clause. In such case // we rewrite all return expresison stores to stfld to $return. Instead of treating // returns outside of finally and inside of finally differently. // rfield = AddCompilerGeneratedField("$return", new TypeExpression(bt.TypeArguments [0], Location)); } else { rfield = null; } var set_state_machine = new Method(this, new TypeExpression(Compiler.BuiltinTypes.Void, Location), Modifiers.COMPILER_GENERATED | Modifiers.DEBUGGER_HIDDEN | Modifiers.PUBLIC, new MemberName("SetStateMachine"), ParametersCompiled.CreateFullyResolved( new Parameter(new TypeExpression(istate_machine.TypeSpec, Location), "stateMachine", Parameter.Modifier.NONE, null, Location), istate_machine.TypeSpec), null); ToplevelBlock block = new ToplevelBlock(Compiler, set_state_machine.ParameterInfo, Location); block.IsCompilerGenerated = true; set_state_machine.Block = block; Members.Add(set_state_machine); if (!base.DoDefineMembers()) { return(false); } // // Fabricates SetStateMachine method // // public void SetStateMachine (IAsyncStateMachine stateMachine) // { // $builder.SetStateMachine (stateMachine); // } // var mg = MethodGroupExpr.CreatePredefined(set_statemachine, bt, Location); mg.InstanceExpression = new FieldExpr(builder, Location); var param_reference = block.GetParameterReference(0, Location); param_reference.Type = istate_machine.TypeSpec; param_reference.eclass = ExprClass.Variable; var args = new Arguments(1); args.Add(new Argument(param_reference)); set_state_machine.Block.AddStatement(new StatementExpression(new Invocation(mg, args))); if (has_task_return_type) { if (rfield != null) { HoistedReturnValue = new FieldExpr(rfield, Location) { InstanceExpression = new CompilerGeneratedThis(CurrentType, Location.Null) }; } else { HoistedReturnValue = TemporaryVariableReference.Create(bt.TypeArguments [0], StateMachineMethod.Block, Location); } } return(true); }
void CreateAutomaticProperty () { // Create backing field Field field = new BackingField (this); if (!field.Define ()) return; Parent.PartialContainer.Members.Add (field); FieldExpr fe = new FieldExpr (field, Location); if ((field.ModFlags & Modifiers.STATIC) == 0) fe.InstanceExpression = new CompilerGeneratedThis (Parent.CurrentType, Location); // // Create get block but we careful with location to // emit only single sequence point per accessor. This allow // to set a breakpoint on it even with no user code // Get.Block = new ToplevelBlock (Compiler, ParametersCompiled.EmptyReadOnlyParameters, Location.Null); Return r = new Return (fe, Get.Location); Get.Block.AddStatement (r); // Create set block Set.Block = new ToplevelBlock (Compiler, Set.ParameterInfo, Location.Null); Assign a = new SimpleAssign (fe, new SimpleName ("value", Location.Null), Location.Null); Set.Block.AddStatement (new StatementExpression (a, Set.Location)); }
void CreateAutomaticProperty () { // Create backing field backing_field = new BackingField (this, Initializer != null && Set == null); if (!backing_field.Define ()) return; if (Initializer != null) { backing_field.Initializer = Initializer; Parent.RegisterFieldForInitialization (backing_field, new FieldInitializer (backing_field, Initializer, Location)); backing_field.ModFlags |= Modifiers.READONLY; } Parent.PartialContainer.Members.Add (backing_field); FieldExpr fe = new FieldExpr (backing_field, Location); if ((backing_field.ModFlags & Modifiers.STATIC) == 0) fe.InstanceExpression = new CompilerGeneratedThis (Parent.CurrentType, Location); // // Create get block but we careful with location to // emit only single sequence point per accessor. This allow // to set a breakpoint on it even with no user code // Get.Block = new ToplevelBlock (Compiler, ParametersCompiled.EmptyReadOnlyParameters, Location.Null); Return r = new Return (fe, Get.Location); Get.Block.AddStatement (r); Get.ModFlags |= Modifiers.COMPILER_GENERATED; // Create set block if (Set != null) { Set.Block = new ToplevelBlock (Compiler, Set.ParameterInfo, Location.Null); Assign a = new SimpleAssign (fe, new SimpleName ("value", Location.Null), Location.Null); Set.Block.AddStatement (new StatementExpression (a, Set.Location)); Set.ModFlags |= Modifiers.COMPILER_GENERATED; } }
public void EmitAssign(EmitContext ec, FieldExpr field) { stmt.EmitPrologue(ec); field.InstanceExpression.Emit(ec); stmt.Emit(ec); }
// // Creates storey instance expression regardless of currect IP // public Expression GetStoreyInstanceExpression (EmitContext ec) { AnonymousExpression am = ec.CurrentAnonymousMethod; // // Access from original block -> storey // if (am == null) return Instance; // // Access from anonymous method implemented as a static -> storey // if (am.Storey == null) return Instance; Field f = am.Storey.GetReferencedStoreyField (this); if (f == null) { if (am.Storey == this) { // // Access from inside of same storey (S -> S) // return new CompilerGeneratedThis (CurrentType, Location); } // // External field access // return Instance; } // // Storey was cached to local field // FieldExpr f_ind = new FieldExpr (f, Location); f_ind.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location); return f_ind; }
public void EmitPrologue(EmitContext ec) { awaiter = ((AsyncTaskStorey)machine_initializer.Storey).AddAwaiter(expr.Type); var fe_awaiter = new FieldExpr(awaiter, loc); fe_awaiter.InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, loc); Label skip_continuation = ec.DefineLabel(); using (ec.With(BuilderContext.Options.OmitDebugInfo, true)) { // // awaiter = expr.GetAwaiter (); // fe_awaiter.EmitAssign(ec, expr, false, false); Expression completed_expr; if (IsDynamic) { var rc = new ResolveContext(ec.MemberContext); Arguments dargs = new Arguments(1); dargs.Add(new Argument(fe_awaiter)); completed_expr = new DynamicMemberBinder("IsCompleted", dargs, loc).Resolve(rc); dargs = new Arguments(1); dargs.Add(new Argument(completed_expr)); completed_expr = new DynamicConversion(ec.Module.Compiler.BuiltinTypes.Bool, 0, dargs, loc).Resolve(rc); } else { var pe = PropertyExpr.CreatePredefined(awaiter_definition.IsCompleted, loc); pe.InstanceExpression = fe_awaiter; completed_expr = pe; } completed_expr.EmitBranchable(ec, skip_continuation, true); } base.DoEmit(ec); // // The stack has to be empty before calling await continuation. We handle this // by lifting values which would be left on stack into class fields. The process // is quite complicated and quite hard to test because any expression can possibly // leave a value on the stack. // // Following assert fails when some of expression called before is missing EmitToField // or parent expression fails to find await in children expressions // ec.AssertEmptyStack(); var storey = (AsyncTaskStorey)machine_initializer.Storey; if (IsDynamic) { storey.EmitAwaitOnCompletedDynamic(ec, fe_awaiter); } else { storey.EmitAwaitOnCompleted(ec, fe_awaiter); } // Return ok machine_initializer.EmitLeave(ec, unwind_protect); ec.MarkLabel(resume_point); ec.MarkLabel(skip_continuation); }
public void EmitPrologue(EmitContext ec) { var fe_awaiter = new FieldExpr(awaiter, loc); fe_awaiter.InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, loc); // // awaiter = expr.GetAwaiter (); // fe_awaiter.EmitAssign(ec, expr, false, false); Label skip_continuation = ec.DefineLabel(); is_completed.InstanceExpression = fe_awaiter; is_completed.EmitBranchable(ec, skip_continuation, true); base.DoEmit(ec); FieldSpec[] stack_fields = null; TypeSpec[] stack = null; // // Here is the clever bit. We know that await statement has to yield the control // back but it can appear inside almost any expression. This means the stack can // contain any depth of values and same values have to be present when the continuation // handles control back. // // For example: await a + await b // // In this case we fabricate a static stack forwarding method which moves the values // from the stack to async storey fields. On re-entry point we restore exactly same // stack using these fields. // // We fabricate a static method because we don't want to touch original stack and // the instance method would require `this' as the first stack value on the stack // if (ec.StackHeight > 0) { var async_storey = (AsyncTaskStorey)machine_initializer.Storey; stack = ec.GetStackTypes(); var method = async_storey.GetStackForwarder(stack, out stack_fields); ec.EmitThis(); ec.Emit(OpCodes.Call, method); } var mg_completed = MethodGroupExpr.CreatePredefined(on_completed, fe_awaiter.Type, loc); mg_completed.InstanceExpression = fe_awaiter; var args = new Arguments(1); var storey = (AsyncTaskStorey)machine_initializer.Storey; var fe_cont = new FieldExpr(storey.Continuation, loc); fe_cont.InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, loc); args.Add(new Argument(fe_cont)); // // awaiter.OnCompleted (continuation); // mg_completed.EmitCall(ec, args); // Return ok machine_initializer.EmitLeave(ec, unwind_protect); ec.MarkLabel(resume_point); if (stack_fields != null) { for (int i = 0; i < stack_fields.Length; ++i) { ec.EmitThis(); var field = stack_fields[i]; // // We don't store `this' because it can be easily re-created // if (field == null) { continue; } if (stack[i] is ReferenceContainer) { ec.Emit(OpCodes.Ldflda, field); } else { ec.Emit(OpCodes.Ldfld, field); } } } ec.MarkLabel(skip_continuation); }
// // Initializes all hoisted variables // public void EmitStoreyInstantiation (EmitContext ec, ExplicitBlock block) { // There can be only one instance variable for each storey type if (Instance != null) throw new InternalErrorException (); // // Create an instance of this storey // ResolveContext rc = new ResolveContext (ec.MemberContext); rc.CurrentBlock = block; var storey_type_expr = CreateStoreyTypeExpression (ec); var source = new New (storey_type_expr, null, Location).Resolve (rc); // // When the current context is async (or iterator) lift local storey // instantiation to the currect storey // if (ec.CurrentAnonymousMethod is StateMachineInitializer && (block.HasYield || block.HasAwait)) { // // Unfortunately, normal capture mechanism could not be used because we are // too late in the pipeline and standart assign cannot be used either due to // recursive nature of GetStoreyInstanceExpression // var field = ec.CurrentAnonymousMethod.Storey.AddCompilerGeneratedField ( LocalVariable.GetCompilerGeneratedName (block), storey_type_expr, true); field.Define (); field.Emit (); var fexpr = new FieldExpr (field, Location); fexpr.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, Location); fexpr.EmitAssign (ec, source, false, false); Instance = fexpr; } else { var local = TemporaryVariableReference.Create (source.Type, block, Location); if (source.Type.IsStruct) { local.LocalInfo.CreateBuilder (ec); } else { local.EmitAssign (ec, source); } Instance = local; } EmitHoistedFieldsInitialization (rc, ec); // TODO: Implement properly //SymbolWriter.DefineScopeVariable (ID, Instance.Builder); }
void EmitHoistedFieldsInitialization (ResolveContext rc, EmitContext ec) { // // Initialize all storey reference fields by using local or hoisted variables // if (used_parent_storeys != null) { foreach (StoreyFieldPair sf in used_parent_storeys) { // // Get instance expression of storey field // Expression instace_expr = GetStoreyInstanceExpression (ec); var fs = sf.Field.Spec; if (TypeManager.IsGenericType (instace_expr.Type)) fs = MemberCache.GetMember (instace_expr.Type, fs); FieldExpr f_set_expr = new FieldExpr (fs, Location); f_set_expr.InstanceExpression = instace_expr; SimpleAssign a = new SimpleAssign (f_set_expr, sf.Storey.GetStoreyInstanceExpression (ec)); if (a.Resolve (rc) != null) a.EmitStatement (ec); } } // // Define hoisted `this' in top-level storey only // if (OriginalSourceBlock.Explicit.HasCapturedThis && !(Parent is AnonymousMethodStorey)) { AddCapturedThisField (ec); rc.CurrentBlock.AddScopeStatement (new ThisInitializer (hoisted_this)); } // // Setting currect anonymous method to null blocks any further variable hoisting // AnonymousExpression ae = ec.CurrentAnonymousMethod; ec.CurrentAnonymousMethod = null; if (hoisted_params != null) { EmitHoistedParameters (ec, hoisted_params); } ec.CurrentAnonymousMethod = ae; }
protected virtual void EmitHoistedParameters (EmitContext ec, List<HoistedParameter> hoisted) { foreach (HoistedParameter hp in hoisted) { // // Parameters could be proxied via local fields for value type storey // if (hoisted_local_params != null) { var local_param = hoisted_local_params.Find (l => l.Parameter.Parameter == hp.Parameter.Parameter); var source = new FieldExpr (local_param.Field, Location); source.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location); hp.EmitAssign (ec, source, false, false); continue; } hp.EmitHoistingAssignment (ec); } }
// // Creates temporary field in current async storey // public FieldExpr GetTemporaryField (TypeSpec type) { var f = AsyncTaskStorey.AddCapturedLocalVariable (type); var fexpr = new FieldExpr (f, Location.Null); fexpr.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location.Null); return fexpr; }
// // Creates field access expression for hoisted variable // protected virtual FieldExpr GetFieldExpression (EmitContext ec) { if (ec.CurrentAnonymousMethod == null || ec.CurrentAnonymousMethod.Storey == null) { if (cached_outer_access != null) return cached_outer_access; // // When setting top-level hoisted variable in generic storey // change storey generic types to method generic types (VAR -> MVAR) // if (storey.Instance.Type.IsGenericOrParentIsGeneric) { var fs = MemberCache.GetMember (storey.Instance.Type, field.Spec); cached_outer_access = new FieldExpr (fs, field.Location); } else { cached_outer_access = new FieldExpr (field, field.Location); } cached_outer_access.InstanceExpression = storey.GetStoreyInstanceExpression (ec); return cached_outer_access; } FieldExpr inner_access; if (cached_inner_access != null) { if (!cached_inner_access.TryGetValue (ec.CurrentAnonymousMethod, out inner_access)) inner_access = null; } else { inner_access = null; cached_inner_access = new Dictionary<AnonymousExpression, FieldExpr> (4); } if (inner_access == null) { if (field.Parent.IsGenericOrParentIsGeneric) { var fs = MemberCache.GetMember (field.Parent.CurrentType, field.Spec); inner_access = new FieldExpr (fs, field.Location); } else { inner_access = new FieldExpr (field, field.Location); } inner_access.InstanceExpression = storey.GetStoreyInstanceExpression (ec); cached_inner_access.Add (ec.CurrentAnonymousMethod, inner_access); } return inner_access; }
void ResolveStringSwitchMap (ResolveContext ec) { FullNamedExpression string_dictionary_type; if (TypeManager.generic_ienumerable_type != null) { MemberAccess system_collections_generic = new MemberAccess (new MemberAccess ( new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc), "Generic", loc); string_dictionary_type = new MemberAccess (system_collections_generic, "Dictionary", new TypeArguments ( new TypeExpression (TypeManager.string_type, loc), new TypeExpression (TypeManager.int32_type, loc)), loc); } else { MemberAccess system_collections_generic = new MemberAccess ( new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc); string_dictionary_type = new MemberAccess (system_collections_generic, "Hashtable", loc); } var ctype = ec.CurrentMemberDefinition.Parent.PartialContainer; Field field = new Field (ctype, string_dictionary_type, Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, new MemberName (CompilerGeneratedClass.MakeName (null, "f", "switch$map", unique_counter++), loc), null); if (!field.Define ()) return; ctype.AddField (field); var init = new List<Expression> (); int counter = 0; Elements.Clear (); string value = null; foreach (SwitchSection section in Sections) { int last_count = init.Count; foreach (SwitchLabel sl in section.Labels) { if (sl.Label == null || sl.Converted == SwitchLabel.NullStringCase) continue; value = (string) sl.Converted; var init_args = new List<Expression> (2); init_args.Add (new StringLiteral (value, sl.Location)); init_args.Add (new IntConstant (counter, loc)); init.Add (new CollectionElementInitializer (init_args, loc)); } // // Don't add empty sections // if (last_count == init.Count) continue; Elements.Add (counter, section.Labels [0]); ++counter; } Arguments args = new Arguments (1); args.Add (new Argument (new IntConstant (init.Count, loc))); Expression initializer = new NewInitialize (string_dictionary_type, args, new CollectionOrObjectInitializers (init, loc), loc); switch_cache_field = new FieldExpr (field, loc); string_dictionary = new SimpleAssign (switch_cache_field, initializer.Resolve (ec)); }