コード例 #1
0
        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);
        }
コード例 #2
0
        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);
        }
コード例 #3
0
        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);
            }
        }
コード例 #4
0
        /// <summary>
        /// Method that enumerates all referenced global types.
        /// EnumerateReferencedTypes(Action&lt;string, RuntimeTypeHandle&gt; callback)
        /// </summary>
        MethodSymbol CreateBuiltinTypesSymbol()
        {
            var compilation        = DeclaringCompilation;
            var action_T           = compilation.GetWellKnownType(WellKnownType.System_Action_T);
            var action_phptypeinfo = action_T.Construct(compilation.CoreTypes.PhpTypeInfo);

            var method = new SynthesizedMethodSymbol(this, "BuiltinTypes", true, false, compilation.CoreTypes.Void, Accessibility.Public);

            method.SetParameters(new SynthesizedParameterSymbol(method, action_phptypeinfo, 0, RefKind.None, "callback"));

            //
            return(method);
        }
コード例 #5
0
        /// <summary>
        /// Method that enumerates all script Main functions.
        /// EnumerateScripts(Action&lt;string, RuntimeMethodHandle&gt; callback)
        /// </summary>
        MethodSymbol CreateEnumerateScriptsSymbol()
        {
            var compilation          = DeclaringCompilation;
            var action_T2            = compilation.GetWellKnownType(WellKnownType.System_Action_T2);
            var action_string_method = action_T2.Construct(compilation.CoreTypes.String, compilation.CoreTypes.RuntimeMethodHandle);

            var method = new SynthesizedMethodSymbol(this, "EnumerateScripts", true, false, compilation.CoreTypes.Void, Accessibility.Public);

            method.SetParameters(new SynthesizedParameterSymbol(method, action_string_method, 0, RefKind.None, "callback"));

            //
            return(method);
        }
コード例 #6
0
        /// <summary>
        /// Method that enumerates all app-wide global constants.
        /// EnumerateConstants(Action&lt;string, PhpValue, bool&gt; callback)
        /// </summary>
        MethodSymbol CreateEnumerateConstantsSymbol()
        {
            var compilation = DeclaringCompilation;
            var action_T3   = compilation.GetWellKnownType(WellKnownType.System_Action_T3);
            var action_string_value_bool = action_T3.Construct(compilation.CoreTypes.String, compilation.CoreTypes.PhpValue, compilation.CoreTypes.Boolean);

            var method = new SynthesizedMethodSymbol(this, "EnumerateConstants", true, false, compilation.CoreTypes.Void, Accessibility.Public);

            method.SetParameters(new SynthesizedParameterSymbol(method, action_string_value_bool, 0, RefKind.None, "callback"));

            //
            return(method);
        }
コード例 #7
0
        /// <summary>
        /// Method that enumerates all app-wide global constants.
        /// EnumerateConstants(Context.IConstantsComposition composer)
        /// </summary>
        MethodSymbol CreateEnumerateConstantsSymbol()
        {
            var compilation = DeclaringCompilation;
            var t           = (TypeSymbol)compilation.GetTypeByMetadataName(CoreTypes.IConstantsCompositionFullName);

            Debug.Assert(t != null);

            var method = new SynthesizedMethodSymbol(this, "BuiltinConstants", true, false, compilation.CoreTypes.Void, Accessibility.Public);

            method.SetParameters(new SynthesizedParameterSymbol(method, t, 0, RefKind.None, name: "composer"));

            //
            return(method);
        }
コード例 #8
0
        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);
        }
コード例 #9
0
ファイル: SourceFileSymbol.cs プロジェクト: ruo2012/peachpie
        /// <summary>
        /// Main method wrapper in case it does not return PhpValue.
        /// </summary>
        /// <returns></returns>
        internal SynthesizedMethodSymbol EnsureMainMethodRegular()
        {
            if (_mainMethodRegularOpt == null &&
                _mainMethod.ControlFlowGraph != null && // => main routine initialized
                _mainMethod.ReturnType != DeclaringCompilation.CoreTypes.PhpValue)
            {
                // PhpValue <Main>`0(parameters)
                _mainMethodRegularOpt = new SynthesizedMethodSymbol(
                    this, WellKnownPchpNames.GlobalRoutineName + "`0", true, false,
                    DeclaringCompilation.CoreTypes.PhpValue, Accessibility.Public);

                _mainMethodRegularOpt.SetParameters(_mainMethod.Parameters.Select(p =>
                                                                                  new SpecialParameterSymbol(_mainMethodRegularOpt, p.Type, p.Name, p.Ordinal)).ToArray());
            }

            return(_mainMethodRegularOpt);
        }
