private void GenerateGeneratorMethod(CodeGenerator cg) { Debug.Assert(this.IsGeneratorMethod()); var genSymbol = new SourceGeneratorSymbol(this); var il = cg.Builder; /* Template: * return BuildGenerator( <ctx>, this, new PhpArray(){ p1, p2, ... }, new GeneratorStateMachineDelegate((IntPtr)<genSymbol>), (RuntimeMethodHandle)this ) */ cg.EmitLoadContext(); // ctx for generator cg.EmitThisOrNull(); // @this for generator // new PhpArray for generator's locals cg.EmitCall(ILOpCode.Newobj, cg.CoreMethods.Ctors.PhpArray); var generatorsLocals = cg.GetTemporaryLocal(cg.CoreTypes.PhpArray); cg.Builder.EmitLocalStore(generatorsLocals); // initialize parameters (set their _isOptimized and copy them to locals array) InitializeParametersForGeneratorMethod(cg, il, generatorsLocals); cg.Builder.EmitLoad(generatorsLocals); cg.ReturnTemporaryLocal(generatorsLocals); // new PhpArray for generator's synthesizedLocals cg.EmitCall(ILOpCode.Newobj, cg.CoreMethods.Ctors.PhpArray); // new GeneratorStateMachineDelegate(<genSymbol>) delegate for generator cg.Builder.EmitNullConstant(); // null cg.EmitOpCode(ILOpCode.Ldftn); // method cg.EmitSymbolToken(genSymbol, null); cg.EmitCall(ILOpCode.Newobj, cg.CoreTypes.GeneratorStateMachineDelegate.Ctor(cg.CoreTypes.Object, cg.CoreTypes.IntPtr)); // GeneratorStateMachineDelegate(object @object, IntPtr method) // handleof(this) cg.EmitLoadToken(this, null); // create generator object via Operators factory method cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.BuildGenerator_Context_Object_PhpArray_PhpArray_GeneratorStateMachineDelegate_RuntimeMethodHandle); // .UseDynamicScope( scope ) : Generator if (this is SourceLambdaSymbol lambda) { lambda.GetCallerTypePlace().EmitLoad(cg.Builder); // RuntimeTypeContext cg.EmitCall(ILOpCode.Call, cg.CoreTypes.Operators.Method("UseDynamicScope", cg.CoreTypes.Generator, cg.CoreTypes.RuntimeTypeHandle)) .Expect(cg.CoreTypes.Generator); } // Convert to return type (Generator or PhpValue, depends on analysis) cg.EmitConvert(cg.CoreTypes.Generator, 0, this.ReturnType); il.EmitRet(false); // Generate SM method. Must be generated after EmitInit of parameters (it sets their _isUnoptimized field). CreateStateMachineNextMethod(cg, genSymbol); }
public virtual void Generate(CodeGenerator cg) { if (!this.IsGeneratorMethod()) { //Proceed with normal method generation cg.GenerateScope(this.ControlFlowGraph.Start, int.MaxValue); } else { var genSymbol = new SourceGeneratorSymbol(this); var il = cg.Builder; /* Template: * return BuildGenerator( <ctx>, this, new PhpArray(){ p1, p2, ... }, new GeneratorStateMachineDelegate((IntPtr)<genSymbol>), (RuntimeMethodHandle)this ) */ cg.EmitLoadContext(); // ctx for generator cg.EmitThisOrNull(); // @this for generator // new PhpArray for generator's locals cg.EmitCall(ILOpCode.Newobj, cg.CoreMethods.Ctors.PhpArray); var generatorsLocals = cg.GetTemporaryLocal(cg.CoreTypes.PhpArray); cg.Builder.EmitLocalStore(generatorsLocals); // initialize parameters (set their _isOptimized and copy them to locals array) InitializeParametersForGeneratorMethod(cg, il, generatorsLocals); cg.Builder.EmitLoad(generatorsLocals); cg.ReturnTemporaryLocal(generatorsLocals); // new PhpArray for generator's synthesizedLocals cg.EmitCall(ILOpCode.Newobj, cg.CoreMethods.Ctors.PhpArray); // new GeneratorStateMachineDelegate(<genSymbol>) delegate for generator cg.Builder.EmitNullConstant(); // null cg.EmitOpCode(ILOpCode.Ldftn); // method cg.EmitSymbolToken(genSymbol, null); cg.EmitCall(ILOpCode.Newobj, cg.CoreTypes.GeneratorStateMachineDelegate.Ctor(cg.CoreTypes.Object, cg.CoreTypes.IntPtr)); // GeneratorStateMachineDelegate(object @object, IntPtr method) // handleof(this) cg.EmitLoadToken(this, null); // create generator object via Operators factory method cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.BuildGenerator_Context_Object_PhpArray_PhpArray_GeneratorStateMachineDelegate_RuntimeMethodHandle); // Convert to return type (Generator or PhpValue, depends on analysis) cg.EmitConvert(cg.CoreTypes.Generator, 0, this.ReturnType); il.EmitRet(false); // Generate SM method. Must be generated after EmitInit of parameters (it sets their _isUnoptimized field). CreateStateMachineNextMethod(cg, genSymbol); } }
private void CreateStateMachineNextMethod(CodeGenerator cg, SourceGeneratorSymbol genSymbol) { cg.Module.SynthesizedManager.AddMethod(ContainingType, genSymbol); // save method symbol to module // generate generator's next method body var genMethodBody = MethodGenerator.GenerateMethodBody(cg.Module, genSymbol, (_il) => { GenerateStateMachinesNextMethod(cg, _il, genSymbol); } , null, cg.Diagnostics, cg.EmitPdbSequencePoints); cg.Module.SetMethodBody(genSymbol, genMethodBody); }
//Initialized a new CodeGenerator for generation of SourceGeneratorSymbol (state machine's next method) private void GenerateStateMachinesNextMethod(CodeGenerator cg, Microsoft.CodeAnalysis.CodeGen.ILBuilder _il, SourceGeneratorSymbol genSymbol) { // TODO: get correct ThisPlace, ReturnType etc. resolution & binding out of the box without GN_SGS hacks // using SourceGeneratorSymbol //Refactor parameters references to proper fields using (var stateMachineNextCg = new CodeGenerator( _il, cg.Module, cg.Diagnostics, cg.DeclaringCompilation.Options.OptimizationLevel, cg.EmitPdbSequencePoints, this.ContainingType, contextPlace: new ParamPlace(genSymbol.ContextParameter), thisPlace: new ParamPlace(genSymbol.ThisParameter), routine: this, locals: new ParamPlace(genSymbol.LocalsParameter), localsInitialized: true, tempLocals: new ParamPlace(genSymbol.TmpLocalsParameter) ) { GeneratorStateMachineMethod = genSymbol, // Pass SourceGeneratorSymbol to CG for additional yield and StartBlock emit }) { stateMachineNextCg.GenerateScope(this.ControlFlowGraph.Start, int.MaxValue); } }
private void GenerateGeneratorMethod(CodeGenerator cg) { Debug.Assert(this.IsGeneratorMethod()); var genSymbol = new SourceGeneratorSymbol(this); //var genConstructed = (genSymbol.ContainingType is SourceTraitTypeSymbol st) // ? genSymbol.AsMember(st.Construct(st.TypeArguments)) // : genSymbol; var il = cg.Builder; var lambda = this as SourceLambdaSymbol; /* Template: * return BuildGenerator( <ctx>, new PhpArray(){ p1, p2, ... }, new GeneratorStateMachineDelegate((IntPtr)<genSymbol>), (RuntimeMethodHandle)this ) */ cg.EmitLoadContext(); // ctx for generator // new PhpArray for generator's locals cg.EmitCall(ILOpCode.Newobj, cg.CoreMethods.Ctors.PhpArray); var generatorsLocals = cg.GetTemporaryLocal(cg.CoreTypes.PhpArray); cg.Builder.EmitLocalStore(generatorsLocals); // initialize parameters (set their _isOptimized and copy them to locals array) InitializeParametersForGeneratorMethod(cg, il, generatorsLocals); cg.Builder.EmitLoad(generatorsLocals); cg.ReturnTemporaryLocal(generatorsLocals); // new PhpArray for generator's synthesizedLocals cg.EmitCall(ILOpCode.Newobj, cg.CoreMethods.Ctors.PhpArray); // new GeneratorStateMachineDelegate(<genSymbol>) delegate for generator cg.Builder.EmitNullConstant(); // null cg.EmitOpCode(ILOpCode.Ldftn); // method cg.EmitSymbolToken(genSymbol, null); cg.EmitCall(ILOpCode.Newobj, cg.CoreTypes.GeneratorStateMachineDelegate.Ctor(cg.CoreTypes.Object, cg.CoreTypes.IntPtr)); // GeneratorStateMachineDelegate(object @object, IntPtr method) // handleof(this) cg.EmitLoadToken(this, null); // create generator object via Operators factory method cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.BuildGenerator_Context_PhpArray_PhpArray_GeneratorStateMachineDelegate_RuntimeMethodHandle); // .SetGeneratorThis( object ) : Generator if (!this.IsStatic || (lambda != null && lambda.UseThis)) { GetPhpThisVariablePlaceWithoutGenerator(cg.Module).EmitLoad(cg.Builder); cg.EmitCastClass(cg.DeclaringCompilation.GetSpecialType(SpecialType.System_Object)); cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.SetGeneratorThis_Generator_Object) .Expect(cg.CoreTypes.Generator); } // .SetGeneratorLazyStatic( PhpTypeInfo ) : Generator if ((this.Flags & RoutineFlags.UsesLateStatic) != 0 && this.IsStatic) { cg.EmitLoadStaticPhpTypeInfo(); cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.SetGeneratorLazyStatic_Generator_PhpTypeInfo) .Expect(cg.CoreTypes.Generator); } // .SetGeneratorDynamicScope( scope ) : Generator if (lambda != null) { lambda.GetCallerTypePlace().EmitLoad(cg.Builder); // RuntimeTypeContext cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.SetGeneratorDynamicScope_Generator_RuntimeTypeHandle) .Expect(cg.CoreTypes.Generator); } // Convert to return type (Generator or PhpValue, depends on analysis) cg.EmitConvert(cg.CoreTypes.Generator, 0, this.ReturnType); il.EmitRet(false); // Generate SM method. Must be generated after EmitInit of parameters (it sets their _isUnoptimized field). CreateStateMachineNextMethod(cg, genSymbol); }
//Initialized a new CodeGenerator for generation of SourceGeneratorSymbol (state machine's next method) private void generateStateMachinesNextMethod(CodeGenerator cg, Microsoft.CodeAnalysis.CodeGen.ILBuilder _il, SourceGeneratorSymbol genSymbol) { // TODO: Pass SourceGeneratorSymbol to CG instead of this to get correct ThisPlace, ReturnType etc. resolution & binding out of the box without GN_SGS hacks // ..can't do that easily beacuse CodeGenerator accepts only SourceRoutineSymbol and SGS derives from SynthesizedMethodSymbol (shim over too general MethodSymbol) //Refactor parameters references to proper fields using (var stateMachineNextCg = new CodeGenerator( _il, cg.Module, cg.Diagnostics, cg.DeclaringCompilation.Options.OptimizationLevel, cg.EmitPdbSequencePoints, this.ContainingType, contextPlace: new ParamPlace(genSymbol.Parameters[0]), thisPlace: new ParamPlace(genSymbol.Parameters[1]), routine: this, locals: new ParamPlace(genSymbol.Parameters[2]), localsInitialized: true )) { stateMachineNextCg.GenerateScope(this.ControlFlowGraph.Start, int.MaxValue); } }