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-boun...@rubyforge.org 
[mailto:ironruby-core-boun...@rubyforge.org] On Behalf Of Shri Borde
Sent: Tuesday, December 30, 2008 2:28 PM
To: ironruby-core@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#

_______________________________________________
Ironruby-core mailing list
Ironruby-core@rubyforge.org
http://rubyforge.org/mailman/listinfo/ironruby-core

Reply via email to