Beispiel #1
0
        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);
                    //    }
                    //}
                }
            }
        }
Beispiel #2
0
        internal override void EmitInit(CodeGenerator cg)
        {
            // TODO: ? if (cg.HasUnoptimizedLocals && $this) <locals>["this"] = ...

            var srcparam = _symbol as SourceParameterSymbol;

            if (srcparam != null)
            {
                var srcplace = new ParamPlace(_symbol);
                var routine  = srcparam.Routine;

                if (cg.HasUnoptimizedLocals)
                {
                    Debug.Assert(cg.LocalsPlaceOpt != null);

                    // copy parameter to <locals>[Name]

                    // <locals>[name] = value
                    cg.LocalsPlaceOpt.EmitLoad(cg.Builder);                     // <locals>
                    cg.EmitIntStringKey(new BoundLiteral(this.Name));           // [key]
                    cg.EmitConvertToPhpValue(srcplace.EmitLoad(cg.Builder), 0); // value
                    cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpArray.SetItemValue_IntStringKey_PhpValue);

                    //
                    _isUnoptimized = true;
                }
                else
                {
                    // TODO: copy parameter by value in case of PhpValue, Array, PhpString

                    // create local variable in case of parameter type is not enough for its use within routine
                    if (_symbol.Type != cg.CoreTypes.PhpValue && _symbol.Type != cg.CoreTypes.PhpAlias)
                    {
                        var tmask   = routine.ControlFlowGraph.GetParamTypeMask(srcparam);
                        var clrtype = cg.DeclaringCompilation.GetTypeFromTypeRef(routine, tmask);
                        if (clrtype != _symbol.Type)    // Assert: only if clrtype is not covered by _symbol.Type
                        {
                            // TODO: performance warning

                            _lazyLocal = new BoundLocal(new SynthesizedLocalSymbol(routine, srcparam.Name, clrtype));
                            _lazyLocal.EmitInit(cg);
                            var localplace = _lazyLocal.Place(cg.Builder);

                            // <local> = <param>
                            localplace.EmitStorePrepare(cg.Builder);
                            cg.EmitConvert(srcplace.EmitLoad(cg.Builder), 0, clrtype);
                            localplace.EmitStore(cg.Builder);
                        }
                    }
                }
            }
        }
Beispiel #3
0
        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);
                }
            }
        }
Beispiel #4
0
        internal override IPlace Place(ILBuilder il)
        {
            if (_lazyplace != null)
            {
                return(_lazyplace);
            }

            if (_isUnoptimized)
            {
                return(null);
            }

            IPlace place = new ParamPlace(_symbol);

            if (this.VariableKind == VariableKind.ThisParameter)
            {
                place = new ReadOnlyPlace(place);
            }

            return(place);
        }
Beispiel #5
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);
        }
        /// <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;
        }
Beispiel #7
0
        internal override void EmitInit(CodeGenerator cg)
        {
            var srcparam = _symbol as SourceParameterSymbol;

            if (srcparam == null)
            {
                // an implicit parameter
                return;
            }

            // TODO: check callable, iterable

            // TODO: ? if (cg.HasUnoptimizedLocals && $this) <locals>["this"] = ...

            var srcplace = new ParamPlace(_symbol);
            var routine  = srcparam.Routine;

            if (cg.HasUnoptimizedLocals)
            {
                Debug.Assert(cg.LocalsPlaceOpt != null);

                // copy parameter to <locals>[Name]

                // <locals>[name] = value
                cg.LocalsPlaceOpt.EmitLoad(cg.Builder);           // <locals>
                cg.EmitIntStringKey(new BoundLiteral(this.Name)); // [key]

                if (srcparam.Syntax.PassedByRef)
                {
                    var srcpt = srcplace.EmitLoad(cg.Builder);  // PhpAlias
                    Debug.Assert(srcpt == cg.CoreTypes.PhpAlias);
                    cg.EmitConvert(srcpt, 0, cg.CoreTypes.PhpAlias);
                    cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpArray.SetItemAlias_IntStringKey_PhpAlias);
                }
                else
                {
                    if (_symbol.IsParams)
                    {
                        // (PhhpValue)new PhpArray( params )
                        cg.EmitConvertToPhpValue(cg.ArrayToPhpArray(srcplace, true), 0);
                    }
                    else
                    {
                        if (_symbol.Type == cg.CoreTypes.PhpValue)
                        {
                            // <param>.GetValue()
                            srcplace.EmitLoadAddress(cg.Builder);
                            cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.GetValue);
                        }
                        else
                        {
                            // (PhpValue)<param>
                            cg.EmitConvertToPhpValue(srcplace.EmitLoad(cg.Builder), 0); // PhpValue
                        }

                        // copy <value>
                        if (cg.IsCopiable(_symbol.Type))
                        {
                            cg.EmitDeepCopy(cg.CoreTypes.PhpValue);
                        }
                    }

                    cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpArray.Add_IntStringKey_PhpValue);
                }

                //
                _isUnoptimized = true;
            }
            else
            {
                // create local variable in case of parameter type is not enough for its use within routine
                if (_symbol.Type != cg.CoreTypes.PhpValue && _symbol.Type != cg.CoreTypes.PhpAlias)
                {
                    var tmask   = routine.ControlFlowGraph.GetLocalTypeMask(srcparam.Name);
                    var clrtype = cg.DeclaringCompilation.GetTypeFromTypeRef(routine, tmask);
                    if (clrtype != _symbol.Type)    // Assert: only if clrtype is not covered by _symbol.Type
                    {
                        // TODO: performance warning

                        _lazyLocal = new BoundLocal(new SynthesizedLocalSymbol(routine, srcparam.Name, clrtype));
                        _lazyLocal.EmitInit(cg);
                        var localplace = _lazyLocal.Place(cg.Builder);

                        localplace.EmitStorePrepare(cg.Builder);

                        if (_symbol.IsParams)
                        {
                            Debug.Assert(_symbol.Type.IsSZArray());
                            Debug.Assert(clrtype == cg.CoreTypes.PhpArray);

                            // <local> = new PhpArray(){ ... }
                            cg.ArrayToPhpArray(srcplace, true);
                        }
                        else
                        {
                            // <local> = <param>
                            cg.EmitConvert(srcplace.EmitLoad(cg.Builder), 0, clrtype);
                        }
                        localplace.EmitStore(cg.Builder);
                    }
                }
                else
                {
                    if (_symbol.Type == cg.CoreTypes.PhpValue)
                    {
                        srcplace.EmitStorePrepare(cg.Builder);

                        // dereference & copy
                        // <param> = <param>.GetValue().DeepCopy()
                        srcplace.EmitLoadAddress(cg.Builder);
                        cg.EmitDeepCopy(cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.GetValue));

                        srcplace.EmitStore(cg.Builder);
                    }
                    else if (cg.IsCopiable(_symbol.Type))
                    {
                        srcplace.EmitStorePrepare(cg.Builder);

                        // copy
                        // <param> = DeepCopy(<param>)
                        cg.EmitDeepCopy(srcplace.EmitLoad(cg.Builder));

                        srcplace.EmitStore(cg.Builder);
                    }
                }
            }
        }
Beispiel #8
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;
        }