|
| 1 | +// This file creates the internal module & binding loaders used by built-in |
| 2 | +// modules. In contrast, user land modules are loaded using |
| 3 | +// lib/module.js (CommonJS Modules) or lib/internal/loader/* (ES Modules). |
| 4 | +// |
| 5 | +// This file is compiled and run by node.cc before bootstrap_node.js |
| 6 | +// was called, therefore the loaders are bootstraped before we start to |
| 7 | +// actually bootstrap Node.js. It creates the following objects: |
| 8 | +// |
| 9 | +// C++ binding loaders: |
| 10 | +// - process.binding(): the legacy C++ binding loader, accessible from user land |
| 11 | +// because it is an object attached to the global process object. |
| 12 | +// These C++ bindings are created using NODE_BUILTIN_MODULE_CONTEXT_AWARE() |
| 13 | +// and have their nm_flags set to NM_F_BUILTIN. We do not make any guarantees |
| 14 | +// about the stability of these bindings, but still have to take care of |
| 15 | +// compatibility issues caused by them from time to time. |
| 16 | +// - process._linkedBinding(): intended to be used by embedders to add |
| 17 | +// additional C++ bindings in their applications. These C++ bindings |
| 18 | +// can be created using NODE_MODULE_CONTEXT_AWARE_CPP() with the flag |
| 19 | +// NM_F_LINKED. |
| 20 | +// - internalBinding(): the private internal C++ binding loader, inaccessible |
| 21 | +// from user land because they are only available from NativeModule.require() |
| 22 | +// These C++ bindings are created using NODE_MODULE_CONTEXT_AWARE_INTERNAL() |
| 23 | +// and have their nm_flags set to NM_F_INTERNAL. |
| 24 | +// |
| 25 | +// Internal JavaScript module loader: |
| 26 | +// - NativeModule: a minimal module system used to load the JavaScript core |
| 27 | +// modules found in lib/**/*.js and deps/**/*.js. All core modules are |
| 28 | +// compiled into the node binary via node_javascript.cc generated by js2c.py, |
| 29 | +// so they can be loaded faster without the cost of I/O. This class makes the |
| 30 | +// lib/internal/*, deps/internal/* modules and internalBinding() available by |
| 31 | +// default to core modules, and lets the core modules require itself via |
| 32 | +// require('internal/bootstrap_loaders') even when this file is not written in |
| 33 | +// CommonJS style. |
| 34 | +// |
| 35 | +// Other objects: |
| 36 | +// - process.moduleLoadList: an array recording the bindings and the modules |
| 37 | +// loaded in the process and the order in which they are loaded. |
| 38 | + |
| 39 | +'use strict'; |
| 40 | + |
| 41 | +(functionbootstrapInternalLoaders(process,getBinding,getLinkedBinding, |
| 42 | +getInternalBinding){ |
| 43 | + |
| 44 | +// Set up process.moduleLoadList |
| 45 | +constmoduleLoadList=[]; |
| 46 | +Object.defineProperty(process,'moduleLoadList',{ |
| 47 | +value: moduleLoadList, |
| 48 | +configurable: true, |
| 49 | +enumerable: true, |
| 50 | +writable: false |
| 51 | +}); |
| 52 | + |
| 53 | +// Set up process.binding() and process._linkedBinding() |
| 54 | +{ |
| 55 | +constbindingObj=Object.create(null); |
| 56 | + |
| 57 | +process.binding=functionbinding(module){ |
| 58 | +module=String(module); |
| 59 | +letmod=bindingObj[module]; |
| 60 | +if(typeofmod!=='object'){ |
| 61 | +mod=bindingObj[module]=getBinding(module); |
| 62 | +moduleLoadList.push(`Binding ${module}`); |
| 63 | +} |
| 64 | +returnmod; |
| 65 | +}; |
| 66 | + |
| 67 | +process._linkedBinding=function_linkedBinding(module){ |
| 68 | +module=String(module); |
| 69 | +letmod=bindingObj[module]; |
| 70 | +if(typeofmod!=='object') |
| 71 | +mod=bindingObj[module]=getLinkedBinding(module); |
| 72 | +returnmod; |
| 73 | +}; |
| 74 | +} |
| 75 | + |
| 76 | +// Set up internalBinding() in the closure |
| 77 | +letinternalBinding; |
| 78 | +{ |
| 79 | +constbindingObj=Object.create(null); |
| 80 | +internalBinding=functioninternalBinding(module){ |
| 81 | +letmod=bindingObj[module]; |
| 82 | +if(typeofmod!=='object'){ |
| 83 | +mod=bindingObj[module]=getInternalBinding(module); |
| 84 | +moduleLoadList.push(`Internal Binding ${module}`); |
| 85 | +} |
| 86 | +returnmod; |
| 87 | +}; |
| 88 | +} |
| 89 | + |
| 90 | +// Minimal sandbox helper |
| 91 | +constContextifyScript=process.binding('contextify').ContextifyScript; |
| 92 | +functionrunInThisContext(code,options){ |
| 93 | +constscript=newContextifyScript(code,options); |
| 94 | +returnscript.runInThisContext(); |
| 95 | +} |
| 96 | + |
| 97 | +// Set up NativeModule |
| 98 | +functionNativeModule(id){ |
| 99 | +this.filename=`${id}.js`; |
| 100 | +this.id=id; |
| 101 | +this.exports={}; |
| 102 | +this.loaded=false; |
| 103 | +this.loading=false; |
| 104 | +} |
| 105 | + |
| 106 | +NativeModule._source=getBinding('natives'); |
| 107 | +NativeModule._cache={}; |
| 108 | + |
| 109 | +constconfig=getBinding('config'); |
| 110 | + |
| 111 | +// Think of this as module.exports in this file even though it is not |
| 112 | +// written in CommonJS style. |
| 113 | +constloaderExports={ internalBinding, NativeModule }; |
| 114 | +constloaderId='internal/bootstrap_loaders'; |
| 115 | +NativeModule.require=function(id){ |
| 116 | +if(id===loaderId){ |
| 117 | +returnloaderExports; |
| 118 | +} |
| 119 | + |
| 120 | +constcached=NativeModule.getCached(id); |
| 121 | +if(cached&&(cached.loaded||cached.loading)){ |
| 122 | +returncached.exports; |
| 123 | +} |
| 124 | + |
| 125 | +if(!NativeModule.exists(id)){ |
| 126 | +// Model the error off the internal/errors.js model, but |
| 127 | +// do not use that module given that it could actually be |
| 128 | +// the one causing the error if there's a bug in Node.js |
| 129 | +consterr=newError(`No such built-in module: ${id}`); |
| 130 | +err.code='ERR_UNKNOWN_BUILTIN_MODULE'; |
| 131 | +err.name='Error [ERR_UNKNOWN_BUILTIN_MODULE]'; |
| 132 | +throwerr; |
| 133 | +} |
| 134 | + |
| 135 | +moduleLoadList.push(`NativeModule ${id}`); |
| 136 | + |
| 137 | +constnativeModule=newNativeModule(id); |
| 138 | + |
| 139 | +nativeModule.cache(); |
| 140 | +nativeModule.compile(); |
| 141 | + |
| 142 | +returnnativeModule.exports; |
| 143 | +}; |
| 144 | + |
| 145 | +NativeModule.requireForDeps=function(id){ |
| 146 | +if(!NativeModule.exists(id)|| |
| 147 | +// TODO(TimothyGu): remove when DEP0084 reaches end of life. |
| 148 | +id.startsWith('node-inspect/')|| |
| 149 | +id.startsWith('v8/')){ |
| 150 | +id=`internal/deps/${id}`; |
| 151 | +} |
| 152 | +returnNativeModule.require(id); |
| 153 | +}; |
| 154 | + |
| 155 | +NativeModule.getCached=function(id){ |
| 156 | +returnNativeModule._cache[id]; |
| 157 | +}; |
| 158 | + |
| 159 | +NativeModule.exists=function(id){ |
| 160 | +returnNativeModule._source.hasOwnProperty(id); |
| 161 | +}; |
| 162 | + |
| 163 | +if(config.exposeInternals){ |
| 164 | +NativeModule.nonInternalExists=function(id){ |
| 165 | +// Do not expose this to user land even with --expose-internals |
| 166 | +if(id===loaderId){ |
| 167 | +returnfalse; |
| 168 | +} |
| 169 | +returnNativeModule.exists(id); |
| 170 | +}; |
| 171 | + |
| 172 | +NativeModule.isInternal=function(id){ |
| 173 | +// Do not expose this to user land even with --expose-internals |
| 174 | +returnid===loaderId; |
| 175 | +}; |
| 176 | +}else{ |
| 177 | +NativeModule.nonInternalExists=function(id){ |
| 178 | +returnNativeModule.exists(id)&&!NativeModule.isInternal(id); |
| 179 | +}; |
| 180 | + |
| 181 | +NativeModule.isInternal=function(id){ |
| 182 | +returnid.startsWith('internal/'); |
| 183 | +}; |
| 184 | +} |
| 185 | + |
| 186 | +NativeModule.getSource=function(id){ |
| 187 | +returnNativeModule._source[id]; |
| 188 | +}; |
| 189 | + |
| 190 | +NativeModule.wrap=function(script){ |
| 191 | +returnNativeModule.wrapper[0]+script+NativeModule.wrapper[1]; |
| 192 | +}; |
| 193 | + |
| 194 | +NativeModule.wrapper=[ |
| 195 | +'(function (exports, require, module, process){', |
| 196 | +'\n});' |
| 197 | +]; |
| 198 | + |
| 199 | +NativeModule.prototype.compile=function(){ |
| 200 | +letsource=NativeModule.getSource(this.id); |
| 201 | +source=NativeModule.wrap(source); |
| 202 | + |
| 203 | +this.loading=true; |
| 204 | + |
| 205 | +try{ |
| 206 | +constfn=runInThisContext(source,{ |
| 207 | +filename: this.filename, |
| 208 | +lineOffset: 0, |
| 209 | +displayErrors: true |
| 210 | +}); |
| 211 | +constrequireFn=this.id.startsWith('internal/deps/') ? |
| 212 | +NativeModule.requireForDeps : |
| 213 | +NativeModule.require; |
| 214 | +fn(this.exports,requireFn,this,process); |
| 215 | + |
| 216 | +this.loaded=true; |
| 217 | +}finally{ |
| 218 | +this.loading=false; |
| 219 | +} |
| 220 | +}; |
| 221 | + |
| 222 | +NativeModule.prototype.cache=function(){ |
| 223 | +NativeModule._cache[this.id]=this; |
| 224 | +}; |
| 225 | + |
| 226 | +// This will be passed to the bootstrapNodeJSCore function in |
| 227 | +// bootstrap_node.js. |
| 228 | +returnloaderExports; |
| 229 | +}); |
0 commit comments