/// <summary>Push a new try block onto the exception information stack.</summary> /// <remarks>Push a new try block onto the exception information stack.</remarks> /// <param name="node"> /// an exception handling node (node.getType() == /// Token.TRY) /// </param> internal virtual void PushExceptionInfo(Jump node) { Node fBlock = this._enclosing.GetFinallyAtTarget(node.GetFinally()); BodyCodegen.ExceptionManager.ExceptionInfo ei = new BodyCodegen.ExceptionManager.ExceptionInfo(this, node, fBlock); this.exceptionInfo.Add(ei); }
private void VisitTryCatchFinally(Jump node, Node child) { // OPT we only need to do this if there are enclosed WITH // statements; could statically check and omit this if there aren't any. // XXX OPT Maybe instead do syntactic transforms to associate // each 'with' with a try/finally block that does the exitwith. short savedVariableObject = GetNewWordLocal(); cfw.AddALoad(variableObjectLocal); cfw.AddAStore(savedVariableObject); int startLabel = cfw.AcquireLabel(); cfw.MarkLabel(startLabel, (short)0); Node catchTarget = node.target; Node finallyTarget = node.GetFinally(); int[] handlerLabels = new int[EXCEPTION_MAX]; exceptionManager.PushExceptionInfo(node); if (catchTarget != null) { handlerLabels[JAVASCRIPT_EXCEPTION] = cfw.AcquireLabel(); handlerLabels[EVALUATOR_EXCEPTION] = cfw.AcquireLabel(); handlerLabels[ECMAERROR_EXCEPTION] = cfw.AcquireLabel(); Context cx = Context.GetCurrentContext(); if (cx != null && cx.HasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS)) { handlerLabels[THROWABLE_EXCEPTION] = cfw.AcquireLabel(); } } if (finallyTarget != null) { handlerLabels[FINALLY_EXCEPTION] = cfw.AcquireLabel(); } exceptionManager.SetHandlers(handlerLabels, startLabel); // create a table for the equivalent of JSR returns if (isGenerator && finallyTarget != null) { BodyCodegen.FinallyReturnPoint ret = new BodyCodegen.FinallyReturnPoint(); if (finallys == null) { finallys = new Dictionary<Node, BodyCodegen.FinallyReturnPoint>(); } // add the finally target to hashtable finallys.Put(finallyTarget, ret); // add the finally node as well to the hash table finallys.Put(finallyTarget.GetNext(), ret); } while (child != null) { if (child == catchTarget) { int catchLabel = GetTargetLabel(catchTarget); exceptionManager.RemoveHandler(JAVASCRIPT_EXCEPTION, catchLabel); exceptionManager.RemoveHandler(EVALUATOR_EXCEPTION, catchLabel); exceptionManager.RemoveHandler(ECMAERROR_EXCEPTION, catchLabel); exceptionManager.RemoveHandler(THROWABLE_EXCEPTION, catchLabel); } GenerateStatement(child); child = child.GetNext(); } // control flow skips the handlers int realEnd = cfw.AcquireLabel(); cfw.Add(ByteCode.GOTO, realEnd); int exceptionLocal = GetLocalBlockRegister(node); // javascript handler; unwrap exception and GOTO to javascript // catch area. if (catchTarget != null) { // get the label to goto int catchLabel = catchTarget.LabelId(); // If the function is a generator, then handlerLabels will consist // of zero labels. generateCatchBlock will create its own label // in this case. The extra parameter for the label is added for // the case of non-generator functions that inline finally blocks. GenerateCatchBlock(JAVASCRIPT_EXCEPTION, savedVariableObject, catchLabel, exceptionLocal, handlerLabels[JAVASCRIPT_EXCEPTION]); GenerateCatchBlock(EVALUATOR_EXCEPTION, savedVariableObject, catchLabel, exceptionLocal, handlerLabels[EVALUATOR_EXCEPTION]); GenerateCatchBlock(ECMAERROR_EXCEPTION, savedVariableObject, catchLabel, exceptionLocal, handlerLabels[ECMAERROR_EXCEPTION]); Context cx = Context.GetCurrentContext(); if (cx != null && cx.HasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS)) { GenerateCatchBlock(THROWABLE_EXCEPTION, savedVariableObject, catchLabel, exceptionLocal, handlerLabels[THROWABLE_EXCEPTION]); } } // finally handler; catch all exceptions, store to a local; JSR to // the finally, then re-throw. if (finallyTarget != null) { int finallyHandler = cfw.AcquireLabel(); int finallyEnd = cfw.AcquireLabel(); cfw.MarkHandler(finallyHandler); if (!isGenerator) { cfw.MarkLabel(handlerLabels[FINALLY_EXCEPTION]); } cfw.AddAStore(exceptionLocal); // reset the variable object local cfw.AddALoad(savedVariableObject); cfw.AddAStore(variableObjectLocal); // get the label to JSR to int finallyLabel = finallyTarget.LabelId(); if (isGenerator) { AddGotoWithReturn(finallyTarget); } else { InlineFinally(finallyTarget, handlerLabels[FINALLY_EXCEPTION], finallyEnd); } // rethrow cfw.AddALoad(exceptionLocal); if (isGenerator) { cfw.Add(ByteCode.CHECKCAST, "java/lang/Throwable"); } cfw.Add(ByteCode.ATHROW); cfw.MarkLabel(finallyEnd); // mark the handler if (isGenerator) { cfw.AddExceptionHandler(startLabel, finallyLabel, finallyHandler, null); } } // catch any ReleaseWordLocal(savedVariableObject); cfw.MarkLabel(realEnd); if (!isGenerator) { exceptionManager.PopExceptionInfo(); } }