diff --git a/lib/module.js b/lib/module.js index c9e4e2c785b..65e44b60b16 100644 --- a/lib/module.js +++ b/lib/module.js @@ -6,6 +6,7 @@ const runInThisContext = require('vm').runInThisContext; const assert = require('assert').ok; const fs = require('fs'); const path = require('path'); +const internalModuleReadFile = process.binding('fs').internalModuleReadFile; const internalModuleStat = process.binding('fs').internalModuleStat; @@ -65,10 +66,10 @@ function readPackage(requestPath) { return packageMainCache[requestPath]; } - try { - var jsonPath = path.resolve(requestPath, 'package.json'); - var json = fs.readFileSync(jsonPath, 'utf8'); - } catch (e) { + var jsonPath = path.resolve(requestPath, 'package.json'); + var json = internalModuleReadFile(jsonPath); + + if (json === undefined) { return false; } diff --git a/src/node_file.cc b/src/node_file.cc index 4e00f15e268..c8696f12954 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -22,6 +22,8 @@ # include #endif +#include + namespace node { using v8::Array; @@ -433,6 +435,50 @@ Local BuildStatsObject(Environment* env, const uv_stat_t* s) { return handle_scope.Escape(stats); } +// Used to speed up module loading. Returns the contents of the file as +// a string or undefined when the file cannot be opened. The speedup +// comes from not creating Error objects on failure. +static void InternalModuleReadFile(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + + CHECK(args[0]->IsString()); + node::Utf8Value path(env->isolate(), args[0]); + + FILE* const stream = fopen(*path, "rb"); + if (stream == nullptr) { + return; + } + + std::vector chars; + while (!ferror(stream)) { + const size_t kBlockSize = 32 << 10; + const size_t start = chars.size(); + chars.resize(start + kBlockSize); + const size_t numchars = fread(&chars[start], 1, kBlockSize, stream); + if (numchars < kBlockSize) { + chars.resize(start + numchars); + } + if (numchars == 0) { + break; + } + } + + CHECK_EQ(false, ferror(stream)); + CHECK_EQ(0, fclose(stream)); + + size_t start = 0; + if (chars.size() >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) { + start = 3; // Skip UTF-8 BOM. + } + + Local chars_string = + String::NewFromUtf8(env->isolate(), + &chars[start], + String::kNormalString, + chars.size() - start); + args.GetReturnValue().Set(chars_string); +} + // Used to speed up module loading. Returns 0 if the path refers to // a file, 1 when it's a directory or < 0 on error (usually -ENOENT.) // The speedup comes from not creating thousands of Stat and Error objects. @@ -1161,6 +1207,7 @@ void InitFs(Handle target, env->SetMethod(target, "rmdir", RMDir); env->SetMethod(target, "mkdir", MKDir); env->SetMethod(target, "readdir", ReadDir); + env->SetMethod(target, "internalModuleReadFile", InternalModuleReadFile); env->SetMethod(target, "internalModuleStat", InternalModuleStat); env->SetMethod(target, "stat", Stat); env->SetMethod(target, "lstat", LStat);