root/core/StackTrace.cpp

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

DEFINITIONS

This source file includes following definitions.
  1. init
  2. init
  3. init
  4. init
  5. reset
  6. enumerateScopeChainAtoms
  7. dumpFilename
  8. getStackTraceLine
  9. format

/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is [Open Source Virtual Machine.].
 *
 * The Initial Developer of the Original Code is
 * Adobe System Incorporated.
 * Portions created by the Initial Developer are Copyright (C) 2004-2006
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Adobe AS3 Team
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */


#include "avmplus.h"

namespace avmplus
{
#ifdef DEBUGGER
        void CallStackNode::init(
                                        MethodEnv*                              env
                                        , FramePtr                              framep
                                        , Traits**                              frameTraits
                                        , intptr_t volatile*    eip
                        )
        {
                AvmAssert(env != NULL);
                m_functionId    = 0;
                m_core                  = env->core();
                m_env                   = env;
                m_info                  = env ? env->method : NULL;
                m_next                  = m_core->callStack; m_core->callStack = this;
                m_fakename              = NULL;
                m_depth                 = m_next ? (m_next->m_depth + 1) : 1;
                m_eip                   = eip;     // ptr to where the current instruction pointer is stored
                m_filename              = NULL;
                m_framep                = framep;
                m_traits                = frameTraits;
                m_linenum               = 0;
        }

        void CallStackNode::init(MethodInfo* methodInfo)
        {
                AvmAssert(methodInfo != NULL);
                
                m_env                   = NULL;
                m_info                  = methodInfo;
                m_fakename              = NULL;
                m_core                  = NULL;
                m_next                  = NULL;
                m_depth                 = 0;
                m_eip                   = NULL;    
                m_filename              = NULL;
                m_framep                = NULL;
                m_traits                = NULL;
                m_linenum               = 0;
        }
        
        void CallStackNode::init(AvmCore* core, Stringp name)
        {
                // careful, core and/or name can be null
                m_functionId    = 0;
                m_env                   = NULL;
                m_info                  = NULL;
                m_fakename              = name;
                if (name)
                {
                        AvmAssert(core != NULL);
                        m_core          = core;
                        m_next          = core->callStack; core->callStack = this;
                        m_depth         = m_next ? (m_next->m_depth + 1) : 1;
                }
                else
                {
                        m_core          = NULL;
                        m_next          = NULL;
                        m_depth         = 0;
                }
                m_eip                   = 0;    
                m_filename              = 0;
                m_framep                = 0;
                m_traits                = 0;
                m_linenum               = 0;
        }
        
        void CallStackNode::init(AvmCore* core, uint64_t functionId, int32_t lineno)
        {
                AvmAssert(core != NULL);
                AvmAssert(functionId != 0);
                
                m_functionId    = functionId;
                m_info                  = NULL;
                m_env                   = NULL;
                m_fakename              = NULL;
                m_core          = core;
                m_next          = core->callStack; core->callStack = this;
                m_depth         = m_next ? (m_next->m_depth + 1) : 1;
                m_eip                   = NULL;    
                m_filename              = NULL;
                m_framep                = NULL;
                m_traits                = NULL;
                m_linenum               = lineno;
        }

        CallStackNode::~CallStackNode()
        {
                // The destructor /must not/ do anything except call reset()
                reset();
        }
        
        void FASTCALL  CallStackNode::reset()
        {
                AvmCore* core = m_core; // save it since exit() resets to null
                if (core)
                {
                        AvmAssert(core != NULL);
                        core->callStack = m_next;
                        m_next = NULL;
                        m_core = NULL; // so the dtor doesn't pop again
                        core->sampleCheck();
                }
        }

