pjs/js/jsd/jsd_high.c

299 строки
7.7 KiB
C

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
** JavaScript Debugger Navigator API - 'High Level' functions
*/
#include "jsd.h"
/***************************************************************************/
/* use a global context for now (avoid direct references to it!) */
static JSDContext _static_context;
/* these are global now, they transcend our concept of JSDContext...*/
static JSD_UserCallbacks _callbacks;
static void* _user;
static JSTaskState* _jstaskstate;
static PRThread * _dangerousThread1;
#ifdef DEBUG
void JSD_ASSERT_VALID_CONTEXT( JSDContext* jsdc )
{
PR_ASSERT( jsdc == &_static_context );
PR_ASSERT( jsdc->inited );
PR_ASSERT( jsdc->jstaskstate );
PR_ASSERT( jsdc->jscontexts );
}
#endif
static PRHashNumber
_hash_root(const void *key)
{
PRHashNumber num = (PRHashNumber) key;
return num >> 2;
}
static JSClass global_class = {
"JSDGlobal", 0,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
};
static JSDContext*
NewJSDContext(void)
{
JSDContext* jsdc = &_static_context;
if( jsdc->inited )
return NULL;
if( ! _jstaskstate )
return NULL;
memset( jsdc, 0, sizeof(JSDContext) );
jsdc->jstaskstate = _jstaskstate;
PR_INIT_CLIST(&jsdc->threadsStates);
jsdc->dumbContext = JS_NewContext( _jstaskstate, 256 );
if( ! jsdc->dumbContext )
return NULL;
jsdc->glob = JS_NewObject(jsdc->dumbContext, &global_class, NULL, NULL);
if( ! jsdc->glob )
return NULL;
if( ! JS_InitStandardClasses(jsdc->dumbContext, jsdc->glob) )
return NULL;
jsdc->jscontexts = PR_NewHashTable(256, _hash_root,
PR_CompareValues, PR_CompareValues,
NULL, NULL);
if( ! jsdc->jscontexts )
return NULL;
jsdc->inited = JS_TRUE;
return jsdc;
}
PR_STATIC_CALLBACK(PRIntn)
_hash_entry_zapper(PRHashEntry *he, PRIntn i, void *arg)
{
PR_FREEIF(he->value);
he->value = NULL;
he->key = NULL;
return HT_ENUMERATE_NEXT;
}
static void
DestroyJSDContext( JSDContext* jsdc )
{
JSD_ASSERT_VALID_CONTEXT(jsdc);
if( jsdc->jscontexts )
{
PR_HashTableEnumerateEntries(jsdc->jscontexts, _hash_entry_zapper, NULL);
PR_HashTableDestroy(jsdc->jscontexts);
}
jsdc->inited = JS_FALSE;
}
JSDContext*
jsd_GetDefaultJSDContext(void)
{
JSDContext* jsdc = &_static_context;
if( ! jsdc->inited )
return NULL;
return jsdc;
}
/***************************************************************************/
JSDContext*
jsd_DebuggerOn(void)
{
JSDContext* jsdc = NewJSDContext();
JSContext* iter = NULL;
JSContext* cx;
if( ! jsdc )
return NULL;
/* set hooks here */
JS_SetNewScriptHookProc( jsdc->jstaskstate, jsd_NewScriptHookProc, jsdc );
JS_SetDestroyScriptHookProc( jsdc->jstaskstate, jsd_DestroyScriptHookProc, jsdc );
/* enumerate contexts for JSTaskState and add them to our table */
while( NULL != (cx = JS_ContextIterator(jsdc->jstaskstate, &iter)) )
jsd_JSContextUsed( jsdc, cx );
if( _callbacks.setContext )
_callbacks.setContext( jsdc, _user );
return jsdc;
}
void
jsd_DebuggerOff(JSDContext* jsdc)
{
/* clear hooks here */
JS_SetNewScriptHookProc( jsdc->jstaskstate, NULL, NULL );
JS_SetDestroyScriptHookProc( jsdc->jstaskstate, NULL, NULL );
/* clean up */
jsd_DestroyAllJSDScripts( jsdc );
jsd_DestroyAllSources( jsdc );
DestroyJSDContext( jsdc );
if( _callbacks.setContext )
_callbacks.setContext( NULL, _user );
}
void
jsd_SetUserCallbacks(JSTaskState* jstaskstate, JSD_UserCallbacks* callbacks, void* user)
{
_jstaskstate = jstaskstate;
_user = user;
_dangerousThread1 = PR_CurrentThread();
if( callbacks )
memcpy( &_callbacks, callbacks, sizeof(JSD_UserCallbacks) );
else
memset( &_callbacks, 0 , sizeof(JSD_UserCallbacks) );
if( _callbacks.setContext && _static_context.inited )
_callbacks.setContext( &_static_context, _user );
}
JSDContextWrapper*
jsd_JSDContextWrapperForJSContext( JSDContext* jsdc, JSContext* context )
{
return (JSDContextWrapper*) PR_HashTableLookup(jsdc->jscontexts, context);
}
PR_STATIC_CALLBACK(void)
jsd_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
{
JSDContextWrapper* wrapper;
JSDContext* jsdc;
PRUintn action = JSD_ERROR_REPORTER_PASS_ALONG;
jsdc = jsd_GetDefaultJSDContext();
if( ! jsdc )
{
PR_ASSERT(0);
return;
}
wrapper = jsd_JSDContextWrapperForJSContext( jsdc, cx );
if( ! wrapper )
{
PR_ASSERT(0);
return;
}
if( jsdc->errorReporter && ! jsd_IsCurrentThreadDangerous() )
action = jsdc->errorReporter(jsdc, cx, message, report,
jsdc->errorReporterData);
switch(action)
{
case JSD_ERROR_REPORTER_PASS_ALONG:
if( wrapper->originalErrorReporter )
wrapper->originalErrorReporter(cx, message, report);
break;
case JSD_ERROR_REPORTER_RETURN:
break;
case JSD_ERROR_REPORTER_DEBUG:
{
JSDThreadState* jsdthreadstate;
if( ! jsdc->debugBreakHook )
return;
jsdthreadstate = jsd_NewThreadState(jsdc,cx);
if( jsdthreadstate )
{
(*jsdc->debugBreakHook)(jsdc, jsdthreadstate,
JSD_HOOK_DEBUG_REQUESTED,
jsdc->debugBreakHookData );
jsd_DestroyThreadState(jsdc, jsdthreadstate);
}
}
default:;
}
}
void
jsd_JSContextUsed( JSDContext* jsdc, JSContext* context )
{
JSDContextWrapper* wrapper;
wrapper = jsd_JSDContextWrapperForJSContext(jsdc, context);
if( wrapper )
{
/* error reporters are sometimes overwritten by other code... */
JSErrorReporter oldrep = JS_SetErrorReporter(context, jsd_ErrorReporter);
if( jsd_ErrorReporter != oldrep )
wrapper->originalErrorReporter = oldrep;
return;
}
/* else... */
wrapper = PR_NEWZAP(JSDContextWrapper);
if( ! wrapper )
return;
if( ! PR_HashTableAdd(jsdc->jscontexts, context, wrapper ) )
{
PR_FREEIF(wrapper);
return;
}
wrapper->context = context;
wrapper->jsdc = jsdc;
/* add our error reporter */
wrapper->originalErrorReporter = JS_SetErrorReporter(context, jsd_ErrorReporter);
/* add our printer */
/* add our loader */
}
JSD_ErrorReporter
jsd_SetErrorReporter( JSDContext* jsdc, JSD_ErrorReporter reporter, void* callerdata)
{
JSD_ErrorReporter old = jsdc->errorReporter;
jsdc->errorReporter = reporter;
jsdc->errorReporterData = callerdata;
return old;
}
JSBool
jsd_IsCurrentThreadDangerous()
{
return PR_CurrentThread() == _dangerousThread1;
}