summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJames Pickard <james.pickard@gmail.com>2014-02-27 15:45:18 -0500
committerTrevor Norris <trev.norris@gmail.com>2014-03-31 15:02:17 -0700
commite9ce8fc82a6d12e790511b62852e820d8be03186 (patch)
tree4ba7a41c95eaf0a484b716602096d3fef7cbeb42 /src
parent5d2aef17ee56fbbf415ca1e3034cdb02cd97117c (diff)
downloadandroid-node-v8-e9ce8fc82a6d12e790511b62852e820d8be03186.tar.gz
android-node-v8-e9ce8fc82a6d12e790511b62852e820d8be03186.tar.bz2
android-node-v8-e9ce8fc82a6d12e790511b62852e820d8be03186.zip
fs: improve performance of all stat functions
By building the fs.Stats object in JS, which is returned by all fs stat functions, calls to v8::Object::Set() are removed. This also includes creating all associated Date objects in JS, rather than using v8::Date::New(). Both these changes have significant performance gains. Note that the returned value from fs.stat changes slightly for non-POSIX systems. Whereas before the stats object would be missing blocks and blksize keys, it now has these keys with undefined as the value. Signed-off-by: Trevor Norris <trev.norris@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/env.h2
-rw-r--r--src/node_file.cc103
-rw-r--r--src/node_internals.h2
3 files changed, 68 insertions, 39 deletions
diff --git a/src/env.h b/src/env.h
index 6a3b5944be..95e1df6e59 100644
--- a/src/env.h
+++ b/src/env.h
@@ -243,6 +243,7 @@ namespace node {
V(buffer_constructor_function, v8::Function) \
V(context, v8::Context) \
V(domain_array, v8::Array) \
+ V(fs_stats_constructor_function, v8::Function) \
V(gc_info_callback_function, v8::Function) \
V(module_load_list_array, v8::Array) \
V(pipe_constructor_template, v8::FunctionTemplate) \
@@ -250,7 +251,6 @@ namespace node {
V(script_context_constructor_template, v8::FunctionTemplate) \
V(script_data_constructor_function, v8::Function) \
V(secure_context_constructor_template, v8::FunctionTemplate) \
- V(stats_constructor_function, v8::Function) \
V(tcp_constructor_template, v8::FunctionTemplate) \
V(tick_callback_function, v8::Function) \
V(tls_wrap_constructor_function, v8::Function) \
diff --git a/src/node_file.cc b/src/node_file.cc
index 1d454abb3b..8b18b82c96 100644
--- a/src/node_file.cc
+++ b/src/node_file.cc
@@ -323,17 +323,12 @@ static void Close(const FunctionCallbackInfo<Value>& args) {
}
-Local<Object> BuildStatsObject(Environment* env, const uv_stat_t* s) {
+Local<Value> BuildStatsObject(Environment* env, const uv_stat_t* s) {
// If you hit this assertion, you forgot to enter the v8::Context first.
assert(env->context() == env->isolate()->GetCurrentContext());
EscapableHandleScope handle_scope(env->isolate());
- Local<Object> stats = env->stats_constructor_function()->NewInstance();
- if (stats.IsEmpty()) {
- return handle_scope.Escape(Local<Object>());
- }
-
// The code below is very nasty-looking but it prevents a segmentation fault
// when people run JS code like the snippet below. It's apparently more
// common than you would expect, several people have reported this crash...
@@ -345,13 +340,13 @@ Local<Object> BuildStatsObject(Environment* env, const uv_stat_t* s) {
//
// We need to check the return value of Integer::New() and Date::New()
// and make sure that we bail out when V8 returns an empty handle.
+
+ // Integers.
#define X(name) \
- { \
- Local<Value> val = Integer::New(env->isolate(), s->st_##name); \
- if (val.IsEmpty()) \
- return handle_scope.Escape(Local<Object>()); \
- stats->Set(env->name ## _string(), val); \
- }
+ Local<Value> name = Integer::New(env->isolate(), s->st_##name); \
+ if (name.IsEmpty()) \
+ return handle_scope.Escape(Local<Object>()); \
+
X(dev)
X(mode)
X(nlink)
@@ -360,39 +355,67 @@ Local<Object> BuildStatsObject(Environment* env, const uv_stat_t* s) {
X(rdev)
# if defined(__POSIX__)
X(blksize)
+# else
+ Local<Value> blksize = Undefined(env->isolate());
# endif
#undef X
+ // Numbers.
#define X(name) \
- { \
- Local<Value> val = Number::New(env->isolate(), \
- static_cast<double>(s->st_##name)); \
- if (val.IsEmpty()) \
- return handle_scope.Escape(Local<Object>()); \
- stats->Set(env->name ## _string(), val); \
- }
+ Local<Value> name = Number::New(env->isolate(), \
+ static_cast<double>(s->st_##name)); \
+ if (name.IsEmpty()) \
+ return handle_scope.Escape(Local<Object>()); \
+
X(ino)
X(size)
# if defined(__POSIX__)
X(blocks)
+# else
+ Local<Value> blocks = Undefined(env->isolate());
# endif
#undef X
-#define X(name, rec) \
- { \
- double msecs = static_cast<double>(s->st_##rec.tv_sec) * 1000; \
- msecs += static_cast<double>(s->st_##rec.tv_nsec / 1000000); \
- Local<Value> val = v8::Date::New(env->isolate(), msecs); \
- if (val.IsEmpty()) \
- return handle_scope.Escape(Local<Object>()); \
- stats->Set(env->name ## _string(), val); \
- }
- X(atime, atim)
- X(mtime, mtim)
- X(ctime, ctim)
- X(birthtime, birthtim)
+ // Dates.
+#define X(name) \
+ Local<Value> name##_msec = \
+ Number::New(env->isolate(), \
+ (static_cast<double>(s->st_##name.tv_sec) * 1000) + \
+ (static_cast<double>(s->st_##name.tv_nsec / 1000000))); \
+ \
+ if (name##_msec.IsEmpty()) \
+ return handle_scope.Escape(Local<Object>()); \
+
+ X(atim)
+ X(mtim)
+ X(ctim)
+ X(birthtim)
#undef X
+ // Pass stats as the first argument, this is the object we are modifying.
+ Local<Value> argv[] = {
+ dev,
+ mode,
+ nlink,
+ uid,
+ gid,
+ rdev,
+ ino,
+ size,
+ blocks,
+ atim_msec,
+ mtim_msec,
+ ctim_msec,
+ birthtim_msec
+ };
+
+ // Call out to JavaScript to create the stats object.
+ Local<Value> stats =
+ env->fs_stats_constructor_function()->NewInstance(ARRAY_SIZE(argv), argv);
+
+ if (stats.IsEmpty())
+ return handle_scope.Escape(Local<Object>());
+
return handle_scope.Escape(stats);
}
@@ -1081,6 +1104,13 @@ static void FUTimes(const FunctionCallbackInfo<Value>& args) {
}
}
+void FSInitialize(const FunctionCallbackInfo<Value>& args) {
+ Local<Function> stats_constructor = args[0].As<Function>();
+ assert(stats_constructor->IsFunction());
+
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ env->set_fs_stats_constructor_function(stats_constructor);
+}
void InitFs(Handle<Object> target,
Handle<Value> unused,
@@ -1088,11 +1118,10 @@ void InitFs(Handle<Object> target,
void* priv) {
Environment* env = Environment::GetCurrent(context);
- // Initialize the stats object
- Local<Function> constructor =
- FunctionTemplate::New(env->isolate())->GetFunction();
- target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "Stats"), constructor);
- env->set_stats_constructor_function(constructor);
+ // Function which creates a new Stats object.
+ target->Set(
+ FIXED_ONE_BYTE_STRING(env->isolate(), "FSInitialize"),
+ FunctionTemplate::New(env->isolate(), FSInitialize)->GetFunction());
NODE_SET_METHOD(target, "close", Close);
NODE_SET_METHOD(target, "open", Open);
diff --git a/src/node_internals.h b/src/node_internals.h
index 7844a9c114..d38a3f019f 100644
--- a/src/node_internals.h
+++ b/src/node_internals.h
@@ -126,7 +126,7 @@ void AppendExceptionLine(Environment* env,
NO_RETURN void FatalError(const char* location, const char* message);
-v8::Local<v8::Object> BuildStatsObject(Environment* env, const uv_stat_t* s);
+v8::Local<v8::Value> BuildStatsObject(Environment* env, const uv_stat_t* s);
enum Endianness {
kLittleEndian, // _Not_ LITTLE_ENDIAN, clashes with endian.h.