/// <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; }
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); } } } } }