Skip to content

Commit

Permalink
src: remove templating from StreamBase
Browse files Browse the repository at this point in the history
PR-URL: nodejs#25142
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
maclover7 authored and BridgeAR committed Mar 12, 2019
1 parent dc04dc0 commit 3b06d29
Show file tree
Hide file tree
Showing 12 changed files with 133 additions and 159 deletions.
6 changes: 4 additions & 2 deletions src/js_stream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ JSStream::JSStream(Environment* env, Local<Object> obj)
: AsyncWrap(env, obj, AsyncWrap::PROVIDER_JSSTREAM),
StreamBase(env) {
MakeWeak();
StreamBase::AttachToObject(obj);
}


Expand Down Expand Up @@ -203,15 +204,16 @@ void JSStream::Initialize(Local<Object> target,
Local<String> jsStreamString =
FIXED_ONE_BYTE_STRING(env->isolate(), "JSStream");
t->SetClassName(jsStreamString);
t->InstanceTemplate()->SetInternalFieldCount(1);
t->InstanceTemplate()
->SetInternalFieldCount(StreamBase::kStreamBaseField + 1);
t->Inherit(AsyncWrap::GetConstructorTemplate(env));

env->SetProtoMethod(t, "finishWrite", Finish<WriteWrap>);
env->SetProtoMethod(t, "finishShutdown", Finish<ShutdownWrap>);
env->SetProtoMethod(t, "readBuffer", ReadBuffer);
env->SetProtoMethod(t, "emitEOF", EmitEOF);

StreamBase::AddMethods<JSStream>(env, t);
StreamBase::AddMethods(env, t);
target->Set(env->context(),
jsStreamString,
t->GetFunction(context).ToLocalChecked()).FromJust();
Expand Down
5 changes: 3 additions & 2 deletions src/node_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ FileHandle::FileHandle(Environment* env, Local<Object> obj, int fd)
StreamBase(env),
fd_(fd) {
MakeWeak();
StreamBase::AttachToObject(GetObject());
}

FileHandle* FileHandle::New(Environment* env, int fd, Local<Object> obj) {
Expand Down Expand Up @@ -2227,11 +2228,11 @@ void Initialize(Local<Object> target,
env->SetProtoMethod(fd, "close", FileHandle::Close);
env->SetProtoMethod(fd, "releaseFD", FileHandle::ReleaseFD);
Local<ObjectTemplate> fdt = fd->InstanceTemplate();
fdt->SetInternalFieldCount(1);
fdt->SetInternalFieldCount(StreamBase::kStreamBaseField + 1);
Local<String> handleString =
FIXED_ONE_BYTE_STRING(isolate, "FileHandle");
fd->SetClassName(handleString);
StreamBase::AddMethods<FileHandle>(env, fd);
StreamBase::AddMethods(env, fd);
target
->Set(context, handleString,
fd->GetFunction(env->context()).ToLocalChecked())
Expand Down
5 changes: 3 additions & 2 deletions src/node_http2.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1868,6 +1868,7 @@ Http2Stream::Http2Stream(Http2Session* session,
id_(id),
current_headers_category_(category) {
MakeWeak();
StreamBase::AttachToObject(GetObject());
statistics_.start_time = uv_hrtime();

// Limit the number of header pairs
Expand Down Expand Up @@ -3009,9 +3010,9 @@ void Initialize(Local<Object> target,
env->SetProtoMethod(stream, "rstStream", Http2Stream::RstStream);
env->SetProtoMethod(stream, "refreshState", Http2Stream::RefreshState);
stream->Inherit(AsyncWrap::GetConstructorTemplate(env));
StreamBase::AddMethods<Http2Stream>(env, stream);
StreamBase::AddMethods(env, stream);
Local<ObjectTemplate> streamt = stream->InstanceTemplate();
streamt->SetInternalFieldCount(1);
streamt->SetInternalFieldCount(StreamBase::kStreamBaseField + 1);
env->set_http2stream_constructor_template(streamt);
target->Set(context,
FIXED_ONE_BYTE_STRING(env->isolate(), "Http2Stream"),
Expand Down
3 changes: 2 additions & 1 deletion src/pipe_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ void PipeWrap::Initialize(Local<Object> target,
Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
Local<String> pipeString = FIXED_ONE_BYTE_STRING(env->isolate(), "Pipe");
t->SetClassName(pipeString);
t->InstanceTemplate()->SetInternalFieldCount(1);
t->InstanceTemplate()
->SetInternalFieldCount(StreamBase::kStreamBaseField + 1);

t->Inherit(LibuvStreamWrap::GetConstructorTemplate(env));

Expand Down
142 changes: 7 additions & 135 deletions src/stream_base-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,144 +273,16 @@ inline WriteWrap* StreamBase::CreateWriteWrap(
return new SimpleWriteWrap<AsyncWrap>(this, object);
}

template <class Base>
void StreamBase::AddMethods(Environment* env, Local<FunctionTemplate> t) {
HandleScope scope(env->isolate());

enum PropertyAttribute attributes =
static_cast<PropertyAttribute>(
v8::ReadOnly | v8::DontDelete | v8::DontEnum);

Local<Signature> signature = Signature::New(env->isolate(), t);

Local<FunctionTemplate> get_fd_templ =
env->NewFunctionTemplate(GetFD<Base>,
signature,
v8::ConstructorBehavior::kThrow,
v8::SideEffectType::kHasNoSideEffect);

Local<FunctionTemplate> get_external_templ =
env->NewFunctionTemplate(GetExternal<Base>,
signature,
v8::ConstructorBehavior::kThrow,
v8::SideEffectType::kHasNoSideEffect);

Local<FunctionTemplate> get_bytes_read_templ =
env->NewFunctionTemplate(GetBytesRead<Base>,
signature,
v8::ConstructorBehavior::kThrow,
v8::SideEffectType::kHasNoSideEffect);

Local<FunctionTemplate> get_bytes_written_templ =
env->NewFunctionTemplate(GetBytesWritten<Base>,
signature,
v8::ConstructorBehavior::kThrow,
v8::SideEffectType::kHasNoSideEffect);

t->PrototypeTemplate()->SetAccessorProperty(env->fd_string(),
get_fd_templ,
Local<FunctionTemplate>(),
attributes);

t->PrototypeTemplate()->SetAccessorProperty(env->external_stream_string(),
get_external_templ,
Local<FunctionTemplate>(),
attributes);

t->PrototypeTemplate()->SetAccessorProperty(env->bytes_read_string(),
get_bytes_read_templ,
Local<FunctionTemplate>(),
attributes);

t->PrototypeTemplate()->SetAccessorProperty(env->bytes_written_string(),
get_bytes_written_templ,
Local<FunctionTemplate>(),
attributes);

env->SetProtoMethod(t, "readStart", JSMethod<Base, &StreamBase::ReadStartJS>);
env->SetProtoMethod(t, "readStop", JSMethod<Base, &StreamBase::ReadStopJS>);
env->SetProtoMethod(t, "shutdown", JSMethod<Base, &StreamBase::Shutdown>);
env->SetProtoMethod(t, "writev", JSMethod<Base, &StreamBase::Writev>);
env->SetProtoMethod(t,
"writeBuffer",
JSMethod<Base, &StreamBase::WriteBuffer>);
env->SetProtoMethod(t,
"writeAsciiString",
JSMethod<Base, &StreamBase::WriteString<ASCII> >);
env->SetProtoMethod(t,
"writeUtf8String",
JSMethod<Base, &StreamBase::WriteString<UTF8> >);
env->SetProtoMethod(t,
"writeUcs2String",
JSMethod<Base, &StreamBase::WriteString<UCS2> >);
env->SetProtoMethod(t,
"writeLatin1String",
JSMethod<Base, &StreamBase::WriteString<LATIN1> >);
inline void StreamBase::AttachToObject(v8::Local<v8::Object> obj) {
obj->SetAlignedPointerInInternalField(kStreamBaseField, this);
}

inline StreamBase* StreamBase::FromObject(v8::Local<v8::Object> obj) {
if (obj->GetAlignedPointerFromInternalField(0) == nullptr)
return nullptr;

template <class Base>
void StreamBase::GetFD(const FunctionCallbackInfo<Value>& args) {
// Mimic implementation of StreamBase::GetFD() and UDPWrap::GetFD().
Base* handle;
ASSIGN_OR_RETURN_UNWRAP(&handle,
args.This(),
args.GetReturnValue().Set(UV_EINVAL));

StreamBase* wrap = static_cast<StreamBase*>(handle);
if (!wrap->IsAlive())
return args.GetReturnValue().Set(UV_EINVAL);

args.GetReturnValue().Set(wrap->GetFD());
}

template <class Base>
void StreamBase::GetBytesRead(const FunctionCallbackInfo<Value>& args) {
Base* handle;
ASSIGN_OR_RETURN_UNWRAP(&handle,
args.This(),
args.GetReturnValue().Set(0));

StreamBase* wrap = static_cast<StreamBase*>(handle);
// uint64_t -> double. 53bits is enough for all real cases.
args.GetReturnValue().Set(static_cast<double>(wrap->bytes_read_));
}

template <class Base>
void StreamBase::GetBytesWritten(const FunctionCallbackInfo<Value>& args) {
Base* handle;
ASSIGN_OR_RETURN_UNWRAP(&handle,
args.This(),
args.GetReturnValue().Set(0));

StreamBase* wrap = static_cast<StreamBase*>(handle);
// uint64_t -> double. 53bits is enough for all real cases.
args.GetReturnValue().Set(static_cast<double>(wrap->bytes_written_));
}

template <class Base>
void StreamBase::GetExternal(const FunctionCallbackInfo<Value>& args) {
Base* handle;
ASSIGN_OR_RETURN_UNWRAP(&handle, args.This());

StreamBase* wrap = static_cast<StreamBase*>(handle);
Local<External> ext = External::New(args.GetIsolate(), wrap);
args.GetReturnValue().Set(ext);
}


template <class Base,
int (StreamBase::*Method)(const FunctionCallbackInfo<Value>& args)>
void StreamBase::JSMethod(const FunctionCallbackInfo<Value>& args) {
Base* handle;
ASSIGN_OR_RETURN_UNWRAP(&handle, args.Holder());

StreamBase* wrap = static_cast<StreamBase*>(handle);
if (!wrap->IsAlive())
return args.GetReturnValue().Set(UV_EINVAL);

AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(handle);
args.GetReturnValue().Set((wrap->*Method)(args));
return static_cast<StreamBase*>(
obj->GetAlignedPointerFromInternalField(kStreamBaseField));
}


Expand Down
87 changes: 87 additions & 0 deletions src/stream_base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,93 @@ Local<Object> StreamBase::GetObject() {
return GetAsyncWrap()->object();
}

void StreamBase::AddMethod(Environment* env,
Local<Signature> signature,
enum PropertyAttribute attributes,
Local<FunctionTemplate> t,
JSMethodFunction* stream_method,
Local<String> string) {
Local<FunctionTemplate> templ =
env->NewFunctionTemplate(stream_method,
signature,
v8::ConstructorBehavior::kThrow,
v8::SideEffectType::kHasNoSideEffect);
t->PrototypeTemplate()->SetAccessorProperty(
string, templ, Local<FunctionTemplate>(), attributes);
}

void StreamBase::AddMethods(Environment* env, Local<FunctionTemplate> t) {
HandleScope scope(env->isolate());

enum PropertyAttribute attributes = static_cast<PropertyAttribute>(
v8::ReadOnly | v8::DontDelete | v8::DontEnum);
Local<Signature> sig = Signature::New(env->isolate(), t);

AddMethod(env, sig, attributes, t, GetFD, env->fd_string());
AddMethod(
env, sig, attributes, t, GetExternal, env->external_stream_string());
AddMethod(env, sig, attributes, t, GetBytesRead, env->bytes_read_string());
AddMethod(
env, sig, attributes, t, GetBytesWritten, env->bytes_written_string());
env->SetProtoMethod(t, "readStart", JSMethod<&StreamBase::ReadStartJS>);
env->SetProtoMethod(t, "readStop", JSMethod<&StreamBase::ReadStopJS>);
env->SetProtoMethod(t, "shutdown", JSMethod<&StreamBase::Shutdown>);
env->SetProtoMethod(t, "writev", JSMethod<&StreamBase::Writev>);
env->SetProtoMethod(t, "writeBuffer", JSMethod<&StreamBase::WriteBuffer>);
env->SetProtoMethod(
t, "writeAsciiString", JSMethod<&StreamBase::WriteString<ASCII>>);
env->SetProtoMethod(
t, "writeUtf8String", JSMethod<&StreamBase::WriteString<UTF8>>);
env->SetProtoMethod(
t, "writeUcs2String", JSMethod<&StreamBase::WriteString<UCS2>>);
env->SetProtoMethod(
t, "writeLatin1String", JSMethod<&StreamBase::WriteString<LATIN1>>);
}

void StreamBase::GetFD(const FunctionCallbackInfo<Value>& args) {
// Mimic implementation of StreamBase::GetFD() and UDPWrap::GetFD().
StreamBase* wrap = StreamBase::FromObject(args.This().As<Object>());
if (wrap == nullptr) return args.GetReturnValue().Set(UV_EINVAL);

if (!wrap->IsAlive()) return args.GetReturnValue().Set(UV_EINVAL);

args.GetReturnValue().Set(wrap->GetFD());
}

void StreamBase::GetBytesRead(const FunctionCallbackInfo<Value>& args) {
StreamBase* wrap = StreamBase::FromObject(args.This().As<Object>());
if (wrap == nullptr) return args.GetReturnValue().Set(0);

// uint64_t -> double. 53bits is enough for all real cases.
args.GetReturnValue().Set(static_cast<double>(wrap->bytes_read_));
}

void StreamBase::GetBytesWritten(const FunctionCallbackInfo<Value>& args) {
StreamBase* wrap = StreamBase::FromObject(args.This().As<Object>());
if (wrap == nullptr) return args.GetReturnValue().Set(0);

// uint64_t -> double. 53bits is enough for all real cases.
args.GetReturnValue().Set(static_cast<double>(wrap->bytes_written_));
}

void StreamBase::GetExternal(const FunctionCallbackInfo<Value>& args) {
StreamBase* wrap = StreamBase::FromObject(args.This().As<Object>());
if (wrap == nullptr) return;

Local<External> ext = External::New(args.GetIsolate(), wrap);
args.GetReturnValue().Set(ext);
}

template <int (StreamBase::*Method)(const FunctionCallbackInfo<Value>& args)>
void StreamBase::JSMethod(const FunctionCallbackInfo<Value>& args) {
StreamBase* wrap = StreamBase::FromObject(args.Holder().As<Object>());
if (wrap == nullptr) return;

if (!wrap->IsAlive()) return args.GetReturnValue().Set(UV_EINVAL);

AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(wrap->GetAsyncWrap());
args.GetReturnValue().Set((wrap->*Method)(args));
}

int StreamResource::DoTryWrite(uv_buf_t** bufs, size_t* count) {
// No TryWrite by default
Expand Down
26 changes: 14 additions & 12 deletions src/stream_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ struct StreamWriteResult {
size_t bytes;
};

using JSMethodFunction = void(const v8::FunctionCallbackInfo<v8::Value>& args);

class StreamReq {
public:
Expand Down Expand Up @@ -259,9 +260,9 @@ class StreamResource {

class StreamBase : public StreamResource {
public:
template <class Base>
static inline void AddMethods(Environment* env,
v8::Local<v8::FunctionTemplate> target);
static constexpr int kStreamBaseField = 1;
static void AddMethods(Environment* env,
v8::Local<v8::FunctionTemplate> target);

virtual bool IsAlive() = 0;
virtual bool IsClosing() = 0;
Expand Down Expand Up @@ -305,6 +306,8 @@ class StreamBase : public StreamResource {
virtual AsyncWrap* GetAsyncWrap() = 0;
virtual v8::Local<v8::Object> GetObject();

static StreamBase* FromObject(v8::Local<v8::Object> obj);

protected:
explicit StreamBase(Environment* env);

Expand All @@ -317,20 +320,13 @@ class StreamBase : public StreamResource {
template <enum encoding enc>
int WriteString(const v8::FunctionCallbackInfo<v8::Value>& args);

template <class Base>
static void GetFD(const v8::FunctionCallbackInfo<v8::Value>& args);

template <class Base>
static void GetExternal(const v8::FunctionCallbackInfo<v8::Value>& args);

template <class Base>
static void GetBytesRead(const v8::FunctionCallbackInfo<v8::Value>& args);

template <class Base>
static void GetBytesWritten(const v8::FunctionCallbackInfo<v8::Value>& args);
void AttachToObject(v8::Local<v8::Object> obj);

template <class Base,
int (StreamBase::*Method)(
template <int (StreamBase::*Method)(
const v8::FunctionCallbackInfo<v8::Value>& args)>
static void JSMethod(const v8::FunctionCallbackInfo<v8::Value>& args);

Expand All @@ -348,6 +344,12 @@ class StreamBase : public StreamResource {
EmitToJSStreamListener default_listener_;

void SetWriteResult(const StreamWriteResult& res);
static void AddMethod(Environment* env,
v8::Local<v8::Signature> sig,
enum v8::PropertyAttribute attributes,
v8::Local<v8::FunctionTemplate> t,
JSMethodFunction* stream_method,
v8::Local<v8::String> str);

friend class WriteWrap;
friend class ShutdownWrap;
Expand Down
Loading

0 comments on commit 3b06d29

Please sign in to comment.