コード例 #10
0
        /// <summary>
        /// In case the class implements <c>__invoke</c> method, we create special Invoke() method that is compatible with IPhpCallable interface.
        /// </summary>
        internal SynthesizedMethodSymbol EnsureInvokeMethod()
        {
            if (_lazyInvokeSymbol == null)
            {
                if (GetMembers(Pchp.Syntax.Name.SpecialMethodNames.Invoke.Value).Any(s => s is MethodSymbol))
                {
                    _lazyInvokeSymbol = new SynthesizedMethodSymbol(this, "IPhpCallable.Invoke", false, true, DeclaringCompilation.CoreTypes.PhpValue)
                    {
                        ExplicitOverride = (MethodSymbol)DeclaringCompilation.CoreTypes.IPhpCallable.Symbol.GetMembers("Invoke").Single(),
                    };
                    _lazyInvokeSymbol.SetParameters(
                        new SpecialParameterSymbol(_lazyInvokeSymbol, DeclaringCompilation.CoreTypes.Context, SpecialParameterSymbol.ContextName, 0),
                        new SpecialParameterSymbol(_lazyInvokeSymbol, ArrayTypeSymbol.CreateSZArray(ContainingAssembly, DeclaringCompilation.CoreTypes.PhpValue.Symbol), "arguments", 1));

                    _lazyMembers = _lazyMembers.Add(_lazyInvokeSymbol);
                }
            }
            return(_lazyInvokeSymbol);
        }
コード例 #11
0
        /// <summary>
        /// Creates ghost stub that calls current method.
        /// </summary>
        protected void CreateGhostOverload(PEModuleBuilder module, DiagnosticBag diagnostic,
                                           TypeSymbol ghostreturn, IEnumerable <ParameterSymbol> ghostparams,
                                           MethodSymbol explicitOverride = null)
        {
            var ghost = new SynthesizedMethodSymbol(
                this.ContainingType, this.Name, this.IsStatic, explicitOverride != null, ghostreturn, this.DeclaredAccessibility)
            {
                ExplicitOverride = explicitOverride,
            };

            ghost.SetParameters(ghostparams.Select(p =>
                                                   new SynthesizedParameterSymbol(ghost, p.Type, p.Ordinal, p.RefKind, p.Name)).ToArray());

            // save method symbol to module
            module.SynthesizedManager.AddMethod(this.ContainingType, ghost);

            // generate method body
            GenerateGhostBody(module, diagnostic, ghost);
        }
コード例 #12
0
        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);
            }
        }
コード例 #13
0
        /// <summary>
        /// Creates ghost stub that calls current method.
        /// </summary>
        protected void CreateGhostOverload(PEModuleBuilder module, DiagnosticBag diagnostic,
            TypeSymbol ghostreturn, IEnumerable<ParameterSymbol> ghostparams,
            MethodSymbol explicitOverride = null)
        {
            var ghost = new SynthesizedMethodSymbol(
                this.ContainingType, this.Name, this.IsStatic, explicitOverride != null, ghostreturn, this.DeclaredAccessibility)
            {
                ExplicitOverride = explicitOverride,
            };

            ghost.SetParameters(ghostparams.Select(p =>
                new SynthesizedParameterSymbol(ghost, p.Type, p.Ordinal, p.RefKind, p.Name)).ToArray());

            // save method symbol to module
            module.SynthesizedManager.AddMethod(this.ContainingType, ghost);

            // generate method body
            GenerateGhostBody(module, diagnostic, ghost);
        }
