示例#1
0
        /// <summary>
        /// Creates ghost stub that calls method.
        /// </summary>
        public static void CreateGhostOverload(this MethodSymbol method, NamedTypeSymbol containingtype, PEModuleBuilder module, DiagnosticBag diagnostic,
                                               TypeSymbol ghostreturn, IEnumerable <ParameterSymbol> ghostparams,
                                               MethodSymbol explicitOverride = null)
        {
            var ghost = new SynthesizedMethodSymbol(
                containingtype, method.Name, method.IsStatic, explicitOverride != null, ghostreturn, method.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(containingtype, ghost);

            // generate method body
            GenerateGhostBody(module, diagnostic, method, ghost);
        }
        /// <summary>
        /// Creates ghost stub that calls method.
        /// </summary>
        public static void CreateGhostOverload(this MethodSymbol method, NamedTypeSymbol containingtype, PEModuleBuilder module, DiagnosticBag diagnostic,
                                               TypeSymbol ghostreturn, IEnumerable <ParameterSymbol> ghostparams,
                                               MethodSymbol explicitOverride = null)
        {
            string prefix = (explicitOverride != null && explicitOverride.ContainingType.IsInterface)
                ? (explicitOverride.ContainingType.GetFullName() + ".")   // explicit interface override
                : null;

            var ghost = new SynthesizedMethodSymbol(
                containingtype, prefix + method.Name, method.IsStatic, explicitOverride != null, ghostreturn, method.DeclaredAccessibility)
            {
                ExplicitOverride = explicitOverride,
                ForwardedCall    = method,
            };

            ghost.SetParameters(ghostparams.Select(p => SynthesizedParameterSymbol.Create(ghost, p)).ToArray());

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

            // generate method body
            GenerateGhostBody(module, diagnostic, method, ghost);
        }
        /// <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]);

                //
                this.EmitBootstrap(il);

                // 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);
                var ex_loc  = il.LocalSlotManager.AllocateSlot(types.Exception.Symbol, LocalSlotConstraints.None);
                var onUnhandledException_method = types.Context.Symbol.LookupMember <MethodSymbol>("OnUnhandledException");

                if (_compilation.Options.OutputKind == OutputKind.ConsoleApplication)
                {
                    // CreateConsole(string mainscript, params string[] args)
                    var create_method = types.Context.Symbol.LookupMember <MethodSymbol>("CreateConsole", m =>
                    {
                        return
                        (m.ParameterCount == 2 &&
                         m.Parameters[0].Type == types.String &&            // string mainscript
                         m.Parameters[1].Type == args_place.Type);          // params string[] args
                    });
                    Debug.Assert(create_method != null);

                    il.EmitStringConstant(EntryPointScriptName(method));        // mainscript
                    args_place.EmitLoad(il);                                    // args

                    il.EmitOpCode(ILOpCode.Call, +2);
                    il.EmitToken(create_method, null, diagnostic);
                }
                else
                {
                    // CreateEmpty(args)
                    MethodSymbol create_method = types.Context.Symbol.LookupMember <MethodSymbol>("CreateEmpty");
                    Debug.Assert(create_method != null);
                    Debug.Assert(create_method.ParameterCount == 1);
                    Debug.Assert(create_method.Parameters[0].Type == args_place.Type);
                    args_place.EmitLoad(il);        // args
                    il.EmitOpCode(ILOpCode.Call, +1);
                    il.EmitToken(create_method, null, diagnostic);
                }

                il.EmitLocalStore(ctx_loc);

                // Template:
                // try { Main(...); } catch (ScriptDiedException) { } catch (Exception) { ... } 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)
                        {
                            switch (p.Name)
                            {
                            case SpecialParameterSymbol.ContextName:
                                // <ctx>
                                il.EmitLocalLoad(ctx_loc);
                                break;

                            case SpecialParameterSymbol.LocalsName:
                                // <ctx>.Globals
                                il.EmitLocalLoad(ctx_loc);
                                il.EmitCall(this, diagnostic, ILOpCode.Call, methods.Context.Globals.Getter)
                                .Expect(p.Type);
                                break;

                            case SpecialParameterSymbol.ThisName:
                                // null
                                il.EmitNullConstant();
                                break;

                            case SpecialParameterSymbol.SelfName:
                                // default(RuntimeTypeHandle)
                                var runtimetypehandle_loc = il.LocalSlotManager.AllocateSlot(types.RuntimeTypeHandle.Symbol, LocalSlotConstraints.None);
                                il.EmitValueDefault(this, diagnostic, runtimetypehandle_loc);
                                il.LocalSlotManager.FreeSlot(runtimetypehandle_loc);
                                break;

                            default:
                                throw new ArgumentException(p.Name);
                            }
                        }

                        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, types.ScriptDiedException.Symbol);
                    {
                        // exitcode = <exception>.ProcessStatus(ctx)
                        il.EmitLocalLoad(ctx_loc);
                        il.EmitCall(this, diagnostic, ILOpCode.Callvirt, types.ScriptDiedException.Symbol.LookupMember <MethodSymbol>("ProcessStatus"));
                        il.EmitLocalStore(exitcode_loc);
                    }
                    il.CloseLocalScope();                    // /Catch
                    if (onUnhandledException_method != null) // only if runtime defines the method (backward compat.)
                    {
                        il.OpenLocalScope(ScopeType.Catch, types.Exception.Symbol);
                        {
                            // <ex_loc> = <stack>
                            il.EmitLocalStore(ex_loc);

                            // <ctx_loc>.OnUnhandledException( <ex_loc> ) : bool
                            il.EmitLocalLoad(ctx_loc);
                            il.EmitLocalLoad(ex_loc);
                            il.EmitCall(this, diagnostic, ILOpCode.Callvirt, onUnhandledException_method)
                            .Expect(SpecialType.System_Boolean);

                            // if ( !<bool> )
                            // {
                            var lbl_end = new object();
                            il.EmitBranch(ILOpCode.Brtrue, lbl_end);

                            // rethrow <ex_loc>;
                            il.EmitLocalLoad(ex_loc);
                            il.EmitThrow(true);

                            // }
                            il.MarkLabel(lbl_end);
                        }
                        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;
        }
