/// <summary> /// Generates ghost method body that calls <c>this</c> method. /// </summary> static void GenerateGhostBody(PEModuleBuilder module, DiagnosticBag diagnostic, MethodSymbol method, SynthesizedMethodSymbol ghost) { var containingtype = ghost.ContainingType; var body = MethodGenerator.GenerateMethodBody(module, ghost, (il) => { // $this var thisPlace = ghost.HasThis ? new ArgPlace(containingtype, 0) : null; // Context var ctxPlace = thisPlace != null && ghost.ContainingType is SourceTypeSymbol sourcetype ? (sourcetype.ContextStore != null ? new FieldPlace(thisPlace, sourcetype.ContextStore, module) : null) : (IPlace) new ArgPlace(module.Compilation.CoreTypes.Context, 0); // .callvirt bool callvirt = ghost.ExplicitOverride != null && ghost.ExplicitOverride.ContainingType.IsInterface; // implementing interface, otherwise we should be able to call specific method impl. non-virtually via ghost var cg = new CodeGenerator(il, module, diagnostic, module.Compilation.Options.OptimizationLevel, false, containingtype, ctxPlace, thisPlace) { DebugRoutine = ghost, }; // return (T){routine}(p0, ..., pN); cg.EmitConvert(cg.EmitForwardCall(method, ghost, callvirt: callvirt), 0, ghost.ReturnType); cg.EmitRet(ghost.ReturnType); }, null, diagnostic, false); module.SetMethodBody(ghost, body); }
/// <summary> /// Generates ghost method body that calls <c>this</c> method. /// </summary> static void GenerateGhostBody(PEModuleBuilder module, DiagnosticBag diagnostic, MethodSymbol method, SynthesizedMethodSymbol ghost) { var containingtype = ghost.ContainingType; var body = MethodGenerator.GenerateMethodBody(module, ghost, (il) => { // $this var thisPlace = ghost.HasThis ? new ArgPlace(containingtype, 0) : null; // Context var ctxPlace = thisPlace != null && ghost.ContainingType is SourceTypeSymbol sourcetype ? new FieldPlace(thisPlace, sourcetype.ContextStore) : (IPlace) new ArgPlace(module.Compilation.CoreTypes.Context, 0); var cg = new CodeGenerator(il, module, diagnostic, module.Compilation.Options.OptimizationLevel, false, containingtype, ctxPlace, thisPlace); // return (T){routine}(p0, ..., pN); cg.EmitConvert(cg.EmitForwardCall(method, ghost), 0, ghost.ReturnType); cg.EmitRet(ghost.ReturnType); }, null, diagnostic, false); module.SetMethodBody(ghost, body); }
internal override void Emit(CodeGenerator cg) { cg.EmitSequencePoint(this.PhpSyntax); var rtype = cg.Routine.ReturnType; var rvoid = rtype.SpecialType == SpecialType.System_Void; // if (this.Returned == null) { if (rvoid) { // <void> } else { // <default> cg.EmitLoadDefault(rtype, cg.Routine.ResultTypeMask); } } else { if (rvoid) { // <expr>; cg.EmitPop(this.Returned.Emit(cg)); } else { // return (T)<expr>; cg.EmitConvert(this.Returned, rtype); } } // .ret cg.EmitRet(rtype); }
void EmitInvoke(MethodSymbol invoke, Emit.PEModuleBuilder module) { if (invoke == null) { return; } module.SetMethodBody(invoke, MethodGenerator.GenerateMethodBody(module, invoke, il => { var cg = new CodeGenerator(il, module, DiagnosticBag.GetInstance(), OptimizationLevel.Release, false, this, new ParamPlace(invoke.Parameters[0]), new ArgPlace(this, 0)); //var __invoke = (MethodSymbol)GetMembers(Pchp.Syntax.Name.SpecialMethodNames.Invoke.Value).Single(s => s is MethodSymbol); // TODO: call __invoke() directly // context.Call<T>(T, TypeMethods.MagicMethods, params PhpValue[]) var call_t = cg.CoreTypes.Context.Symbol.GetMembers("Call") .OfType<MethodSymbol>() .Where(s => s.Arity == 1 && s.ParameterCount == 3 && s.Parameters[2].IsParams) .Single() .Construct(this); // return context.Call<T>(this, __invoke, args) cg.EmitLoadContext(); cg.EmitThis(); cg.Builder.EmitIntConstant((int)Core.Reflection.TypeMethods.MagicMethods.__invoke); cg.Builder.EmitLoadArgumentOpcode(2); cg.EmitCall(ILOpCode.Call, call_t); cg.EmitRet(invoke.ReturnType); }, null, DiagnosticBag.GetInstance(), false)); }
void EmitPhpCtor(MethodSymbol ctor, Emit.PEModuleBuilder module) { if (ctor == null) return; // static class Debug.Assert(ctor.MethodKind == MethodKind.Constructor); module.SetMethodBody(ctor, MethodGenerator.GenerateMethodBody(module, ctor, il => { Debug.Assert(SpecialParameterSymbol.IsContextParameter(ctor.Parameters[0])); var cg = new CodeGenerator(il, module, DiagnosticBag.GetInstance(), OptimizationLevel.Release, false, this, new ParamPlace(ctor.Parameters[0]), new ArgPlace(this, 0)); // call .phpnew var phpnew = this.InitializeInstanceMethod; cg.EmitPop(cg.EmitThisCall(phpnew, ctor)); // call __construct var phpctor = this.ResolvePhpCtor(true); cg.EmitPop(cg.EmitThisCall(phpctor, ctor)); Debug.Assert(ctor.ReturnsVoid); cg.EmitRet(ctor.ReturnType); }, null, DiagnosticBag.GetInstance(), false)); }
void EmitPhpNew(SynthesizedPhpNewMethodSymbol phpnew, Emit.PEModuleBuilder module) { if (phpnew == null) return; // static class module.SetMethodBody(phpnew, MethodGenerator.GenerateMethodBody(module, phpnew, (Action<Microsoft.CodeAnalysis.CodeGen.ILBuilder>)(il => { Debug.Assert(SpecialParameterSymbol.IsContextParameter(phpnew.Parameters[0])); var cg = new CodeGenerator(il, module, DiagnosticBag.GetInstance(), OptimizationLevel.Release, false, this, new ParamPlace(phpnew.Parameters[0]), new ArgPlace(this, 0)); // initialize <ctx> field, // if field is declared within this type var ctxField = this.ContextStore; if (ctxField != null && object.ReferenceEquals((object)ctxField.ContainingType, this)) { var ctxFieldPlace = new FieldPlace(cg.ThisPlaceOpt, (IFieldSymbol)ctxField); // Debug.Assert(<ctx> != null) cg.EmitDebugAssertNotNull(cg.ContextPlaceOpt, "Context cannot be null."); // <this>.<ctx> = <ctx> ctxFieldPlace.EmitStorePrepare(il); cg.EmitLoadContext(); ctxFieldPlace.EmitStore(il); } // initialize class fields foreach (var fld in this.GetFieldsToEmit().OfType<SourceFieldSymbol>().Where(fld => !fld.RequiresHolder && !fld.IsStatic && !fld.IsConst)) { fld.EmitInit(cg); } // base..phpnew ?? base..ctor var basenew = phpnew.BasePhpNew; Debug.Assert(basenew != null); cg.EmitPop(cg.EmitThisCall(basenew, phpnew)); Debug.Assert(phpnew.ReturnsVoid); cg.EmitRet(phpnew.ReturnType); }), null, DiagnosticBag.GetInstance(), false)); }
/// <summary> /// Generates ghost method body that calls <c>this</c> method. /// </summary> protected void GenerateGhostBody(PEModuleBuilder module, DiagnosticBag diagnostic, SynthesizedMethodSymbol ghost) { var body = MethodGenerator.GenerateMethodBody(module, ghost, (il) => { var cg = new CodeGenerator(il, module, diagnostic, OptimizationLevel.Release, false, this.ContainingType, this.GetContextPlace(), this.GetThisPlace()); // return (T){routine}(p0, ..., pN); cg.EmitConvert(cg.EmitThisCall(this, ghost), 0, ghost.ReturnType); cg.EmitRet(ghost.ReturnType); }, null, diagnostic, false); module.SetMethodBody(ghost, body); }