Skip to content

Instantly share code, notes, and snippets.

@TimothyGu
Last active May 5, 2017 01:03
Show Gist options
  • Select an option

  • Save TimothyGu/c70e7cb557d1290b5c2150111eb95a01 to your computer and use it in GitHub Desktop.

Select an option

Save TimothyGu/c70e7cb557d1290b5c2150111eb95a01 to your computer and use it in GitHub Desktop.

Only fs.statSync is reimplemented.

Old:

fs/bench-statSync.js kind="fstatSync" n=1000000: 1,416,492.410950682
fs/bench-statSync.js kind="lstatSync" n=1000000: 413,511.3373933365
fs/bench-statSync.js kind="statSync" n=1000000: 428,459.00313251

New:

fs/bench-statSync.js kind="fstatSync" n=1000000: 1,461,069.6501428399
fs/bench-statSync.js kind="lstatSync" n=1000000: 413,238.4644709924
fs/bench-statSync.js kind="statSync" n=1000000: 277,281.55040191
diff --git a/src/env.h b/src/env.h
index 1010d649c6..d41b855547 100644
--- a/src/env.h
+++ b/src/env.h
@@ -259,6 +259,7 @@ namespace node {
V(context, v8::Context) \
V(domain_array, v8::Array) \
V(domains_stack_array, v8::Array) \
+ V(fs_stats_template, v8::ObjectTemplate) \
V(generic_internal_field_template, v8::ObjectTemplate) \
V(jsstream_constructor_template, v8::FunctionTemplate) \
V(module_load_list_array, v8::Array) \
diff --git a/src/node_file.cc b/src/node_file.cc
index 4a0b1527d6..b598c629ba 100644
--- a/src/node_file.cc
+++ b/src/node_file.cc
@@ -50,6 +50,7 @@ namespace {
using v8::Array;
using v8::ArrayBuffer;
using v8::Context;
+using v8::Date;
using v8::Float64Array;
using v8::Function;
using v8::FunctionCallbackInfo;
@@ -58,8 +59,11 @@ using v8::HandleScope;
using v8::Integer;
using v8::Local;
using v8::MaybeLocal;
+using v8::Name;
using v8::Number;
using v8::Object;
+using v8::ObjectTemplate;
+using v8::PropertyCallbackInfo;
using v8::String;
using v8::Value;
@@ -373,6 +377,64 @@ class fs_req_wrap {
};
+MaybeLocal<Object> CreateStatsObject(Environment* env, Local<ArrayBuffer> fields) {
+ Local<ObjectTemplate> tmpl = env->fs_stats_template();
+ auto maybe_obj = tmpl->NewInstance(env->context());
+ if (maybe_obj.IsEmpty())
+ return maybe_obj;
+ auto obj = maybe_obj.ToLocalChecked();
+ obj->SetInternalField(0, fields);
+ // obj->SetPrototype(env->context(), proto);
+ return MaybeLocal<Object>(obj);
+}
+
+#define STATS_PROPS_NUM(V) \
+ V(0, dev, Dev) \
+ V(1, mode, Mode) \
+ V(2, nlink, Nlink) \
+ V(3, uid, Uid) \
+ V(4, gid, Gid) \
+ V(5, rdev, Rdev) \
+ V(6, blksize, Blksize) \
+ V(7, ino, Ino) \
+ V(8, size, Size) \
+ V(9, blocks, Blocks)
+
+#define STATS_PROPS_DATE(V) \
+ V(10, atime, Atime) \
+ V(11, mtime, Mtime) \
+ V(12, ctime, Ctime) \
+ V(13, birthtime, Birthtime)
+
+#define STATS_PROPS(V) \
+ STATS_PROPS_NUM(V) \
+ STATS_PROPS_DATE(V)
+
+#define STATS_GETTER(ToJS, idx, prop, func_name) \
+ static void StatsAccessorGetter ## func_name( \
+ Local<Name> property, const PropertyCallbackInfo<Value>& info) { \
+ const auto env = Environment::GetCurrent(info); \
+ auto obj = info.This(); \
+ CHECK(obj->InternalFieldCount() >= 1); \
+ auto fields_arrbuf = obj->GetInternalField(0); \
+ CHECK(fields_arrbuf->IsArrayBuffer()); \
+ const double* fields = static_cast<double*>( \
+ fields_arrbuf.As<ArrayBuffer>()->GetContents().Data()); \
+ info.GetReturnValue().Set(ToJS(env, fields[idx])); \
+ }
+#define DBL_TO_NUM(env, num) Number::New(env->isolate(), num)
+#define DBL_TO_DATE(env, num) Date::New(env->context(), num).ToLocalChecked()
+#define V(idx, prop, func_name) STATS_GETTER(DBL_TO_NUM, idx, prop, func_name)
+STATS_PROPS_NUM(V)
+#undef V
+#define V(idx, prop, func_name) STATS_GETTER(DBL_TO_DATE, idx, prop, func_name)
+STATS_PROPS_DATE(V)
+#undef V
+#undef DBL_TO_NUM
+#undef DBL_TO_DATE
+#undef STATS_GETTER
+
+
#define ASYNC_DEST_CALL(func, request, dest, encoding, ...) \
Environment* env = Environment::GetCurrent(args); \
CHECK(request->IsObject()); \
@@ -574,8 +636,13 @@ static void Stat(const FunctionCallbackInfo<Value>& args) {
ASYNC_CALL(stat, args[1], UTF8, *path)
} else {
SYNC_CALL(stat, *path, *path)
- FillStatsArray(env->fs_stats_field_array(),
+ Local<ArrayBuffer> stats_buf = ArrayBuffer::New(env->isolate(), sizeof(double) * 14);
+ FillStatsArray(static_cast<double*>(stats_buf->GetContents().Data()),
static_cast<const uv_stat_t*>(SYNC_REQ.ptr));
+ auto stats_maybe = CreateStatsObject(env, stats_buf);
+ if (stats_maybe.IsEmpty())
+ return;
+ args.GetReturnValue().Set(stats_maybe.ToLocalChecked());
}
}
@@ -1477,6 +1544,20 @@ void InitFs(Local<Object> target,
fst->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "FSReqWrap"));
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "FSReqWrap"),
fst->GetFunction());
+
+ // Create ObjectTemplate for Stats
+ Local<ObjectTemplate> stats_tmpl =
+ ObjectTemplate::New(env->isolate());
+ stats_tmpl->SetInternalFieldCount(1);
+
+#define V(idx, name, func_name) \
+ stats_tmpl->SetLazyDataProperty( \
+ FIXED_ONE_BYTE_STRING(env->isolate(), #name), \
+ StatsAccessorGetter ## func_name);
+ STATS_PROPS(V)
+#undef V
+
+ env->set_fs_stats_template(stats_tmpl);
}
} // end namespace node
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment