gecko-dev/js/jsd/jsd_scpt.cpp
Till Schneidereit 2af809133c Bug 886193 - Part 2: Introduce JSScript::nonDelazifyingFunction and use it whereever possible. r=jandem
--HG--
extra : rebase_source : cd6926e6e1fead242263e50763ce89348b5e9cd5
2014-01-09 17:13:25 +01:00

883 lines
21 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* JavaScript Debugging support - Script support
*/
#include "jsd.h"
#include "jsfriendapi.h"
#include "nsCxPusher.h"
using mozilla::AutoSafeJSContext;
/* Comment this out to disable (NT specific) dumping as we go */
/*
** #ifdef DEBUG
** #define JSD_DUMP 1
** #endif
*/
#define NOT_SET_YET -1
/***************************************************************************/
#ifdef DEBUG
void JSD_ASSERT_VALID_SCRIPT(JSDScript* jsdscript)
{
JS_ASSERT(jsdscript);
JS_ASSERT(jsdscript->script);
}
void JSD_ASSERT_VALID_EXEC_HOOK(JSDExecHook* jsdhook)
{
JS_ASSERT(jsdhook);
JS_ASSERT(jsdhook->hook);
}
#endif
static JSDScript*
_newJSDScript(JSDContext* jsdc,
JSContext *cx,
JSScript *script_)
{
JS::RootedScript script(cx, script_);
if ( JS_GetScriptIsSelfHosted(script) )
return nullptr;
JSDScript* jsdscript;
unsigned lineno;
const char* raw_filename;
JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
/* these are inlined javascript: urls and we can't handle them now */
lineno = (unsigned) JS_GetScriptBaseLineNumber(cx, script);
if( lineno == 0 )
return nullptr;
jsdscript = (JSDScript*) calloc(1, sizeof(JSDScript));
if( ! jsdscript )
return nullptr;
raw_filename = JS_GetScriptFilename(cx,script);
JS_HashTableAdd(jsdc->scriptsTable, (void *)script, (void *)jsdscript);
JS_APPEND_LINK(&jsdscript->links, &jsdc->scripts);
jsdscript->jsdc = jsdc;
jsdscript->script = script;
jsdscript->lineBase = lineno;
jsdscript->lineExtent = (unsigned)NOT_SET_YET;
jsdscript->data = nullptr;
jsdscript->url = (char*) jsd_BuildNormalizedURL(raw_filename);
JS_INIT_CLIST(&jsdscript->hooks);
return jsdscript;
}
static void
_destroyJSDScript(JSDContext* jsdc,
JSDScript* jsdscript)
{
JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
/* destroy all hooks */
jsd_ClearAllExecutionHooksForScript(jsdc, jsdscript);
JS_REMOVE_LINK(&jsdscript->links);
if(jsdscript->url)
free(jsdscript->url);
if (jsdscript->profileData)
free(jsdscript->profileData);
free(jsdscript);
}
/***************************************************************************/
#ifdef JSD_DUMP
#ifndef XP_WIN
void
OutputDebugString (char *buf)
{
fprintf (stderr, "%s", buf);
}
#endif
static void
_dumpJSDScript(JSDContext* jsdc, JSDScript* jsdscript, const char* leadingtext)
{
const char* name;
JSString* fun;
unsigned base;
unsigned extent;
char Buf[256];
size_t n;
name = jsd_GetScriptFilename(jsdc, jsdscript);
fun = jsd_GetScriptFunctionId(jsdc, jsdscript);
base = jsd_GetScriptBaseLineNumber(jsdc, jsdscript);
extent = jsd_GetScriptLineExtent(jsdc, jsdscript);
n = size_t(snprintf(Buf, sizeof(Buf), "%sscript=%08X, %s, ",
leadingtext, (unsigned) jsdscript->script,
name ? name : "no URL"));
if (n + 1 < sizeof(Buf)) {
if (fun) {
n += size_t(snprintf(Buf + n, sizeof(Buf) - n, "%s", "no fun"));
} else {
n += JS_PutEscapedFlatString(Buf + n, sizeof(Buf) - n,
JS_ASSERT_STRING_IS_FLAT(fun), 0);
Buf[sizeof(Buf) - 1] = '\0';
}
if (n + 1 < sizeof(Buf))
snprintf(Buf + n, sizeof(Buf) - n, ", %d-%d\n", base, base + extent - 1);
}
OutputDebugString( Buf );
}
static void
_dumpJSDScriptList( JSDContext* jsdc )
{
JSDScript* iterp = nullptr;
JSDScript* jsdscript = nullptr;
OutputDebugString( "*** JSDScriptDump\n" );
while( nullptr != (jsdscript = jsd_IterateScripts(jsdc, &iterp)) )
_dumpJSDScript( jsdc, jsdscript, " script: " );
}
#endif /* JSD_DUMP */
/***************************************************************************/
static JSHashNumber
jsd_hash_script(const void *key)
{
return ((JSHashNumber)(ptrdiff_t) key) >> 2; /* help lame MSVC1.5 on Win16 */
}
static void *
jsd_alloc_script_table(void *priv, size_t size)
{
return malloc(size);
}
static void
jsd_free_script_table(void *priv, void *item, size_t size)
{
free(item);
}
static JSHashEntry *
jsd_alloc_script_entry(void *priv, const void *item)
{
return (JSHashEntry*) malloc(sizeof(JSHashEntry));
}
static void
jsd_free_script_entry(void *priv, JSHashEntry *he, unsigned flag)
{
if (flag == HT_FREE_ENTRY)
{
_destroyJSDScript((JSDContext*) priv, (JSDScript*) he->value);
free(he);
}
}
static const JSHashAllocOps script_alloc_ops = {
jsd_alloc_script_table, jsd_free_script_table,
jsd_alloc_script_entry, jsd_free_script_entry
};
#ifndef JSD_SCRIPT_HASH_SIZE
#define JSD_SCRIPT_HASH_SIZE 1024
#endif
bool
jsd_InitScriptManager(JSDContext* jsdc)
{
JS_INIT_CLIST(&jsdc->scripts);
jsdc->scriptsTable = JS_NewHashTable(JSD_SCRIPT_HASH_SIZE, jsd_hash_script,
JS_CompareValues, JS_CompareValues,
&script_alloc_ops, (void*) jsdc);
return !!jsdc->scriptsTable;
}
void
jsd_DestroyScriptManager(JSDContext* jsdc)
{
JSD_LOCK_SCRIPTS(jsdc);
if (jsdc->scriptsTable)
JS_HashTableDestroy(jsdc->scriptsTable);
JSD_UNLOCK_SCRIPTS(jsdc);
}
JSDScript*
jsd_FindJSDScript( JSDContext* jsdc,
JSScript *script )
{
JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
return (JSDScript*) JS_HashTableLookup(jsdc->scriptsTable, (void *)script);
}
JSDScript *
jsd_FindOrCreateJSDScript(JSDContext *jsdc,
JSContext *cx,
JSScript *script_,
JSAbstractFramePtr frame)
{
JS::RootedScript script(cx, script_);
JSDScript *jsdscript;
JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
jsdscript = jsd_FindJSDScript(jsdc, script);
if (jsdscript)
return jsdscript;
/* Fallback for unknown scripts: create a new script. */
if (!frame) {
JSBrokenFrameIterator iter(cx);
if (!iter.done())
frame = iter.abstractFramePtr();
}
if (frame)
jsdscript = _newJSDScript(jsdc, cx, script);
return jsdscript;
}
JSDProfileData*
jsd_GetScriptProfileData(JSDContext* jsdc, JSDScript *script)
{
if (!script->profileData)
script->profileData = (JSDProfileData*)calloc(1, sizeof(JSDProfileData));
return script->profileData;
}
uint32_t
jsd_GetScriptFlags(JSDContext *jsdc, JSDScript *script)
{
return script->flags;
}
void
jsd_SetScriptFlags(JSDContext *jsdc, JSDScript *script, uint32_t flags)
{
script->flags = flags;
}
unsigned
jsd_GetScriptCallCount(JSDContext* jsdc, JSDScript *script)
{
if (script->profileData)
return script->profileData->callCount;
return 0;
}
unsigned
jsd_GetScriptMaxRecurseDepth(JSDContext* jsdc, JSDScript *script)
{
if (script->profileData)
return script->profileData->maxRecurseDepth;
return 0;
}
double
jsd_GetScriptMinExecutionTime(JSDContext* jsdc, JSDScript *script)
{
if (script->profileData)
return script->profileData->minExecutionTime;
return 0.0;
}
double
jsd_GetScriptMaxExecutionTime(JSDContext* jsdc, JSDScript *script)
{
if (script->profileData)
return script->profileData->maxExecutionTime;
return 0.0;
}
double
jsd_GetScriptTotalExecutionTime(JSDContext* jsdc, JSDScript *script)
{
if (script->profileData)
return script->profileData->totalExecutionTime;
return 0.0;
}
double
jsd_GetScriptMinOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
{
if (script->profileData)
return script->profileData->minOwnExecutionTime;
return 0.0;
}
double
jsd_GetScriptMaxOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
{
if (script->profileData)
return script->profileData->maxOwnExecutionTime;
return 0.0;
}
double
jsd_GetScriptTotalOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
{
if (script->profileData)
return script->profileData->totalOwnExecutionTime;
return 0.0;
}
void
jsd_ClearScriptProfileData(JSDContext* jsdc, JSDScript *script)
{
if (script->profileData)
{
free(script->profileData);
script->profileData = nullptr;
}
}
JSScript *
jsd_GetJSScript (JSDContext *jsdc, JSDScript *script)
{
return script->script;
}
JSFunction *
jsd_GetJSFunction (JSDContext *jsdc, JSDScript *script)
{
AutoSafeJSContext cx;
return JS_GetScriptFunction(cx, script->script);
}
JSDScript*
jsd_IterateScripts(JSDContext* jsdc, JSDScript **iterp)
{
JSDScript *jsdscript = *iterp;
JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
if( !jsdscript )
jsdscript = (JSDScript *)jsdc->scripts.next;
if( jsdscript == (JSDScript *)&jsdc->scripts )
return nullptr;
*iterp = (JSDScript*) jsdscript->links.next;
return jsdscript;
}
void *
jsd_SetScriptPrivate(JSDScript *jsdscript, void *data)
{
void *rval = jsdscript->data;
jsdscript->data = data;
return rval;
}
void *
jsd_GetScriptPrivate(JSDScript *jsdscript)
{
return jsdscript->data;
}
bool
jsd_IsActiveScript(JSDContext* jsdc, JSDScript *jsdscript)
{
JSDScript *current;
JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
for( current = (JSDScript *)jsdc->scripts.next;
current != (JSDScript *)&jsdc->scripts;
current = (JSDScript *)current->links.next )
{
if(jsdscript == current)
return true;
}
return false;
}
const char*
jsd_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript)
{
return jsdscript->url;
}
JSString*
jsd_GetScriptFunctionId(JSDContext* jsdc, JSDScript *jsdscript)
{
JSString* str;
JSFunction *fun = jsd_GetJSFunction(jsdc, jsdscript);
if( ! fun )
return nullptr;
str = JS_GetFunctionId(fun);
/* For compatibility we return "anonymous", not an empty string here. */
return str ? str : JS_GetAnonymousString(jsdc->jsrt);
}
unsigned
jsd_GetScriptBaseLineNumber(JSDContext* jsdc, JSDScript *jsdscript)
{
return jsdscript->lineBase;
}
unsigned
jsd_GetScriptLineExtent(JSDContext* jsdc, JSDScript *jsdscript)
{
AutoSafeJSContext cx;
JSAutoCompartment ac(cx, jsdc->glob); // Just in case.
if( NOT_SET_YET == (int)jsdscript->lineExtent )
jsdscript->lineExtent = JS_GetScriptLineExtent(cx, jsdscript->script);
return jsdscript->lineExtent;
}
uintptr_t
jsd_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, unsigned line)
{
uintptr_t pc;
if( !jsdscript )
return 0;
AutoSafeJSContext cx;
JSAutoCompartment ac(cx, jsdscript->script);
pc = (uintptr_t) JS_LineNumberToPC(cx, jsdscript->script, line );
return pc;
}
unsigned
jsd_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, uintptr_t pc)
{
unsigned first = jsdscript->lineBase;
unsigned last = first + jsd_GetScriptLineExtent(jsdc, jsdscript) - 1;
unsigned line = 0;
if (pc) {
AutoSafeJSContext cx;
JSAutoCompartment ac(cx, jsdscript->script);
line = JS_PCToLineNumber(cx, jsdscript->script, (jsbytecode*)pc);
}
if( line < first )
return first;
if( line > last )
return last;
return line;
}
bool
jsd_GetLinePCs(JSDContext* jsdc, JSDScript* jsdscript,
unsigned startLine, unsigned maxLines,
unsigned* count, unsigned** retLines, uintptr_t** retPCs)
{
unsigned first = jsdscript->lineBase;
unsigned last = first + jsd_GetScriptLineExtent(jsdc, jsdscript) - 1;
bool ok;
jsbytecode **pcs;
unsigned i;
if (last < startLine)
return true;
AutoSafeJSContext cx;
JSAutoCompartment ac(cx, jsdscript->script);
ok = JS_GetLinePCs(cx, jsdscript->script,
startLine, maxLines,
count, retLines, &pcs);
if (ok) {
if (retPCs) {
for (i = 0; i < *count; ++i) {
(*retPCs)[i] = (*pcs)[i];
}
}
JS_free(cx, pcs);
}
return ok;
}
bool
jsd_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata)
{
JSD_LOCK();
jsdc->scriptHook = hook;
jsdc->scriptHookData = callerdata;
JSD_UNLOCK();
return true;
}
bool
jsd_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata)
{
JSD_LOCK();
if( hook )
*hook = jsdc->scriptHook;
if( callerdata )
*callerdata = jsdc->scriptHookData;
JSD_UNLOCK();
return true;
}
bool
jsd_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript* jsdscript, bool enable)
{
bool rv;
AutoSafeJSContext cx;
JSAutoCompartment ac(cx, jsdscript->script);
JSD_LOCK();
rv = JS_SetSingleStepMode(cx, jsdscript->script, enable);
JSD_UNLOCK();
return rv;
}
/***************************************************************************/
void
jsd_NewScriptHookProc(
JSContext *cx,
const char *filename, /* URL this script loads from */
unsigned lineno, /* line where this script starts */
JSScript *script,
JSFunction *fun,
void* callerdata )
{
JSDScript* jsdscript = nullptr;
JSDContext* jsdc = (JSDContext*) callerdata;
JSD_ScriptHookProc hook;
void* hookData;
JSD_ASSERT_VALID_CONTEXT(jsdc);
if( JSD_IS_DANGEROUS_THREAD(jsdc) )
return;
JSD_LOCK_SCRIPTS(jsdc);
jsdscript = _newJSDScript(jsdc, cx, script);
JSD_UNLOCK_SCRIPTS(jsdc);
if( ! jsdscript )
return;
#ifdef JSD_DUMP
JSD_LOCK_SCRIPTS(jsdc);
_dumpJSDScript(jsdc, jsdscript, "***NEW Script: ");
_dumpJSDScriptList( jsdc );
JSD_UNLOCK_SCRIPTS(jsdc);
#endif /* JSD_DUMP */
/* local in case jsdc->scriptHook gets cleared on another thread */
JSD_LOCK();
hook = jsdc->scriptHook;
if( hook )
jsdscript->flags = jsdscript->flags | JSD_SCRIPT_CALL_DESTROY_HOOK_BIT;
hookData = jsdc->scriptHookData;
JSD_UNLOCK();
if( hook )
hook(jsdc, jsdscript, true, hookData);
}
void
jsd_DestroyScriptHookProc(
JSFreeOp *fop,
JSScript *script_,
void* callerdata )
{
JSDScript* jsdscript = nullptr;
JSDContext* jsdc = (JSDContext*) callerdata;
// NB: We're called during GC, so we can't push a cx. Root directly with
// the runtime.
JS::RootedScript script(jsdc->jsrt, script_);
JSD_ScriptHookProc hook;
void* hookData;
JSD_ASSERT_VALID_CONTEXT(jsdc);
if( JSD_IS_DANGEROUS_THREAD(jsdc) )
return;
JSD_LOCK_SCRIPTS(jsdc);
jsdscript = jsd_FindJSDScript(jsdc, script);
JSD_UNLOCK_SCRIPTS(jsdc);
if( ! jsdscript )
return;
#ifdef JSD_DUMP
JSD_LOCK_SCRIPTS(jsdc);
_dumpJSDScript(jsdc, jsdscript, "***DESTROY Script: ");
JSD_UNLOCK_SCRIPTS(jsdc);
#endif /* JSD_DUMP */
/* local in case hook gets cleared on another thread */
JSD_LOCK();
hook = (jsdscript->flags & JSD_SCRIPT_CALL_DESTROY_HOOK_BIT) ? jsdc->scriptHook
: nullptr;
hookData = jsdc->scriptHookData;
JSD_UNLOCK();
if( hook )
hook(jsdc, jsdscript, false, hookData);
JSD_LOCK_SCRIPTS(jsdc);
JS_HashTableRemove(jsdc->scriptsTable, (void *)script);
JSD_UNLOCK_SCRIPTS(jsdc);
#ifdef JSD_DUMP
JSD_LOCK_SCRIPTS(jsdc);
_dumpJSDScriptList(jsdc);
JSD_UNLOCK_SCRIPTS(jsdc);
#endif /* JSD_DUMP */
}
/***************************************************************************/
static JSDExecHook*
_findHook(JSDContext* jsdc, JSDScript* jsdscript, uintptr_t pc)
{
JSDExecHook* jsdhook;
JSCList* list = &jsdscript->hooks;
for( jsdhook = (JSDExecHook*)list->next;
jsdhook != (JSDExecHook*)list;
jsdhook = (JSDExecHook*)jsdhook->links.next )
{
if (jsdhook->pc == pc)
return jsdhook;
}
return nullptr;
}
static bool
_isActiveHook(JSDContext* jsdc, JSScript *script, JSDExecHook* jsdhook)
{
JSDExecHook* current;
JSCList* list;
JSDScript* jsdscript;
JSD_LOCK_SCRIPTS(jsdc);
jsdscript = jsd_FindJSDScript(jsdc, script);
if( ! jsdscript)
{
JSD_UNLOCK_SCRIPTS(jsdc);
return false;
}
list = &jsdscript->hooks;
for( current = (JSDExecHook*)list->next;
current != (JSDExecHook*)list;
current = (JSDExecHook*)current->links.next )
{
if(current == jsdhook)
{
JSD_UNLOCK_SCRIPTS(jsdc);
return true;
}
}
JSD_UNLOCK_SCRIPTS(jsdc);
return false;
}
JSTrapStatus
jsd_TrapHandler(JSContext *cx, JSScript *script_, jsbytecode *pc, jsval *rval,
jsval closure)
{
JS::RootedScript script(cx, script_);
JSDExecHook* jsdhook = (JSDExecHook*) JSVAL_TO_PRIVATE(closure);
JSD_ExecutionHookProc hook;
void* hookData;
JSDContext* jsdc;
JSD_LOCK();
if( nullptr == (jsdc = jsd_JSDContextForJSContext(cx)) ||
! _isActiveHook(jsdc, script, jsdhook) )
{
JSD_UNLOCK();
return JSTRAP_CONTINUE;
}
JSD_ASSERT_VALID_EXEC_HOOK(jsdhook);
JS_ASSERT(!jsdhook->pc || jsdhook->pc == (uintptr_t)pc);
JS_ASSERT(jsdhook->jsdscript->script == script);
JS_ASSERT(jsdhook->jsdscript->jsdc == jsdc);
hook = jsdhook->hook;
hookData = jsdhook->callerdata;
/* do not use jsdhook-> after this point */
JSD_UNLOCK();
if( ! jsdc || ! jsdc->inited )
return JSTRAP_CONTINUE;
if( JSD_IS_DANGEROUS_THREAD(jsdc) )
return JSTRAP_CONTINUE;
return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_BREAKPOINT,
hook, hookData, rval);
}
bool
jsd_SetExecutionHook(JSDContext* jsdc,
JSDScript* jsdscript,
uintptr_t pc,
JSD_ExecutionHookProc hook,
void* callerdata)
{
JSDExecHook* jsdhook;
bool rv;
JSD_LOCK();
if( ! hook )
{
jsd_ClearExecutionHook(jsdc, jsdscript, pc);
JSD_UNLOCK();
return true;
}
jsdhook = _findHook(jsdc, jsdscript, pc);
if( jsdhook )
{
jsdhook->hook = hook;
jsdhook->callerdata = callerdata;
JSD_UNLOCK();
return true;
}
/* else... */
jsdhook = (JSDExecHook*)calloc(1, sizeof(JSDExecHook));
if( ! jsdhook ) {
JSD_UNLOCK();
return false;
}
jsdhook->jsdscript = jsdscript;
jsdhook->pc = pc;
jsdhook->hook = hook;
jsdhook->callerdata = callerdata;
{
AutoSafeJSContext cx;
JSAutoCompartment ac(cx, jsdscript->script);
rv = JS_SetTrap(cx, jsdscript->script,
(jsbytecode*)pc, jsd_TrapHandler,
PRIVATE_TO_JSVAL(jsdhook));
}
if ( ! rv ) {
free(jsdhook);
JSD_UNLOCK();
return false;
}
JS_APPEND_LINK(&jsdhook->links, &jsdscript->hooks);
JSD_UNLOCK();
return true;
}
bool
jsd_ClearExecutionHook(JSDContext* jsdc,
JSDScript* jsdscript,
uintptr_t pc)
{
JSDExecHook* jsdhook;
JSD_LOCK();
jsdhook = _findHook(jsdc, jsdscript, pc);
if( ! jsdhook )
{
JSD_UNLOCK();
return false;
}
{
AutoSafeJSContext cx;
JSAutoCompartment ac(cx, jsdscript->script);
JS_ClearTrap(cx, jsdscript->script,
(jsbytecode*)pc, nullptr, nullptr);
}
JS_REMOVE_LINK(&jsdhook->links);
free(jsdhook);
JSD_UNLOCK();
return true;
}
bool
jsd_ClearAllExecutionHooksForScript(JSDContext* jsdc, JSDScript* jsdscript)
{
JSDExecHook* jsdhook;
JSCList* list = &jsdscript->hooks;
JSD_LOCK();
while( (JSDExecHook*)list != (jsdhook = (JSDExecHook*)list->next) )
{
JS_REMOVE_LINK(&jsdhook->links);
free(jsdhook);
}
JS_ClearScriptTraps(jsdc->jsrt, jsdscript->script);
JSD_UNLOCK();
return true;
}
bool
jsd_ClearAllExecutionHooks(JSDContext* jsdc)
{
JSDScript* jsdscript;
JSDScript* iterp = nullptr;
JSD_LOCK();
while( nullptr != (jsdscript = jsd_IterateScripts(jsdc, &iterp)) )
jsd_ClearAllExecutionHooksForScript(jsdc, jsdscript);
JSD_UNLOCK();
return true;
}
void
jsd_ScriptCreated(JSDContext* jsdc,
JSContext *cx,
const char *filename, /* URL this script loads from */
unsigned lineno, /* line where this script starts */
JSScript *script,
JSFunction *fun)
{
jsd_NewScriptHookProc(cx, filename, lineno, script, fun, jsdc);
}
void
jsd_ScriptDestroyed(JSDContext* jsdc,
JSFreeOp *fop,
JSScript *script)
{
jsd_DestroyScriptHookProc(fop, script, jsdc);
}