Package org.apache.flex.compiler.internal.as.codegen

Source Code of org.apache.flex.compiler.internal.as.codegen.ExceptionHandlingContext

/*
*
*  Licensed to the Apache Software Foundation (ASF) under one or more
*  contributor license agreements.  See the NOTICE file distributed with
*  this work for additional information regarding copyright ownership.
*  The ASF licenses this file to You under the Apache License, Version 2.0
*  (the "License"); you may not use this file except in compliance with
*  the License.  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*
*/

package org.apache.flex.compiler.internal.as.codegen;

import java.util.Vector;

import org.apache.flex.abc.instructionlist.InstructionList;
import org.apache.flex.abc.semantics.Label;

import static org.apache.flex.abc.ABCConstants.*;


/**
*  An ExceptionHandlingContext manages the tree-crossing
*  state of a try/catch/finally composite statement; its
*  actual processing state (try, catch, and finally have
*  slightly different requirements), and most importantly
*  the return instruction fragments for the finally block's
*  "callers."
*/
public final class ExceptionHandlingContext extends ControlFlowContext
{

    /**
     *  @param flow_mgr - the flow manager that owns this context.
     */
    ExceptionHandlingContext( ControlFlowContextManager flow_mgr)
    {
        super(null);
        this.flowMgr = flow_mgr;
    }

    /**
     *  The flow manager that owns this context.
     *  Used to find the associated LexicalScope and
     *  allocate temporaries.
     */
    ControlFlowContextManager flowMgr;

    /**
     *  The finally block's label, if there is a finally block.
     */
    Label finallyBlock = null;

    /**
     *  The "error return" from the finally.
     */
    Label finallyDoRethrow = null;

    /**
     *  The "normal return" from the finally.
     */
    Label finallyDoFallthrough = null;

    /**
     *  A local set to a distinct value by each caller;
     *  corresponds with the position of that caller's
     *  finally return fragment in the returns array.
     */
    Binding finallyReturnStorage = null;

    /**
     *  A local used to store the exception scope; needed to
     *  restore nested exception scopes in an inner catch.
     */
    Binding exceptionStorage = null;

    /**
     *  The possible states of the exception-handling context.
     *  There's an edge from TRY to FINALLY, from FINALLY to
     *  CATCH, and from TRY to CATCH (if there's no FINALLY).
     *  @see #setFinallyControlState(boolean)
     *  @see #setCatchControlState(boolean)
     */
    enum TryCatchFinallyState
    {
        INITIAL,
        TRY,
        FINALLY,
        CATCH
    };

    /**
     *  This exception-handling context's state.
     */
    TryCatchFinallyState tryCatchFinallyState = TryCatchFinallyState.INITIAL;

    /**
     *  Finally return fragments and their labels.
     *  The labels go into the finally's concluding
     *  lookupswitch a.k.a. computed GOTO instruction.
     */
    public static class FinallyReturn
    {
        Label finallyLabel;
        InstructionList finallyInsns;

        FinallyReturn(Label label, InstructionList list)
        {
            this.finallyLabel = label;
            this.finallyInsns = list;
        }

        Label getLabel()
        {
            return finallyLabel;
        }

        InstructionList getInstructions()
        {
            return finallyInsns;
        }
    };

    /**
     *  The marshalled finally returns.
     *  @warn order is significant; the order here must match
     *    the order of the callers' "return index" saved into
     *    the finallyReturnStorage local.
     *  @see finallyReturnStorage
     */
    Vector<FinallyReturn> finallyReturns = null;

    /**
     *  true => this exception handling context has a finally block.
     */
    boolean hasFinally = false;

    @Override
    InstructionList addExitPath(InstructionList exitBranch)
    {
        InstructionList result = exitBranch;
       
        //  Enter any finally blocks
        //  that are not already active.
        if ( hasFinallyBlock() )
        {
            if ( ! isActiveFinally() )
                result = addFinallyReturn(result);
           
        }

        //  Pop the scope of any active catch blocks.
        if ( isActiveCatchBlock() )
        {
            InstructionList catch_fixup = new InstructionList();
            catch_fixup.addInstruction(OP_popscope);
            catch_fixup.addInstruction(getExceptionStorage().kill());

            catch_fixup.addAll(result);
            result = catch_fixup;
        }
        return result;
    }
   
