root/libcore/vm/ActionExec.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


// 
//   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
//   2011 Free Software Foundation, Inc
// 
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

#ifndef GNASH_ACTIONEXEC_H
#define GNASH_ACTIONEXEC_H

#include <string>
#include <list>
#include <vector>
#include <boost/noncopyable.hpp>

#include "as_environment.h" 
#include "SWF.h"
#include "action_buffer.h"

// Forward declarations
namespace gnash {
        class as_value;
        class Function;
        class ActionExec;
}

namespace gnash {

class TryBlock
{
public:
        friend class ActionExec;

        enum tryState
        {
                TRY_TRY, // In a try block.
                TRY_CATCH, // In a catch block.
                TRY_FINALLY, // In a finally block.
                TRY_END // Finished with finally
        };

    TryBlock(size_t cur_off, size_t try_size, size_t catch_size,
                size_t finally_size, std::string catchName)
                :
                _catchOffset(cur_off + try_size),
                _finallyOffset(cur_off + try_size + catch_size),
                _afterTriedOffset(cur_off + try_size + catch_size + finally_size),
                _hasName(true),
                _name(catchName),
                _registerIndex(0),
                _tryState(TryBlock::TRY_TRY),
                _lastThrow()
        {}

        TryBlock(size_t cur_off, size_t try_size, size_t catch_size,
                size_t finally_size, boost::uint8_t register_index)
                :
                _catchOffset(cur_off + try_size),
                _finallyOffset(cur_off + try_size + catch_size),
                _afterTriedOffset(cur_off + try_size + catch_size + finally_size),
                _hasName(false),
                _name(),
                _registerIndex(register_index),
                _tryState(TryBlock::TRY_TRY),
                _lastThrow()
        {}

private:
        size_t _catchOffset;
        size_t _finallyOffset;
        size_t _afterTriedOffset;
        size_t _savedEndOffset;
        bool _hasName;
        std::string _name;
        unsigned int _registerIndex;
        tryState _tryState;
        as_value _lastThrow;
};

class With
{
public: 

        With(as_object* obj, size_t end)
                :
                _object(obj),
                _block_end_pc(end)
        {
        }

        size_t end_pc() const {
                return _block_end_pc;
        }

        as_object* object() const {
                return _object;
        }

private:
        as_object* _object;
        size_t _block_end_pc;
};

/// Executor of an action_buffer 
class ActionExec : boost::noncopyable
{

    typedef as_environment::ScopeStack ScopeStack;

public:

        /// Create an execution thread 
        //
        /// @param abuf             the action code
        /// @param newEnv               the timeline context.
        /// @param abortOnUnloaded  If true (default) execution aborts as soon
    ///                         as the target sprite is unloaded.
        ///     NOTE: original target is fetched from the environment.
        ActionExec(const action_buffer& abuf, as_environment& newEnv,
            bool abortOnUnloaded = true);

        /// Create an execution thread for a function call.
        //
        /// @param func     The function 
        /// @param newEnv   The execution environment (variables scope, stack etc.)
        /// @param nRetval  Where to return a value. If NULL any return will
    ///                 be discarded.
        ActionExec(const Function& func, as_environment& newEnv,
            as_value* nRetVal, as_object* this_ptr);

        /// Use this to push a try block. It will be copied
        void pushTryBlock(TryBlock t);

        /// Set the return value.
        void pushReturn(const as_value& t);

        /// The actual action buffer
        //
        /// TODO: provide a getter and make private
        const action_buffer& code;

        /// TODO: provide a getter and make private ?
        as_environment& env;

        /// TODO: provide a setter and make private ?
        as_value* retval;

        /// Is this execution thread a function call ?
        bool isFunction() const { return _func != 0; }

        /// Get the current 'this' pointer, for use in function calls
        as_object* getThisPointer();

        /// Returns the scope stack associated with this execution thread
        const ScopeStack& getScopeStack() const {
                return _scopeStack;
        }

        /// Push an entry to the with stack
        //
        /// @return     true if the entry was pushed, false otherwise. This
    ///             depends on the with stack limit.
        bool pushWith(const With& entry);

        /// Skip the specified number of action tags 
        //
        /// The offset is relative to next_pc
        void skip_actions(size_t offset);

        /// Delete named variable, seeking for it in the with stack if any
        //
        /// @param name     Name of the variable. Supports slash and dot syntax.
        bool delVariable(const std::string& name);

