0
0
mirror of https://github.com/nodejs/node.git synced 2024-12-01 16:10:02 +01:00
Commit Graph

7 Commits

Author SHA1 Message Date
Joyee Cheung
0858e5d9d8
src: always compile and store code cache for native modules
This patch changes the NativeModuleLoader to always try to find
code cache for native modules when it compiles them, and always
produce and store the code cache after compilation. The cache
map is protected by a mutex and can be accessed by different
threads - including the worker threads and the main thread. Hence any
thread can reuse the code cache if the native module has already
been compiled by another thread - in particular the cache of the
bootstrappers and per_context.js will always be hit when a new thread
is spun.

This results in a ~6% startup overhead in the worst case
(when only the main thread is launched without requiring any additional
native module - it now needs to do the extra work of finding and
storing caches), which balances out the recent improvements by moving
the compilation to C++, but it also leads to a ~60% improvement in
the best case (when a worker thread is spun and requires a lot of native
modules thus hitting the cache compiled by the main thread).

PR-URL: https://github.com/nodejs/node/pull/24950
Reviewed-By: Anna Henningsen <anna@addaleax.net>
2018-12-18 18:02:11 +08:00
Joyee Cheung
ceb6635223
src: remove code cache integrity check
In preparation of sharing code cache among different threads -
we simply rely on v8 to reject invalid cache, since there isn't
any serious consequence when the cache is invalid anyway.

PR-URL: https://github.com/nodejs/node/pull/24950
Reviewed-By: Anna Henningsen <anna@addaleax.net>
2018-12-18 18:02:08 +08:00
Joyee Cheung
7778c035a0
src: use STL containers instead of v8 values for static module data
Instead of putting the source code and the cache in v8::Objects,
put them in per-process std::maps. This has the following benefits:

- It's slightly lighter in weight compared to storing things on the
  v8 heap. Also it may be slightly faster since the preivous v8::Object
  is already in dictionary mode - though the difference is very small
  given the number of native modules is limited.
- The source and code cache generation templates are now much simpler
  since they just initialize static arrays and manipulate STL
  constructs.
- The static native module data can be accessed independently of any
  Environment or Isolate, and it's easy to look them up from the
  C++'s side.
- It's now impossible to mutate the source code used to compile
  native modules from the JS land since it's completely separate
  from the v8 heap. We can still get the constant strings from
  process.binding('natives') but that's all.

A few drive-by fixes:

- Remove DecorateErrorStack in LookupAndCompile - We don't need to
  capture the exception to decorate when we encounter
  errors during native module compilation, as those errors should be
  syntax errors and v8 is able to decorate them well. We use
  CompileFunctionInContext so there is no need to worry about
  wrappers either.
- The code cache could be rejected when node is started with v8 flags.
  Instead of aborting in that case, simply keep a record in the
  native_module_without_cache set.
- Refactor js2c.py a bit, reduce code duplication and inline Render()
  to make the one-byte/two-byte special treatment easier to read.

PR-URL: https://github.com/nodejs/node/pull/24384
Fixes: https://github.com/Remove
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2018-11-20 01:17:15 +08:00
Joyee Cheung
bd765d61d7
src: compile native modules and their code cache in C++
This patch refactors out a part of NativeModule.prototype.compile
(in JS land) into a C++ NativeModule class, this enables a
couple of possibilities:

1. By moving the code to the C++ land, we have more opportunity
  to specialize the compilation process of the native modules
  (e.g. compilation options, code cache) that is orthogonal to
  how user land modules are compiled
2. We can reuse the code to compile bootstrappers and context
  fixers and enable them to be compiled with the code cache later,
  since they are not loaded by NativeModule in the JS land their
  caching must be done in C++.
3. Since there is no need to pass the static data to JS for
  compilation anymore, this enables us to use
  (std::map<std::string, const char*>) in the generated
  node_code_cache.cc and node_javascript.cc later, and scope
  every actual access to the source of native modules to a
  std::map lookup instead of a lookup on a v8::Object in
  dictionary mode.