コード例 #14
0
        /// <summary>
        /// Main method wrapper in case it does not return PhpValue.
        /// </summary>
        void SynthesizeMainMethodWrapper(PEModuleBuilder module, DiagnosticBag diagnostics)
        {
            if (this.ReturnType != DeclaringCompilation.CoreTypes.PhpValue)
            {
                // PhpValue <Main>`0(parameters)
                var wrapper = new SynthesizedMethodSymbol(
                    this.ContainingFile, WellKnownPchpNames.GlobalRoutineName + "`0", true, false,
                    DeclaringCompilation.CoreTypes.PhpValue, Accessibility.Public);

                wrapper.SetParameters(this.Parameters.Select(p =>
                                                             new SynthesizedParameterSymbol(wrapper, p.Type, p.Ordinal, p.RefKind, p.Name)).ToArray());

                // save method symbol to module
                module.SynthesizedManager.AddMethod(this.ContainingFile, wrapper);

                // generate method body
                module.CreateMainMethodWrapper(wrapper, this, diagnostics);
            }
        }
コード例 #15
0
        /// <summary>
        /// In case the class implements <c>__invoke</c> method, we create special Invoke() method that is compatible with IPhpCallable interface.
        /// </summary>
        internal SynthesizedMethodSymbol EnsureInvokeMethod(Emit.PEModuleBuilder module)
        {
            if (_lazyInvokeSymbol == null)
            {
                if (IsInvokable)
                {
                    _lazyInvokeSymbol = new SynthesizedMethodSymbol(this, "IPhpCallable.Invoke", false, true, DeclaringCompilation.CoreTypes.PhpValue)
                    {
                        ExplicitOverride = (MethodSymbol)DeclaringCompilation.CoreTypes.IPhpCallable.Symbol.GetMembers("Invoke").Single(),
                    };
                    _lazyInvokeSymbol.SetParameters(
                        new SpecialParameterSymbol(_lazyInvokeSymbol, DeclaringCompilation.CoreTypes.Context, SpecialParameterSymbol.ContextName, 0),
                        new SynthesizedParameterSymbol(_lazyInvokeSymbol, ArrayTypeSymbol.CreateSZArray(ContainingAssembly, DeclaringCompilation.CoreTypes.PhpValue.Symbol), 1, RefKind.None, "arguments"));

                    //
                    module.SynthesizedManager.AddMethod(this, _lazyInvokeSymbol);
                }
            }
            return(_lazyInvokeSymbol);
        }
コード例 #16
0
        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);
        }
コード例 #17
0
        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);
