Jsd

From FirebugWiki

(Difference between revisions)
Jump to: navigation, search
(jsd)
(Changed code blocks to use syntax highlighting)
 
(7 intermediate revisions not shown)
Line 1: Line 1:
-
= jsd =
 
-
 
-
 
Implementation of the JavaScript interface for debugging Javascript
Implementation of the JavaScript interface for debugging Javascript
Line 8: Line 5:
== Files ==
== Files ==
-
=== jsdIDebuggerService.idl ===
+
=== [http://mxr.mozilla.org/mozilla-central/source/js/jsd/idl/jsdIDebuggerService.idl#82 jsdIDebuggerService.idl] ===
definitions of the entry points. Javascript calls these. For example code see Firebug's firebug-service.js. Here is how the onScriptCreated hook is set in firebug:
definitions of the entry points. Javascript calls these. For example code see Firebug's firebug-service.js. Here is how the onScriptCreated hook is set in firebug:
-
      jsd.scriptHook = {
+
<source lang="javascript">
-
            onScriptCreated: hook(this.onScriptCreated),
+
jsd.scriptHook = {
-
            onScriptDestroyed: hook(this.onScriptDestroyed)
+
    onScriptCreated: hook(this.onScriptCreated),
-
        };
+
    onScriptDestroyed: hook(this.onScriptDestroyed)
 +
};
 +
</source>
=== jsd_xpc.cpp ===
=== jsd_xpc.cpp ===
-
 
C++ implementations of the jsdIDebuggerService interfaces. Defines the jsdService object that receives the get/set calls for hooks from Javascript. For example, jsdService::SetScriptHook implements the setter for jsdIDebuggerService.scriptHook.
C++ implementations of the jsdIDebuggerService interfaces. Defines the jsdService object that receives the get/set calls for hooks from Javascript. For example, jsdService::SetScriptHook implements the setter for jsdIDebuggerService.scriptHook.
Line 24: Line 22:
The set calls store the hook reference and set hooks into a deeper layer called JSD_ Note the caps on this one. The hook function in this C++ file is a static void function with parameters that are JSDContext and other JSD*  things (note again the caps). For example, the SetScriptHook() function above calls JSD_SetScriptHook(mCx, jsds_ScriptHookProc, null), where the function jsds_ScriptHookProc is define in this file to match the C function declaration in jsdebug.h.
The set calls store the hook reference and set hooks into a deeper layer called JSD_ Note the caps on this one. The hook function in this C++ file is a static void function with parameters that are JSDContext and other JSD*  things (note again the caps). For example, the SetScriptHook() function above calls JSD_SetScriptHook(mCx, jsds_ScriptHookProc, null), where the function jsds_ScriptHookProc is define in this file to match the C function declaration in jsdebug.h.
-
static void jsds_ScriptHookProc (JSDContext* jsdc, JSDScript* jsdscript, JSBool creating, void* callerdata)
+
<source lang="cpp">
 +
static void jsds_ScriptHookProc (JSDContext* jsdc, JSDScript* jsdscript, JSBool creating, void* callerdata)
 +
</source>
 +
 
=== jsdebug.h ===
=== jsdebug.h ===
Glue between jsd_xpc.cpp and C code. The header file defines C types callable by the C++ functions in jsd_xpc.cpp. For example,
Glue between jsd_xpc.cpp and C code. The header file defines C types callable by the C++ functions in jsd_xpc.cpp. For example,
-
typedef void (* JSD_ScriptHookProc)(JSDContext* jsdc, JSDScript* jsdscript, JSBool creating, void* callerdata);
+
<source lang="cpp">
 +
typedef void (* JSD_ScriptHookProc)(JSDContext* jsdc, JSDScript* jsdscript, JSBool creating, void* callerdata);
 +
</source>
Also the header declares the C functions to accept these hook calls, like:
Also the header declares the C functions to accept these hook calls, like:
-
  JSD_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata);
+
<source lang="c">
 +
JSD_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata);
 +
</source>
=== jsdebug.c ===
=== jsdebug.c ===
Line 39: Line 44:
C implementations of the JSD_ functions. Unfortunately the implementations are silly they just call jsd_ (lower case) functions declared in jsd.h
C implementations of the JSD_ functions. Unfortunately the implementations are silly they just call jsd_ (lower case) functions declared in jsd.h
 +
<source lang="c">
  JSD_PUBLIC_API(JSBool)
  JSD_PUBLIC_API(JSBool)
  JSD_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata)
  JSD_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata)
Line 45: Line 51:
     return jsd_SetScriptHook(jsdc, hook, callerdata);
     return jsd_SetScriptHook(jsdc, hook, callerdata);
  }
  }
 +
</source>
=== jsd.h ===
=== jsd.h ===
   
   
-
 
Declarations of the jsd_ functions called by jsdebug.c. For example:
Declarations of the jsd_ functions called by jsdebug.c. For example:
-
extern JSBool
+
<source lang="c">
-
jsd_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata);
+
extern JSBool
 +
jsd_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata);
 +
</source>
This header is included in a lot of files in the jsd directory, so every time you touch it lots of things get compiled.
This header is included in a lot of files in the jsd directory, so every time you touch it lots of things get compiled.
-
=== jsdscpt.c ===
+
=== jsd_scpt.c ===
Definitions of jsdIScript focused functions of jsd.h. For example
Definitions of jsdIScript focused functions of jsd.h. For example
-
JSBool
+
<source lang="c">
-
jsd_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata)
+
JSBool
-
{
+
jsd_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata)
 +
{
     JSD_LOCK();
     JSD_LOCK();
     jsdc->scriptHook = hook;
     jsdc->scriptHook = hook;
Line 68: Line 77:
     JSD_UNLOCK();
     JSD_UNLOCK();
     return JS_TRUE;
     return JS_TRUE;
-
}
+
}
 +
</source>
So the original Javascript causes the JSDContext to have a field set to a function pointer.
So the original Javascript causes the JSDContext to have a field set to a function pointer.
-
Also in this file is the call to the hook, in the function jsd_NewScriptHookProc:
+
Also in this file is the call to the hook, in the function '''jsd_NewScriptHookProc''':
-
hook = jsdc->scriptHook;  
+
<source lang="c">
-
...   
+
hook = jsdc->scriptHook;  
-
if( hook )
+
...   
-
        hook(jsdc, jsdscript, JS_TRUE, hookData);
+
if( hook )
 +
    hook(jsdc, jsdscript, JS_TRUE, hookData);
 +
</source>
So every time we call jsd_NewScriptHookProc it looks to see if the scriptHook has been set, and if so calls it.
So every time we call jsd_NewScriptHookProc it looks to see if the scriptHook has been set, and if so calls it.
 +
 +
The argument '''jsdscript''' is created just before the hook is called. It is a wrapper around the JS script object.
(The function jsd_NewScriptHookProc is called by jsd_ScriptCreated (it only reorders the arguments) and that called by JSD_ScriptCreated back in jsdebug.c. Note again the caps. This path is a dead end).
(The function jsd_NewScriptHookProc is called by jsd_ScriptCreated (it only reorders the arguments) and that called by JSD_ScriptCreated back in jsdebug.c. Note again the caps. This path is a dead end).
-
jsd_high.c
+
 
-
Edit section
+
=== jsd_high.c ===
Support for creating jsd wrappers around the JS Context, for turning jsd on and off, and the error reporting connection for jsd. Near the top of the file is jsd_DebuggerOnForUser, which loads all of the pointers like jsd_NewScriptHookProc into the Javascript engine with statements like:
Support for creating jsd wrappers around the JS Context, for turning jsd on and off, and the error reporting connection for jsd. Near the top of the file is jsd_DebuggerOnForUser, which loads all of the pointers like jsd_NewScriptHookProc into the Javascript engine with statements like:
-
JS_SetNewScriptHookProc(jsdc->jsrt, jsd_NewScriptHookProc, jsdc);
+
<source lang="c">
 +
JS_SetNewScriptHookProc(jsdc->jsrt, jsd_NewScriptHookProc, jsdc);
 +
</source>
In js/jsdbgapi.cpp, part of the JS engine, we store the hook pointers:
In js/jsdbgapi.cpp, part of the JS engine, we store the hook pointers:
 +
<source lang="cpp">
  JS_PUBLIC_API(void)  
  JS_PUBLIC_API(void)  
  JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata) {  
  JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata) {  
Line 96: Line 113:
       rt->globalDebugHooks.newScriptHookData = callerdata;   
       rt->globalDebugHooks.newScriptHookData = callerdata;   
  }  
  }  
 +
