js/jsd/jsd_high.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 - 'High Level' functions
     9  */
    11 #include "jsd.h"
    12 #include "nsCxPusher.h"
    14 using mozilla::AutoSafeJSContext;
    16 /***************************************************************************/
    18 /* XXX not 'static' because of old Mac CodeWarrior bug */ 
    19 JSCList _jsd_context_list = JS_INIT_STATIC_CLIST(&_jsd_context_list);
    21 /* these are used to connect JSD_SetUserCallbacks() with JSD_DebuggerOn() */
    22 static JSD_UserCallbacks _callbacks;
    23 static void*             _user = nullptr; 
    24 static JSRuntime*        _jsrt = nullptr;
    26 #ifdef JSD_HAS_DANGEROUS_THREAD
    27 static void* _dangerousThread = nullptr;
    28 #endif
    30 #ifdef JSD_THREADSAFE
    31 JSDStaticLock* _jsd_global_lock = nullptr;
    32 #endif
    34 #ifdef DEBUG
    35 void JSD_ASSERT_VALID_CONTEXT(JSDContext* jsdc)
    36 {
    37     MOZ_ASSERT(jsdc->inited);
    38     MOZ_ASSERT(jsdc->jsrt);
    39     MOZ_ASSERT(jsdc->glob);
    40 }
    41 #endif
    43 /***************************************************************************/
    44 /* xpconnect related utility functions implemented in jsd_xpc.cpp */
    46 extern void
    47 global_finalize(JSFreeOp* fop, JSObject* obj);
    49 extern JSObject*
    50 CreateJSDGlobal(JSContext *cx, const JSClass *clasp);
    52 /***************************************************************************/
    55 static const JSClass global_class = {
    56     "JSDGlobal", JSCLASS_GLOBAL_FLAGS |
    57     JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS,
    58     JS_PropertyStub,  JS_DeletePropertyStub,  JS_PropertyStub,  JS_StrictPropertyStub,
    59     JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,   global_finalize,
    60     nullptr, nullptr, nullptr,
    61     JS_GlobalObjectTraceHook
    62 };
    64 static bool
    65 _validateUserCallbacks(JSD_UserCallbacks* callbacks)
    66 {
    67     return !callbacks ||
    68            (callbacks->size && callbacks->size <= sizeof(JSD_UserCallbacks));
    69 }    
    71 static JSDContext*
    72 _newJSDContext(JSRuntime*         jsrt, 
    73                JSD_UserCallbacks* callbacks, 
    74                void*              user,
    75                JSObject*          scopeobj)
    76 {
    77     JSDContext* jsdc = nullptr;
    78     bool ok = true;
    79     AutoSafeJSContext cx;
    81     if( ! jsrt )
    82         return nullptr;
    84     if( ! _validateUserCallbacks(callbacks) )
    85         return nullptr;
    87     jsdc = (JSDContext*) calloc(1, sizeof(JSDContext));
    88     if( ! jsdc )
    89         goto label_newJSDContext_failure;
    91     if( ! JSD_INIT_LOCKS(jsdc) )
    92         goto label_newJSDContext_failure;
    94     JS_INIT_CLIST(&jsdc->links);
    96     jsdc->jsrt = jsrt;
    98     if( callbacks )
    99         memcpy(&jsdc->userCallbacks, callbacks, callbacks->size);
   101     jsdc->user = user;
   103 #ifdef JSD_HAS_DANGEROUS_THREAD
   104     jsdc->dangerousThread = _dangerousThread;
   105 #endif
   107     JS_INIT_CLIST(&jsdc->threadsStates);
   108     JS_INIT_CLIST(&jsdc->sources);
   109     JS_INIT_CLIST(&jsdc->removedSources);
   111     jsdc->sourceAlterCount = 1;
   113     if( ! jsd_CreateAtomTable(jsdc) )
   114         goto label_newJSDContext_failure;
   116     if( ! jsd_InitObjectManager(jsdc) )
   117         goto label_newJSDContext_failure;
   119     if( ! jsd_InitScriptManager(jsdc) )
   120         goto label_newJSDContext_failure;
   122     {
   123         JS::RootedObject global(cx, CreateJSDGlobal(cx, &global_class));
   124         if( ! global )
   125             goto label_newJSDContext_failure;
   127         jsdc->glob = global;
   129         JSAutoCompartment ac(cx, jsdc->glob);
   130         ok = JS::AddNamedObjectRoot(cx, &jsdc->glob, "JSD context global") &&
   131              JS_InitStandardClasses(cx, global);
   132     }
   133     if( ! ok )
   134         goto label_newJSDContext_failure;
   136     jsdc->data = nullptr;
   137     jsdc->inited = true;
   139     JSD_LOCK();
   140     JS_INSERT_LINK(&jsdc->links, &_jsd_context_list);
   141     JSD_UNLOCK();
   143     return jsdc;
   145 label_newJSDContext_failure:
   146     if( jsdc ) {
   147         if ( jsdc->glob )
   148             JS::RemoveObjectRootRT(JS_GetRuntime(cx), &jsdc->glob);
   149         jsd_DestroyObjectManager(jsdc);
   150         jsd_DestroyAtomTable(jsdc);
   151         free(jsdc);
   152     }
   153     return nullptr;
   154 }
   156 static void
   157 _destroyJSDContext(JSDContext* jsdc)
   158 {
   159     JSD_ASSERT_VALID_CONTEXT(jsdc);
   161     JSD_LOCK();
   162     JS_REMOVE_LINK(&jsdc->links);
   163     JSD_UNLOCK();
   165     if ( jsdc->glob ) {
   166         JS::RemoveObjectRootRT(jsdc->jsrt, &jsdc->glob);
   167     }
   168     jsd_DestroyObjectManager(jsdc);
   169     jsd_DestroyAtomTable(jsdc);
   171     jsdc->inited = false;
   173     /*
   174     * We should free jsdc here, but we let it leak in case there are any 
   175     * asynchronous hooks calling into the system using it as a handle
   176     *
   177     * XXX we also leak the locks
   178     */
   179 }
   181 /***************************************************************************/
   183 JSDContext*
   184 jsd_DebuggerOnForUser(JSRuntime*         jsrt, 
   185                       JSD_UserCallbacks* callbacks, 
   186                       void*              user,
   187                       JSObject*          scopeobj)
   188 {
   189     JSDContext* jsdc;
   191     jsdc = _newJSDContext(jsrt, callbacks, user, scopeobj);
   192     if( ! jsdc )
   193         return nullptr;
   195     /*
   196      * Set hooks here.  The new/destroy script hooks are on even when
   197      * the debugger is paused.  The destroy hook so we'll clean up
   198      * internal data structures when scripts are destroyed, and the
   199      * newscript hook for backwards compatibility for now.  We'd like
   200      * to stop doing that.
   201      */
   202     JS_SetNewScriptHookProc(jsdc->jsrt, jsd_NewScriptHookProc, jsdc);
   203     JS_SetDestroyScriptHookProc(jsdc->jsrt, jsd_DestroyScriptHookProc, jsdc);
   204     jsd_DebuggerUnpause(jsdc);
   206     if( jsdc->userCallbacks.setContext )
   207         jsdc->userCallbacks.setContext(jsdc, jsdc->user);
   208     return jsdc;
   209 }
   211 JSDContext*
   212 jsd_DebuggerOn(void)
   213 {
   214     MOZ_ASSERT(_jsrt);
   215     MOZ_ASSERT(_validateUserCallbacks(&_callbacks));
   216     return jsd_DebuggerOnForUser(_jsrt, &_callbacks, _user, nullptr);
   217 }
   219 void
   220 jsd_DebuggerOff(JSDContext* jsdc)
   221 {
   222     jsd_DebuggerPause(jsdc, true);
   223     /* clear hooks here */
   224     JS_SetNewScriptHookProc(jsdc->jsrt, nullptr, nullptr);
   225     JS_SetDestroyScriptHookProc(jsdc->jsrt, nullptr, nullptr);
   227     /* clean up */
   228     JSD_LockScriptSubsystem(jsdc);
   229     jsd_DestroyScriptManager(jsdc);
   230     JSD_UnlockScriptSubsystem(jsdc);
   231     jsd_DestroyAllSources(jsdc);
   233     _destroyJSDContext(jsdc);
   235     if( jsdc->userCallbacks.setContext )
   236         jsdc->userCallbacks.setContext(nullptr, jsdc->user);
   237 }
   239 void
   240 jsd_DebuggerPause(JSDContext* jsdc, bool forceAllHooksOff)
   241 {
   242     JS_SetDebuggerHandler(jsdc->jsrt, nullptr, nullptr);
   243     if (forceAllHooksOff || !(jsdc->flags & JSD_COLLECT_PROFILE_DATA)) {
   244         JS_SetExecuteHook(jsdc->jsrt, nullptr, nullptr);
   245         JS_SetCallHook(jsdc->jsrt, nullptr, nullptr);
   246     }
   247     JS_SetThrowHook(jsdc->jsrt, nullptr, nullptr);
   248     JS_SetDebugErrorHook(jsdc->jsrt, nullptr, nullptr);
   249 }
   251 static bool
   252 jsd_DebugErrorHook(JSContext *cx, const char *message,
   253                    JSErrorReport *report, void *closure);
   255 void
   256 jsd_DebuggerUnpause(JSDContext* jsdc)
   257 {
   258     JS_SetDebuggerHandler(jsdc->jsrt, jsd_DebuggerHandler, jsdc);
   259     JS_SetExecuteHook(jsdc->jsrt, jsd_TopLevelCallHook, jsdc);
   260     JS_SetCallHook(jsdc->jsrt, jsd_FunctionCallHook, jsdc);
   261     JS_SetThrowHook(jsdc->jsrt, jsd_ThrowHandler, jsdc);
   262     JS_SetDebugErrorHook(jsdc->jsrt, jsd_DebugErrorHook, jsdc);
   263 }
   265 void
   266 jsd_SetUserCallbacks(JSRuntime* jsrt, JSD_UserCallbacks* callbacks, void* user)
   267 {
   268     _jsrt = jsrt;
   269     _user = user;
   271 #ifdef JSD_HAS_DANGEROUS_THREAD
   272     _dangerousThread = JSD_CURRENT_THREAD();
   273 #endif
   275     if( callbacks )
   276         memcpy(&_callbacks, callbacks, sizeof(JSD_UserCallbacks));
   277     else
   278         memset(&_callbacks, 0 , sizeof(JSD_UserCallbacks));
   279 }
   281 void*
   282 jsd_SetContextPrivate(JSDContext* jsdc, void *data)
   283 {
   284     jsdc->data = data;
   285     return data;
   286 }
   288 void*
   289 jsd_GetContextPrivate(JSDContext* jsdc)
   290 {
   291     return jsdc->data;
   292 }
   294 void
   295 jsd_ClearAllProfileData(JSDContext* jsdc)
   296 {
   297     JSDScript *current;
   299     JSD_LOCK_SCRIPTS(jsdc);
   300     current = (JSDScript *)jsdc->scripts.next;
   301     while (current != (JSDScript *)&jsdc->scripts)
   302     {
   303         jsd_ClearScriptProfileData(jsdc, current);
   304         current = (JSDScript *)current->links.next;
   305     }
   307     JSD_UNLOCK_SCRIPTS(jsdc);
   308 }
   310 JSDContext*
   311 jsd_JSDContextForJSContext(JSContext* context)
   312 {
   313     JSDContext* iter;
   314     JSDContext* jsdc = nullptr;
   315     JSRuntime*  runtime = JS_GetRuntime(context);
   317     JSD_LOCK();
   318     for( iter = (JSDContext*)_jsd_context_list.next;
   319          iter != (JSDContext*)&_jsd_context_list;
   320          iter = (JSDContext*)iter->links.next )
   321     {
   322         if( runtime == iter->jsrt )
   323         {
   324             jsdc = iter;
   325             break;
   326         }
   327     }
   328     JSD_UNLOCK();
   329     return jsdc;
   330 }    
   332 static bool
   333 jsd_DebugErrorHook(JSContext *cx, const char *message,
   334                    JSErrorReport *report, void *closure)
   335 {
   336     JSDContext* jsdc = (JSDContext*) closure;
   337     JSD_ErrorReporter errorReporter;
   338     void*             errorReporterData;
   340     if( ! jsdc )
   341     {
   342         MOZ_ASSERT(0);
   343         return true;
   344     }
   345     if( JSD_IS_DANGEROUS_THREAD(jsdc) )
   346         return true;
   348     /* local in case hook gets cleared on another thread */
   349     JSD_LOCK();
   350     errorReporter     = jsdc->errorReporter;
   351     errorReporterData = jsdc->errorReporterData;
   352     JSD_UNLOCK();
   354     if(!errorReporter)
   355         return true;
   357     switch(errorReporter(jsdc, cx, message, report, errorReporterData))
   358     {
   359         case JSD_ERROR_REPORTER_PASS_ALONG:
   360             return true;
   361         case JSD_ERROR_REPORTER_RETURN:
   362             return false;
   363         case JSD_ERROR_REPORTER_DEBUG:
   364         {
   365             JS::RootedValue rval(cx);
   366             JSD_ExecutionHookProc   hook;
   367             void*                   hookData;
   369             /* local in case hook gets cleared on another thread */
   370             JSD_LOCK();
   371             hook = jsdc->debugBreakHook;
   372             hookData = jsdc->debugBreakHookData;
   373             JSD_UNLOCK();
   375             jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_DEBUG_REQUESTED,
   376                                   hook, hookData, rval.address());
   377             /* XXX Should make this dependent on ExecutionHook retval */
   378             return true;
   379         }
   380         case JSD_ERROR_REPORTER_CLEAR_RETURN:
   381             if(report && JSREPORT_IS_EXCEPTION(report->flags))
   382                 JS_ClearPendingException(cx);
   383             return false;
   384         default:
   385             MOZ_ASSERT(0);
   386             break;
   387     }
   388     return true;
   389 }
   391 bool
   392 jsd_SetErrorReporter(JSDContext*       jsdc, 
   393                      JSD_ErrorReporter reporter, 
   394                      void*             callerdata)
   395 {
   396     JSD_LOCK();
   397     jsdc->errorReporter = reporter;
   398     jsdc->errorReporterData = callerdata;
   399     JSD_UNLOCK();
   400     return true;
   401 }
   403 bool
   404 jsd_GetErrorReporter(JSDContext*        jsdc, 
   405                      JSD_ErrorReporter* reporter, 
   406                      void**             callerdata)
   407 {
   408     JSD_LOCK();
   409     if( reporter )
   410         *reporter = jsdc->errorReporter;
   411     if( callerdata )
   412         *callerdata = jsdc->errorReporterData;
   413     JSD_UNLOCK();
   414     return true;
   415 }

mercurial