コード例 #18
0
        /// <summary>
        /// Matches all methods that can be overriden (non-static, public or protected, abstract or virtual)
        /// within this type sub-tree (this type, its base and interfaces)
        /// with its override.
        /// Methods without an override are either abstract or a ghost stup has to be synthesized.
        /// </summary>
        /// <param name="diagnostics"></param>
        internal OverrideInfo[] ResolveOverrides(DiagnosticBag diagnostics)
        {
            if (_lazyOverrides != null)
            {
                // already resolved
                return(_lazyOverrides);
            }

            // inherit abstracts from base type
            // ignoring System.Object (we don't override its methods from PHP)
            var overrides = new List <OverrideInfo>();

            if (BaseType != null && BaseType.SpecialType != SpecialType.System_Object)
            {
                overrides.AddRange(BaseType.ResolveOverrides(diagnostics));
            }

            // collect this type declared methods including synthesized methods
            var members = this.GetMembers();

            // resolve overrides of inherited members
            for (int i = 0; i < overrides.Count; i++)
            {
                var m = overrides[i];
                if (m.HasOverride == false)
                {
                    // update override info of the inherited member
                    overrides[i] = new OverrideInfo(m.Method, OverrideHelper.ResolveMethodImplementation(m.Method, members));
                }
                else
                {
                    // clear the interface flag of inherited override info
                    m.ImplementsInterface = false;
                    overrides[i]          = m;
                }
            }

            // resolve overrides of interface methods
            foreach (var iface in Interfaces)
            {
                // skip interfaces implemented by base type or other interfaces,
                // we don't want to add redundant override entries:
                if ((BaseType != null && BaseType.ImplementsInterface(iface)) ||
                    Interfaces.Any(x => x != iface && x.ImplementsInterface(iface)))
                {
                    // iface is already handled within overrides => skip
                    // note: iface can be ignored in metadata at all actually
                    continue;
                }

                var iface_abstracts = iface.ResolveOverrides(diagnostics);
                foreach (var m in iface_abstracts)
                {
                    if (BaseType != null && m.Method.ContainingType != iface && BaseType.ImplementsInterface(m.Method.ContainingType))
                    {
                        // iface {m.Method.ContainingType} already handled within overrides => skip
                        continue;
                    }

                    // ignore interface method that is already implemented:
                    if (overrides.Any(o => OverrideHelper.SignaturesMatch(o.Method, m.Method)))
                    {
                        continue;
                    }

                    // add interface member,
                    // resolve its override
                    overrides.Add(new OverrideInfo(m.Method, this.IsInterface ? null : OverrideHelper.ResolveMethodImplementation(m.Method, this))
                    {
                        ImplementsInterface = true
                    });
                }
            }

            // add overrideable routines from this type
            foreach (var s in members)
            {
                if (s is MethodSymbol m && m.IsOverrideable())
                {
                    overrides.Add(new OverrideInfo(m));
                }
            }

            // handle unresolved abstracts
            for (int i = 0; i < overrides.Count; i++)
            {
                var m = overrides[i];

                if (m.IsUnresolvedAbstract && this is SourceTypeSymbol srct && !this.IsInterface)
                {
                    if (!this.IsAbstract)
                    {
                        // Class '{0}' doesn't implement abstract method {1}::{2}()
                        diagnostics.Add(DiagnosticBagExtensions.ParserDiagnostic(srct.ContainingFile.SyntaxTree, srct.Syntax.HeadingSpan,
                                                                                 Devsense.PHP.Errors.Errors.AbstractMethodNotImplemented,
                                                                                 srct.FullName.ToString(), ((IPhpTypeSymbol)m.Method.ContainingType).FullName.ToString(), m.RoutineName));
                    }
                    else if (m.ImplementsInterface /*&& this.IsAbstract*/)
                    {
                        m.ImplementsInterface = false;

                        var method = m.Method;

                        Debug.Assert(!method.IsStatic);
                        Debug.Assert(method.DeclaredAccessibility != Accessibility.Private);
                        Debug.Assert(method.ContainingType.IsInterface);

                        // Template: abstract function {name}({parameters})
                        var ghost = new SynthesizedMethodSymbol(this, method.RoutineName,
                                                                isstatic: false, isvirtual: true, isabstract: true, isfinal: false,
                                                                returnType: method.ReturnType,
                                                                accessibility: method.DeclaredAccessibility);

                        ghost.SetParameters(SynthesizedParameterSymbol.Create(ghost, method.Parameters));
                        //module.SynthesizedManager.AddMethod(this, ghost); // will be added to synthesized manager by FinalizeMethodTable

                        m.Method = ghost;   // replace the interface method with synthesized abstract method

                        // update overrides
                        overrides[i] = m;
                    }
                }
            }

            // cache & return
            return(_lazyOverrides = overrides.ToArray());
        }
コード例 #19
0
        /// <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);
        }
