Node. js source code Research (startup and module loading)

Source: Internet
Author: User

I. Source Code Composition
1. It has 8000 lines of C ++ code and 2000 lines of javascript code.
2. the built-in javascript in node. js includes the main program src/node. js and the Module Program lib/*. js.
3. main libraries on which node. js depends: v8, uv, and zlib
Ii. js2c. py Tool
Node. js uses the js2c. py tool attached with V8 to convert all built-in js Code into arrays in C ++,
Generate node_natives.h and directly include it into the program. It becomes part of the C ++ source code,
This improves the compilation efficiency of the built-in js module.
Use js2c. py to generate a source code array for each js file, which is stored in build/src/node_natives.h after conversion,
Node_natives.h is generated only after node. js is compiled.
The code structure is as follows:
Struct _ native {
Const char * name;
Const char * source;
Size_t source_len;
};
Static const struct _ native natives [] = {
{"Node", node_native, sizeof (node_native)-1 },
{"_ Debugger", _ debugger_native, sizeof (_ debugger_native)-1 },
{"_ Linklist", _ linklist_native, sizeof (_ linklist_native)-1 },
{"Assert", assert_native, sizeof (assert_native)-1 },
{"Buffer", buffer_native, sizeof (buffer_native)-1}
}
Iii. Start and Load
1. Entry: node_main.cc. After parsing the command line parameters, call node: Start (argc, argv) to Start
2. Initialize the v8 interface, V8: Initialize ()
3. Create and set the process Object in v8: Handle <Object> SetupProcessObject (int argc, char * argv []) {}
4. Load node. js and void Load (Handle <Object> process_l)
Node. js description:
This file is the core of node startup. It is called by node: Load in src/node. cc. Considering the performance of the startup process,
All dependencies adopt delayed Loading
Use MainSource () to obtain the converted source code of src/node. js and execute it: the source code has been included in node_natives.h through conversion,
Node_native is a string containing the source code.
Local <Value> f_value = ExecuteString (MainSource (),
IMMUTABLE_STRING ("node. js "));

Node. js code:
(Function (process ){
.........
});
It can be seen that after node. js is executed, a function is obtained.
Function processing in node. cc:
Assert (f_value-> IsFunction ());

Local <Function> f = Local <Function>: Cast (f_value );
Create a function execution environment, call the function, and pass the process
Local <Object> global = v8: Context: GetCurrent ()-> Global ();

Local <Value> args [1] = {Local <Value >:: New (process_l )};
F-> Call (global, 1, args );
Run:
Uv_run (uv_default_loop (), UV_RUN_DEFAULT );


For the code of the startup entry function, refer:
Int Start (int argc, char * argv []) {
// Hack aroung with the argv pointer. Used for process. title = "blah ".
Argv = uv_setup_args (argc, argv );


// Logic to duplicate argv as Init () modifies arguments
// That are passed into it.
Char ** argv_copy = copy_argv (argc, argv );


// This needs to run * before * V8: Initialize ()
// Use copy here as to not modify the original argv:
Init (argc, argv_copy );
V8: Initialize ();
{
Locker locker;
HandleScope handle_scope;


// Create the one and only Context.
Persistent <Context> context = Context: New ();
Context: Scope context_scope (context );


// Use original argv, as we're just copying values out of it.
Handle <Object> process_l = SetupProcessObject (argc, argv );
V8_typed_array: AttachBindings (context-> Global ());


// Create all the objects, load modules, do everything.
// So your next reading stop shoshould be node: Load ()!
Load (process_l );


// All our arguments are loaded. We 've evaluated all of the scripts. We
// Might even have created TCP servers. Now we enter the main eventloop. If
// There are no watchers on the loop (Response t for the ones that were
// Uv_unref 'd) then this function exits. As long as there are active
// Watchers, it blocks.
Uv_run (uv_default_loop (), UV_RUN_DEFAULT );


EmitExit (process_l );
RunAtExit ();


# Ifndef NDEBUG
Context. Dispose ();
# Endif
}


# Ifndef NDEBUG
// Clean up. Not strictly necessary.
V8: Dispose ();
# Endif // NDEBUG


// Clean up the copy:
Free (argv_copy );


Return 0;
}
Iv. Loading of built-in c ++ modules
The node. js module is written in the js language in lib/*. js, and some system modules are written in C ++,
These modules are stored in the Variable _ module through the NODE_MODULE method provided by node. h.
Node_extensions.cc provides the get_builtin_module (name) interface to search for these modules from a hash table.


Static Handle <Value> Binding (const Arguments & args ){
HandleScope scope;


Local <String> module = args [0]-> ToString ();
String: Utf8Value module_v (module );
Node_module_struct * modp;


If (binding_cache.IsEmpty ()){
Binding_cache = Persistent <Object >:: New (Object: New ());
}


Local <Object> exports;


If (binding_cache-> Has (module )){
Exports = binding_cache-> Get (module)-> ToObject ();
Return scope. Close (exports );
}


// Append a string to process. moduleLoadList
Char buf [1024];
Snprintf (buf, 1024, "Binding % s", * module_v );
Uint32_t l = module_load_list-> Length ();
Module_load_list-> Set (l, String: New (buf ));


If (modp = get_builtin_module (* module_v ))! = NULL ){
Exports = Object: New ();
// Internal bindings don't have a "module" object,
// Only exports.
Modp-> register_func (exports, Undefined ());
Binding_cache-> Set (module, exports );


} Else if (! Strcmp (* module_v, "constants ")){
Exports = Object: New ();
DefineConstants (exports );
Binding_cache-> Set (module, exports );


} Else if (! Strcmp (* module_v, "natives ")){
Exports = Object: New ();
DefineJavaScript (exports );
Binding_cache-> Set (module, exports );


} Else {


Return ThrowException (Exception: Error (String: New ("No such module ")));
}


Return scope. Close (exports );
}
From the source code, we can see that when loading the c ++ module, we first find it from the cache. If we cannot find it, we can find the C ++ built-in module in get_builtin_module,
If it is found, bind it to exports and return exports at the end.
V. Loading c ++ extension modules
For modules with the. node extension, use Dlopen to load
Handle <Value> DLOpen (const v8: Arguments & args ){
HandleScope scope;
Char symbol [1024], * base, * pos;
Uv_lib_t lib;
Int r;


If (args. Length () <2 ){
Local <Value> exception = Exception: Error (
String: New ("process. dlopen takes exactly 2 arguments ."));
Return ThrowException (exception );
}


Local <Object> module = args [0]-> ToObject (); // Cast
String: Utf8Value filename (args [1]); // Cast


If (exports_symbol.IsEmpty ()){
Exports_symbol = NODE_PSYMBOL ("exports ");
}
Local <Object> exports = module-> Get (exports_symbol)-> ToObject ();


If (uv_dlopen (* filename, & lib )){
Local <String> errmsg = String: New (uv_dlerror (& lib ));
# Ifdef _ WIN32
// Windows needs to add the filename into the error message
Errmsg = String: Concat (errmsg, args [1]-> ToString ());
# Endif
Return ThrowException (Exception: Error (errmsg ));
}


String: Utf8Value path (args [1]);
Base = * path;


/* Find the shared library filename within the full path .*/
# Ifdef _ POSIX __
Pos = strrchr (base ,'/');
If (pos! = NULL ){
Base = pos + 1;
}
# Else // Windows
For (;;){
Pos = strpbrk (base ,"\\/:");
If (pos = NULL ){
Break;
}
Base = pos + 1;
}
# Endif


