先在Microsoft.Scripting.Actions.CallSite<T>的构造器设断点,然后开始调试。
在IronPythonConsole里,输入[color=darkred][b]1+2[/b][/color]回车,然后观察调用栈。可以看到在很多层调用之前是一个对Microsoft.Scripting.Generation.GlobalRewriter.RewriteLambda(lambda)的调用(注意到GlobalRewriter近期将会被refactor而去除掉,CodeContext也会消失掉)。在rewrite前,lambda(也就是console所执行的main,委托类型为DlrMainCallTarget)是:
rewrite后则是:
Rewrite的意义在于把所有DynamicExpression重写为静态类型的节点,其中的动态行为则编译为CallSite的初始化(Expression.Constant())与调用(Expression.Call())。
编译出来的委托的类型为Func<Microsoft.Runtime.CompilerServices.Closure, Microsoft.Scripting.Runtime.Scope, Microsoft.Scripting.Runtime.LanguageContext, object>,内容是:
执行这个委托,在原本的加法调用点会进入到先前生成的UpdateDelegates.Update2<Func<CalSite,int,int,object>,int,int,object>中,进而调用CallSite<T>.UpdateAndExecute()。
此时,该调用点尚未有任何调用记录,所以会生成一个新的monomorphic rule(CallSite<T>.CreateNewRule())。在这里,通过CallSiteBinder<T>.Bind()(具体来说是IronPython.Runtime.Binding.OperationBinder,{Python Add};Bind()方法来自MetaAction类)得到一个Rule<Func<CalSite,int,int,object>>:
接下来,这个Rule<T>会被加入Level 2 Cache,然后赋值给Level 0 Cache并执行,如果成功则加入Level 1 Cache并将执行结果返回;失败的话则会尝试再次创建Rule<T>,重复上述创建过程。
这样就完成了一次1+2的执行。上面省略了一些Python特定的步骤(如PythonBinder、PythonOps里许多初始化),专注于DLR一侧的运行步骤。
在IronPythonConsole里,输入[color=darkred][b]1+2[/b][/color]回车,然后观察调用栈。可以看到在很多层调用之前是一个对Microsoft.Scripting.Generation.GlobalRewriter.RewriteLambda(lambda)的调用(注意到GlobalRewriter近期将会被refactor而去除掉,CodeContext也会消失掉)。在rewrite前,lambda(也就是console所执行的main,委托类型为DlrMainCallTarget)是:
//
// AST: Expression`1
//
.lambda (<module> Microsoft.Func`1[System.Object] #1)
//
// LAMBDA: <module>(1)
//
.lambda System.Object <module> ()(
) {
.scope <module> (
System.Int32 $lineNo
System.Boolean $lineUpdated
) {
{
(PythonOps.ModuleStarted)(
.extension (CodeContext) ;
,
(BinderState)IronPython.Runtime.Binding.BinderState,
(PythonLanguageFeatures)Default,
)
(.var $lineNo) = 0
(.var $lineUpdated) = (Boolean)False
.try {
{
{
}
/*empty*/;
{
(.var $lineNo) = 1
{
(PythonOps.PrintExpressionValue)(
.extension (CodeContext) ;
,
.site (Object) Operation Add( // Python Add
1
2
),
)
}
}
}
} .fault {
{
.if (!(.var $lineUpdated) ) {(ExceptionHelpers.UpdateStackTrace)(
.extension (CodeContext) ;
,
(MethodBase.GetCurrentMethod)(),
"<module>",
"<stdin>",
(.var $lineNo),
)} .else {/*empty*/;
}
(.var $lineUpdated) = (Boolean)True
}
}
}
}
}
rewrite后则是:
//
// AST: Expression`1
//
.lambda (<module> Microsoft.Func`1[System.Object] #1)
//
// LAMBDA: <module>(1)
//
.lambda System.Object <module> ()(
) {
.scope <module> (
System.Int32 $lineNo
System.Boolean $lineUpdated
) {
{
(PythonOps.ModuleStarted)(
(.var $globalContext),
(BinderState)IronPython.Runtime.Binding.BinderState,
(PythonLanguageFeatures)Default,
)
(.var $lineNo) = 0
(.var $lineUpdated) = (Boolean)False
.try {
{
{
}
/*empty*/;
{
(.var $lineNo) = 1
{
(PythonOps.PrintExpressionValue)(
(.var $globalContext),
.scope (
Microsoft.Scripting.Actions.CallSite`1[Microsoft.Func`4[Microsoft.Scripting.Actions.CallSite,System.Int32,System.Int32,System.Object]] $site
) {
((.var $site) = (CallSite`1)Microsoft.Scripting.Actions.CallSite`1[Microsoft.Func`4[Microsoft.Scripting.Actions.CallSite,System.Int32,System.Int32,System.Object]].Target).(Func`4.Invoke)(
(.var $site),
1,
2,
)}
,
)
}
}
}
} .fault {
{
.if (!(.var $lineUpdated) ) {(ExceptionHelpers.UpdateStackTrace)(
(.var $globalContext),
(MethodBase.GetCurrentMethod)(),
"<module>",
"<stdin>",
(.var $lineNo),
)} .else {/*empty*/;
}
(.var $lineUpdated) = (Boolean)True
}
}
}
}
}
Rewrite的意义在于把所有DynamicExpression重写为静态类型的节点,其中的动态行为则编译为CallSite的初始化(Expression.Constant())与调用(Expression.Call())。
编译出来的委托的类型为Func<Microsoft.Runtime.CompilerServices.Closure, Microsoft.Scripting.Runtime.Scope, Microsoft.Scripting.Runtime.LanguageContext, object>,内容是:
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: call Microsoft.Scripting.Runtime.CodeContext CreateTopLevelCodeContext(Microsoft.Scripting.Runtime.Scope, Microsoft.Scripting.Runtime.LanguageContext)/Microsoft.Scripting.Runtime.RuntimeHelpers
IL_0007: stloc.2
IL_0008: ldloc.2
IL_0009: ldarg.0
IL_000a: ldfld !"指定的转换无效。"!
IL_000f: ldc.i4.0
IL_0010: ldelem.ref
IL_0011: ldc.i4.0
IL_0012: call Void ModuleStarted(Microsoft.Scripting.Runtime.CodeContext, System.Object, IronPython.Compiler.PythonLanguageFeatures)/IronPython.Runtime.Operations.PythonOps
IL_0017: ldc.i4.0
IL_0018: stloc.0
IL_0019: ldc.i4.0
IL_001a: stloc.1
IL_001b: ldc.i4.1
IL_001c: stloc.0
IL_001d: ldloc.2
IL_001e: ldarg.0
IL_001f: ldfld !"指定的转换无效。"!
IL_0024: ldc.i4.1
IL_0025: ldelem.ref
IL_0026: castclass Microsoft.Scripting.Actions.CallSite`1[Microsoft.Func`4[Microsoft.Scripting.Actions.CallSite,System.Int32,System.Int32,System.Object]]
IL_002b: dup
IL_002c: stloc.3
IL_002d: ldfld !"指定的转换无效。"!
IL_0032: ldloc.3
IL_0033: ldc.i4.1
IL_0034: ldc.i4.2
IL_0035: callvirt System.Object Invoke(Microsoft.Scripting.Actions.CallSite, Int32, Int32)/Microsoft.Func`4[Microsoft.Scripting.Actions.CallSite,System.Int32,System.Int32,System.Object]
IL_003a: call Void PrintExpressionValue(Microsoft.Scripting.Runtime.CodeContext, System.Object)/IronPython.Runtime.Operations.PythonOps
IL_003f: leave IL_006c
IL_0044: ldloc.1
IL_0045: ldc.i4.0
IL_0046: ceq
IL_0048: brfalse IL_0063
IL_004d: ldloc.2
IL_004e: call System.Reflection.MethodBase GetCurrentMethod()/System.Reflection.MethodBase
IL_0053: ldstr "<module>"
IL_0058: ldstr "<stdin>"
IL_005d: ldloc.0
IL_005e: call Void UpdateStackTrace(Microsoft.Scripting.Runtime.CodeContext, System.Reflection.MethodBase, System.String, System.String, Int32)/Microsoft.Scripting.Runtime.ExceptionHelpers
IL_0063: ldc.i4.1
IL_0064: stloc.1
IL_0065: rethrow
IL_0067: leave IL_006c
IL_006c: ldnull
IL_006d: ret
执行这个委托,在原本的加法调用点会进入到先前生成的UpdateDelegates.Update2<Func<CalSite,int,int,object>,int,int,object>中,进而调用CallSite<T>.UpdateAndExecute()。
此时,该调用点尚未有任何调用记录,所以会生成一个新的monomorphic rule(CallSite<T>.CreateNewRule())。在这里,通过CallSiteBinder<T>.Bind()(具体来说是IronPython.Runtime.Binding.OperationBinder,{Python Add};Bind()方法来自MetaAction类)得到一个Rule<Func<CalSite,int,int,object>>:
//
// AST: Rule
//
.scope <rule> (
) {
.scope (
) {
.return (Int32Ops.Add)(
(.arg $arg0),
(.arg $arg1),
);
}
}
接下来,这个Rule<T>会被加入Level 2 Cache,然后赋值给Level 0 Cache并执行,如果成功则加入Level 1 Cache并将执行结果返回;失败的话则会尝试再次创建Rule<T>,重复上述创建过程。
这样就完成了一次1+2的执行。上面省略了一些Python特定的步骤(如PythonBinder、PythonOps里许多初始化),专注于DLR一侧的运行步骤。