void GenerateFieldAccessorProperty(Emit.PEModuleBuilder module, DiagnosticBag diagnostics, SourceFieldSymbol srcf, PropertySymbol paccessor) { // module.SynthesizedManager.AddProperty(this, paccessor); // var get_body = MethodGenerator.GenerateMethodBody(module, paccessor.GetMethod, (il) => { // Template: return field; var place = new FieldPlace(new ArgPlace(this, 0), srcf.OverridenDefinition, module); place.EmitLoad(il); il.EmitRet(false); }, null, diagnostics, false); module.SetMethodBody(paccessor.GetMethod, get_body); module.SynthesizedManager.AddMethod(this, paccessor.GetMethod); // var set_body = MethodGenerator.GenerateMethodBody(module, paccessor.SetMethod, (il) => { // Template: field = value; var place = new FieldPlace(new ArgPlace(this, 0), srcf.OverridenDefinition, module); place.EmitStorePrepare(il); new ArgPlace(this, 1).EmitLoad(il); place.EmitStore(il); il.EmitRet(true); }, null, diagnostics, false); module.SetMethodBody(paccessor.SetMethod, set_body); module.SynthesizedManager.AddMethod(this, paccessor.SetMethod); }
void EmitPhpCallable(Emit.PEModuleBuilder module, DiagnosticBag diagnostics) { var __invoke = TryGetMagicInvoke(); if (__invoke == null || IsAlreadyImplemented(__invoke) || IsAlreadyImplemented(DeclaringCompilation.CoreTypes.IPhpCallable)) { // already implemented in a base class return; } // // IPhpCallable.Invoke(Context <ctx>, PhpVaue[] arguments) // var invoke = new SynthesizedMethodSymbol(this, "IPhpCallable.Invoke", false, true, DeclaringCompilation.CoreTypes.PhpValue, isfinal: false) { ExplicitOverride = (MethodSymbol)DeclaringCompilation.CoreTypes.IPhpCallable.Symbol.GetMembers("Invoke").Single(), ForwardedCall = __invoke, }; invoke.SetParameters( new SpecialParameterSymbol(invoke, DeclaringCompilation.CoreTypes.Context, SpecialParameterSymbol.ContextName, 0), new SynthesizedParameterSymbol(invoke, ArrayTypeSymbol.CreateSZArray(ContainingAssembly, DeclaringCompilation.CoreTypes.PhpValue.Symbol), 1, RefKind.None, name: "arguments", isParams: true)); module.SetMethodBody(invoke, MethodGenerator.GenerateMethodBody(module, invoke, il => { var cg = new CodeGenerator(il, module, diagnostics, module.Compilation.Options.OptimizationLevel, false, this, new ParamPlace(invoke.Parameters[0]), new ArgPlace(this, 0)) { CallerType = this, }; cg.EmitRet(cg.EmitForwardCall(__invoke, invoke, callvirt: true)); }, null, diagnostics, false)); module.SynthesizedManager.AddMethod(this, invoke); // // IPhpCallable.ToPhpValue() // var tophpvalue = new SynthesizedMethodSymbol(this, "IPhpCallable.ToPhpValue", false, true, DeclaringCompilation.CoreTypes.PhpValue, isfinal: false) { ExplicitOverride = (MethodSymbol)DeclaringCompilation.CoreTypes.IPhpCallable.Symbol.GetMembers("ToPhpValue").Single(), }; // module.SetMethodBody(tophpvalue, MethodGenerator.GenerateMethodBody(module, tophpvalue, il => { var thisPlace = new ArgPlace(this, 0); var ctxPlace = new FieldPlace(thisPlace, this.ContextStore, module); var cg = new CodeGenerator(il, module, diagnostics, module.Compilation.Options.OptimizationLevel, false, this, ctxPlace, thisPlace); // return PhpValue.FromClass(this) cg.EmitThis(); cg.EmitRet(cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.FromClass_Object)); }, null, diagnostics, false)); module.SynthesizedManager.AddMethod(this, tophpvalue); }
void EmitInit(Emit.PEModuleBuilder module) { EnsureMembers(); // void Init(Context) var tt = DeclaringCompilation.CoreTypes; var diagnostic = DiagnosticBag.GetInstance(); // override IStaticInit.Init(Context) { .. } var initMethod = new SynthesizedMethodSymbol(this, "Init", false, true, tt.Void, Accessibility.Public); initMethod.SetParameters(new SynthesizedParameterSymbol(initMethod, tt.Context, 0, RefKind.None, "ctx")); var body = MethodGenerator.GenerateMethodBody(module, initMethod, (il) => { var cg = new CodeGenerator(il, module, diagnostic, OptimizationLevel.Release, false, this, new ArgPlace(tt.Context, 1), new ArgPlace(this, 0)); GetMembers().OfType <SourceFieldSymbol>().Where(f => f.InitializerRequiresContext).ForEach(f => f.EmitInit(cg)); // il.EmitRet(true); }, null, diagnostic, false); module.SetMethodBody(initMethod, body); // _lazyMembers = _lazyMembers.Add(initMethod); }
void EmitInit(Emit.PEModuleBuilder module) { // void Init(Context) var tt = DeclaringCompilation.CoreTypes; var diagnostic = DiagnosticBag.GetInstance(); // override IStaticInit.Init(Context) { .. } var initMethod = new SynthesizedMethodSymbol(this, "Init", false, true, tt.Void, Accessibility.Public); initMethod.SetParameters(new SynthesizedParameterSymbol(initMethod, tt.Context, 0, RefKind.None, "ctx")); var body = MethodGenerator.GenerateMethodBody(module, initMethod, (il) => { var cg = new CodeGenerator(il, module, diagnostic, OptimizationLevel.Release, false, this, new ArgPlace(tt.Context, 1), new ArgPlace(this, 0)); foreach (var fld in this.Fields) { if (fld.RequiresContext) { fld.EmitInit(cg); } } // il.EmitRet(true); }, null, diagnostic, false); module.SetMethodBody(initMethod, body); module.SynthesizedManager.AddMethod(this, initMethod); }
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 EmitTraitImplementations(Emit.PEModuleBuilder module) { foreach (var t in TraitUses) { foreach (var m in t.GetMembers().OfType <SynthesizedMethodSymbol>()) { Debug.Assert(m.ForwardedCall != null); module.SetMethodBody(m, MethodGenerator.GenerateMethodBody(module, m, il => { IPlace thisPlace = null; IPlace traitInstancePlace = null; IPlace ctxPlace; if (m.IsStatic) { // Template: return TRAIT.method(...) Debug.Assert(SpecialParameterSymbol.IsContextParameter(m.Parameters[0])); ctxPlace = new ParamPlace(m.Parameters[0]); } else { // Template: return this.<>trait.method(...) thisPlace = new ArgPlace(this, 0); // this ctxPlace = new FieldPlace(thisPlace, this.ContextStore, module); // this.<ctx> traitInstancePlace = new FieldPlace(thisPlace, t.TraitInstanceField, module); // this.<>trait } using (var cg = new CodeGenerator(il, module, DiagnosticBag.GetInstance(), module.Compilation.Options.OptimizationLevel, false, this, ctxPlace, thisPlace) { CallerType = this, }) { var forwarded_type = cg.EmitForwardCall(m.ForwardedCall, m, thisPlaceExplicit: traitInstancePlace); var target_type = m.ReturnType; cg.EmitConvert(forwarded_type, 0, target_type); // always (forwarded_type === target_type) cg.EmitRet(target_type); } }, null, DiagnosticBag.GetInstance(), false)); module.SynthesizedManager.AddMethod(this, m); // NOTE: following is not needed anymore: //// ghost stubs: // ... resolve this already in SourceTypeSymbol.GetMembers(), now it does not get overloaded properly //var ps = m.Parameters; //for (int i = 0; i < ps.Length; i++) //{ // if (ps[i].HasUnmappedDefaultValue()) // => ConstantValue couldn't be resolved for optional parameter // { // // create ghost stub foo(p0, .. pi-1) => foo(p0, .. , pN) // GhostMethodBuilder.CreateGhostOverload(m, module, DiagnosticBag.GetInstance(), i); // } //} } } }
void EmitToString(Emit.PEModuleBuilder module) { if (this.IsInterface || this.IsTrait) { return; } var __tostring = this.GetMembersByPhpName(SpecialMethodNames.Tostring.Value).OfType <MethodSymbol>().FirstOrDefault(); if (__tostring != null) // implement ToString if: there is __toString() function { // lookup base string ToString() var overriden = this.LookupMember <MethodSymbol>( WellKnownMemberNames.ObjectToString, m => OverrideHelper.SignaturesMatch(m, (MethodSymbol)DeclaringCompilation.GetSpecialTypeMember(SpecialMember.System_Object__ToString))); Debug.Assert(overriden != null); if (overriden == null || overriden.IsSealed || overriden.ContainingType == this) { // cannot be overriden return; } // public sealed override string ToString() var tostring = new SynthesizedMethodSymbol(this, WellKnownMemberNames.ObjectToString, false, true, DeclaringCompilation.CoreTypes.String, Accessibility.Public, isfinal: false, phphidden: true) { ExplicitOverride = overriden, ForwardedCall = __tostring, }; module.SetMethodBody(tostring, MethodGenerator.GenerateMethodBody(module, tostring, il => { var thisPlace = new ArgPlace(this, 0); var cg = new CodeGenerator(il, module, DiagnosticBag.GetInstance(), module.Compilation.Options.OptimizationLevel, false, this, new FieldPlace(thisPlace, this.ContextStore, module), thisPlace); if (__tostring != null) { // __tostring().ToString() cg.EmitConvert(cg.EmitForwardCall(__tostring, tostring, callvirt: true), 0, tostring.ReturnType); } else { // PhpException.ObjectToStringNotSupported(this) cg.EmitThis(); cg.EmitPop(cg.EmitCall(ILOpCode.Call, cg.CoreTypes.PhpException.Method("ObjectToStringNotSupported", cg.CoreTypes.Object))); // return "" cg.Builder.EmitStringConstant(string.Empty); } cg.EmitRet(tostring.ReturnType); }, null, DiagnosticBag.GetInstance(), false)); module.SynthesizedManager.AddMethod(this, tostring); } }
void EmitPhpCtors(ImmutableArray <MethodSymbol> instancectors, Emit.PEModuleBuilder module, DiagnosticBag diagnostics) { foreach (SynthesizedPhpCtorSymbol ctor in instancectors) { module.SetMethodBody(ctor, MethodGenerator.GenerateMethodBody(module, ctor, il => { Debug.Assert(SpecialParameterSymbol.IsContextParameter(ctor.Parameters[0])); var cg = new CodeGenerator(il, module, diagnostics, OptimizationLevel.Release, false, this, new ParamPlace(ctor.Parameters[0]), new ArgPlace(this, 0)); Debug.Assert(ctor.BaseCtor != null); // base..ctor or this..ctor cg.EmitPop(cg.EmitThisCall(ctor.BaseCtor, ctor)); if (ctor.PhpConstructor == null) { // 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, 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.EnsureMembers().OfType <SourceFieldSymbol>().Where(fld => !fld.RequiresHolder && !fld.IsStatic && !fld.IsConst)) { fld.EmitInit(cg); } } else { Debug.Assert(ctor.BaseCtor.ContainingType == this); // this.__construct cg.EmitPop(cg.EmitThisCall(ctor.PhpConstructor, ctor)); } // ret Debug.Assert(ctor.ReturnsVoid); cg.EmitRet(ctor.ReturnType); }, null, diagnostics, false)); } }
public void EmitCtor(Emit.PEModuleBuilder module, Action <Microsoft.CodeAnalysis.CodeGen.ILBuilder> builder) { Debug.Assert(_ctor == null); // emit default .ctor _ctor = new SynthesizedCtorSymbol(this); _ctor.SetParameters();// empty params (default ctor) var body = CodeGen.MethodGenerator.GenerateMethodBody(module, _ctor, builder, null, DiagnosticBag.GetInstance(), false); module.SetMethodBody(_ctor, body); }
internal void EmitCtors(Emit.PEModuleBuilder module) { bool requiresInit = false; // .ctor() var tt = DeclaringCompilation.CoreTypes; var diagnostic = DiagnosticBag.GetInstance(); var ctor = new SynthesizedCtorSymbol(this); var body = MethodGenerator.GenerateMethodBody(module, ctor, (il) => { var cg = new CodeGenerator(il, module, diagnostic, module.Compilation.Options.OptimizationLevel, false, this, null, new ArgPlace(this, 0)) { CallerType = this.ContainingType, ContainingFile = _class.ContainingFile, }; // base..ctor() cg.EmitThis(); // this il.EmitCall(module, diagnostic, ILOpCode.Call, this.BaseType.InstanceConstructors.Single()); // .ctor() // foreach (var p in this.Fields.Cast <IPhpPropertySymbol>()) { if (p.RequiresContext) { requiresInit = true; } else { p.EmitInit(cg); } } // il.EmitRet(true); }, null, diagnostic, false); module.SetMethodBody(ctor, body); module.SynthesizedManager.AddMethod(this, ctor); // if (requiresInit) { EmitInit(module); } }
public void EmitInit(Emit.PEModuleBuilder module, Action <Microsoft.CodeAnalysis.CodeGen.ILBuilder> builder) { Debug.Assert(_initMethod == null); var tt = DeclaringCompilation.CoreTypes; // override IStaticInit.Init(Context) _initMethod = new SynthesizedMethodSymbol(this, "Init", false, true, tt.Void, Accessibility.Public); _initMethod.SetParameters(new SynthesizedParameterSymbol(_initMethod, tt.Context, 0, RefKind.None, "ctx")); var body = CodeGen.MethodGenerator.GenerateMethodBody(module, _initMethod, builder, null, DiagnosticBag.GetInstance(), false); module.SetMethodBody(_initMethod, body); }
internal void EmitCtors(Emit.PEModuleBuilder module) { EnsureMembers(); bool requiresInit = false; // .ctor() var tt = DeclaringCompilation.CoreTypes; var diagnostic = DiagnosticBag.GetInstance(); var ctor = new SynthesizedCtorSymbol(this); ctor.SetParameters();// empty params (default ctor) var body = MethodGenerator.GenerateMethodBody(module, ctor, (il) => { var cg = new CodeGenerator(il, module, diagnostic, OptimizationLevel.Release, false, this, null, new ArgPlace(this, 0)); foreach (var fld in GetMembers().OfType <SourceFieldSymbol>()) { if (fld.InitializerRequiresContext) { requiresInit = true; } else { fld.EmitInit(cg); } } // il.EmitRet(true); }, null, diagnostic, false); module.SetMethodBody(ctor, body); // _lazyMembers = _lazyMembers.Add(ctor); // if (requiresInit) { EmitInit(module); } }
void EmitPhpNew(SynthesizedPhpNewMethodSymbol phpnew, Emit.PEModuleBuilder module) { if (phpnew == null) { return; // static class } module.SetMethodBody(phpnew, MethodGenerator.GenerateMethodBody(module, phpnew, 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.ContextField; if (ctxField != null && object.ReferenceEquals(ctxField.ContainingType, this)) { var ctxFieldPlace = new FieldPlace(cg.ThisPlaceOpt, 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, // default(PhpValue) is not a valid value, its TypeTable must not be null foreach (var fld in this.GetFieldsToEmit().OfType <SourceFieldSymbol>().Where(fld => !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(true); }, null, DiagnosticBag.GetInstance(), false)); }
void EmitTraitImplementations(Emit.PEModuleBuilder module) { foreach (var t in TraitUses) { foreach (var m in t.GetMembers().OfType <SynthesizedMethodSymbol>()) { Debug.Assert(m.ForwardedCall != null); module.SetMethodBody(m, MethodGenerator.GenerateMethodBody(module, m, il => { IPlace thisPlace = null; IPlace traitInstancePlace = null; IPlace ctxPlace; if (m.IsStatic) { // Template: return TRAIT.method(...) Debug.Assert(SpecialParameterSymbol.IsContextParameter(m.Parameters[0])); ctxPlace = new ParamPlace(m.Parameters[0]); } else { // Template: return this.<>trait.method(...) thisPlace = new ArgPlace(this, 0); // this ctxPlace = new FieldPlace(thisPlace, this.ContextStore, module); // this.<ctx> traitInstancePlace = new FieldPlace(thisPlace, t.TraitInstanceField, module); // this.<>trait } using (var cg = new CodeGenerator(il, module, DiagnosticBag.GetInstance(), module.Compilation.Options.OptimizationLevel, false, this, ctxPlace, thisPlace) { CallerType = this, }) { var forwarded_type = cg.EmitForwardCall(m.ForwardedCall, m, thisPlaceExplicit: traitInstancePlace); var target_type = m.ReturnType; cg.EmitConvert(forwarded_type, 0, target_type); // always (forwarded_type === target_type) cg.EmitRet(target_type); } }, null, DiagnosticBag.GetInstance(), false)); module.SynthesizedManager.AddMethod(this, m); } } }
void EmitToString(Emit.PEModuleBuilder module) { if (this.IsInterface || this.IsTrait) { return; } var __tostring = this.GetMembers(SpecialMethodNames.Tostring.Value, true).OfType <MethodSymbol>().FirstOrDefault(); if (__tostring != null || this.Syntax.BaseClass == null) // implement ToString if: there is __tostring() function or ToString is not overriden yet { // public override string ToString() // Note, there might be two ToString methods with same parameters only differing by their return type, CLR allows that var tostring = new SynthesizedMethodSymbol(this, "ToString", false, true, DeclaringCompilation.CoreTypes.String, Accessibility.Public, isfinal: false) { ExplicitOverride = (MethodSymbol)DeclaringCompilation.GetSpecialTypeMember(SpecialMember.System_Object__ToString), ForwardedCall = __tostring, }; module.SetMethodBody(tostring, MethodGenerator.GenerateMethodBody(module, tostring, il => { var thisPlace = new ArgPlace(this, 0); var cg = new CodeGenerator(il, module, DiagnosticBag.GetInstance(), module.Compilation.Options.OptimizationLevel, false, this, new FieldPlace(thisPlace, this.ContextStore, module), thisPlace); if (__tostring != null) { // __tostring().ToString() cg.EmitConvert(cg.EmitForwardCall(__tostring, tostring, callvirt: true), 0, tostring.ReturnType); } else { // PhpException.ObjectToStringNotSupported(this) cg.EmitThis(); cg.EmitPop(cg.EmitCall(ILOpCode.Call, cg.CoreTypes.PhpException.Method("ObjectToStringNotSupported", cg.CoreTypes.Object))); // return "" cg.Builder.EmitStringConstant(string.Empty); } cg.EmitRet(tostring.ReturnType); }, null, DiagnosticBag.GetInstance(), false)); module.SynthesizedManager.AddMethod(this, tostring); } }
internal void EmitCtors(Emit.PEModuleBuilder module) { bool requiresInit = false; // .ctor() var tt = DeclaringCompilation.CoreTypes; var diagnostic = DiagnosticBag.GetInstance(); var ctor = new SynthesizedCtorSymbol(this); var body = MethodGenerator.GenerateMethodBody(module, ctor, (il) => { var cg = new CodeGenerator(il, module, diagnostic, OptimizationLevel.Release, false, this, null, new ArgPlace(this, 0)); foreach (var fld in this.Fields) { if (fld.RequiresContext) { requiresInit = true; } else { fld.EmitInit(cg); } } // il.EmitRet(true); }, null, diagnostic, false); module.SetMethodBody(ctor, body); module.SynthesizedManager.AddMethod(this, ctor); // if (requiresInit) { EmitInit(module); } }
void EmitInit(Emit.PEModuleBuilder module) { // void Init(Context) var tt = DeclaringCompilation.CoreTypes; var diagnostic = DiagnosticBag.GetInstance(); // override IStaticInit.Init(Context) { .. } var initMethod = new SynthesizedMethodSymbol(this, "Init", false, true, tt.Void, Accessibility.Public); initMethod.SetParameters(new SynthesizedParameterSymbol(initMethod, tt.Context, 0, RefKind.None, SpecialParameterSymbol.ContextName)); var body = MethodGenerator.GenerateMethodBody(module, initMethod, (il) => { var cg = new CodeGenerator(il, module, diagnostic, module.Compilation.Options.OptimizationLevel, false, this, new ArgPlace(tt.Context, 1), new ArgPlace(this, 0), initMethod) { CallerType = this.ContainingType, ContainingFile = _class.ContainingFile, }; foreach (var p in this.Fields.Cast <IPhpPropertySymbol>()) { if (p.RequiresContext) { p.EmitInit(cg); } } // il.EmitRet(true); }, null, diagnostic, false); module.SetMethodBody(initMethod, body); module.SynthesizedManager.AddMethod(this, initMethod); }
void EmitPhpCallable(Emit.PEModuleBuilder module, DiagnosticBag diagnostics) { var iphpcallable = DeclaringCompilation.CoreTypes.IPhpCallable; var __invoke = TryGetMagicInvoke(); if (__invoke == null || IsAlreadyImplemented(__invoke) || IsAlreadyImplemented(iphpcallable)) { // already implemented in a base class return; } // // IPhpCallable.Invoke(Context <ctx>, PhpVaue[] arguments) // var invoke = new SynthesizedMethodSymbol(this, iphpcallable.FullName + ".Invoke", false, true, DeclaringCompilation.CoreTypes.PhpValue, isfinal: true) { ExplicitOverride = (MethodSymbol)iphpcallable.Symbol.GetMembers("Invoke").Single(), ForwardedCall = __invoke, }; invoke.SetParameters( new SpecialParameterSymbol(invoke, DeclaringCompilation.CoreTypes.Context, SpecialParameterSymbol.ContextName, 0), new SynthesizedParameterSymbol(invoke, ArrayTypeSymbol.CreateSZArray(ContainingAssembly, DeclaringCompilation.CoreTypes.PhpValue.Symbol), 1, RefKind.None, name: "arguments", isParams: true)); module.SetMethodBody(invoke, MethodGenerator.GenerateMethodBody(module, invoke, il => { var cg = new CodeGenerator(il, module, diagnostics, module.Compilation.Options.OptimizationLevel, false, this, new ParamPlace(invoke.Parameters[0]), new ArgPlace(this, 0)) { CallerType = this, }; var rtype = invoke.ReturnType; // Template: return (T)__invoke() cg.EmitConvert(cg.EmitForwardCall(__invoke, invoke, callvirt: true), default, rtype);
void EmitPhpCallable(Emit.PEModuleBuilder module, DiagnosticBag diagnostics) { var __invoke = TryGetMagicInvoke(); if (__invoke == null || __invoke.OverriddenMethod != null) { return; } // // IPhpCallable.Invoke(Context, PhpVaue[]) // var invoke = new SynthesizedMethodSymbol(this, "IPhpCallable.Invoke", false, true, DeclaringCompilation.CoreTypes.PhpValue, isfinal: false) { ExplicitOverride = (MethodSymbol)DeclaringCompilation.CoreTypes.IPhpCallable.Symbol.GetMembers("Invoke").Single(), }; invoke.SetParameters( new SpecialParameterSymbol(invoke, DeclaringCompilation.CoreTypes.Context, SpecialParameterSymbol.ContextName, 0), new SynthesizedParameterSymbol(invoke, ArrayTypeSymbol.CreateSZArray(ContainingAssembly, DeclaringCompilation.CoreTypes.PhpValue.Symbol), 1, RefKind.None, "arguments")); module.SetMethodBody(invoke, MethodGenerator.GenerateMethodBody(module, invoke, il => { var cg = new CodeGenerator(il, module, diagnostics, OptimizationLevel.Release, false, this, new ParamPlace(invoke.Parameters[0]), new ArgPlace(this, 0)); var argsplace = new ParamPlace(invoke.Parameters[1]); var args_element = ((ArrayTypeSymbol)argsplace.TypeOpt).ElementType; var ps = __invoke.Parameters; // Template: this.__invoke(args[0], args[1], ...) cg.EmitThis(); for (int i = 0; i < ps.Length; i++) { var p = ps[i]; // LOAD args[i] // Template: (i < args.Length) ? (T)args[i] : default(T) var lbldefault = new NamedLabel("args_default"); var lblend = new NamedLabel("args_end"); cg.Builder.EmitIntConstant(i); // <i> argsplace.EmitLoad(cg.Builder); // <args> cg.EmitArrayLength(); // .Length cg.Builder.EmitBranch(ILOpCode.Bge, lbldefault); // (T)args[i] if (p.IsImplicitlyDeclared) { throw new NotImplementedException(); } else if (p.Type == cg.CoreTypes.PhpAlias) { // args[i].EnsureAlias() argsplace.EmitLoad(cg.Builder); // <args> cg.Builder.EmitIntConstant(i); // <i> cg.Builder.EmitOpCode(ILOpCode.Ldelema); // ref args[i] cg.EmitSymbolToken(args_element, null); cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.EnsureAlias); } else { // (T)args[i] argsplace.EmitLoad(cg.Builder); // <args> cg.Builder.EmitIntConstant(i); // <i> cg.Builder.EmitOpCode(ILOpCode.Ldelem); // args[i] cg.EmitSymbolToken(args_element, null); cg.EmitConvert(args_element, 0, p.Type); } cg.Builder.EmitBranch(ILOpCode.Br, lblend); // default(T) cg.Builder.MarkLabel(lbldefault); cg.EmitParameterDefaultValue(p); // cg.Builder.MarkLabel(lblend); } cg.EmitCall(ILOpCode.Callvirt, __invoke); cg.EmitRet(invoke.ReturnType); }, null, diagnostics, false)); module.SynthesizedManager.AddMethod(this, invoke); // // IPhpCallable.ToPhpValue() // var tophpvalue = new SynthesizedMethodSymbol(this, "IPhpCallable.ToPhpValue", false, true, DeclaringCompilation.CoreTypes.PhpValue, isfinal: false) { ExplicitOverride = (MethodSymbol)DeclaringCompilation.CoreTypes.IPhpCallable.Symbol.GetMembers("ToPhpValue").Single(), }; // module.SetMethodBody(tophpvalue, MethodGenerator.GenerateMethodBody(module, tophpvalue, il => { var thisPlace = new ArgPlace(this, 0); var cg = new CodeGenerator(il, module, diagnostics, OptimizationLevel.Release, false, this, new FieldPlace(thisPlace, this.ContextStore), thisPlace); // return PhpValue.FromClass(this) cg.EmitThis(); cg.EmitRet(cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.FromClass_Object)); }, null, diagnostics, false)); module.SynthesizedManager.AddMethod(this, tophpvalue); }
void EmitPhpCtors(ImmutableArray <MethodSymbol> instancectors, Emit.PEModuleBuilder module, DiagnosticBag diagnostics) { foreach (SynthesizedPhpCtorSymbol ctor in instancectors) { module.SetMethodBody(ctor, MethodGenerator.GenerateMethodBody(module, ctor, il => { if (ctor is SynthesizedParameterlessPhpCtorSymbol) { EmitParameterlessCtor(ctor, il, module, diagnostics); return; } Debug.Assert(SpecialParameterSymbol.IsContextParameter(ctor.Parameters[0])); var cg = new CodeGenerator(il, module, diagnostics, module.Compilation.Options.OptimizationLevel, false, this, new ParamPlace(ctor.Parameters[0]), new ArgPlace(this, 0)) { CallerType = this, ContainingFile = ContainingFile, }; Debug.Assert(ctor.BaseCtor != null); // base..ctor or this..ctor cg.EmitPop(cg.EmitForwardCall(ctor.BaseCtor, ctor)); if (ctor.PhpConstructor == null) { // 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, ctxField, module); // Debug.Assert(<ctx> != null) cg.EmitDebugAssertNotNull(cg.ContextPlaceOpt, "Context cannot be null."); // <this>.<ctx> = <ctx> ctxFieldPlace.EmitStorePrepare(il); cg.EmitLoadContext(); ctxFieldPlace.EmitStore(il); } // trait specific: if (ctor is SynthesizedPhpTraitCtorSymbol tctor) { EmitTraitCtorInit(cg, tctor); } // trait instances: foreach (var t in this.TraitUses) { EmitTraitInstanceInit(cg, ctor, t); } // initialize instance fields: foreach (var f in this.GetMembers().OfType <IPhpPropertySymbol>().Where(f => f.FieldKind == PhpPropertyKind.InstanceField)) { Debug.Assert(f.ContainingStaticsHolder == null); f.EmitInit(cg); } } else { Debug.Assert(ctor.BaseCtor.ContainingType == this); // this.__construct cg.EmitPop(cg.EmitForwardCall(ctor.PhpConstructor, ctor)); } // ret Debug.Assert(ctor.ReturnsVoid); cg.EmitRet(ctor.ReturnType); }, null, diagnostics, false)); } }
void EmitDisposable(Emit.PEModuleBuilder module, DiagnosticBag diagnostics) { var __destruct = TryGetDestruct(); if (__destruct == null || IsAlreadyImplemented(__destruct) || IsAlreadyImplemented(DeclaringCompilation.GetSpecialType(SpecialType.System_IDisposable))) { // already implemented in a base class return; } // // IDisposable.Dispose() // var dispose = new SynthesizedMethodSymbol(this, "IDisposable.Dispose", false, true, DeclaringCompilation.GetSpecialType(SpecialType.System_Void), isfinal: true) { ExplicitOverride = (MethodSymbol)DeclaringCompilation.GetSpecialTypeMember(SpecialMember.System_IDisposable__Dispose), ForwardedCall = __destruct, }; module.SetMethodBody(dispose, MethodGenerator.GenerateMethodBody(module, dispose, il => { var thisPlace = new ArgPlace(this, 0); var ctxPlace = new FieldPlace(thisPlace, this.ContextStore, module); var cg = new CodeGenerator(il, module, diagnostics, module.Compilation.Options.OptimizationLevel, false, this, ctxPlace, thisPlace) { CallerType = this, }; // private bool <>b_disposed; var disposedField = cg.Module.SynthesizedManager.GetOrCreateSynthesizedField(this, DeclaringCompilation.CoreTypes.Boolean, WellKnownPchpNames.SynthesizedDisposedFieldName, Accessibility.Private, false, false, false); var disposedPlace = new FieldPlace(thisPlace, disposedField, cg.Module); // if (<>b_disposed) return; var lblContinue = new object(); disposedPlace.EmitLoad(cg.Builder); cg.Builder.EmitBranch(ILOpCode.Brfalse, lblContinue); cg.EmitRet(DeclaringCompilation.CoreTypes.Void); cg.Builder.MarkLabel(lblContinue); // <>b_disposed = true; disposedPlace.EmitStorePrepare(cg.Builder); cg.Builder.EmitBoolConstant(true); disposedPlace.EmitStore(cg.Builder); // __destruct() cg.EmitPop(cg.EmitForwardCall(__destruct, dispose, callvirt: true)); // .ret cg.EmitRet(DeclaringCompilation.GetSpecialType(SpecialType.System_Void)); }, null, diagnostics, false)); module.SynthesizedManager.AddMethod(this, dispose); //// //// Finalize() //// //var finalize = new SynthesizedFinalizeSymbol(this) //{ // ForwardedCall = dispose, //}; //Debug.Assert(finalize.OverriddenMethod != null); //module.SetMethodBody(finalize, MethodGenerator.GenerateMethodBody(module, finalize, il => //{ // var thisPlace = new ArgPlace(this, 0); // var ctxPlace = new FieldPlace(thisPlace, this.ContextStore, module); // var cg = new CodeGenerator(il, module, diagnostics, module.Compilation.Options.OptimizationLevel, false, this, ctxPlace, thisPlace) // { // CallerType = this, // }; // // // cg.Builder.OpenLocalScope(ScopeType.TryCatchFinally); // // try { // cg.Builder.OpenLocalScope(ScopeType.Try); // // Dispose() // cg.EmitPop(cg.EmitForwardCall(dispose, finalize, callvirt: false)); // //if (cg.EmitPdbSequencePoints) cg.Builder.EmitOpCode(ILOpCode.Nop); // // } // cg.Builder.CloseLocalScope(); // // finally { // cg.Builder.OpenLocalScope(ScopeType.Finally); // // base.Finalize() // thisPlace.EmitLoad(cg.Builder); // cg.EmitCall(ILOpCode.Call, finalize.ExplicitOverride); // //if (cg.EmitPdbSequencePoints) cg.Builder.EmitOpCode(ILOpCode.Nop); // // } // cg.Builder.CloseLocalScope(); // cg.Builder.CloseLocalScope(); // // .ret // cg.EmitRet(DeclaringCompilation.GetSpecialType(SpecialType.System_Void)); //}, null, diagnostics, false)); //module.SynthesizedManager.AddMethod(this, finalize); }