internal override void TranslateToIL(ILGenerator il, Type rtype){ //This assumes that rtype == Void.class. bool savedInsideProtectedRegion = compilerGlobals.InsideProtectedRegion; compilerGlobals.InsideProtectedRegion = true; compilerGlobals.BreakLabelStack.Push(compilerGlobals.BreakLabelStack.Peek(0)); compilerGlobals.ContinueLabelStack.Push(compilerGlobals.ContinueLabelStack.Peek(0)); il.BeginExceptionBlock(); if (this.finally_block != null){ if (this.finallyHasControlFlowOutOfIt) il.BeginExceptionBlock(); if (this.handler != null) il.BeginExceptionBlock(); } this.body.TranslateToIL(il, Typeob.Void); if (this.tryEndContext != null) this.tryEndContext.EmitLineInfo(il); if (this.handler != null){ if (this.type == null){ il.BeginCatchBlock(typeof(Exception)); this.handler.context.EmitLineInfo(il); this.EmitILToLoadEngine(il); il.Emit(OpCodes.Call, CompilerGlobals.jScriptExceptionValueMethod); }else{ Type filterType = this.type.ToType(); if (typeof(Exception).IsAssignableFrom(filterType)){ il.BeginCatchBlock(filterType); this.handler.context.EmitLineInfo(il); } else{ il.BeginExceptFilterBlock(); this.handler.context.EmitLineInfo(il); this.EmitILToLoadEngine(il); il.Emit(OpCodes.Call, CompilerGlobals.jScriptExceptionValueMethod); il.Emit(OpCodes.Isinst, filterType); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Cgt_Un); il.BeginCatchBlock(null); this.EmitILToLoadEngine(il); il.Emit(OpCodes.Call, CompilerGlobals.jScriptExceptionValueMethod); Convert.Emit(this, il, Typeob.Object, filterType); } } Object tok = this.field is JSVariableField ? ((JSVariableField)this.field).GetMetaData() : this.field; if (tok is LocalBuilder) il.Emit(OpCodes.Stloc, (LocalBuilder)tok); else if (tok is FieldInfo) il.Emit(OpCodes.Stsfld, (FieldInfo)tok); else Convert.EmitLdarg(il, (short)tok); if (this.handler_scope != null){ if (!this.handler_scope.isKnownAtCompileTime){ //I.e. eval or nested func this.EmitILToLoadEngine(il); il.Emit(OpCodes.Ldstr, this.fieldName); ConstantWrapper.TranslateToILInt(il, this.handler_scope.scopeId); il.Emit(OpCodes.Call, typeof(Try).GetMethod("PushHandlerScope")); Globals.ScopeStack.Push(this.handler_scope); } il.BeginScope(); // so that we can emit local scoped information for the handler variable if (this.context.document.debugOn) this.handler_scope.EmitLocalInfoForFields(il); } this.handler.TranslateToIL(il, Typeob.Void); if (this.handler_scope != null){ il.EndScope(); if (!this.handler_scope.isKnownAtCompileTime){ //I.e. eval or nested func this.EmitILToLoadEngine(il); il.Emit(OpCodes.Call, CompilerGlobals.popScriptObjectMethod); il.Emit(OpCodes.Pop); Globals.ScopeStack.Pop(); } } il.EndExceptionBlock(); } if (this.finally_block != null){ bool savedInsideFinally = compilerGlobals.InsideFinally; int savedFinallyStackTop = compilerGlobals.FinallyStackTop; compilerGlobals.InsideFinally = true; compilerGlobals.FinallyStackTop = compilerGlobals.BreakLabelStack.Size(); il.BeginFinallyBlock(); this.finally_block.TranslateToIL(il, Typeob.Void); il.EndExceptionBlock(); compilerGlobals.InsideFinally = savedInsideFinally; compilerGlobals.FinallyStackTop = savedFinallyStackTop; if (this.finallyHasControlFlowOutOfIt){ il.BeginCatchBlock(typeof(BreakOutOfFinally)); il.Emit(OpCodes.Ldfld, typeof(BreakOutOfFinally).GetField("target")); // don't need to go to 0 in the loop because 0 is the outmost block (i.e. function body) // and that would generate a JIT assert because the jump is sometimes outside the function for (int i = compilerGlobals.BreakLabelStack.Size()-1, n = i; i > 0; i--){ il.Emit(OpCodes.Dup); ConstantWrapper.TranslateToILInt(il, i); Label lab = il.DefineLabel(); il.Emit(OpCodes.Blt_S, lab); il.Emit(OpCodes.Pop); if (savedInsideFinally && i < savedFinallyStackTop) il.Emit(OpCodes.Rethrow); else il.Emit(OpCodes.Leave, (Label)compilerGlobals.BreakLabelStack.Peek(n-i)); il.MarkLabel(lab); } il.Emit(OpCodes.Pop); il.BeginCatchBlock(typeof(ContinueOutOfFinally)); il.Emit(OpCodes.Ldfld, typeof(ContinueOutOfFinally).GetField("target")); // don't need to go to 0 in the loop because 0 is the outmost block (i.e. function body) for (int i = compilerGlobals.ContinueLabelStack.Size()-1, n = i; i > 0; i--){ il.Emit(OpCodes.Dup); ConstantWrapper.TranslateToILInt(il, i); Label lab = il.DefineLabel(); il.Emit(OpCodes.Blt_S, lab); il.Emit(OpCodes.Pop); if (savedInsideFinally && i < savedFinallyStackTop) il.Emit(OpCodes.Rethrow); else il.Emit(OpCodes.Leave, (Label)compilerGlobals.ContinueLabelStack.Peek(n-i)); il.MarkLabel(lab); } il.Emit(OpCodes.Pop); ScriptObject scope = Globals.ScopeStack.Peek(); while (scope != null && !(scope is FunctionScope)) scope = scope.GetParent(); if (scope != null && !savedInsideFinally){ il.BeginCatchBlock(typeof(ReturnOutOfFinally)); il.Emit(OpCodes.Pop); il.Emit(OpCodes.Leave, ((FunctionScope)scope).owner.returnLabel); } il.EndExceptionBlock(); } } compilerGlobals.InsideProtectedRegion = savedInsideProtectedRegion; compilerGlobals.BreakLabelStack.Pop(); compilerGlobals.ContinueLabelStack.Pop(); }
/// <summary> /// Try to emit something like that: /// /// .method public static bool TestFilter (bool execute_handler) /// { /// .locals init(bool) /// try { /// newobj instance void [mscorlib]System.Exception::.ctor() /// throw /// } filter { /// pop /// ldarg.0 /// endfilter /// } { /// ldc.i4.1 /// stloc.0 /// leave quit /// } /// ldc.i4.0 /// stloc.0 /// quit: /// ldloc.0 /// ret /// } /// /// It should return true if the handler has been executed /// Otherwise, the exception should not be catched /// </summary> void DefineTestFilterMethod () { MethodBuilder mb = tb.DefineMethod("TestFilter", MethodAttributes.Public | MethodAttributes.Static, typeof(bool), new Type [] { typeof (bool) }); ConstructorInfo exCtor = typeof (Exception).GetConstructor (new Type [0]); il_gen = mb.GetILGenerator (); il_gen.DeclareLocal (typeof (bool)); Label quit = il_gen.DefineLabel (); il_gen.BeginExceptionBlock (); il_gen.Emit (OpCodes.Newobj, exCtor); il_gen.Emit (OpCodes.Throw); il_gen.BeginExceptFilterBlock (); il_gen.Emit (OpCodes.Pop); il_gen.Emit (OpCodes.Ldarg_0); il_gen.BeginCatchBlock (null); il_gen.Emit (OpCodes.Ldc_I4_1); il_gen.Emit (OpCodes.Stloc_0); il_gen.Emit (OpCodes.Leave, quit); il_gen.EndExceptionBlock (); il_gen.Emit (OpCodes.Ldc_I4_0); il_gen.Emit (OpCodes.Stloc_0); il_gen.MarkLabel (quit); il_gen.Emit (OpCodes.Ldloc_0); il_gen.Emit (OpCodes.Ret); }
///<inheritdoc/> public override void BeginFilterBlock() { Generator.BeginExceptFilterBlock(); }