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