        /// Set a named variable, seeking for it in the with stack if any.
        //
        /// @param name     Name of the variable. Supports slash and dot syntax.
        void setVariable(const std::string& name, const as_value& val);

        /// Set a function-local variable
    //
    /// If we're not in a function, set a normal variable.
        //
        /// @param name Name of the variable. Supports slash and dot syntax.
    /// @param val  The value to set the variable to.
        void setLocalVariable(const std::string& name, const as_value& val);

        /// Get a named variable, seeking for it in the with stack if any.
        //
        /// @param name     Name of the variable. Supports slash and dot syntax.
        /// @param target   An output parameter, will be set to point to the object
        ///                     containing any found variable. If you aren't interested,
    ///                 pass null (default). If the variable does not belong
    ///                 to an object, target will be set to null.
        as_value getVariable(const std::string& name, as_object** target = 0);

        /// Get current target.
        //
        /// This function returns top 'with' stack entry, if any.
        /// Main use for this function is for calling methods and
        /// properly setting the "this" pointer. 
        ///
        /// TODO:
        /// A better, cleaner and less error-prone approach
        /// would be providing a callFunction() method in
        /// ActionExec. This will likely help debugger too
        as_object* getTarget();

        /// Execute.
        void operator()();

    // TODO: cut down these accessors.
    bool atActionTag(SWF::ActionType t) { return code[pc] == t; }
        
        size_t getCurrentPC() const { return pc; }
        
        void skipRemainingBuffer() { next_pc = stop_pc; }
        
        void adjustNextPC(int offset);
        
        size_t getNextPC() const { return next_pc; }
        
        void setNextPC(size_t pc) { next_pc = pc; }
        
        size_t getStopPC() const { return stop_pc; }
        
private: 

        /// \brief
        /// Debugging function:
        /// print opcodes from start (included) to end (not-included) PCs.
        //
        /// @param start
        ///     First opcode to dump
        ///
        /// @param end
        ///     One-past last opcode to dump
        ///
        /// @param os
        ///     Output stream to dump to
        ///
        void dumpActions(size_t start, size_t end, std::ostream& os);

    /// Processes the current try - catch - finally block
    //
    /// This function is called after each stage of a
    /// try/catch/finally block. It ensures it is called
    /// after each stage by setting stop_pc to the appropriate
    /// number. If an exception is on the stack at any stage,
    /// it takes the appropriate action (catch, set register
    /// values, return, or leave it on the stack). Return
    /// false means that the action processing loop should be
    /// interrupted.
    //
    /// @return whether to continue executing the buffer
    /// @param t the try block to process.
    bool processExceptions(TryBlock& t);

        /// Run after a complete run, or after an run interrupted by 
        /// a bail-out exception (ActionLimitException, for example)
        //
        /// The method restores original target of the as_environment,
        /// checks for stack smashing (stack contains less entries
        /// then it had at time of execution start) or leftovers
        /// (stack contains more entries then it had at time of execution
        /// start) and finally gives movie_root a chance to execute
        /// actions queued in higher priority action queues.
        ///
        /// The higher priority action queue flush is needed to allow
        /// initialize/construct/initactions queued by effect of gotoFrame
        /// calls in DOACTION block before frame actions queued by the same
        /// cause (the latter would be pushed in the same level gotoFrame is
        /// found)
        void cleanupAfterRun();

        /// the 'with' stack associated with this execution thread
        std::vector<With> _withStack;

        /// the scope stack associated with this execution thread
        ScopeStack _scopeStack;

        /// A pointer to the function being executed, or NULL
        /// for non-function execution
        ///
        /// TODO: 
        /// This should likely be put in a larger
        /// structure including return address 
        /// and maintained in a stack (the call stack)
        ///
        const Function* _func;

        /// The 'this' pointer, if this is a function call
        as_object* _this_ptr;

        /// Stack size at start of execution
        size_t _initialStackSize;

        DisplayObject* _originalTarget;

        int _origExecSWFVersion;

        std::list<TryBlock> _tryList;

        bool _returning;

        bool _abortOnUnload;

    /// Program counter (offset of current action tag)
        size_t pc;

        /// Offset to next action tag
        size_t next_pc;

        /// End of current function execution
        /// Used for try/throw/catch blocks.
        size_t stop_pc;

};

} // namespace gnash

#endif // GNASH_ACTIONEXEC_H

// Local Variables:
// mode: C++
// indent-tabs-mode: t
// End:

/* [<][>][^][v][top][bottom][index][help] */