示例#4
0
        /// <summary>
        /// Generates ghost method body that calls <c>this</c> method.
        /// </summary>
        static void GenerateGhostBody(PEModuleBuilder module, DiagnosticBag diagnostic, MethodSymbol method, SynthesizedMethodSymbol ghost)
        {
            var containingtype = ghost.ContainingType;

            var body = MethodGenerator.GenerateMethodBody(module, ghost,
                                                          (il) =>
            {
                // $this
                var thisPlace = ghost.HasThis ? new ArgPlace(containingtype, 0) : null;

                // Context
                var ctxPlace = thisPlace != null && ghost.ContainingType is SourceTypeSymbol sourcetype
                        ? new FieldPlace(thisPlace, sourcetype.ContextStore)
                        : (IPlace) new ArgPlace(module.Compilation.CoreTypes.Context, 0);

                var cg = new CodeGenerator(il, module, diagnostic, module.Compilation.Options.OptimizationLevel, false, containingtype, ctxPlace, thisPlace);

                // return (T){routine}(p0, ..., pN);
                cg.EmitConvert(cg.EmitForwardCall(method, ghost), 0, ghost.ReturnType);
                cg.EmitRet(ghost.ReturnType);
            },
                                                          null, diagnostic, false);

            module.SetMethodBody(ghost, body);
        }
示例#5
0
        /// <summary>
        /// Generates ghost method body that calls <c>this</c> method.
        /// </summary>
        static void GenerateGhostBody(PEModuleBuilder module, DiagnosticBag diagnostic, MethodSymbol method, SynthesizedMethodSymbol ghost)
        {
            var containingtype = ghost.ContainingType;

            var body = MethodGenerator.GenerateMethodBody(module, ghost,
                                                          (il) =>
            {
                // $this
                var thisPlace = ghost.HasThis ? new ArgPlace(containingtype, 0) : null;

                // Context
                var ctxPlace = thisPlace != null && ghost.ContainingType is SourceTypeSymbol sourcetype
                        ? (sourcetype.ContextStore != null ? new FieldPlace(thisPlace, sourcetype.ContextStore, module) : null)
                        : (IPlace) new ArgPlace(module.Compilation.CoreTypes.Context, 0);

                // .callvirt
                bool callvirt = ghost.ExplicitOverride != null && ghost.ExplicitOverride.ContainingType.IsInterface;      // implementing interface, otherwise we should be able to call specific method impl. non-virtually via ghost

                var cg = new CodeGenerator(il, module, diagnostic, module.Compilation.Options.OptimizationLevel, false, containingtype, ctxPlace, thisPlace)
                {
                    DebugRoutine = ghost,
                };

                // return (T){routine}(p0, ..., pN);
                cg.EmitConvert(cg.EmitForwardCall(method, ghost, callvirt: callvirt), 0, ghost.ReturnType);
                cg.EmitRet(ghost.ReturnType);
            },
                                                          null, diagnostic, false);

            module.SetMethodBody(ghost, body);
        }