コード例 #20
0
ファイル: PEModuleBuilder.cs プロジェクト: iolevel/peachpie
        /// <summary>
        /// Create real CIL entry point, where it calls given method.
        /// </summary>
        internal void CreateEntryPoint(MethodSymbol method, DiagnosticBag diagnostic)
        {
            // "static int Main(string[] args)"
            var realmethod = new SynthesizedMethodSymbol(this.ScriptType, "Main", true, false, _compilation.CoreTypes.Int32, Accessibility.Private);
            realmethod.SetParameters(new SynthesizedParameterSymbol(realmethod, ArrayTypeSymbol.CreateSZArray(this.Compilation.SourceAssembly, this.Compilation.CoreTypes.String), 0, RefKind.None, "args"));

            //
            var body = MethodGenerator.GenerateMethodBody(this, realmethod,
                (il) =>
                {
                    var types = this.Compilation.CoreTypes;
                    var methods = this.Compilation.CoreMethods;
                    var args_place = new ParamPlace(realmethod.Parameters[0]);

                    // AddScriptReference<Script>()
                    var AddScriptReferenceMethod = (MethodSymbol)methods.Context.AddScriptReference_TScript.Symbol.Construct(this.ScriptType);
                    il.EmitCall(this, diagnostic, ILOpCode.Call, AddScriptReferenceMethod);

                    // int exitcode = 0;
                    var exitcode_loc = il.LocalSlotManager.AllocateSlot(types.Int32.Symbol, LocalSlotConstraints.None);
                    il.EmitIntConstant(0);
                    il.EmitLocalStore(exitcode_loc);

                    // create Context
                    var ctx_loc = il.LocalSlotManager.AllocateSlot(types.Context.Symbol, LocalSlotConstraints.None);

                    // ctx_loc = Context.Create***(args)
                    args_place.EmitLoad(il);
                    MethodSymbol create_method = (_compilation.Options.OutputKind == OutputKind.ConsoleApplication)
                        ? _compilation.CoreTypes.Context.Symbol.LookupMember<MethodSymbol>("CreateConsole")
                        : null;
                    Debug.Assert(create_method != null);
                    il.EmitOpCode(ILOpCode.Call, +1);
                    il.EmitToken(create_method, null, diagnostic);
                    il.EmitLocalStore(ctx_loc);

                    // Template:
                    // try { Main(...); } catch (ScriptDiedException) { } finally { ctx.Dispose; }

                    il.OpenLocalScope(ScopeType.TryCatchFinally);   // try { try ... } finally {}
                    il.OpenLocalScope(ScopeType.Try);
                    {
                        // IL requires catches and finally block to be distinct try

                        il.OpenLocalScope(ScopeType.TryCatchFinally);   // try {} catch (ScriptDiedException) {}
                        il.OpenLocalScope(ScopeType.Try);
                        {
                            // emit .call method;
                            if (method.HasThis)
                            {
                                throw new NotImplementedException();    // TODO: create instance of ContainingType
                            }

                            // params
                            foreach (var p in method.Parameters)
                            {
                                if (p.Type == types.Context && p.Name == SpecialParameterSymbol.ContextName)
                                {
                                    // <ctx>
                                    il.EmitLocalLoad(ctx_loc);
                                }
                                else if (p.Type == types.PhpArray && p.Name == SpecialParameterSymbol.LocalsName)
                                {
                                    // <ctx>.Globals
                                    il.EmitLocalLoad(ctx_loc);
                                    il.EmitCall(this, diagnostic, ILOpCode.Call, methods.Context.Globals.Getter)
                                        .Expect(p.Type);
                                }
                                else if (p.Type == types.Object && p.Name == SpecialParameterSymbol.ThisName)
                                {
                                    // null
                                    il.EmitNullConstant();
                                }
                                else
                                {
                                    throw new NotImplementedException();    // TODO: default parameter
                                }
                            }

                            if (il.EmitCall(this, diagnostic, ILOpCode.Call, method).SpecialType != SpecialType.System_Void)
                                il.EmitOpCode(ILOpCode.Pop);
                        }
                        il.CloseLocalScope();   // /Try

                        il.AdjustStack(1); // Account for exception on the stack.
                        il.OpenLocalScope(ScopeType.Catch, Compilation.CoreTypes.ScriptDiedException.Symbol);
                        {
                            // exitcode = <exception>.ProcessStatus(ctx)
                            il.EmitLocalLoad(ctx_loc);
                            il.EmitCall(this, diagnostic, ILOpCode.Callvirt, Compilation.CoreTypes.ScriptDiedException.Symbol.LookupMember<MethodSymbol>("ProcessStatus"));
                            il.EmitLocalStore(exitcode_loc);
                        }
                        il.CloseLocalScope();   // /Catch
                        il.CloseLocalScope();   // /TryCatch
                    }
                    il.CloseLocalScope();   // /Try

                    il.OpenLocalScope(ScopeType.Finally);
                    {
                        // ctx.Dispose
                        il.EmitLocalLoad(ctx_loc);
                        il.EmitOpCode(ILOpCode.Call, -1);
                        il.EmitToken(methods.Context.Dispose.Symbol, null, diagnostic);
                    }
                    il.CloseLocalScope();   // /Finally
                    il.CloseLocalScope();   // /TryCatch

                    // return ctx.ExitCode
                    il.EmitLocalLoad(exitcode_loc);
                    il.EmitRet(false);
                },
                null, diagnostic, false);

            SetMethodBody(realmethod, body);

            //
            this.ScriptType.EntryPointSymbol = realmethod;
        }
