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

build: enable loading internal modules from disk #31321

Merged
merged 1 commit into from Jan 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 16 additions & 6 deletions configure.py
Expand Up @@ -609,6 +609,12 @@
default=False,
help='compile V8 with minimal optimizations and with runtime checks')

parser.add_option('--node-builtin-modules-path',
action='store',
dest='node_builtin_modules_path',
default=False,
help='node will load builtin modules from disk instead of from binary')

# Create compile_commands.json in out/Debug and out/Release.
parser.add_option('-C',
action='store_true',
Expand Down Expand Up @@ -992,18 +998,18 @@ def configure_node(o):

o['variables']['want_separate_host_toolset'] = int(cross_compiling)

if not options.without_node_snapshot:
if options.without_node_snapshot or options.node_builtin_modules_path:
o['variables']['node_use_node_snapshot'] = 'false'
else:
o['variables']['node_use_node_snapshot'] = b(
not cross_compiling and not options.shared)
else:
o['variables']['node_use_node_snapshot'] = 'false'

if not options.without_node_code_cache:
if options.without_node_code_cache or options.node_builtin_modules_path:
o['variables']['node_use_node_code_cache'] = 'false'
else:
# TODO(refack): fix this when implementing embedded code-cache when cross-compiling.
o['variables']['node_use_node_code_cache'] = b(
not cross_compiling and not options.shared)
else:
o['variables']['node_use_node_code_cache'] = 'false'

if target_arch == 'arm':
configure_arm(o)
Expand Down Expand Up @@ -1145,6 +1151,10 @@ def configure_node(o):
else:
o['variables']['node_target_type'] = 'executable'

if options.node_builtin_modules_path:
print('Warning! Loading builtin modules from disk is for development')
o['variables']['node_builtin_modules_path'] = options.node_builtin_modules_path

def configure_napi(output):
version = getnapibuildversion.get_napi_version()
output['variables']['napi_build_version'] = version
Expand Down
4 changes: 4 additions & 0 deletions node.gyp
Expand Up @@ -25,6 +25,7 @@
'node_core_target_name%': 'node',
'node_lib_target_name%': 'libnode',
'node_intermediate_lib_type%': 'static_library',
'node_builtin_modules_path%': '',
'library_files': [
'lib/internal/bootstrap/environment.js',
'lib/internal/bootstrap/loaders.js',
Expand Down Expand Up @@ -709,6 +710,9 @@
'msvs_disabled_warnings!': [4244],

'conditions': [
[ 'node_builtin_modules_path!=""', {
'defines': [ 'NODE_BUILTIN_MODULES_PATH="<(node_builtin_modules_path)"' ]
}],
[ 'node_shared=="true"', {
'sources': [
'src/node_snapshot_stub.cc',
Expand Down
1 change: 1 addition & 0 deletions src/node.cc
Expand Up @@ -27,6 +27,7 @@
#include "env-inl.h"
#include "memory_tracker-inl.h"
#include "node_binding.h"
#include "node_errors.h"
#include "node_internals.h"
#include "node_main_instance.h"
#include "node_metadata.h"
Expand Down
65 changes: 62 additions & 3 deletions src/node_native_module.cc
Expand Up @@ -174,6 +174,64 @@ MaybeLocal<Function> NativeModuleLoader::CompileAsModule(
return LookupAndCompile(context, id, &parameters, result);
}

#ifdef NODE_BUILTIN_MODULES_PATH
static std::string OnDiskFileName(const char* id) {
std::string filename = NODE_BUILTIN_MODULES_PATH;
filename += "/";

if (strncmp(id, "internal/deps", strlen("internal/deps")) == 0) {
id += strlen("internal/");
} else {
filename += "lib/";
}
filename += id;
filename += ".js";

return filename;
}
#endif // NODE_BUILTIN_MODULES_PATH

MaybeLocal<String> NativeModuleLoader::LoadBuiltinModuleSource(Isolate* isolate,
const char* id) {
#ifdef NODE_BUILTIN_MODULES_PATH
std::string filename = OnDiskFileName(id);

uv_fs_t req;
uv_file file =
uv_fs_open(nullptr, &req, filename.c_str(), O_RDONLY, 0, nullptr);
CHECK_GE(req.result, 0);
uv_fs_req_cleanup(&req);

std::shared_ptr<void> defer_close(nullptr, [file](...) {
uv_fs_t close_req;
CHECK_EQ(0, uv_fs_close(nullptr, &close_req, file, nullptr));
uv_fs_req_cleanup(&close_req);
});

std::string contents;
char buffer[4096];
uv_buf_t buf = uv_buf_init(buffer, sizeof(buffer));

while (true) {
const int r =
uv_fs_read(nullptr, &req, file, &buf, 1, contents.length(), nullptr);
CHECK_GE(req.result, 0);
uv_fs_req_cleanup(&req);
if (r <= 0) {
break;
}
contents.append(buf.base, r);
}
devsnek marked this conversation as resolved.
Show resolved Hide resolved

return String::NewFromUtf8(
isolate, contents.c_str(), v8::NewStringType::kNormal, contents.length());
#else
const auto source_it = source_.find(id);
CHECK_NE(source_it, source_.end());
return source_it->second.ToStringChecked(isolate);
#endif // NODE_BUILTIN_MODULES_PATH
}

// Returns Local<Function> of the compiled module if return_code_cache
// is false (we are only compiling the function).
// Otherwise return a Local<Object> containing the cache.
Expand All @@ -185,9 +243,10 @@ MaybeLocal<Function> NativeModuleLoader::LookupAndCompile(
Isolate* isolate = context->GetIsolate();
EscapableHandleScope scope(isolate);

const auto source_it = source_.find(id);
CHECK_NE(source_it, source_.end());
Local<String> source = source_it->second.ToStringChecked(isolate);
Local<String> source;
if (!LoadBuiltinModuleSource(isolate, id).ToLocal(&source)) {
return {};
}

std::string filename_s = id + std::string(".js");
Local<String> filename =
Expand Down
2 changes: 2 additions & 0 deletions src/node_native_module.h
Expand Up @@ -66,6 +66,8 @@ class NativeModuleLoader {
NativeModuleCacheMap* code_cache();
v8::ScriptCompiler::CachedData* GetCodeCache(const char* id) const;
enum class Result { kWithCache, kWithoutCache };
v8::MaybeLocal<v8::String> LoadBuiltinModuleSource(v8::Isolate* isolate,
const char* id);
// If an exception is encountered (e.g. source code contains
// syntax error), the returned value is empty.
v8::MaybeLocal<v8::Function> LookupAndCompile(
Expand Down