</source>
These functions like newScriptHook will be by the JS engine at appropriate points, but they will not call back towards Javascript unless jsdIDebuggerService has set hooks into the jsd_xpc layer.
These functions like newScriptHook will be by the JS engine at appropriate points, but they will not call back towards Javascript unless jsdIDebuggerService has set hooks into the jsd_xpc layer.
Line 113: Line 131:
Observations for [https://bugzilla.mozilla.org/show_bug.cgi?id=449464 Bug 449464].
Observations for [https://bugzilla.mozilla.org/show_bug.cgi?id=449464 Bug 449464].
-
===  script tag ===
+
===  Script tag ===
-
 
+
Since I have no idea how the js engine works, I am running the debugger and taking a look. Setting a breakpoint on js_CallNewScriptHook() hits when we compile a script tag.
Since I have no idea how the js engine works, I am running the debugger and taking a look. Setting a breakpoint on js_CallNewScriptHook() hits when we compile a script tag.
 +
MXR says there should be [http://mxr.mozilla.org/mozilla1.9.2/search?string=js_CallNewScriptHook 5 callers]
 +
 +
#[http://mxr.mozilla.org/mozilla1.9.2/source/js/src/jsscript.cpp#296 script_compile_sub] The jsFunction argument is null
 +
#[http://mxr.mozilla.org/mozilla1.9.2/source/js/src/jsscript.cpp#831 script_thaw] The jsFunction argument is null
 +
#[http://mxr.mozilla.org/mozilla1.9.2/source/js/src/jsscript.cpp#1566 js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)]
 +
* CreateHiddenWindow
 +
* chrome://browser/content/sanitize.js
 +
* This one seems to be the main caller
 +
#[http://mxr.mozilla.org/mozilla1.9.2/source/js/src/jsfun.cpp#1697 js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)] Components via nsiFastLoadService
 +
#[http://mxr.mozilla.org/mozilla1.9.2/source/js/src/jsxdrapi.cpp#687 JS_XDRScript(JSXDRState *xdr, JSScript **scriptp)] ?
* JS_EvaluateUCScriptForPrincipals() calls JSCompiler::compileScript then executes the return value (probably the outerScript). It has the source as a string, chars and length. The second argument is the scope obj. We have to put the onCompilationEnd() call between the compile and execute.
* JS_EvaluateUCScriptForPrincipals() calls JSCompiler::compileScript then executes the return value (probably the outerScript). It has the source as a string, chars and length. The second argument is the scope obj. We have to put the onCompilationEnd() call between the compile and execute.

Latest revision as of 08:49, 18 May 2011

Implementation of the JavaScript interface for debugging Javascript

Source is under js/jsd in the mozilla tree.

Contents

[edit] Files

[edit] jsdIDebuggerService.idl

definitions of the entry points. Javascript calls these. For example code see Firebug's firebug-service.js. Here is how the onScriptCreated hook is set in firebug:

jsd.scriptHook = {
    onScriptCreated: hook(this.onScriptCreated),
    onScriptDestroyed: hook(this.onScriptDestroyed)
};

[edit] jsd_xpc.cpp

C++ implementations of the jsdIDebuggerService interfaces. Defines the jsdService object that receives the get/set calls for hooks from Javascript. For example, jsdService::SetScriptHook implements the setter for jsdIDebuggerService.scriptHook.

The set calls store the hook reference and set hooks into a deeper layer called JSD_ Note the caps on this one. The hook function in this C++ file is a static void function with parameters that are JSDContext and other JSD* things (note again the caps). For example, the SetScriptHook() function above calls JSD_SetScriptHook(mCx, jsds_ScriptHookProc, null), where the function jsds_ScriptHookProc is define in this file to match the C function declaration in jsdebug.h.

static void jsds_ScriptHookProc (JSDContext* jsdc, JSDScript* jsdscript, JSBool creating, void* callerdata)

[edit] jsdebug.h

Glue between jsd_xpc.cpp and C code. The header file defines C types callable by the C++ functions in jsd_xpc.cpp. For example,

typedef void (* JSD_ScriptHookProc)(JSDContext* jsdc, JSDScript* jsdscript, JSBool creating, void* callerdata);

Also the header declares the C functions to accept these hook calls, like:

JSD_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata);

[edit] jsdebug.c

C implementations of the JSD_ functions. Unfortunately the implementations are silly they just call jsd_ (lower case) functions declared in jsd.h

 JSD_PUBLIC_API(JSBool)
 JSD_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata)
 {
    JSD_ASSERT_VALID_CONTEXT(jsdc);
    return jsd_SetScriptHook(jsdc, hook, callerdata);
 }

[edit] jsd.h

Declarations of the jsd_ functions called by jsdebug.c. For example:

extern JSBool
jsd_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata);

