js/jsd/jsd_stak.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 - Call stack support
     9  */
    11 #include "jsd.h"
    12 #include "jsfriendapi.h"
    13 #include "nsCxPusher.h"
    15 using mozilla::AutoPushJSContext;
    17 #ifdef DEBUG
    18 void JSD_ASSERT_VALID_THREAD_STATE(JSDThreadState* jsdthreadstate)
    19 {
    20     MOZ_ASSERT(jsdthreadstate);
    21     MOZ_ASSERT(jsdthreadstate->stackDepth > 0);
    22 }
    24 void JSD_ASSERT_VALID_STACK_FRAME(JSDStackFrameInfo* jsdframe)
    25 {
    26     MOZ_ASSERT(jsdframe);
    27     MOZ_ASSERT(jsdframe->jsdthreadstate);
    28 }
    29 #endif
    31 static JSDStackFrameInfo* 
    32 _addNewFrame(JSDContext*        jsdc,
    33              JSDThreadState*    jsdthreadstate,
    34              JSScript*          script,
    35              uintptr_t          pc,
    36              bool               isConstructing,
    37              JSAbstractFramePtr frame)
    38 {
    39     JSDStackFrameInfo* jsdframe;
    40     JSDScript*         jsdscript = nullptr;
    42     JSD_LOCK_SCRIPTS(jsdc);
    43     jsdscript = jsd_FindJSDScript(jsdc, script);
    44     JSD_UNLOCK_SCRIPTS(jsdc);
    45     if (!jsdscript || (jsdc->flags & JSD_HIDE_DISABLED_FRAMES &&
    46                        !JSD_IS_DEBUG_ENABLED(jsdc, jsdscript)))
    47     {
    48         return nullptr;
    49     }
    51     if (!JSD_IS_DEBUG_ENABLED(jsdc, jsdscript))
    52         jsdthreadstate->flags |= TS_HAS_DISABLED_FRAME;
    54     jsdframe = (JSDStackFrameInfo*) calloc(1, sizeof(JSDStackFrameInfo));
    55     if( ! jsdframe )
    56         return nullptr;
    58     jsdframe->jsdthreadstate = jsdthreadstate;
    59     jsdframe->jsdscript      = jsdscript;
    60     jsdframe->isConstructing = isConstructing;
    61     jsdframe->pc             = pc;
    62     jsdframe->frame          = frame;
    64     JS_APPEND_LINK(&jsdframe->links, &jsdthreadstate->stack);
    65     jsdthreadstate->stackDepth++;
    67     return jsdframe;
    68 }
    70 static void
    71 _destroyFrame(JSDStackFrameInfo* jsdframe)
    72 {
    73     /* kill any alloc'd objects in frame here... */
    75     if( jsdframe )
    76         free(jsdframe);
    77 }
    79 JSDThreadState*
    80 jsd_NewThreadState(JSDContext* jsdc, JSContext *cx )
    81 {
    82     JSDThreadState* jsdthreadstate;
    84     jsdthreadstate = (JSDThreadState*)calloc(1, sizeof(JSDThreadState));
    85     if( ! jsdthreadstate )
    86         return nullptr;
    88     jsdthreadstate->context = cx;
    89     jsdthreadstate->thread = JSD_CURRENT_THREAD();
    90     JS_INIT_CLIST(&jsdthreadstate->stack);
    91     jsdthreadstate->stackDepth = 0;
    93     JS_BeginRequest(jsdthreadstate->context);
    95     JSBrokenFrameIterator iter(cx);
    96     while(!iter.done())
    97     {
    98         JSAbstractFramePtr frame = iter.abstractFramePtr();
    99         JS::RootedScript script(cx, frame.script());
   100         uintptr_t  pc = (uintptr_t)frame.pc();
   101         JS::RootedValue dummyThis(cx);
   103         /*
   104          * don't construct a JSDStackFrame for dummy frames (those without a
   105          * |this| object, or native frames, if JSD_INCLUDE_NATIVE_FRAMES
   106          * isn't set.
   107          */
   108         if (frame.getThisValue(cx, &dummyThis))
   109         {
   110             bool isConstructing = iter.isConstructing();
   111             JSDStackFrameInfo *frameInfo = _addNewFrame( jsdc, jsdthreadstate, script, pc, isConstructing, frame );
   113             if ((jsdthreadstate->stackDepth == 0 && !frameInfo) ||
   114                 (jsdthreadstate->stackDepth == 1 && frameInfo &&
   115                  frameInfo->jsdscript && !JSD_IS_DEBUG_ENABLED(jsdc, frameInfo->jsdscript)))
   116             {
   117                 /*
   118                  * if we failed to create the first frame, or the top frame
   119                  * is not enabled for debugging, fail the entire thread state.
   120                  */
   121                 JS_INIT_CLIST(&jsdthreadstate->links);
   122                 JS_EndRequest(jsdthreadstate->context);
   123                 jsd_DestroyThreadState(jsdc, jsdthreadstate);
   124                 return nullptr;
   125             }
   126         }
   128         ++iter;
   129     }
   130     JS_EndRequest(jsdthreadstate->context);
   132     if (jsdthreadstate->stackDepth == 0)
   133     {
   134         free(jsdthreadstate);
   135         return nullptr;
   136     }
   138     JSD_LOCK_THREADSTATES(jsdc);
   139     JS_APPEND_LINK(&jsdthreadstate->links, &jsdc->threadsStates);
   140     JSD_UNLOCK_THREADSTATES(jsdc);
   142     return jsdthreadstate;
   143 }
   145 void
   146 jsd_DestroyThreadState(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
   147 {
   148     JSDStackFrameInfo* jsdframe;
   149     JSCList* list;
   151     MOZ_ASSERT(jsdthreadstate);
   152     MOZ_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread);
   154     JSD_LOCK_THREADSTATES(jsdc);
   155     JS_REMOVE_LINK(&jsdthreadstate->links);
   156     JSD_UNLOCK_THREADSTATES(jsdc);
   158     list = &jsdthreadstate->stack;
   159     while( (JSDStackFrameInfo*)list != (jsdframe = (JSDStackFrameInfo*)list->next) )
   160     {
   161         JS_REMOVE_LINK(&jsdframe->links);
   162         _destroyFrame(jsdframe);
   163     }
   164     free(jsdthreadstate);
   165 }
   167 unsigned
   168 jsd_GetCountOfStackFrames(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
   169 {
   170     unsigned count = 0;
   172     JSD_LOCK_THREADSTATES(jsdc);
   174     if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
   175         count = jsdthreadstate->stackDepth;
   177     JSD_UNLOCK_THREADSTATES(jsdc);
   179     return count;
   180 }
   182 JSDStackFrameInfo*
   183 jsd_GetStackFrame(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
   184 {
   185     JSDStackFrameInfo* jsdframe = nullptr;
   187     JSD_LOCK_THREADSTATES(jsdc);
   189     if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
   190         jsdframe = (JSDStackFrameInfo*) JS_LIST_HEAD(&jsdthreadstate->stack);
   191     JSD_UNLOCK_THREADSTATES(jsdc);
   193     return jsdframe;
   194 }
   196 JSContext *
   197 jsd_GetJSContext (JSDContext* jsdc, JSDThreadState* jsdthreadstate)
   198 {
   199     JSContext* cx = nullptr;
   201     JSD_LOCK_THREADSTATES(jsdc);
   202     if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
   203         cx = jsdthreadstate->context;
   204     JSD_UNLOCK_THREADSTATES(jsdc);
   206     return cx;
   207 }
   209 JSDStackFrameInfo*
   210 jsd_GetCallingStackFrame(JSDContext* jsdc, 
   211                          JSDThreadState* jsdthreadstate,
   212                          JSDStackFrameInfo* jsdframe)
   213 {
   214     JSDStackFrameInfo* nextjsdframe = nullptr;
   216     JSD_LOCK_THREADSTATES(jsdc);
   218     if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
   219         if( JS_LIST_HEAD(&jsdframe->links) != &jsdframe->jsdthreadstate->stack )
   220             nextjsdframe = (JSDStackFrameInfo*) JS_LIST_HEAD(&jsdframe->links);
   222     JSD_UNLOCK_THREADSTATES(jsdc);
   224     return nextjsdframe;
   225 }
   227 JSDScript*
   228 jsd_GetScriptForStackFrame(JSDContext* jsdc, 
   229                            JSDThreadState* jsdthreadstate,
   230                            JSDStackFrameInfo* jsdframe)
   231 {
   232     JSDScript* jsdscript = nullptr;
   234     JSD_LOCK_THREADSTATES(jsdc);
   236     if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
   237         jsdscript = jsdframe->jsdscript;
   239     JSD_UNLOCK_THREADSTATES(jsdc);
   241     return jsdscript;
   242 }
   244 uintptr_t
   245 jsd_GetPCForStackFrame(JSDContext* jsdc, 
   246                        JSDThreadState* jsdthreadstate,
   247                        JSDStackFrameInfo* jsdframe)
   248 {
   249     uintptr_t pc = 0;
   251     JSD_LOCK_THREADSTATES(jsdc);
   253     if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
   254         pc = jsdframe->pc;
   256     JSD_UNLOCK_THREADSTATES(jsdc);
   258     return pc;
   259 }
   261 JSDValue*
   262 jsd_GetCallObjectForStackFrame(JSDContext* jsdc, 
   263                                JSDThreadState* jsdthreadstate,
   264                                JSDStackFrameInfo* jsdframe)
   265 {
   266     JSObject* obj;
   267     JSDValue* jsdval = nullptr;
   269     JSD_LOCK_THREADSTATES(jsdc);
   271     if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
   272     {
   273         obj = jsdframe->frame.callObject(jsdthreadstate->context);
   274         if(obj)                                                             
   275             jsdval = JSD_NewValue(jsdc, OBJECT_TO_JSVAL(obj));              
   276     }
   278     JSD_UNLOCK_THREADSTATES(jsdc);
   280     return jsdval;
   281 }
   283 JSDValue*
   284 jsd_GetScopeChainForStackFrame(JSDContext* jsdc, 
   285                                JSDThreadState* jsdthreadstate,
   286                                JSDStackFrameInfo* jsdframe)
   287 {
   288     JS::RootedObject obj(jsdthreadstate->context);
   289     JSDValue* jsdval = nullptr;
   291     JSD_LOCK_THREADSTATES(jsdc);
   293     if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
   294     {
   295         JS_BeginRequest(jsdthreadstate->context);
   296         obj = jsdframe->frame.scopeChain(jsdthreadstate->context);
   297         JS_EndRequest(jsdthreadstate->context);
   298         if(obj)
   299             jsdval = JSD_NewValue(jsdc, OBJECT_TO_JSVAL(obj));
   300     }
   302     JSD_UNLOCK_THREADSTATES(jsdc);
   304     return jsdval;
   305 }
   307 JSDValue*
   308 jsd_GetThisForStackFrame(JSDContext* jsdc, 
   309                          JSDThreadState* jsdthreadstate,
   310                          JSDStackFrameInfo* jsdframe)
   311 {
   312     JSDValue* jsdval = nullptr;
   313     JSD_LOCK_THREADSTATES(jsdc);
   315     if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
   316     {
   317         bool ok;
   318         JS::RootedValue thisval(jsdthreadstate->context);
   319         JS_BeginRequest(jsdthreadstate->context);
   320         ok = jsdframe->frame.getThisValue(jsdthreadstate->context, &thisval);
   321         JS_EndRequest(jsdthreadstate->context);
   322         if(ok)
   323             jsdval = JSD_NewValue(jsdc, thisval);
   324     }
   326     JSD_UNLOCK_THREADSTATES(jsdc);
   327     return jsdval;
   328 }
   330 JSString*
   331 jsd_GetIdForStackFrame(JSDContext* jsdc, 
   332                        JSDThreadState* jsdthreadstate,
   333                        JSDStackFrameInfo* jsdframe)
   334 {
   335     JSString *rv = nullptr;
   337     JSD_LOCK_THREADSTATES(jsdc);
   339     if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
   340     {
   341         JSFunction *fun = jsdframe->frame.maybeFun();
   342         if( fun )
   343         {
   344             rv = JS_GetFunctionId (fun);
   346             /*
   347              * For compatibility we return "anonymous", not an empty string
   348              * here.
   349              */
   350             if( !rv )
   351                 rv = JS_GetAnonymousString(jsdc->jsrt);
   352         }
   353     }
   355     JSD_UNLOCK_THREADSTATES(jsdc);
   356     return rv;
   357 }
   359 bool
   360 jsd_IsStackFrameDebugger(JSDContext* jsdc, 
   361                          JSDThreadState* jsdthreadstate,
   362                          JSDStackFrameInfo* jsdframe)
   363 {
   364     bool rv = true;
   365     JSD_LOCK_THREADSTATES(jsdc);
   367     if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
   368     {
   369         rv = jsdframe->frame.isDebuggerFrame();
   370     }
   372     JSD_UNLOCK_THREADSTATES(jsdc);
   373     return rv;
   374 }
   376 bool
   377 jsd_IsStackFrameConstructing(JSDContext* jsdc, 
   378                              JSDThreadState* jsdthreadstate,
   379                              JSDStackFrameInfo* jsdframe)
   380 {
   381     bool rv = true;
   382     JSD_LOCK_THREADSTATES(jsdc);
   384     if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
   385     {
   386         rv = jsdframe->isConstructing;
   387     }
   389     JSD_UNLOCK_THREADSTATES(jsdc);
   390     return rv;
   391 }
   393 bool
   394 jsd_EvaluateUCScriptInStackFrame(JSDContext* jsdc, 
   395                                  JSDThreadState* jsdthreadstate,
   396                                  JSDStackFrameInfo* jsdframe,
   397                                  const jschar *bytes, unsigned length,
   398                                  const char *filename, unsigned lineno,
   399                                  bool eatExceptions, JS::MutableHandleValue rval)
   400 {
   401     bool retval;
   402     bool valid;
   403     JSExceptionState* exceptionState = nullptr;
   405     MOZ_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread);
   407     JSD_LOCK_THREADSTATES(jsdc);
   408     valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
   409     JSD_UNLOCK_THREADSTATES(jsdc);
   411     if( ! valid )
   412         return false;
   414     AutoPushJSContext cx(jsdthreadstate->context);
   415     MOZ_ASSERT(cx);
   417     if (eatExceptions)
   418         exceptionState = JS_SaveExceptionState(cx);
   419     JS_ClearPendingException(cx);
   420     jsd_StartingEvalUsingFilename(jsdc, filename);
   421     retval = jsdframe->frame.evaluateUCInStackFrame(cx, bytes, length, filename, lineno,
   422                                                     rval);
   423     jsd_FinishedEvalUsingFilename(jsdc, filename);
   424     if (eatExceptions)
   425         JS_RestoreExceptionState(cx, exceptionState);
   427     return retval;
   428 }
   430 bool
   431 jsd_EvaluateScriptInStackFrame(JSDContext* jsdc, 
   432                                JSDThreadState* jsdthreadstate,
   433                                JSDStackFrameInfo* jsdframe,
   434                                const char *bytes, unsigned length,
   435                                const char *filename, unsigned lineno,
   436                                bool eatExceptions, JS::MutableHandleValue rval)
   437 {
   438     bool retval;
   439     bool valid;
   440     JSExceptionState* exceptionState = nullptr;
   442     MOZ_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread);
   444     JSD_LOCK_THREADSTATES(jsdc);
   445     valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
   446     JSD_UNLOCK_THREADSTATES(jsdc);
   448     if (!valid)
   449         return false;
   451     AutoPushJSContext cx(jsdthreadstate->context);
   452     MOZ_ASSERT(cx);
   454     if (eatExceptions)
   455         exceptionState = JS_SaveExceptionState(cx);
   456     JS_ClearPendingException(cx);
   457     jsd_StartingEvalUsingFilename(jsdc, filename);
   458     retval = jsdframe->frame.evaluateInStackFrame(cx, bytes, length, filename, lineno,
   459                                                   rval);
   460     jsd_FinishedEvalUsingFilename(jsdc, filename);
   461     if (eatExceptions)
   462         JS_RestoreExceptionState(cx, exceptionState);
   464     return retval;
   465 }
   467 JSString*
   468 jsd_ValToStringInStackFrame(JSDContext* jsdc, 
   469                             JSDThreadState* jsdthreadstate,
   470                             JSDStackFrameInfo* jsdframe,
   471                             jsval val)
   472 {
   473     bool valid;
   474     JSExceptionState* exceptionState;
   475     JSContext *cx = jsdthreadstate->context;
   477     JSD_LOCK_THREADSTATES(jsdc);
   478     valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
   479     JSD_UNLOCK_THREADSTATES(jsdc);
   481     if( ! valid )
   482         return nullptr;
   484     JS::RootedString retval(cx);
   485     MOZ_ASSERT(cx);
   486     JS::RootedValue v(cx, val);
   487     {
   488         AutoPushJSContext cx(jsdthreadstate->context);
   489         exceptionState = JS_SaveExceptionState(cx);
   490         retval = JS::ToString(cx, v);
   491         JS_RestoreExceptionState(cx, exceptionState);
   492     }
   494     return retval;
   495 }
   497 bool
   498 jsd_IsValidThreadState(JSDContext*        jsdc, 
   499                        JSDThreadState*    jsdthreadstate)
   500 {
   501     JSDThreadState *cur;
   503     MOZ_ASSERT( JSD_THREADSTATES_LOCKED(jsdc) );
   505     for( cur = (JSDThreadState*)jsdc->threadsStates.next;
   506          cur != (JSDThreadState*)&jsdc->threadsStates;
   507          cur = (JSDThreadState*)cur->links.next ) 
   508     {
   509         if( cur == jsdthreadstate )
   510             return true;
   511     }
   512     return false;
   513 }    
   515 bool
   516 jsd_IsValidFrameInThreadState(JSDContext*        jsdc, 
   517                               JSDThreadState*    jsdthreadstate,
   518                               JSDStackFrameInfo* jsdframe)
   519 {
   520     MOZ_ASSERT(JSD_THREADSTATES_LOCKED(jsdc));
   522     if( ! jsd_IsValidThreadState(jsdc, jsdthreadstate) )
   523         return false;
   524     if( jsdframe->jsdthreadstate != jsdthreadstate )
   525         return false;
   527     JSD_ASSERT_VALID_THREAD_STATE(jsdthreadstate);
   528     JSD_ASSERT_VALID_STACK_FRAME(jsdframe);
   530     return true;
   531 }
   533 static JSContext*
   534 _getContextForThreadState(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
   535 {
   536     bool valid;
   537     JSD_LOCK_THREADSTATES(jsdc);
   538     valid = jsd_IsValidThreadState(jsdc, jsdthreadstate);
   539     JSD_UNLOCK_THREADSTATES(jsdc);
   540     if( valid )
   541         return jsdthreadstate->context;
   542     return nullptr;
   543 }
   545 JSDValue*
   546 jsd_GetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
   547 {
   548     JSContext* cx;
   549     if(!(cx = _getContextForThreadState(jsdc, jsdthreadstate)))
   550         return nullptr;
   552     JS::RootedValue val(cx);
   553     if(JS_GetPendingException(cx, &val))
   554         return jsd_NewValue(jsdc, val);
   555     return nullptr;
   556 }
   558 bool
   559 jsd_SetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate,
   560                  JSDValue* jsdval)
   561 {
   562     JSContext* cx;
   564     if(!(cx = _getContextForThreadState(jsdc, jsdthreadstate)))
   565         return false;
   567     if(jsdval) {
   568         JS::RootedValue exn(cx, JSD_GetValueWrappedJSVal(jsdc, jsdval));
   569         JS_SetPendingException(cx, exn);
   570     } else {
   571         JS_ClearPendingException(cx);
   572     }
   573     return true;
   574 }

mercurial