コード例 #21
0
        /// <summary>
        /// Emits initializers of all parameter's non-standard default values (such as PhpArray)
        /// within the type's static .cctor
        /// </summary>
        private void EmitParametersDefaultValue(PEModuleBuilder module, DiagnosticBag diagnostics)
        {
            foreach (var p in this.SourceParameters)
            {
                var field = p.DefaultValueField;
                if (field is SynthesizedFieldSymbol)
                {
                    Debug.Assert(p.Initializer != null);

                    module.SynthesizedManager.AddField(field.ContainingType, field);

                    // .cctor() {

                    var cctor = module.GetStaticCtorBuilder(field.ContainingType);
                    lock (cctor)
                    {
                        SynthesizedMethodSymbol func = null;

                        if (field.Type.Is_Func_Context_PhpValue())  // Func<Context, PhpValue>
                        {
                            // private static PhpValue func(Context) => INITIALIZER()
                            func = new SynthesizedMethodSymbol(field.ContainingType, field.Name + "Func", isstatic: true, isvirtual: false, DeclaringCompilation.CoreTypes.PhpValue, isfinal: true);
                            func.SetParameters(new SynthesizedParameterSymbol(func, DeclaringCompilation.CoreTypes.Context, 0, RefKind.None, name: SpecialParameterSymbol.ContextName));

                            //
                            module.SetMethodBody(func, MethodGenerator.GenerateMethodBody(module, func, il =>
                            {
                                var ctxPlace = new ArgPlace(DeclaringCompilation.CoreTypes.Context, 0);
                                var cg       = new CodeGenerator(il, module, diagnostics, module.Compilation.Options.OptimizationLevel, false, field.ContainingType, ctxPlace, null)
                                {
                                    CallerType                = ContainingType,
                                    ContainingFile            = ContainingFile,
                                    IsInCachedArrayExpression = true,   // do not cache array initializers twice
                                };

                                // return {Initializer}
                                cg.EmitConvert(p.Initializer, func.ReturnType);
                                cg.EmitRet(func.ReturnType);
                            }, null, diagnostics, false));

                            module.SynthesizedManager.AddMethod(func.ContainingType, func);
                        }

                        using (var cg = new CodeGenerator(cctor, module, diagnostics, module.Compilation.Options.OptimizationLevel, false, field.ContainingType,
                                                          contextPlace: null,
                                                          thisPlace: null)
                        {
                            CallerType = ContainingType,
                            ContainingFile = ContainingFile,
                            IsInCachedArrayExpression = true,   // do not cache array initializers twice
                        })
                        {
                            var fldplace = new FieldPlace(null, field, module);
                            fldplace.EmitStorePrepare(cg.Builder);
                            if (func == null)
                            {
                                // {field} = {Initializer};
                                cg.EmitConvert(p.Initializer, field.Type);
                            }
                            else
                            {
                                MethodSymbol funcsymbol = func;

                                // bind func in case it is generic
                                if (func.ContainingType is SourceTraitTypeSymbol st)
                                {
                                    funcsymbol = func.AsMember(st.Construct(st.TypeArguments));
                                }

                                // Func<,>(object @object, IntPtr method)
                                var func_ctor = ((NamedTypeSymbol)field.Type).InstanceConstructors.Single(m =>
                                                                                                          m.ParameterCount == 2 &&
                                                                                                          m.Parameters[0].Type.SpecialType == SpecialType.System_Object &&
                                                                                                          m.Parameters[1].Type.SpecialType == SpecialType.System_IntPtr
                                                                                                          );

                                // {field} = new Func<Context, PhpValue>( {func} )
                                cg.Builder.EmitNullConstant();                                                                         // null
                                cg.EmitOpCode(ILOpCode.Ldftn);                                                                         // method
                                cg.Builder.EmitToken(module.Translate(funcsymbol, null, cg.Diagnostics, false), null, cg.Diagnostics); // !! needDeclaration: false
                                cg.EmitCall(ILOpCode.Newobj, func_ctor);
                            }
                            fldplace.EmitStore(cg.Builder);
                        }
                    }
                }
            }
        }