示例#6
0
        /// <summary>
        /// Emit body of enumeration of app-wide global constants.
        /// </summary>
        internal void CreateEnumerateConstantsSymbol(DiagnosticBag diagnostic)
        {
            var method = this.ScriptType.EnumerateConstantsSymbol;
            var consts = this.Compilation.GlobalSemantics.GetExportedConstants();

            // void (Action<string, RuntimeMethodHandle> callback)
            var body = MethodGenerator.GenerateMethodBody(this, method,
                                                          (il) =>
            {
                var cg = new CodeGenerator(il, this, diagnostic, this.Compilation.Options.OptimizationLevel, false, this.ScriptType, null, null);

                // interface IConstantsComposition
                var constantscomposition = method.Parameters[0].Type;
                Debug.Assert(constantscomposition.Name == "IConstantsComposition");

                // Define(string, ...)
                var define_xxx = constantscomposition
                                 .GetMembers("Define")
                                 .OfType <MethodSymbol>()
                                 .Where(m => m.ParameterCount == 2)
                                 .ToArray();

                var define_string = define_xxx.Single(m => m.Parameters[1].Type.SpecialType == SpecialType.System_String);
                var define_long   = define_xxx.Single(m => m.Parameters[1].Type.SpecialType == SpecialType.System_Int64);
                var define_double = define_xxx.Single(m => m.Parameters[1].Type.SpecialType == SpecialType.System_Double);
                var define_func   = define_xxx.Single(m => m.Parameters[1].Type.Name == "Func");   // Func<PhpValue>
                var define_value  = define_xxx.Single(m => m.Parameters[1].Type == cg.CoreTypes.PhpValue);

                foreach (var c in consts.OfType <Symbol>())
                {
                    // composer.Define(c.Name, c.Value)
                    il.EmitLoadArgumentOpcode(0);

                    // string : name
                    il.EmitStringConstant(c.MetadataName);

                    if (c is FieldSymbol fld)
                    {
                        // PhpValue : value
                        TypeSymbol consttype;

                        var constvalue = fld.GetConstantValue(false);
                        if (constvalue != null)
                        {
                            consttype = cg.EmitLoadConstant(constvalue.Value, cg.CoreTypes.PhpValue);
                        }
                        else
                        {
                            consttype = new FieldPlace(null, fld, this).EmitLoad(il);
                        }

                        // Define(...)
                        if (consttype.SpecialType == SpecialType.System_Int32)
                        {
                            // i4 -> i8
                            il.EmitOpCode(ILOpCode.Conv_i8);
                            consttype = cg.CoreTypes.Long;
                        }

                        MethodSymbol define_method = null;

                        if (consttype.SpecialType == SpecialType.System_String)
                        {
                            define_method = define_string;
                        }
                        else if (consttype.SpecialType == SpecialType.System_Int64)
                        {
                            define_method = define_long;
                        }
                        else if (consttype.SpecialType == SpecialType.System_Double)
                        {
                            define_method = define_double;
                        }
                        else
                        {
                            cg.EmitConvertToPhpValue(consttype, 0);
                            define_method = define_value;
                        }

                        il.EmitCall(this, diagnostic, ILOpCode.Callvirt, define_method);
                    }
                    else if (c is PropertySymbol prop)
                    {
                        MethodSymbol getter_func;
                        // Func<PhpValue>
                        if (prop.Type == cg.CoreTypes.PhpValue)
                        {
                            getter_func = prop.GetMethod;
                        }
                        else
                        {
                            // static PhpValue get_XXX => get_prop();
                            getter_func = new SynthesizedMethodSymbol(ScriptType, "get_" + prop.Name, true, false, cg.CoreTypes.PhpValue, Accessibility.Internal);
                            SynthesizedManager.AddMethod(ScriptType, getter_func);
                            SetMethodBody(getter_func, MethodGenerator.GenerateMethodBody(this, getter_func, _il =>
                            {
                                var _cg = new CodeGenerator(_il, this, diagnostic, this.Compilation.Options.OptimizationLevel, false, ScriptType, null, null);

                                _cg.EmitRet(_cg.EmitConvertToPhpValue(_cg.EmitForwardCall(prop.GetMethod, getter_func, callvirt: false), 0));
                            }, null, diagnostic, false));
                        }

                        // new Func<PhpValue>(object @object = null, IntPtr method = getter_func)
                        cg.Builder.EmitNullConstant();     // null
                        cg.EmitOpCode(ILOpCode.Ldftn);     // method
                        cg.EmitSymbolToken(getter_func, null);
                        cg.EmitCall(ILOpCode.Newobj, Compilation.GetWellKnownType(WellKnownType.System_Func_T).Construct(cg.CoreTypes.PhpValue).InstanceConstructors[0]);

                        //
                        il.EmitCall(this, diagnostic, ILOpCode.Callvirt, define_func);
                    }
                    else
                    {
                        throw ExceptionUtilities.UnexpectedValue(c);
                    }
                }

                //
                il.EmitRet(true);
            },
                                                          null, diagnostic, false);

            SetMethodBody(method, body);
        }
示例#7
0
        /// <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 args_place = new ParamPlace(realmethod.Parameters[0]);

                // AddScriptReference<Script>()
                var AddScriptReferenceMethod = (MethodSymbol)this.Compilation.CoreMethods.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, this.Compilation.CoreMethods.Context.get_Globals)
                                .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(this.Compilation.CoreMethods.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;
        }