The Labs \ Source Viewer \ SSCLI \ Microsoft.JScript \ Try

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. namespace Microsoft.JScript
  16. {
  17.    
  18.     using Microsoft.JScript.Vsa;
  19.     using System;
  20.     using System.Collections;
  21.     using System.Reflection;
  22.     using System.Reflection.Emit;
  23.    
  24.     public sealed class Try : AST
  25.     {
  26.         private AST body;
  27.         private TypeExpression type;
  28.         private AST handler;
  29.         private AST finally_block;
  30.         private BlockScope handler_scope;
  31.         private FieldInfo field;
  32.         private string fieldName;
  33.         private bool finallyHasControlFlowOutOfIt;
  34.         private Context tryEndContext;
  35.        
  36.         internal Try(Context context, AST body, AST identifier, TypeExpression type, AST handler, AST finally_block, bool finallyHasControlFlowOutOfIt, Context tryEndContext) : base(context)
  37.         {
  38.             this.body = body;
  39.             this.type = type;
  40.             this.handler = handler;
  41.             this.finally_block = finally_block;
  42.             ScriptObject current_scope = (ScriptObject)Globals.ScopeStack.Peek();
  43.             while (current_scope is WithObject)
  44.                 //Can only happen at run time and only if there is an eval
  45.                 current_scope = current_scope.GetParent();
  46.             this.handler_scope = null;
  47.             this.field = null;
  48.             if (identifier != null) {
  49.                 this.fieldName = identifier.ToString();
  50.                 this.field = current_scope.GetField(this.fieldName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
  51.                 if (this.field != null) {
  52.                     if (type == null && (field is JSVariableField && field.IsStatic && ((JSVariableField)field).type == null) && !field.IsLiteral && !field.IsInitOnly)
  53.                         return;
  54.                     //preserve legacy semantics by using the existing variable
  55.                     if (((IActivationObject)current_scope).GetLocalField(this.fieldName) != null)
  56.                         identifier.context.HandleError(JSError.DuplicateName, false);
  57.                 }
  58.                 this.handler_scope = new BlockScope(current_scope);
  59.                 this.handler_scope.catchHanderScope = true;
  60.                 JSVariableField f = this.handler_scope.AddNewField(identifier.ToString(), Missing.Value, FieldAttributes.Public);
  61.                 // must be a local
  62.                 this.field = f;
  63.                 f.originalContext = identifier.context;
  64.                 if (identifier.context.document.debugOn && this.field is JSLocalField) {
  65.                     this.handler_scope.AddFieldForLocalScopeDebugInfo((JSLocalField)this.field);
  66.                 }
  67.             }
  68.             this.finallyHasControlFlowOutOfIt = finallyHasControlFlowOutOfIt;
  69.             this.tryEndContext = tryEndContext;
  70.         }
  71.        
  72.         internal override object Evaluate()
  73.         {
  74.             int i = Globals.ScopeStack.Size();
  75.             int j = Globals.CallContextStack.Size();
  76.             Completion bc = null;
  77.             Completion fc = null;
  78.             try {
  79.                 object eValue = null;
  80.                 try {
  81.                     bc = (Completion)this.body.Evaluate();
  82.                 }
  83.                 catch (Exception e) {
  84.                     if (this.handler == null)
  85.                         throw;
  86.                     eValue = e;
  87.                     if (this.type != null) {
  88.                         Type ht = this.type.ToType();
  89.                         if (Typeob.Exception.IsAssignableFrom(ht)) {
  90.                             if (!ht.IsInstanceOfType(e))
  91.                                 throw;
  92.                         }
  93.                         else if (!ht.IsInstanceOfType(eValue = JScriptExceptionValue(e, this.Engine)))
  94.                             throw;
  95.                     }
  96.                     else
  97.                         eValue = JScriptExceptionValue(e, this.Engine);
  98.                 }
  99.                 catch {
  100.                     eValue = new JScriptException(JSError.NonClsException);
  101.                 }
  102.                
  103.                 if (eValue != null) {
  104.                     Globals.ScopeStack.TrimToSize(i);
  105.                     Globals.CallContextStack.TrimToSize(j);
  106.                     if (this.handler_scope != null) {
  107.                         this.handler_scope.SetParent(Globals.ScopeStack.Peek());
  108.                         Globals.ScopeStack.Push(this.handler_scope);
  109.                     }
  110.                     if (this.field != null)
  111.                         this.field.SetValue(Globals.ScopeStack.Peek(), eValue);
  112.                     bc = (Completion)this.handler.Evaluate();
  113.                 }
  114.             }
  115.             finally {
  116.                 Globals.ScopeStack.TrimToSize(i);
  117.                 Globals.CallContextStack.TrimToSize(j);
  118.                 if (this.finally_block != null) {
  119.                     fc = (Completion)this.finally_block.Evaluate();
  120.                 }
  121.             }
  122.             if (bc == null || fc != null && (fc.Exit > 0 || fc.Continue > 0 || fc.Return))
  123.                 bc = fc;
  124.             else {
  125.                 if (fc != null && fc.value is Missing)
  126.                     bc.value = fc.value;
  127.             }
  128.             Completion result = new Completion();
  129.             result.Continue = bc.Continue - 1;
  130.             result.Exit = bc.Exit - 1;
  131.             result.Return = bc.Return;
  132.             result.value = bc.value;
  133.             return result;
  134.         }
  135.        
  136.         internal override Context GetFirstExecutableContext()
  137.         {
  138.             return this.body.GetFirstExecutableContext();
  139.         }
  140.        
  141.         public static object JScriptExceptionValue(object e, VsaEngine engine)
  142.         {
  143.             if (engine == null) {
  144.                 engine = new VsaEngine(true);
  145.                 engine.InitVsaEngine("JS7://Microsoft.JScript.Vsa.VsaEngine", new DefaultVsaSite());
  146.             }
  147.             ErrorConstructor originalError = engine.Globals.globalObject.originalError;
  148.             if (e is JScriptException) {
  149.                 object value = ((JScriptException)e).value;
  150.                 if (value is Exception || value is Missing || (((JScriptException)e).Number & 65535) != (int)JSError.UncaughtException)
  151.                     return originalError.Construct((Exception)e);
  152.                 return value;
  153.                 //The exception wraps a non-exception value
  154.             }
  155.             else if (e is StackOverflowException)
  156.                 return originalError.Construct(new JScriptException(JSError.OutOfStack));
  157.             else if (e is OutOfMemoryException)
  158.                 return originalError.Construct(new JScriptException(JSError.OutOfMemory));
  159.             return originalError.Construct(e);
  160.         }
  161.        
  162.         internal override AST PartiallyEvaluate()
  163.         {
  164.             if (this.type != null) {
  165.                 this.type.PartiallyEvaluate();
  166.                 ((JSVariableField)this.field).type = type;
  167.             }
  168.             else if (this.field is JSLocalField)
  169.                 ((JSLocalField)this.field).SetInferredType(Typeob.Object, null);
  170.             //This should never give an error
  171.             ScriptObject current_scope = Globals.ScopeStack.Peek();
  172.             while (current_scope is WithObject)
  173.                 current_scope = current_scope.GetParent();
  174.             FunctionScope scope = null;
  175.             BitArray before = null;
  176.             if (current_scope is FunctionScope) {
  177.                 scope = (FunctionScope)current_scope;
  178.                 before = scope.DefinedFlags;
  179.             }
  180.             this.body = this.body.PartiallyEvaluate();
  181.             if (this.handler != null) {
  182.                 if (this.handler_scope != null)
  183.                     Globals.ScopeStack.Push(this.handler_scope);
  184.                 if (this.field is JSLocalField)
  185.                     ((JSLocalField)this.field).isDefined = true;
  186.                 this.handler = this.handler.PartiallyEvaluate();
  187.                 if (this.handler_scope != null)
  188.                     Globals.ScopeStack.Pop();
  189.             }
  190.             if (this.finally_block != null)
  191.                 this.finally_block = this.finally_block.PartiallyEvaluate();
  192.             if (scope != null)
  193.                 scope.DefinedFlags = before;
  194.             return this;
  195.         }
  196.        
  197.         public static void PushHandlerScope(VsaEngine engine, string id, int scopeId)
  198.         {
  199.             engine.PushScriptObject(new BlockScope(engine.ScriptObjectStackTop(), id, scopeId));
  200.         }
  201.        
  202.         internal override void TranslateToIL(ILGenerator il, Type rtype)
  203.         {
  204.             //This assumes that rtype == Void.class.
  205.             bool savedInsideProtectedRegion = compilerGlobals.InsideProtectedRegion;
  206.             compilerGlobals.InsideProtectedRegion = true;
  207.             compilerGlobals.BreakLabelStack.Push(compilerGlobals.BreakLabelStack.Peek(0));
  208.             compilerGlobals.ContinueLabelStack.Push(compilerGlobals.ContinueLabelStack.Peek(0));
  209.             il.BeginExceptionBlock();
  210.             if (this.finally_block != null) {
  211.                 if (this.finallyHasControlFlowOutOfIt)
  212.                     il.BeginExceptionBlock();
  213.                 if (this.handler != null)
  214.                     il.BeginExceptionBlock();
  215.             }
  216.             this.body.TranslateToIL(il, Typeob.Void);
  217.             if (this.tryEndContext != null)
  218.                 this.tryEndContext.EmitLineInfo(il);
  219.             if (this.handler != null) {
  220.                 if (this.type == null) {
  221.                     il.BeginCatchBlock(Typeob.Exception);
  222.                     this.handler.context.EmitLineInfo(il);
  223.                     this.EmitILToLoadEngine(il);
  224.                     il.Emit(OpCodes.Call, CompilerGlobals.jScriptExceptionValueMethod);
  225.                 }
  226.                 else {
  227.                     Type filterType = this.type.ToType();
  228.                     if (Typeob.Exception.IsAssignableFrom(filterType)) {
  229.                         il.BeginCatchBlock(filterType);
  230.                         this.handler.context.EmitLineInfo(il);
  231.                     }
  232.                     else {
  233.                         il.BeginExceptFilterBlock();
  234.                         this.handler.context.EmitLineInfo(il);
  235.                         this.EmitILToLoadEngine(il);
  236.                         il.Emit(OpCodes.Call, CompilerGlobals.jScriptExceptionValueMethod);
  237.                         il.Emit(OpCodes.Isinst, filterType);
  238.                         il.Emit(OpCodes.Ldnull);
  239.                         il.Emit(OpCodes.Cgt_Un);
  240.                         il.BeginCatchBlock(null);
  241.                         this.EmitILToLoadEngine(il);
  242.                         il.Emit(OpCodes.Call, CompilerGlobals.jScriptExceptionValueMethod);
  243.                         Convert.Emit(this, il, Typeob.Object, filterType);
  244.                     }
  245.                 }
  246.                 object tok = this.field is JSVariableField ? ((JSVariableField)this.field).GetMetaData() : this.field;
  247.                 if (tok is LocalBuilder)
  248.                     il.Emit(OpCodes.Stloc, (LocalBuilder)tok);
  249.                 else if (tok is FieldInfo)
  250.                     il.Emit(OpCodes.Stsfld, (FieldInfo)tok);
  251.                 else
  252.                     Convert.EmitLdarg(il, (short)tok);
  253.                
  254.                 if (this.handler_scope != null) {
  255.                     if (!this.handler_scope.isKnownAtCompileTime) {
  256.                         //I.e. eval or nested func
  257.                         this.EmitILToLoadEngine(il);
  258.                         il.Emit(OpCodes.Ldstr, this.fieldName);
  259.                         ConstantWrapper.TranslateToILInt(il, this.handler_scope.scopeId);
  260.                         il.Emit(OpCodes.Call, Typeob.Try.GetMethod("PushHandlerScope"));
  261.                         Globals.ScopeStack.Push(this.handler_scope);
  262.                         il.BeginExceptionBlock();
  263.                     }
  264.                     il.BeginScope();
  265.                     // so that we can emit local scoped information for the handler variable
  266.                     if (this.context.document.debugOn)
  267.                         this.handler_scope.EmitLocalInfoForFields(il);
  268.                 }
  269.                 this.handler.TranslateToIL(il, Typeob.Void);
  270.                 if (this.handler_scope != null) {
  271.                     il.EndScope();
  272.                     if (!this.handler_scope.isKnownAtCompileTime) {
  273.                         //I.e. eval or nested func
  274.                         il.BeginFinallyBlock();
  275.                         this.EmitILToLoadEngine(il);
  276.                         il.Emit(OpCodes.Call, CompilerGlobals.popScriptObjectMethod);
  277.                         il.Emit(OpCodes.Pop);
  278.                         Globals.ScopeStack.Pop();
  279.                         il.EndExceptionBlock();
  280.                     }
  281.                 }
  282.                 il.EndExceptionBlock();
  283.             }
  284.             if (this.finally_block != null) {
  285.                 bool savedInsideFinally = compilerGlobals.InsideFinally;
  286.                 int savedFinallyStackTop = compilerGlobals.FinallyStackTop;
  287.                 compilerGlobals.InsideFinally = true;
  288.                 compilerGlobals.FinallyStackTop = compilerGlobals.BreakLabelStack.Size();
  289.                 il.BeginFinallyBlock();
  290.                 this.finally_block.TranslateToIL(il, Typeob.Void);
  291.                 il.EndExceptionBlock();
  292.                 compilerGlobals.InsideFinally = savedInsideFinally;
  293.                 compilerGlobals.FinallyStackTop = savedFinallyStackTop;
  294.                 if (this.finallyHasControlFlowOutOfIt) {
  295.                     il.BeginCatchBlock(Typeob.BreakOutOfFinally);
  296.                     il.Emit(OpCodes.Ldfld, Typeob.BreakOutOfFinally.GetField("target"));
  297.                     // don't need to go to 0 in the loop because 0 is the outmost block (i.e. function body)
  298.                     // and that would generate a JIT assert because the jump is sometimes outside the function
  299.                     for (int i = compilerGlobals.BreakLabelStack.Size() - 1int n = i; i > 0; i--) {
  300.                         il.Emit(OpCodes.Dup);
  301.                         ConstantWrapper.TranslateToILInt(il, i);
  302.                         Label lab = il.DefineLabel();
  303.                         il.Emit(OpCodes.Blt_S, lab);
  304.                         il.Emit(OpCodes.Pop);
  305.                         if (savedInsideFinally && i < savedFinallyStackTop)
  306.                             il.Emit(OpCodes.Rethrow);
  307.                         else
  308.                             il.Emit(OpCodes.Leave, (Label)compilerGlobals.BreakLabelStack.Peek(n - i));
  309.                         il.MarkLabel(lab);
  310.                     }
  311.                     il.Emit(OpCodes.Pop);
  312.                     il.BeginCatchBlock(Typeob.ContinueOutOfFinally);
  313.                     il.Emit(OpCodes.Ldfld, Typeob.ContinueOutOfFinally.GetField("target"));
  314.                     // don't need to go to 0 in the loop because 0 is the outmost block (i.e. function body)
  315.                     for (int i = compilerGlobals.ContinueLabelStack.Size() - 1int n = i; i > 0; i--) {
  316.                         il.Emit(OpCodes.Dup);
  317.                         ConstantWrapper.TranslateToILInt(il, i);
  318.                         Label lab = il.DefineLabel();
  319.                         il.Emit(OpCodes.Blt_S, lab);
  320.                         il.Emit(OpCodes.Pop);
  321.                         if (savedInsideFinally && i < savedFinallyStackTop)
  322.                             il.Emit(OpCodes.Rethrow);
  323.                         else
  324.                             il.Emit(OpCodes.Leave, (Label)compilerGlobals.ContinueLabelStack.Peek(n - i));
  325.                         il.MarkLabel(lab);
  326.                     }
  327.                     il.Emit(OpCodes.Pop);
  328.                     ScriptObject scope = Globals.ScopeStack.Peek();
  329.                     while (scope != null && !(scope is FunctionScope))
  330.                         scope = scope.GetParent();
  331.                     if (scope != null && !savedInsideFinally) {
  332.                         il.BeginCatchBlock(Typeob.ReturnOutOfFinally);
  333.                         il.Emit(OpCodes.Pop);
  334.                         il.Emit(OpCodes.Leave, ((FunctionScope)scope).owner.returnLabel);
  335.                     }
  336.                     il.EndExceptionBlock();
  337.                 }
  338.             }
  339.             compilerGlobals.InsideProtectedRegion = savedInsideProtectedRegion;
  340.             compilerGlobals.BreakLabelStack.Pop();
  341.             compilerGlobals.ContinueLabelStack.Pop();
  342.         }
  343.        
  344.         internal override void TranslateToILInitializer(ILGenerator il)
  345.         {
  346.             this.body.TranslateToILInitializer(il);
  347.             if (this.handler != null)
  348.                 this.handler.TranslateToILInitializer(il);
  349.             if (this.finally_block != null)
  350.                 this.finally_block.TranslateToILInitializer(il);
  351.         }
  352.        
  353.     }
  354.    
  355. }

Developer Fusion