コード例 #22
0
        /// <summary>
        /// Collects methods that has to be overriden and matches with this declaration.
        /// Missing overrides are reported, needed ghost stubs are synthesized.
        /// </summary>
        public void FinalizeMethodTable(Emit.PEModuleBuilder module, DiagnosticBag diagnostics)
        {
            // creates ghost stubs for overrides that do not match the signature

            foreach (var info in this.ResolveOverrides(diagnostics))
            {
                // note: unresolved abstracts already reported by ResolveOverrides

                // is ghost stub needed?

                if (ReferenceEquals(info.OverrideCandidate?.ContainingType, this) ||    // candidate not matching exactly the signature in this type
                    info.ImplementsInterface)                                           // explicitly implement the interface
                {
                    if (info.HasOverride)
                    {
                        if (info.ImplementsInterface && info.Override != null && info.Override.IsVirtual)
                        {
                            // create explicit override only if the interface method is implemented with a class method that does not implement the interface

                            /*
                             * interface I { foo }  // METHOD
                             * class X { foo }      // OVERRIDE
                             * class Y : X, I { explicit I.foo override }   // GHOST
                             */
                            if (info.Override.ContainingType.ImplementsInterface(info.Method.ContainingType))
                            {
                                /* => X implements I */
                                // explicit method override is not needed
                                continue;
                            }
                        }

                        /*
                         * class A {
                         *    TReturn1 foo(A, B);
                         * }
                         * class B : A {
                         *    TReturn2 foo(A2, B2);
                         *
                         *    // SYNTHESIZED GHOST:
                         *    override TReturn foo(A, B){ return (TReturn)foo((A2)A, (B2)B);
                         * }
                         */

                        // override method with a ghost that calls the override
                        (info.Override ?? info.OverrideCandidate).CreateGhostOverload(
                            this, module, diagnostics,
                            info.Method.ReturnType, info.Method.Parameters,
                            phphidden: true, explicitOverride: info.Method);
                    }
                    else
                    {
                        // synthesize abstract method implementing unresolved interface member
                        if (info.IsUnresolvedAbstract && info.ImplementsInterface && this.IsAbstract && !this.IsInterface)
                        {
                            var method = info.Method;

                            Debug.Assert(!method.IsStatic);
                            Debug.Assert(method.DeclaredAccessibility != Accessibility.Private);
                            Debug.Assert(method.ContainingType.IsInterface);

                            // Template: abstract function {name}({parameters})
                            var ghost = new SynthesizedMethodSymbol(this, method.RoutineName,
                                                                    isstatic: false, isvirtual: true, isabstract: true, isfinal: false,
                                                                    returnType: method.ReturnType,
                                                                    accessibility: method.DeclaredAccessibility);

                            ghost.SetParameters(method.Parameters.Select(p => SynthesizedParameterSymbol.Create(ghost, p)).ToArray());
                            module.SynthesizedManager.AddMethod(this, ghost);
                        }
                    }
                }

                // setup synthesized methods explicit override as resolved
                if (info.Override is SynthesizedMethodSymbol sm && sm.ExplicitOverride == null && sm.ContainingType == this)
                {
                    sm.ExplicitOverride = info.Method;
                }
            }

            // synthesized field accessors:
            foreach (var srcf in GetMembers().OfType <SourceFieldSymbol>())
            {
                var paccessor = srcf.FieldAccessorProperty;
                if (paccessor != null)
                {
                    GenerateFieldAccessorProperty(module, diagnostics, srcf, paccessor);
                }
            }
        }
