/// <summary> /// Emits the try block and the catch blocks. /// </summary> /// <param name="codeGenerator">A code generator.</param> /// <remarks> /// <code> /// try /// { /// // guarded code // /// } /// catch(E1 $e1) /// { /// // E1 // /// } /// catch(E2 $e2) /// { /// // E2 // /// } /// </code> /// is translated as follows: /// <code> /// try /// { /// // guarded code // /// } /// catch(PhpUserException _e) /// { /// PhpObject _o = _e.UserException; /// if (_o instanceOf E1) /// { /// $e1 = _o; /// // E1 // /// } /// else if (_o instanceOf E2) /// { /// $e2 = _o; /// // E2 // /// } /// else /// { /// throw; /// } /// } /// </code> /// </remarks> internal override void Emit(CodeGenerator /*!*/ codeGenerator) { Statistics.AST.AddNode("TryStmt"); // emit try block without CLR exception block if possible if (!HasCatches && !HasFinallyStatements) { this.Statements.Emit(codeGenerator); return; } // emit CLR exception block ILEmitter il = codeGenerator.IL; codeGenerator.ExceptionBlockNestingLevel++; // TRY Label end_label = il.BeginExceptionBlock(); this.Statements.Emit(codeGenerator); // catches if (HasCatches) { // catch (PHP.Core.ScriptDiedException) // { throw; } il.BeginCatchBlock(typeof(PHP.Core.ScriptDiedException)); il.Emit(OpCodes.Rethrow); // catch (System.Exception ex) il.BeginCatchBlock(typeof(System.Exception)); // <exception_local> = (DObject) (STACK is PhpUserException) ? ((PhpUserException)STACK).UserException : ClrObject.WrapRealObject(STACK) Label clrExceptionLabel = il.DefineLabel(); Label wrapEndLabel = il.DefineLabel(); LocalBuilder exception_local = il.GetTemporaryLocal(typeof(DObject)); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Isinst, typeof(PHP.Core.PhpUserException)); // <STACK> as PhpUserException il.Emit(OpCodes.Brfalse, clrExceptionLabel); // if (<STACK> as PhpUserException != null) { il.Emit(OpCodes.Ldfld, Fields.PhpUserException_UserException); il.Emit(OpCodes.Br, wrapEndLabel); } // else il.MarkLabel(clrExceptionLabel); { il.Emit(OpCodes.Call, Methods.ClrObject_WrapRealObject); } il.MarkLabel(wrapEndLabel); il.Stloc(exception_local); // emits all PHP catch-blocks processing into a single CLI catch-block: foreach (CatchItem c in catches) { Label next_catch_label = il.DefineLabel(); // IF (exception <instanceOf> <type>); c.Emit(codeGenerator, exception_local, end_label, next_catch_label); // ELSE il.MarkLabel(next_catch_label); } il.ReturnTemporaryLocal(exception_local); // emits the "else" branch invoked if the exceptions is not catched: il.Emit(OpCodes.Rethrow); } // finally if (HasFinallyStatements) { finallyItem.Emit(codeGenerator); } // il.EndExceptionBlock(); codeGenerator.ExceptionBlockNestingLevel--; }