    @Override
    void addExceptionHandlerEntry(InstructionList exceptionHandler)
    {
        if ( isActiveCatchBlock() )
        {
            exceptionHandler.addInstruction(getExceptionStorage().getlocal());
            exceptionHandler.addInstruction(OP_pushscope);
        }
    }



    /**
     *  Add a return fragment to the active finally clause.
     *  @param retblock - the instructions that make up the
     *    finally return sequence.
     *  @return the substitute return sequence that sets up
     *    the finallyReturnStorage local and jumps to the
     *    finally block.
     */
    private InstructionList addFinallyReturn(InstructionList retblock)
    {
        assert(this.finallyReturns != null): "Not a finally context.";

        Label retblock_label = new Label();
        retblock.labelFirst(retblock_label);
        finallyReturns.add(new FinallyReturn(retblock_label, retblock));

        InstructionList result = new InstructionList();
        CmcEmitter.pushNumericConstant(finallyReturns.size(), result);
        result.addInstruction(OP_coerce_a);
        result.addInstruction(finallyReturnStorage.setlocal());
        result.addInstruction(OP_jump, finallyBlock);
        return result;
    }

    /**
     *  @return this exception-handling context's exceptionStorage local.
     *  @note generated on demand.
     */
    public Binding getExceptionStorage()
    {
        if ( this.exceptionStorage == null )
            this.exceptionStorage = flowMgr.currentScope.allocateTemp();
        return this.exceptionStorage;
    }

    /**
     * Transition from the initial state into the try processing state. There is
     * no method to end the try control state because the BURM does not have
     * reduction for the try block, instead we implicitly end the try processing
     * state when we start a finally or catch processing state.
     */
    void startTryControlState()
    {
        assert ( this.tryCatchFinallyState == TryCatchFinallyState.INITIAL );
        this.tryCatchFinallyState = TryCatchFinallyState.TRY;
    }

    /**
     *  Transition into the finally processing state.
     */
    void startFinallyControlState()
    {
        assert ( this.tryCatchFinallyState == TryCatchFinallyState.TRY );
        this.tryCatchFinallyState = TryCatchFinallyState.FINALLY;
    }
   
    /**
     * Transition out of the finally processing state into
     * the catch state.
     */
    void endFinallyControlState()
    {
        assert ( this.tryCatchFinallyState == TryCatchFinallyState.FINALLY );
        this.tryCatchFinallyState = TryCatchFinallyState.CATCH;
    }

    /**
     * Enter the catch control state.
     */
    void startCatchControlState()
    {
        //  All of the three processing states
        //  are valid previous states.
        this.tryCatchFinallyState = TryCatchFinallyState.CATCH;
    }
   
    void endCatchControlState()
    {
        assert (TryCatchFinallyState.CATCH == this.tryCatchFinallyState) :
            "leaving catch, but control state is " + this.tryCatchFinallyState;
    }

    /**
     *  @return true if the exception handling context is in
     *    catch processing state.
     */
    private boolean isActiveCatchBlock()
    {
        return TryCatchFinallyState.CATCH == this.tryCatchFinallyState;
    }

    /**
     *  @return true if the exception handling context is in
     *    finally processing state.
     */
    private boolean isActiveFinally()
    {
        return TryCatchFinallyState.FINALLY == this.tryCatchFinallyState;
    }

    /**
     * @return true if the exception handling context has a finally block.
     */
    private boolean hasFinallyBlock()
    {
        return this.hasFinally;
    }

    /**
     * Marks this context as having a finally block.
     * @param has_finally true if this context has a finally block, false otherwise.
     */
    void setHasFinallyBlock(boolean has_finally)
    {
        this.hasFinally = has_finally;
    }
}
TOP

Related Classes of org.apache.flex.compiler.internal.as.codegen.ExceptionHandlingContext

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.