示例#1
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 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;
        }
示例#2
0
        internal override void EmitInit(CodeGenerator cg)
        {
            // TODO: check callable, iterable
            
            // 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.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);

                            // <local> = <param>
                            localplace.EmitStorePrepare(cg.Builder);
                            cg.EmitConvert(srcplace.EmitLoad(cg.Builder), 0, clrtype);
                            localplace.EmitStore(cg.Builder);
                        }
                    }
                }
            }
        }