/* Strip the. node extension .*/
Pos = strrchr (base ,'.');
If (pos! = NULL ){
* Pos = '\ 0 ';
}


/* Add the '_ module' suffix to the extension name .*/
R = snprintf (symbol, sizeof symbol, "% s_module", base );
If (r <= 0 | static_cast <size_t> (r)> = sizeof symbol ){
Local <Value> exception =
Exception: Error (String: New ("Out of memory ."));
Return ThrowException (exception );
}


/* Replace dashes with underscores. When loading foo-bar.node,
* Look for foo_bar_module, not foo-bar_module.
*/
For (pos = symbol; * pos! = '\ 0'; ++ pos ){
If (* pos = '-') * pos = '_';
}


Node_module_struct * mod;
If (uv_dlsym (& lib, symbol, reinterpret_cast <void **> (& mod ))){
Char errmsg [1024];
Snprintf (errmsg, sizeof (errmsg), "Symbol % s not found.", symbol );
Return ThrowError (errmsg );
}


If (mod-> version! = NODE_MODULE_VERSION ){
Char errmsg [1024];
Snprintf (errmsg,
Sizeof (errmsg ),
"Module version mismatch. Expected % d, got % d .",
NODE_MODULE_VERSION, mod-> version );
Return ThrowError (errmsg );
}


//
Mod-> register_func (exports, module );


// Tell coverity that 'handle' shoshould not be freed when we return.
// Coverity [leaked_storage]
Return Undefined ();
}


After opening the dynamic link library, Dlopen calls the uv_dlsym of libuv and finds the address of the method defined through NODE_MODULE in the dynamic link library. Mount to the exports object.
Vi. js module Loading
Src/node. js implements an NativeModule object for managing js modules. It calls process. binding ("natives") to place all built-in js modules on NativeModule. _ source,
And provides the require interface for calling. In require, code is encapsulated and some variables are passed to this module.
NativeModule. wrapper = [
'(Function (exports, require, module, _ filename, _ dirname ){',
'\ N });'
];
Use one of the js compilation interfaces provided by process to compile process. runInThisContext to execute the code.
Var Script = process. binding ('evals '). NodeScript;
Var runInThisContext = Script. runInThisContext;
Var fn = runInThisContext (source, this. filename, true );
Fn (this. exports, NativeModule. require, this, this. filename );

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.