        void CallStackNode::enumerateScopeChainAtoms(IScopeChainEnumerator& scb)
        {
                // First, get the "dynamic" portion of the scope chain, that is, the
                // part that is modified on-the-fly within the function.  This includes
                // activation objects for try/catch blocks and "with" clauses.

                if (m_info)
                {
            MethodSignaturep const ms = m_info->getMethodSignature();
            for (int i = (ms->max_scope() + ms->local_count() - 1), n = ms->local_count(); i >= n; --i)
            {
                Atom const scope = m_info->boxOneLocal(m_framep, i, m_traits);
                AvmAssert(atomKind(scope) != kUnusedAtomTag);
                // go ahead and call addScope, even if null or undefined.
                scb.addScope(scope);
            }
                }

                // Next, get the "static" portion of the scope chain, that is, the
                // part that is defined as part of the definition of the function.  This
                // includes the locals of any functions that enclose this one, and the "this"
                // object, if any.

                ScopeChain* scopeChain = m_env ? m_env->scope() : NULL;
                if (scopeChain) 
                {
                        int scopeChainLength = scopeChain->getSize();
                        for (int i = scopeChainLength - 1; i >= 0; --i)
                        {
                                Atom scope = scopeChain->getScope(i);
                                if (AvmCore::isObject(scope))
                                {
                    scb.addScope(scope);
                                }
                        }
                }
        }

        // Dump a filename.  The incoming filename is of the form
        // "C:\path\to\package\root;package/package;filename".  The path format
        // will depend on the platform on which the movie was originally
        // compiled, NOT the platform the the player is running in.
        //
        // We want to replace the semicolons with path separators.  We'll take
        // a guess at the appropriate path separator of the compilation
        // platform by looking for any backslashes in the path.  If there are
        // any, then we'll assume backslash is the path separator.  If not,
        // we'll use forward slash.
        void StackTrace::dumpFilename(Stringp _filename, PrintWriter& out) const
        {
                StringIndexer filename(_filename);
                
                wchar semicolonReplacement = '/';
                int length = filename->length();
                wchar ch;
                int i;

                // look for backslashes; if there are any, then semicolons will be
                // replaced with backslashes, not forward slashes
                for (i=0; i<length; ++i) {
                        ch = filename[i];
                        if (ch == '\\') {
                                semicolonReplacement = '\\';
                                break;
                        }
                }

                // output the entire path
                bool previousWasSlash = false;
                for (i=0; i<length; ++i) {
                        ch = filename[i];
                        if (ch == ';') {
                                if (previousWasSlash)
                                        continue;
                                ch = semicolonReplacement;
                                previousWasSlash = true;
                        } else if (ch == '/' || ch == '\\') {
                                previousWasSlash = true;
                        } else {
                                previousWasSlash = false;
                        }
                        out << ch;
                }
        }

        static Stringp getStackTraceLine(MethodInfo* method, Stringp filename) 
        {
                AvmCore *core = method->pool()->core;
                Stringp s = core->newStringLatin1("\tat ");
                s = core->concatStrings(s, method->format(core));
                if (filename)
                {
                        s = s->appendLatin1("[");
                        s = s->append(filename);
                        s = s->appendLatin1(":");
                }
                return s;
        }

        Stringp StackTrace::format(AvmCore* core)
        {
                if(!stringRep)
                {
                        Stringp s = core->kEmptyString;
                        int displayDepth = depth;
                        if (displayDepth > kMaxDisplayDepth) {
                                displayDepth = kMaxDisplayDepth;
                        }
                        const Element *e = elements;
                        for (int i=0; i<displayDepth; i++, e++)
                        {
                                // env will be NULL if the element is from a fake CallStackNode
                                // omit them since they are only for profiling purposes
                                if (!e->info())
                                        continue;

                                if(i != 0)
                                        s = s->appendLatin1("\n");

                                Stringp filename=NULL;
                                if(e->filename())
                                {
                                        StringBuffer sb(core->gc);
                                        dumpFilename(e->filename(), sb);
                                        filename = core->newStringUTF8(sb.c_str());
                                }
                                s = core->concatStrings(s, getStackTraceLine(e->info(), filename));
                                if(e->filename())
                                {
                                        s = core->concatStrings(s, core->intToString(e->linenum()));
                                        s = s->appendLatin1("]");
                                }
                        }
                        stringRep = s;
                }
                return stringRep;
        }

#endif 
}

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