js/jsd/jsd_step.cpp

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /*
     8  * JavaScript Debugging support - Stepping support
     9  */
    11 #include "jsd.h"
    13 /*
    14 * #define JSD_TRACE 1
    15 */
    17 #ifdef JSD_TRACE
    19 static char*
    20 _indentSpaces(int i)
    21 {
    22 #define MAX_INDENT 63
    23     static char* p = nullptr;
    24     if(!p)
    25     {
    26         p = calloc(1, MAX_INDENT+1);
    27         if(!p) return "";
    28         memset(p, ' ', MAX_INDENT);
    29     }
    30     if(i > MAX_INDENT) return p;
    31     return p + MAX_INDENT-i;
    32 }
    34 static void
    35 _interpreterTrace(JSDContext* jsdc, JSContext *cx, JSAbstractFramePtr frame,
    36                   bool isConstructing, bool before)
    37 {
    38     JSDScript* jsdscript = nullptr;
    39     JSScript * script;
    40     static indent = 0;
    41     JSString* funName = nullptr;
    43     script = frame.script();
    44     if(script)
    45     {
    46         JSD_LOCK_SCRIPTS(jsdc);
    47         jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, frame);
    48         JSD_UNLOCK_SCRIPTS(jsdc);
    49         if(jsdscript)
    50             funName = JSD_GetScriptFunctionId(jsdc, jsdscript);
    51     }
    53     if(before)
    54         printf("%sentering ", _indentSpaces(indent++));
    55     else
    56         printf("%sleaving ", _indentSpaces(--indent));
    58     if (!funName)
    59         printf("TOP_LEVEL");
    60     else
    61         JS_FileEscapedString(stdout, funName, 0);
    63     if(before)
    64     {
    65         jsval thisVal;
    67         printf("%s this: ", isConstructing ? "constructing":"");
    69         if (JS_GetFrameThis(cx, frame, &thisVal))
    70             printf("0x%0llx", (uintptr_t) thisVal);
    71         else
    72             puts("<unavailable>");
    73     }
    74     printf("\n");
    75     MOZ_ASSERT(indent >= 0);
    76 }
    77 #endif
    79 bool
    80 _callHook(JSDContext *jsdc, JSContext *cx, JSAbstractFramePtr frame, bool isConstructing,
    81           bool before, unsigned type, JSD_CallHookProc hook, void *hookData)
    82 {
    83     JSDScript*        jsdscript;
    84     JSScript*         jsscript;
    85     bool              hookresult = true;
    87     if (!jsdc || !jsdc->inited)
    88         return false;
    90     if (!hook && !(jsdc->flags & JSD_COLLECT_PROFILE_DATA))
    91     {
    92         /* no hook to call, no profile data needs to be collected,
    93          * so there is nothing to do here.
    94          */
    95         return hookresult;
    96     }
    98     if (before && isConstructing) {
    99         JS::RootedValue newObj(cx);
   100         if (!frame.getThisValue(cx, &newObj))
   101             return false;
   102         jsd_Constructing(jsdc, cx, JSVAL_TO_OBJECT(newObj), frame);
   103     }
   105     jsscript = frame.script();
   106     if (jsscript)
   107     {
   108         JSD_LOCK_SCRIPTS(jsdc);
   109         jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, jsscript, frame);
   110         JSD_UNLOCK_SCRIPTS(jsdc);
   112         if (jsdscript)
   113         {
   114             if (JSD_IS_PROFILE_ENABLED(jsdc, jsdscript))
   115             {
   116                 JSDProfileData *pdata;
   117                 pdata = jsd_GetScriptProfileData (jsdc, jsdscript);
   118                 if (pdata)
   119                 {
   120                     if (before)
   121                     {
   122                         if (!pdata->lastCallStart)
   123                         {
   124                             int64_t now;
   125                             JSDProfileData *callerpdata;
   127                             /* Get the time just the once, for consistency. */
   128                             now = JS_Now();
   129                             /* This contains a pointer to the profile data for
   130                              * the caller of this function. */
   131                             callerpdata = jsdc->callingFunctionPData;
   132                             if (callerpdata)
   133                             {
   134                                 int64_t ll_delta;
   135                                 pdata->caller = callerpdata;
   136                                 /* We need to 'stop' the timer for the caller.
   137                                  * Use time since last return if appropriate. */
   138                                 ll_delta = jsdc->lastReturnTime
   139                                            ? now - jsdc->lastReturnTime
   140                                            : now - callerpdata->lastCallStart;
   141                                 callerpdata->runningTime += ll_delta;
   142                             }
   143                             /* We're the new current function, and no return
   144                              * has happened yet. */
   145                             jsdc->callingFunctionPData = pdata;
   146                             jsdc->lastReturnTime = 0;
   147                             /* This function has no running time (just been
   148                              * called!), and we'll need the call start time. */
   149                             pdata->runningTime = 0;
   150                             pdata->lastCallStart = now;
   151                         } else {
   152                             if (++pdata->recurseDepth > pdata->maxRecurseDepth)
   153                                 pdata->maxRecurseDepth = pdata->recurseDepth;
   154                         }
   155                         /* make sure we're called for the return too. */
   156                         hookresult = true;
   157                     } else if (!pdata->recurseDepth && pdata->lastCallStart) {
   158                         int64_t now, ll_delta;
   159                         double delta;
   160                         now = JS_Now();
   161                         ll_delta = now - pdata->lastCallStart;
   162                         delta = ll_delta;
   163                         delta /= 1000.0;
   164                         pdata->totalExecutionTime += delta;
   165                         /* minExecutionTime starts as 0, so we need to overwrite
   166                          * it on the first call always. */
   167                         if ((0 == pdata->callCount) ||
   168                             delta < pdata->minExecutionTime)
   169                         {
   170                             pdata->minExecutionTime = delta;
   171                         }
   172                         if (delta > pdata->maxExecutionTime)
   173                             pdata->maxExecutionTime = delta;
   175                         /* If we last returned from a function (as opposed to
   176                          * having last entered this function), we need to inc.
   177                          * the running total by the time delta since the last
   178                          * return, and use the running total instead of the
   179                          * delta calculated above. */
   180                         if (jsdc->lastReturnTime)
   181                         {
   182                             /* Add last chunk to running time, and use total
   183                              * running time as 'delta'. */
   184                             ll_delta = now - jsdc->lastReturnTime;
   185                             pdata->runningTime += ll_delta;
   186                             delta = pdata->runningTime;
   187                             delta /= 1000.0;
   188                         }
   190                         pdata->totalOwnExecutionTime += delta;
   191                         /* See minExecutionTime comment above. */
   192                         if ((0 == pdata->callCount) ||
   193                             delta < pdata->minOwnExecutionTime)
   194                         {
   195                             pdata->minOwnExecutionTime = delta;
   196                         }
   197                         if (delta > pdata->maxOwnExecutionTime)
   198                             pdata->maxOwnExecutionTime = delta;
   200                         /* Current function is now our caller. */
   201                         jsdc->callingFunctionPData = pdata->caller;
   202                         /* No hanging pointers, please. */
   203                         pdata->caller = nullptr;
   204                         /* Mark the time we returned, and indicate this
   205                          * function is no longer running. */
   206                         jsdc->lastReturnTime = now;
   207                         pdata->lastCallStart = 0;
   208                         ++pdata->callCount;
   209                     } else if (pdata->recurseDepth) {
   210                         --pdata->recurseDepth;
   211                         ++pdata->callCount;
   212                     }
   213                 }
   214                 if (hook)
   215                     jsd_CallCallHook (jsdc, cx, type, hook, hookData);
   216             } else {
   217                 if (hook)
   218                     hookresult = 
   219                         jsd_CallCallHook (jsdc, cx, type, hook, hookData);
   220                 else
   221                     hookresult = true;
   222             }
   223         }
   224     }
   226 #ifdef JSD_TRACE
   227     _interpreterTrace(jsdc, cx, frame, isConstructing, before);
   228     return true;
   229 #else
   230     return hookresult;
   231 #endif
   233 }
   235 void *
   236 jsd_FunctionCallHook(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing,
   237                      bool before, bool *ok, void *closure)
   238 {
   239     JSDContext*       jsdc;
   240     JSD_CallHookProc  hook;
   241     void*             hookData;
   243     jsdc = (JSDContext*) closure;
   245     /* local in case jsdc->functionHook gets cleared on another thread */
   246     JSD_LOCK();
   247     hook     = jsdc->functionHook;
   248     hookData = jsdc->functionHookData;
   249     JSD_UNLOCK();
   251     if (_callHook (jsdc, cx, frame, isConstructing, before,
   252                    (before) ? JSD_HOOK_FUNCTION_CALL : JSD_HOOK_FUNCTION_RETURN,
   253                    hook, hookData))
   254     {
   255         return closure;
   256     }
   258     return nullptr;
   259 }
   261 void *
   262 jsd_TopLevelCallHook(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing,
   263                      bool before, bool *ok, void *closure)
   264 {
   265     JSDContext*       jsdc;
   266     JSD_CallHookProc  hook;
   267     void*             hookData;
   269     jsdc = (JSDContext*) closure;
   271     /* local in case jsdc->toplevelHook gets cleared on another thread */
   272     JSD_LOCK();
   273     hook     = jsdc->toplevelHook;
   274     hookData = jsdc->toplevelHookData;
   275     JSD_UNLOCK();
   277     if (_callHook (jsdc, cx, frame, isConstructing, before,
   278                    (before) ? JSD_HOOK_TOPLEVEL_START : JSD_HOOK_TOPLEVEL_END,
   279                    hook, hookData))
   280     {
   281         return closure;
   282     }
   284     return nullptr;
   286 }

mercurial