Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: bootstrap internals loaders before bootstrapping Node.js #19112

Closed
wants to merge 3 commits into from

Conversation

joyeecheung
Copy link
Member

@joyeecheung joyeecheung commented Mar 3, 2018

  • Moves the creation of process.binding(), process._linkedBinding()
    internalBinding() and NativeModule into a separate file
    lib/internal/bootstrap_loaders.js, and documents them there.
    This file will be compiled and run before bootstrap_node.js, which
    means we now bootstrap the internal module & binding system before
    actually bootstrapping Node.js.
  • Rename the special ID that can be used to require NativeModule
    as internal/bootstrap_loaders since it is setup there. Also put
    internalBinding in the object exported by NativeModule.require
    instead of putting it inside the NativeModule.wrapper
  • Names the bootstrapping functions so their names show up
    in the stack trace.
Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • commit message follows commit guidelines
Affected core subsystem(s)

process, modules

@nodejs-github-bot nodejs-github-bot added the lib / src Issues and PRs related to general changes in the lib or src directory. label Mar 3, 2018
@joyeecheung joyeecheung added module Issues and PRs related to the module subsystem. process Issues and PRs related to the process subsystem. labels Mar 3, 2018
@joyeecheung
Copy link
Member Author

};
}

// Set up internalBinding in the closure
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Come to think of it, we may also put internalBinding in the returned object and rename this file inernal_loaders which seem to be more accurate..so it will become const { NativeModule, internalBinding } = require('internal/internal_loaders') (somewhat clashes with internal/loader/* though..)

src/node.cc Outdated

static bool ExecuteFactory(Environment* env, Local<Function> factory, int argc,
Local<Value> argv[], Local<Value>* out) {
bool ret = factory->Call(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This now calls into JS from C++ twice during bootstrapping..maybe passing the loader bootstrapper into the core bootstrapper and call JS from JS will lower the performance impact..are there any existing benchmarks for measuring startup time?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’d expect this to be fine, tbh. It might be nice to have a single call into JS again at some point, but that doesn’t have to be a strict rule.

Copy link
Member

@addaleax addaleax left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, great work!


'use strict';

(function(process) {
let internalBinding;
(function bootstrapNodeJSCore(process, NativeModule) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m wondering whether this function name showing up is more helpful or more confusing when showing up ni embedder code…

const bindingObj = Object.create(null);

const getInternalBinding = process._internalBinding;
delete process._internalBinding;
Copy link
Member

@addaleax addaleax Mar 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you’re at it – how about passing this to bootstrapInternalLoaders as an argument, too?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, also getLinkedBinding and getBinding can be passed in as well so we don’t need to override the original property, which kind of hard to understand at first glance

src/node.cc Outdated

static bool ExecuteFactory(Environment* env, Local<Function> factory, int argc,
Local<Value> argv[], Local<Value>* out) {
bool ret = factory->Call(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’d expect this to be fine, tbh. It might be nice to have a single call into JS again at some point, but that doesn’t have to be a strict rule.

Copy link
Member

@apapirovski apapirovski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I agree with @addaleax that passing in internalBinding into native_module.js would probably be a good idea, instead of declaring it on the process and then deleting it.

@joyeecheung
Copy link
Member Author

joyeecheung commented Mar 4, 2018

Updates:

  • Passing getBinding(), getLinkedBinding() and getInternalBinding() to the loader bootstrapper instead of putting them on process and override latter (suggestion by @addaleax )
  • Add documentation about process._linkedBinding, this fixes What are Node.js "Linked" modules? #12516
  • Rename native_module -> bootstrap_loaders, ExecuteFactory/GetFactory -> ExecuteBootstrapper/GetBootstrapper, so it's consistent with bootstrap_node.js and it's easier to figure out what it does just by looking at the names
  • Expose internalBinding through the object returned by NativeModule.require instead of putting it into the NativeModule.wrapper .

Copy link
Member

@apapirovski apapirovski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still LGTM with a tiny nit.

@@ -109,9 +109,12 @@

const config = process.binding('config');

// Think of this as module.exports in this file even though it is not
// written in CommonJS style.
const exports_ = { internalBinding, NativeModule };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not generally a huge fan of trailing _ variables in JS, esp since it looks similar enough to exports. Could this be like loaderExports or something?

@joyeecheung
Copy link
Member Author

@joyeecheung joyeecheung changed the title src: move internal loaders out of bootstrap_node.js src: bootstrap loaders before bootstrapping Node.js Mar 4, 2018
@joyeecheung joyeecheung changed the title src: bootstrap loaders before bootstrapping Node.js src: bootstrap internals loaders before bootstrapping Node.js Mar 4, 2018
@devsnek
Copy link
Member

devsnek commented Mar 4, 2018

Expose internalBinding through the object returned by NativeModule.require instead of putting it into the NativeModule.wrapper .

i'm feeling -1ish on this with this change, is there any reason it can't be kept in the module wrapper?

also we could move these two files to internal/bootstrap or internal/startup or something and remove the bootstrap_ prefix

@joyeecheung
Copy link
Member Author

i'm feeling -1ish on this with this change, is there any reason it can't be kept in the module wrapper?

Doesn't have to move it out, but this way we have less globals in core modules and this can now be used in bootstrap_node.js. (Also, there is not any reason it has to be in the wrapper either...right?)

@apapirovski
Copy link
Member

I'm +1 on having it be an export rather than a wrapper-introduced global. Given how few modules actually use it, I don't think there's a great argument for having it be a part of the wrapper.

@devsnek
Copy link
Member

devsnek commented Mar 4, 2018

(Also, there is not any reason it has to be in the wrapper either...right?)

this makes it so that it can't be used even if --expose-internals is used, i think that was something @addaleax explicitly did/wanted with her pr, and personally i agree with that change.

@apapirovski
Copy link
Member

apapirovski commented Mar 4, 2018

this makes it so that it can't be used even if --expose-internals is used, i think that was something @addaleax explicitly did/wanted with her pr, and personally i agree with that change.

Given that NativeModule was already exposed, I'm almost certain it was possible — if a bit awkward — to get internalBinding before.

(Edit: Or was it not because of the different module id?)

@joyeecheung
Copy link
Member Author

this makes it so that it can't be used even if --expose-internals is used, i think that was something @addaleax explicitly did/wanted with her pr, and i also like how isolated it is currently

That can be fixed by changing NativeModule.isInternal though (which reminds me this PR leaks NativeModule by prefixing the file internal/). The same could be said about NativeModule - I think we should isolate them the same way, no matter through a wrapper or by tweaking NativeModule.isInternal.

@addaleax
Copy link
Member

addaleax commented Mar 4, 2018

I'm +1 on having it be an export rather than a wrapper-introduced global. Given how few modules actually use it, I don't think there's a great argument for having it be a part of the wrapper.

I don’t really care how it is exposed, but I think the argument that few modules use it shouldn’t have a strong weight, because we really should be and are moving towards using it in place of process.binding() (slowly).

Given that NativeModule was already exposed, I'm almost certain it was possible — if a bit awkward — to get internalBinding before.

At least I couldn’t figure out how (and thought that that was a good thing). ¯\_(ツ)_/¯

@joyeecheung
Copy link
Member Author

also we could move these two files to internal/bootstrap or internal/startup or something and remove the bootstrap_ prefix

I like the idea of having a file named node.js again ;) but probably should do that later since that would involve a lot of stack traces in test/message and comments to fix.

@apapirovski
Copy link
Member

I don’t really care how it is exposed, but I think the argument that few modules use it shouldn’t have a strong weight, because we really should be and are moving towards using it in place of process.binding() (slowly).

I just don't love globals, so the fewer, the better in my mind and the exceptions should be things that we can't really run a module without (or are just used that often). (Needless to say, I would obviously prefer if process.binding wasn't exposed either...)

But anyway, don't have a strong opinion so I'm fine with whatever direction this ends up going in.

@devsnek
Copy link
Member

devsnek commented Mar 4, 2018

actually its worse than i thought, internalBinding can be gotten without any flags on current release/master, so maybe this pr actually makes it harder to get? 😓

$ cat leeks.js
process.binding('natives').owo = 'module.exports = internalBinding';
console.log(require('owo'));

$ node leeks.js
[Function: internalBinding]

@addaleax
Copy link
Member

addaleax commented Mar 4, 2018

@devsnek Yes, that sounds pretty bad :/ I guess we could and should freeze process.binding('natives'), for a start?

@devsnek
Copy link
Member

devsnek commented Mar 4, 2018

ideally it shouldn't be exposed at all, perhaps we can deprecate and remove it? i'm worried that packages might be using this, mostly for reading, not writing (and it also seems that v8_prof_processor modifies several scripts by adding newlines to the ends of them, i'm not quite sure what to make of that)

@devsnek
Copy link
Member

devsnek commented Mar 4, 2018

it should be noted that even with that last commit by joyee, native module can still be gotten with the same tomfoolery i posted above

@addaleax
Copy link
Member

addaleax commented Mar 4, 2018

ideally it shouldn't be exposed at all, perhaps we can deprecate and remove it?

I’m on board with doing that, but it might be a while before we can do it – right now, the latest verions of gulp are famously still using graceful-fs@3, which reads those bindings…

(and it also seems that v8_prof_processor modifies several scripts by adding newlines to the ends of them)

I think that’s still just reading, it basically concatenates them with newlines?

joyeecheung added a commit to joyeecheung/node that referenced this pull request Mar 30, 2018
- Moves the creation of `process.binding()`, `process._linkedBinding()`
  `internalBinding()` and `NativeModule` into a separate file
  `lib/internal/bootstrap_loaders.js`, and documents them there.
  This file will be compiled and run before `bootstrap_node.js`, which
  means we now bootstrap the internal module & binding system before
  actually bootstrapping Node.js.
- Rename the special ID that can be used to require `NativeModule`
  as `internal/bootstrap_loaders` since it is setup there. Also put
  `internalBinding` in the object exported by `NativeModule.require`
  instead of putting it inside the `NativeModule.wrapper`
- Use the original `getBinding()` to get the source code of native
  modules instead of getting it from `process.binding('native')`
  so that users cannot fake native modules by modifying the binding
  object.
- Names the bootstrapping functions so their names show up
  in the stack trace.

PR-URL: nodejs#19112
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
joyeecheung added a commit to joyeecheung/node that referenced this pull request Mar 30, 2018
Otherwise the debug log output might be mixed up with
the expected errors and the assertion matching the error
message would fail.

PR-URL: nodejs#19177
Refs: nodejs#19112
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
joyeecheung added a commit to joyeecheung/node that referenced this pull request Mar 30, 2018
Create `lib/internal/bootstrap/` and put bootstrappers there:

Before:

```
lib/internal
├── ...
├── bootstrap_loaders.js
└── bootstrap_node.js
```

After:

```
lib/internal
├── ...
└── bootstrap
    ├── loaders.js
    └── node.js
```

PR-URL: nodejs#19177
Refs: nodejs#19112
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
joyeecheung added a commit to joyeecheung/node that referenced this pull request Mar 30, 2018
Create `lib/internal/modules` and restructure the module loaders
to make the purpose of those files clearer.

Also make it clear in the code that the object exported by
`lib/internal/modules/cjs/loader.js` is `CJSModule` instead of the
ambiguous `Module`.

Before:

```
lib
├── ...
├── internal
│       ├── loaders
│       │     ├── CreateDynamicModule.js
│       │     ├── DefaultResolve.js
│       │     ├── Loader.js
│       │     ├── ModuleJob.js
│       │     ├── ModuleMap.js
│       │     ├── ModuleWrap.js
│       │     └── Translators.js
│       └── module.js
└── module.js
```

After:

```
lib
├── ...
├── internal
│       ├── ...
│       └── modules
│              ├── cjs
│              │     ├── helpers.js
│              │     └── loader.js
│              └── esm
│                    ├── CreateDynamicModule.js
│                    ├── DefaultResolve.js
│                    ├── Loader.js
│                    ├── ModuleJob.js
│                    ├── ModuleMap.js
│                    └── Translators.js
└── module.js # deleted in this commit to work with git file mode
```

PR-URL: nodejs#19177
Refs: nodejs#19112
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
joyeecheung added a commit to joyeecheung/node that referenced this pull request Mar 30, 2018
The previous commit deleted lib/module.js so that git
recognize the file move `lib/module.js` ->
`lib/internal/modules/cjs/loader.js`. This commit add the
redirection back.

PR-URL: nodejs#19177
Refs: nodejs#19112
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
targos pushed a commit that referenced this pull request Apr 4, 2018
- Moves the creation of `process.binding()`, `process._linkedBinding()`
  `internalBinding()` and `NativeModule` into a separate file
  `lib/internal/bootstrap_loaders.js`, and documents them there.
  This file will be compiled and run before `bootstrap_node.js`, which
  means we now bootstrap the internal module & binding system before
  actually bootstrapping Node.js.
- Rename the special ID that can be used to require `NativeModule`
  as `internal/bootstrap_loaders` since it is setup there. Also put
  `internalBinding` in the object exported by `NativeModule.require`
  instead of putting it inside the `NativeModule.wrapper`
- Use the original `getBinding()` to get the source code of native
  modules instead of getting it from `process.binding('native')`
  so that users cannot fake native modules by modifying the binding
  object.
- Names the bootstrapping functions so their names show up
  in the stack trace.

Backport-PR-URL: #19374
PR-URL: #19112
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
targos pushed a commit that referenced this pull request Apr 4, 2018
Create `lib/internal/bootstrap/` and put bootstrappers there:

Before:

```
lib/internal
├── ...
├── bootstrap_loaders.js
└── bootstrap_node.js
```

After:

```
lib/internal
├── ...
└── bootstrap
    ├── loaders.js
    └── node.js
```

Backport-PR-URL: #19374
PR-URL: #19177
Refs: #19112
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
targos pushed a commit that referenced this pull request Apr 4, 2018
Otherwise the debug log output might be mixed up with
the expected errors and the assertion matching the error
message would fail.

Backport-PR-URL: #19374
PR-URL: #19177
Refs: #19112
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
targos pushed a commit that referenced this pull request Apr 4, 2018
Create `lib/internal/modules` and restructure the module loaders
to make the purpose of those files clearer.

Also make it clear in the code that the object exported by
`lib/internal/modules/cjs/loader.js` is `CJSModule` instead of the
ambiguous `Module`.

Before:

```
lib
├── ...
├── internal
│       ├── loaders
│       │     ├── CreateDynamicModule.js
│       │     ├── DefaultResolve.js
│       │     ├── Loader.js
│       │     ├── ModuleJob.js
│       │     ├── ModuleMap.js
│       │     ├── ModuleWrap.js
│       │     └── Translators.js
│       └── module.js
└── module.js
```

After:

```
lib
├── ...
├── internal
│       ├── ...
│       └── modules
│              ├── cjs
│              │     ├── helpers.js
│              │     └── loader.js
│              └── esm
│                    ├── CreateDynamicModule.js
│                    ├── DefaultResolve.js
│                    ├── Loader.js
│                    ├── ModuleJob.js
│                    ├── ModuleMap.js
│                    └── Translators.js
└── module.js # deleted in this commit to work with git file mode
```

Backport-PR-URL: #19374
PR-URL: #19177
Refs: #19112
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
targos pushed a commit that referenced this pull request Apr 4, 2018
The previous commit deleted lib/module.js so that git
recognize the file move `lib/module.js` ->
`lib/internal/modules/cjs/loader.js`. This commit add the
redirection back.

Backport-PR-URL: #19374
PR-URL: #19177
Refs: #19112
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
@targos targos mentioned this pull request Apr 4, 2018
MayaLekova pushed a commit to MayaLekova/node that referenced this pull request May 8, 2018
- Moves the creation of `process.binding()`, `process._linkedBinding()`
  `internalBinding()` and `NativeModule` into a separate file
  `lib/internal/bootstrap_loaders.js`, and documents them there.
  This file will be compiled and run before `bootstrap_node.js`, which
  means we now bootstrap the internal module & binding system before
  actually bootstrapping Node.js.
- Rename the special ID that can be used to require `NativeModule`
  as `internal/bootstrap_loaders` since it is setup there. Also put
  `internalBinding` in the object exported by `NativeModule.require`
  instead of putting it inside the `NativeModule.wrapper`
- Use the original `getBinding()` to get the source code of native
  modules instead of getting it from `process.binding('native')`
  so that users cannot fake native modules by modifying the binding
  object.
- Names the bootstrapping functions so their names show up
  in the stack trace.

PR-URL: nodejs#19112
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
@MylesBorins
Copy link
Contributor

Would very much like to see this backported to v8.x along with #18365

@joyeecheung joyeecheung self-assigned this May 26, 2018
joyeecheung added a commit to joyeecheung/node that referenced this pull request Jun 13, 2018
- Moves the creation of `process.binding()`, `process._linkedBinding()`
  `internalBinding()` and `NativeModule` into a separate file
  `lib/internal/bootstrap_loaders.js`, and documents them there.
  This file will be compiled and run before `bootstrap_node.js`, which
  means we now bootstrap the internal module & binding system before
  actually bootstrapping Node.js.
- Rename the special ID that can be used to require `NativeModule`
  as `internal/bootstrap_loaders` since it is setup there. Also put
  `internalBinding` in the object exported by `NativeModule.require`
  instead of putting it inside the `NativeModule.wrapper`
- Use the original `getBinding()` to get the source code of native
  modules instead of getting it from `process.binding('native')`
  so that users cannot fake native modules by modifying the binding
  object.
- Names the bootstrapping functions so their names show up
  in the stack trace.

PR-URL: nodejs#19112
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
joyeecheung added a commit to joyeecheung/node that referenced this pull request Jun 13, 2018
Otherwise the debug log output might be mixed up with
the expected errors and the assertion matching the error
message would fail.

PR-URL: nodejs#19177
Refs: nodejs#19112
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
joyeecheung added a commit to joyeecheung/node that referenced this pull request Jun 13, 2018
Create `lib/internal/bootstrap/` and put bootstrappers there:

Before:

```
lib/internal
├── ...
├── bootstrap_loaders.js
└── bootstrap_node.js
```

After:

```
lib/internal
├── ...
└── bootstrap
    ├── loaders.js
    └── node.js
```

PR-URL: nodejs#19177
Refs: nodejs#19112
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lib / src Issues and PRs related to general changes in the lib or src directory. module Issues and PRs related to the module subsystem. process Issues and PRs related to the process subsystem.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants