Shri Borde
2008-Dec-30 22:27 UTC
[Ironruby-core] Interpreter, backtrace, and call site caching
For backtraces to work correctly in interpreter mode, it is required that the
interpreter guard every call to C# code with a try-catch, so that the catch
block has a chance to stash away the backtrace if an exception is thrown. This
is done in Interpreter.InvokeMethod, and the catch block gives the language a
chance to save the backtrace by calling LanguageContext.InterpretExceptionThrow.
However, with call-site caching enabled in interpreter mode,
Interpreter.InterpretMetaAction can directl invoke the compiled delegate instead
of calling Interpreter.InvokeMethod. This breaks the backtrace.
private static object InterpretMetaAction(InterpreterState state,
DynamicMetaObjectBinder action, DynamicExpression node, object[] argValues) {
...
callSiteInfo.Counter++;
if (callSiteInfo.Counter > SiteCompileThreshold) {
if (callSiteInfo.CallSite == null) {
SetCallSite(callSiteInfo, node);
}
return callSiteInfo.CallerTarget(callSiteInfo.CallSite,
argValues);
}
...
var result = Interpret(state, binding.Expression);
return result;
}
Is this a known issue? The interpreter stack trace in the unoptimized case is
shown below. The fix could be for the interpreter to maintain a separate cache
of compiled rules which have a try-catch generated for all MethodCallExpression
nodes so as to match the unoptimized code behavior.
Thanks,
Shri
Microsoft.Scripting.dll!Microsoft.Scripting.Utils.ReflectedCaller.Invoke(object[]
args = {object[0x00000001]}) Line 46 + 0x19 bytes C#
Microsoft.Scripting.dll!Microsoft.Scripting.Interpretation.Interpreter.InvokeMethod(Microsoft.Scripting.Interpretation.InterpreterState
state = {Microsoft.Scripting.Interpretation.InterpreterState},
System.Reflection.MethodInfo method = {System.Reflection.RuntimeMethodInfo},
object instance = null, object[] parameters = {object[0x00000001]}) Line 135 +
0xb bytes C#
Microsoft.Scripting.dll!Microsoft.Scripting.Interpretation.Interpreter.InterpretMethodCallExpression(Microsoft.Scripting.Interpretation.InterpreterState
state = {Microsoft.Scripting.Interpretation.InterpreterState},
System.Linq.Expressions.Expression expr =
{System.Linq.Expressions.MethodCallExpressionN}) Line 251 + 0x30 bytes
C#
Microsoft.Scripting.dll!Microsoft.Scripting.Interpretation.Interpreter.Interpret(Microsoft.Scripting.Interpretation.InterpreterState
state = {Microsoft.Scripting.Interpretation.InterpreterState},
System.Linq.Expressions.Expression expr =
{System.Linq.Expressions.MethodCallExpressionN}) Line 38 + 0xb bytes
C#
Microsoft.Scripting.dll!Microsoft.Scripting.Interpretation.Interpreter.InterpretAndCheckFlow(Microsoft.Scripting.Interpretation.InterpreterState
state = {Microsoft.Scripting.Interpretation.InterpreterState},
System.Linq.Expressions.Expression node =
{System.Linq.Expressions.MethodCallExpressionN}, out object result = null) Line
76 + 0x11 bytes C#
Microsoft.Scripting.dll!Microsoft.Scripting.Interpretation.Interpreter.InterpretBlockExpression(Microsoft.Scripting.Interpretation.InterpreterState
state = {Microsoft.Scripting.Interpretation.InterpreterState},
System.Linq.Expressions.Expression expr = {System.Linq.Expressions.Block2}) Line
1256 + 0xf bytes C#
Microsoft.Scripting.dll!Microsoft.Scripting.Interpretation.Interpreter.Interpret(Microsoft.Scripting.Interpretation.InterpreterState
state = {Microsoft.Scripting.Interpretation.InterpreterState},
System.Linq.Expressions.Expression expr = {System.Linq.Expressions.Block2}) Line
79 + 0xb bytes C#
Microsoft.Scripting.dll!Microsoft.Scripting.Interpretation.Interpreter.InterpretAndCheckYield(Microsoft.Scripting.Interpretation.InterpreterState
state = {Microsoft.Scripting.Interpretation.InterpreterState},
System.Linq.Expressions.Expression target = {System.Linq.Expressions.Block2},
out object res = true) Line 86 + 0x11 bytes C#
Microsoft.Scripting.dll!Microsoft.Scripting.Interpretation.Interpreter.InterpretConditionalExpression(Microsoft.Scripting.Interpretation.InterpreterState
state = {Microsoft.Scripting.Interpretation.InterpreterState},
System.Linq.Expressions.Expression expr =
{System.Linq.Expressions.FullConditionalExpression}) Line 113 + 0x22 bytes
C#
Microsoft.Scripting.dll!Microsoft.Scripting.Interpretation.Interpreter.Interpret(Microsoft.Scripting.Interpretation.InterpreterState
state = {Microsoft.Scripting.Interpretation.InterpreterState},
System.Linq.Expressions.Expression expr =
{System.Linq.Expressions.FullConditionalExpression}) Line 40 + 0xb bytes
C#
Microsoft.Scripting.dll!Microsoft.Scripting.Interpretation.Interpreter.InterpretMetaAction(Microsoft.Scripting.Interpretation.InterpreterState
state = {Microsoft.Scripting.Interpretation.InterpreterState},
System.Dynamic.DynamicMetaObjectBinder action =
{IronRuby.Runtime.Calls.RubyCallAction},
System.Linq.Expressions.DynamicExpression node =
{System.Linq.Expressions.DynamicExpression2}, object[] argValues =
{object[0x00000002]}) Line 810 + 0x2a bytes C#
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://rubyforge.org/pipermail/ironruby-core/attachments/20081230/53c351a0/attachment.html>
Shri Borde
2008-Dec-31 08:05 UTC
[Ironruby-core] Interpreter, backtrace, and call site caching
Adding a try-catch around the optimized case (callSiteInfo.CallerTarget) fixes
the problem. However, this points out that we need to have a try-catch around
every operation in Interpreter.cs that could cause an exception and have the
catch call LanguageContext.InterpretExceptionThrow.
From: ironruby-core-bounces at rubyforge.org [mailto:ironruby-core-bounces at
rubyforge.org] On Behalf Of Shri Borde
Sent: Tuesday, December 30, 2008 2:28 PM
To: ironruby-core at rubyforge.org
Subject: [Ironruby-core] Interpreter, backtrace, and call site caching
For backtraces to work correctly in interpreter mode, it is required that the
interpreter guard every call to C# code with a try-catch, so that the catch
block has a chance to stash away the backtrace if an exception is thrown. This
is done in Interpreter.InvokeMethod, and the catch block gives the language a
chance to save the backtrace by calling LanguageContext.InterpretExceptionThrow.
However, with call-site caching enabled in interpreter mode,
Interpreter.InterpretMetaAction can directl invoke the compiled delegate instead
of calling Interpreter.InvokeMethod. This breaks the backtrace.
private static object InterpretMetaAction(InterpreterState state,
DynamicMetaObjectBinder action, DynamicExpression node, object[] argValues) {
...
callSiteInfo.Counter++;
if (callSiteInfo.Counter > SiteCompileThreshold) {
if (callSiteInfo.CallSite == null) {
SetCallSite(callSiteInfo, node);
}
return callSiteInfo.CallerTarget(callSiteInfo.CallSite,
argValues);
}
...
var result = Interpret(state, binding.Expression);
return result;
}
Is this a known issue? The interpreter stack trace in the unoptimized case is
shown below. The fix could be for the interpreter to maintain a separate cache
of compiled rules which have a try-catch generated for all MethodCallExpression
nodes so as to match the unoptimized code behavior.
Thanks,
Shri
Microsoft.Scripting.dll!Microsoft.Scripting.Utils.ReflectedCaller.Invoke(object[]
args = {object[0x00000001]}) Line 46 + 0x19 bytes C#
Microsoft.Scripting.dll!Microsoft.Scripting.Interpretation.Interpreter.InvokeMethod(Microsoft.Scripting.Interpretation.InterpreterState
state = {Microsoft.Scripting.Interpretation.InterpreterState},
System.Reflection.MethodInfo method = {System.Reflection.RuntimeMethodInfo},
object instance = null, object[] parameters = {object[0x00000001]}) Line 135 +
0xb bytes C#
Microsoft.Scripting.dll!Microsoft.Scripting.Interpretation.Interpreter.InterpretMethodCallExpression(Microsoft.Scripting.Interpretation.InterpreterState
state = {Microsoft.Scripting.Interpretation.InterpreterState},
System.Linq.Expressions.Expression expr =
{System.Linq.Expressions.MethodCallExpressionN}) Line 251 + 0x30 bytes
C#
Microsoft.Scripting.dll!Microsoft.Scripting.Interpretation.Interpreter.Interpret(Microsoft.Scripting.Interpretation.InterpreterState
state = {Microsoft.Scripting.Interpretation.InterpreterState},
System.Linq.Expressions.Expression expr =
{System.Linq.Expressions.MethodCallExpressionN}) Line 38 + 0xb bytes
C#
Microsoft.Scripting.dll!Microsoft.Scripting.Interpretation.Interpreter.InterpretAndCheckFlow(Microsoft.Scripting.Interpretation.InterpreterState
state = {Microsoft.Scripting.Interpretation.InterpreterState},
System.Linq.Expressions.Expression node =
{System.Linq.Expressions.MethodCallExpressionN}, out object result = null) Line
76 + 0x11 bytes C#
Microsoft.Scripting.dll!Microsoft.Scripting.Interpretation.Interpreter.InterpretBlockExpression(Microsoft.Scripting.Interpretation.InterpreterState
state = {Microsoft.Scripting.Interpretation.InterpreterState},
System.Linq.Expressions.Expression expr = {System.Linq.Expressions.Block2}) Line
1256 + 0xf bytes C#
Microsoft.Scripting.dll!Microsoft.Scripting.Interpretation.Interpreter.Interpret(Microsoft.Scripting.Interpretation.InterpreterState
state = {Microsoft.Scripting.Interpretation.InterpreterState},
System.Linq.Expressions.Expression expr = {System.Linq.Expressions.Block2}) Line
79 + 0xb bytes C#
Microsoft.Scripting.dll!Microsoft.Scripting.Interpretation.Interpreter.InterpretAndCheckYield(Microsoft.Scripting.Interpretation.InterpreterState
state = {Microsoft.Scripting.Interpretation.InterpreterState},
System.Linq.Expressions.Expression target = {System.Linq.Expressions.Block2},
out object res = true) Line 86 + 0x11 bytes C#
Microsoft.Scripting.dll!Microsoft.Scripting.Interpretation.Interpreter.InterpretConditionalExpression(Microsoft.Scripting.Interpretation.InterpreterState
state = {Microsoft.Scripting.Interpretation.InterpreterState},
System.Linq.Expressions.Expression expr =
{System.Linq.Expressions.FullConditionalExpression}) Line 113 + 0x22 bytes
C#
Microsoft.Scripting.dll!Microsoft.Scripting.Interpretation.Interpreter.Interpret(Microsoft.Scripting.Interpretation.InterpreterState
state = {Microsoft.Scripting.Interpretation.InterpreterState},
System.Linq.Expressions.Expression expr =
{System.Linq.Expressions.FullConditionalExpression}) Line 40 + 0xb bytes
C#
Microsoft.Scripting.dll!Microsoft.Scripting.Interpretation.Interpreter.InterpretMetaAction(Microsoft.Scripting.Interpretation.InterpreterState
state = {Microsoft.Scripting.Interpretation.InterpreterState},
System.Dynamic.DynamicMetaObjectBinder action =
{IronRuby.Runtime.Calls.RubyCallAction},
System.Linq.Expressions.DynamicExpression node =
{System.Linq.Expressions.DynamicExpression2}, object[] argValues =
{object[0x00000002]}) Line 810 + 0x2a bytes C#
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://rubyforge.org/pipermail/ironruby-core/attachments/20081231/8abb9514/attachment-0001.html>