This patch also refactor the code cache generator and tests
a bit and trace the `withCodeCache` and `withoutCodeCache`
in a Set instead of an Array, and makes sure that all the cachable
builtins are tested.

PR-URL: https://github.com/nodejs/node/pull/24221
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
2018-11-15 02:30:40 +08:00
Joyee Cheung
7cbbb27c07
src: perform integrity checks on built-in code cache
Currently V8 only checks that the length of the source code is the
same as the code used to generate the hash, so we add an additional
check here:

1. During compile time, when generating node_javascript.cc and
   node_code_cache.cc, we compute and include the hash of the
  (unwrapped) JavaScript source in both.
2. At runtime, we check that the hash of the code being compiled
  and the hash of the code used to generate the cache
  (inside the wrapper) is the same.

This is based on the assumptions:

1. `internalBinding('code_cache_hash')` must be in sync with
   `internalBinding('code_cache')` (same C++ file)
2. `internalBinding('natives_hash')` must be in sync with
   `process.binding('natives')` (same C++ file)
3. If `internalBinding('natives_hash')` is in sync with
   `internalBinding('natives_hash')`, then the (unwrapped)
   code used to generate `internalBinding('code_cache')`
   should be in sync with the (unwrapped) code in
   `process.binding('natives')`

There will be, however, false positives if the wrapper used
to generate the cache is different from the one used at run time,
and the length of the wrapper somehow stays the same.
But that should be rare and can be eased once we make the
two bootstrappers cached and checked as well.

PR-URL: https://github.com/nodejs/node/pull/22152
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
2018-08-18 05:21:52 +08:00
Joyee Cheung
186c2fb6d8
build: create V8 code cache after script is run
This patch makes it possible to generate the code cache
for the builtins directly from the original script object
(instead of compiling a new one) and after the script has
been run (via `NativeModule.require`). Before this patch
only the top level functions (the wrapped ones)
are included in the cache, after this patch the inner
functions in those modules will be included as well.

Also blacklists modules from dependencies like V8 and
node-inspect since we cannot guarantee that they are suitable
to be executed directly.

PR-URL: https://github.com/nodejs/node/pull/21567
Refs: https://github.com/nodejs/node/issues/21563
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: John-David Dalton <john.david.dalton@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
2018-07-27 14:51:27 +08:00
Joyee Cheung
4750ce26f2
build: speed up startup with V8 code cache
This patch speeds up the startup time and reduce the startup memory
footprint by using V8 code cache when comiling builtin modules.

The current approach is demonstrated in the `with-code-cache`
Makefile target (no corresponding Windows target at the moment).

1. Build the binary normally (`src/node_code_cache_stub.cc` is used),
  by now `internalBinding('code_cache')` is an empty object
2. Run `tools/generate_code_cache.js` with the binary, which generates
  the code caches by reading source code of builtin modules off source
  code exposed by `require('internal/bootstrap/cache').builtinSource`
  and then generate a C++ file containing static char arrays of the
  code cache, using a format similar to `node_javascript.cc`
3. Run `configure` with the `--code-cache-path` option so that
  the newly generated C++ file will be used when compiling the
  new binary. The generated C++ file will put the cache into
  the `internalBinding('code_cache')` object with the module
  ids as keys
4. The new binary tries to read the code cache from
  `internalBinding('code_cache')` and use it to compile
  builtin modules. If the cache is used, it will put the id
  into `require('internal/bootstrap/cache').compiledWithCache`
  for bookkeeping, otherwise the id will be pushed into
  `require('internal/bootstrap/cache').compiledWithoutCache`

This patch also added tests that verify the code cache is
generated and used when compiling builtin modules.

The binary with code cache:

- Is ~1MB bigger than the binary without code cahe
- Consumes ~1MB less memory during start up
- Starts up about 60% faster

PR-URL: https://github.com/nodejs/node/pull/21405
Reviewed-By: John-David Dalton <john.david.dalton@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Gus Caplan <me@gus.host>
2018-06-27 21:11:31 +08:00