コード例 #23
0
ファイル: SourceTypeSymbol.cs プロジェクト: iolevel/peachpie
        /// <summary>
        /// In case the class implements <c>__invoke</c> method, we create special Invoke() method that is compatible with IPhpCallable interface.
        /// </summary>
        internal SynthesizedMethodSymbol EnsureInvokeMethod(Emit.PEModuleBuilder module)
        {
            if (_lazyInvokeSymbol == null)
            {
                if (IsInvokable)
                {
                    _lazyInvokeSymbol = new SynthesizedMethodSymbol(this, "IPhpCallable.Invoke", false, true, DeclaringCompilation.CoreTypes.PhpValue)
                    {
                        ExplicitOverride = (MethodSymbol)DeclaringCompilation.CoreTypes.IPhpCallable.Symbol.GetMembers("Invoke").Single(),
                    };
                    _lazyInvokeSymbol.SetParameters(
                        new SpecialParameterSymbol(_lazyInvokeSymbol, DeclaringCompilation.CoreTypes.Context, SpecialParameterSymbol.ContextName, 0),
                        new SynthesizedParameterSymbol(_lazyInvokeSymbol, ArrayTypeSymbol.CreateSZArray(ContainingAssembly, DeclaringCompilation.CoreTypes.PhpValue.Symbol), 1, RefKind.None, "arguments"));

                    //
                    module.SynthesizedManager.AddMethod(this, _lazyInvokeSymbol);
                }
            }
            return _lazyInvokeSymbol;
        }
コード例 #24
0
        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);
        }
コード例 #25
0
        /// <summary>
        /// Method that enumerates all script Main functions.
        /// EnumerateScripts(Action&lt;string, RuntimeMethodHandle&gt; callback)
        /// </summary>
        MethodSymbol CreateEnumerateScriptsSymbol()
        {
            var compilation = DeclaringCompilation;
            var action_T2 = compilation.GetWellKnownType(WellKnownType.System_Action_T2);
            var action_string_method = action_T2.Construct(compilation.CoreTypes.String, compilation.CoreTypes.RuntimeMethodHandle);

            var method = new SynthesizedMethodSymbol(this, "EnumerateScripts", true, false, compilation.CoreTypes.Void, Accessibility.Public);
            method.SetParameters(new SynthesizedParameterSymbol(method, action_string_method, 0, RefKind.None, "callback"));

            //
            return method;
        }
コード例 #26
0
        /// <summary>
        /// Method that enumerates all app-wide global constants.
        /// EnumerateConstants(Action&lt;string, PhpValue, bool&gt; callback)
        /// </summary>
        MethodSymbol CreateEnumerateConstantsSymbol()
        {
            var compilation = DeclaringCompilation;
            var action_T3 = compilation.GetWellKnownType(WellKnownType.System_Action_T3);
            var action_string_value_bool = action_T3.Construct(compilation.CoreTypes.String, compilation.CoreTypes.PhpValue, compilation.CoreTypes.Boolean);

            var method = new SynthesizedMethodSymbol(this, "EnumerateConstants", true, false, compilation.CoreTypes.Void, Accessibility.Public);
            method.SetParameters(new SynthesizedParameterSymbol(method, action_string_value_bool, 0, RefKind.None, "callback"));

            //
            return method;
        }
コード例 #27
0
        /// <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);
        }
コード例 #28
0
        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);
        }
コード例 #29
0
        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);
        }
コード例 #30
0
        /// <summary>
        /// Main method wrapper in case it does not return PhpValue.
        /// </summary>
        void SynthesizeMainMethodWrapper(PEModuleBuilder module, DiagnosticBag diagnostics)
        {
            if (this.ReturnType != DeclaringCompilation.CoreTypes.PhpValue)
            {
                // PhpValue <Main>`0(parameters)
                var wrapper = new SynthesizedMethodSymbol(
                    this.ContainingFile, WellKnownPchpNames.GlobalRoutineName + "`0", true, false,
                    DeclaringCompilation.CoreTypes.PhpValue, Accessibility.Public);

                wrapper.SetParameters(this.Parameters.Select(p =>
                    new SynthesizedParameterSymbol(wrapper, p.Type, p.Ordinal, p.RefKind, p.Name)).ToArray());

                // save method symbol to module
                module.SynthesizedManager.AddMethod(this.ContainingFile, wrapper);

                // generate method body
                module.CreateMainMethodWrapper(wrapper, this, diagnostics);
            }
        }