This header is included in a lot of files in the jsd directory, so every time you touch it lots of things get compiled.

[edit] jsd_scpt.c

Definitions of jsdIScript focused functions of jsd.h. For example

JSBool
jsd_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata)
{
    JSD_LOCK();
    jsdc->scriptHook = hook;
    jsdc->scriptHookData = callerdata;
    JSD_UNLOCK();
    return JS_TRUE;
}

So the original Javascript causes the JSDContext to have a field set to a function pointer.

Also in this file is the call to the hook, in the function jsd_NewScriptHookProc:

hook = jsdc->scriptHook; 
...   
if( hook )
    hook(jsdc, jsdscript, JS_TRUE, hookData);

So every time we call jsd_NewScriptHookProc it looks to see if the scriptHook has been set, and if so calls it.

The argument jsdscript is created just before the hook is called. It is a wrapper around the JS script object.

(The function jsd_NewScriptHookProc is called by jsd_ScriptCreated (it only reorders the arguments) and that called by JSD_ScriptCreated back in jsdebug.c. Note again the caps. This path is a dead end).

[edit] jsd_high.c

Support for creating jsd wrappers around the JS Context, for turning jsd on and off, and the error reporting connection for jsd. Near the top of the file is jsd_DebuggerOnForUser, which loads all of the pointers like jsd_NewScriptHookProc into the Javascript engine with statements like:

JS_SetNewScriptHookProc(jsdc->jsrt, jsd_NewScriptHookProc, jsdc);

In js/jsdbgapi.cpp, part of the JS engine, we store the hook pointers:

 JS_PUBLIC_API(void) 
 JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata) { 
      rt->globalDebugHooks.newScriptHook = hook;      
      rt->globalDebugHooks.newScriptHookData = callerdata;  
 }

These functions like newScriptHook will be by the JS engine at appropriate points, but they will not call back towards Javascript unless jsdIDebuggerService has set hooks into the jsd_xpc layer.

[edit] Relationship to js engine.

At various points the js engine will call functions that may result in debugger hook calls. For example, the function js_CallNewScriptHook is called five places:

  1. jsscript.cpp script_compile_sub, the script comes from JSCompiler::compileScript.
  2. jsscript.cpp, script_thaw, the script come from js_XDRScript()
  3. jsscript.cpp js_NewScriptFromCG, the script comes from js_NewScript();
  4. jsxdrapi.cpp js_XDRScript, the script is passed in (see case #2 above).
  5. jsfun.cpp js_XDRFunctionObject, the script seems to come from js_XDRScript in case #4? These are called on startup ReadScriptFromStream().

[edit] Platform callers of Javascript compile functions.

Observations for Bug 449464.

[edit] Script tag

Since I have no idea how the js engine works, I am running the debugger and taking a look. Setting a breakpoint on js_CallNewScriptHook() hits when we compile a script tag. MXR says there should be 5 callers

  1. script_compile_sub The jsFunction argument is null
  2. script_thaw The jsFunction argument is null
  3. js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
  • CreateHiddenWindow
  • chrome://browser/content/sanitize.js
  • This one seems to be the main caller
  1. js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) Components via nsiFastLoadService
  2. JS_XDRScript(JSXDRState *xdr, JSScript **scriptp) ?
  • JS_EvaluateUCScriptForPrincipals() calls JSCompiler::compileScript then executes the return value (probably the outerScript). It has the source as a string, chars and length. The second argument is the scope obj. We have to put the onCompilationEnd() call between the compile and execute.
  • Two frames older has nsScriptLoader.EvaluateScript(). The loader has mCurrentScript pointing to an element. If we put the onCompilationBegin() call here we have the includer and source. This function is in content/base/src, so the function we call has to be declared in jsprvtd.h.
  • The context object has GetProcessingScriptTag()
  • For web pages nsscriptLoader fires an event before compiling and after evaluating. There is an nsIScriptLoader interface and an observer for these events but apparently no way to get the loader in JS.

[edit] XBL

   * XBLProtoImplMethod Calls nsIScriptContext.CompileFunction
   * XBLProtoImplProperty Apparently this is for getter and setters. Calls nsIScriptContext.CompileFunction
Personal tools