Skip to content

Commit fe36076

Browse files
committed
stream_base: WriteWrap::New/::Dispose
Encapsulate allocation/disposal of `WriteWrap` instances into the `WriteWrap` class itself. PR-URL: #1090 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
1 parent 7f4c95e commit fe36076

File tree

4 files changed

+72
-47
lines changed

4 files changed

+72
-47
lines changed

src/stream_base-inl.h

+26
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ using v8::FunctionTemplate;
1515
using v8::Handle;
1616
using v8::HandleScope;
1717
using v8::Local;
18+
using v8::Object;
1819
using v8::PropertyAttribute;
1920
using v8::PropertyCallbackInfo;
2021
using v8::String;
@@ -82,6 +83,31 @@ void StreamBase::JSMethod(const FunctionCallbackInfo<Value>& args) {
8283
args.GetReturnValue().Set((wrap->*Method)(args));
8384
}
8485

86+
87+
WriteWrap* WriteWrap::New(Environment* env,
88+
Local<Object> obj,
89+
StreamBase* wrap,
90+
DoneCb cb,
91+
size_t extra) {
92+
size_t storage_size = ROUND_UP(sizeof(WriteWrap), kAlignSize) + extra;
93+
char* storage = new char[storage_size];
94+
95+
return new(storage) WriteWrap(env, obj, wrap, cb);
96+
}
97+
98+
99+
void WriteWrap::Dispose() {
100+
this->~WriteWrap();
101+
delete[] reinterpret_cast<char*>(this);
102+
}
103+
104+
105+
char* WriteWrap::Extra(size_t offset) {
106+
return reinterpret_cast<char*>(this) +
107+
ROUND_UP(sizeof(*this), kAlignSize) +
108+
offset;
109+
}
110+
85111
} // namespace node
86112

87113
#endif // SRC_STREAM_BASE_INL_H_

src/stream_base.cc

+23-31
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "stream_base.h"
2+
#include "stream_base-inl.h"
23
#include "stream_wrap.h"
34

45
#include "node.h"
@@ -108,6 +109,8 @@ int StreamBase::Writev(const FunctionCallbackInfo<Value>& args) {
108109
// Determine storage size first
109110
size_t storage_size = 0;
110111
for (size_t i = 0; i < count; i++) {
112+
storage_size = ROUND_UP(storage_size, WriteWrap::kAlignSize);
113+
111114
Handle<Value> chunk = chunks->Get(i * 2);
112115

113116
if (Buffer::HasInstance(chunk))
@@ -124,7 +127,7 @@ int StreamBase::Writev(const FunctionCallbackInfo<Value>& args) {
124127
else
125128
chunk_size = StringBytes::StorageSize(env->isolate(), string, encoding);
126129

127-
storage_size += chunk_size + 15;
130+
storage_size += chunk_size;
128131
}
129132

130133
if (storage_size > INT_MAX)
@@ -133,13 +136,14 @@ int StreamBase::Writev(const FunctionCallbackInfo<Value>& args) {
133136
if (ARRAY_SIZE(bufs_) < count)
134137
bufs = new uv_buf_t[count];
135138

136-
storage_size += sizeof(WriteWrap);
137-
char* storage = new char[storage_size];
138-
WriteWrap* req_wrap =
139-
new(storage) WriteWrap(env, req_wrap_obj, this, AfterWrite);
139+
WriteWrap* req_wrap = WriteWrap::New(env,
140+
req_wrap_obj,
141+
this,
142+
AfterWrite,
143+
storage_size);
140144

141145
uint32_t bytes = 0;
142-
size_t offset = sizeof(WriteWrap);
146+
size_t offset = 0;
143147
for (size_t i = 0; i < count; i++) {
144148
Handle<Value> chunk = chunks->Get(i * 2);
145149

@@ -152,9 +156,9 @@ int StreamBase::Writev(const FunctionCallbackInfo<Value>& args) {
152156
}
153157

154158
// Write string
155-
offset = ROUND_UP(offset, 16);
159+
offset = ROUND_UP(offset, WriteWrap::kAlignSize);
156160
CHECK_LT(offset, storage_size);
157-
char* str_storage = storage + offset;
161+
char* str_storage = req_wrap->Extra(offset);
158162
size_t str_size = storage_size - offset;
159163

160164
Handle<String> string = chunk->ToString(env->isolate());
@@ -187,10 +191,8 @@ int StreamBase::Writev(const FunctionCallbackInfo<Value>& args) {
187191
ClearError();
188192
}
189193

190-
if (err) {
191-
req_wrap->~WriteWrap();
192-
delete[] storage;
193-
}
194+
if (err)
195+
req_wrap->Dispose();
194196

195197
return err;
196198
}
@@ -207,7 +209,6 @@ int StreamBase::WriteBuffer(const FunctionCallbackInfo<Value>& args) {
207209
const char* data = Buffer::Data(args[1]);
208210
size_t length = Buffer::Length(args[1]);
209211

210-
char* storage;
211212
WriteWrap* req_wrap;
212213
uv_buf_t buf;
213214
buf.base = const_cast<char*>(data);
@@ -224,17 +225,14 @@ int StreamBase::WriteBuffer(const FunctionCallbackInfo<Value>& args) {
224225
CHECK_EQ(count, 1);
225226

226227
// Allocate, or write rest
227-
storage = new char[sizeof(WriteWrap)];
228-
req_wrap = new(storage) WriteWrap(env, req_wrap_obj, this, AfterWrite);
228+
req_wrap = WriteWrap::New(env, req_wrap_obj, this, AfterWrite);
229229

230230
err = DoWrite(req_wrap, bufs, count, nullptr);
231231
req_wrap->Dispatched();
232232
req_wrap_obj->Set(env->async(), True(env->isolate()));
233233

234-
if (err) {
235-
req_wrap->~WriteWrap();
236-
delete[] storage;
237-
}
234+
if (err)
235+
req_wrap->Dispose();
238236

239237
done:
240238
const char* msg = Error();
@@ -275,14 +273,13 @@ int StreamBase::WriteString(const FunctionCallbackInfo<Value>& args) {
275273
return UV_ENOBUFS;
276274

277275
// Try writing immediately if write size isn't too big
278-
char* storage;
279276
WriteWrap* req_wrap;
280277
char* data;
281278
char stack_storage[16384]; // 16kb
282279
size_t data_size;
283280
uv_buf_t buf;
284281

285-
bool try_write = storage_size + 15 <= sizeof(stack_storage) &&
282+
bool try_write = storage_size <= sizeof(stack_storage) &&
286283
(!IsIPCPipe() || send_handle_obj.IsEmpty());
287284
if (try_write) {
288285
data_size = StringBytes::Write(env->isolate(),
@@ -308,11 +305,9 @@ int StreamBase::WriteString(const FunctionCallbackInfo<Value>& args) {
308305
CHECK_EQ(count, 1);
309306
}
310307

311-
storage = new char[sizeof(WriteWrap) + storage_size + 15];
312-
req_wrap = new(storage) WriteWrap(env, req_wrap_obj, this, AfterWrite);
308+
req_wrap = WriteWrap::New(env, req_wrap_obj, this, AfterWrite, storage_size);
313309

314-
data = reinterpret_cast<char*>(ROUND_UP(
315-
reinterpret_cast<uintptr_t>(storage) + sizeof(WriteWrap), 16));
310+
data = req_wrap->Extra();
316311

317312
if (try_write) {
318313
// Copy partial data
@@ -355,10 +350,8 @@ int StreamBase::WriteString(const FunctionCallbackInfo<Value>& args) {
355350
req_wrap->Dispatched();
356351
req_wrap->object()->Set(env->async(), True(env->isolate()));
357352

358-
if (err) {
359-
req_wrap->~WriteWrap();
360-
delete[] storage;
361-
}
353+
if (err)
354+
req_wrap->Dispose();
362355

363356
done:
364357
const char* msg = Error();
@@ -404,8 +397,7 @@ void StreamBase::AfterWrite(WriteWrap* req_wrap, int status) {
404397
if (req_wrap->object()->Has(env->oncomplete_string()))
405398
req_wrap->MakeCallback(env->oncomplete_string(), ARRAY_SIZE(argv), argv);
406399

407-
req_wrap->~WriteWrap();
408-
delete[] reinterpret_cast<char*>(req_wrap);
400+
req_wrap->Dispose();
409401
}
410402

411403

src/stream_base.h

+18-9
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,23 @@ class ShutdownWrap : public ReqWrap<uv_shutdown_t>,
5656
class WriteWrap: public ReqWrap<uv_write_t>,
5757
public StreamReq<WriteWrap> {
5858
public:
59+
static inline WriteWrap* New(Environment* env,
60+
v8::Local<v8::Object> obj,
61+
StreamBase* wrap,
62+
DoneCb cb,
63+
size_t extra = 0);
64+
inline void Dispose();
65+
inline char* Extra(size_t offset = 0);
66+
67+
inline StreamBase* wrap() const { return wrap_; }
68+
69+
static void NewWriteWrap(const v8::FunctionCallbackInfo<v8::Value>& args) {
70+
CHECK(args.IsConstructCall());
71+
}
72+
73+
static const size_t kAlignSize = 16;
74+
75+
protected:
5976
WriteWrap(Environment* env,
6077
v8::Local<v8::Object> obj,
6178
StreamBase* wrap,
@@ -66,24 +83,16 @@ class WriteWrap: public ReqWrap<uv_write_t>,
6683
Wrap(obj, this);
6784
}
6885

86+
void* operator new(size_t size) = delete;
6987
void* operator new(size_t size, char* storage) { return storage; }
7088

7189
// This is just to keep the compiler happy. It should never be called, since
7290
// we don't use exceptions in node.
7391
void operator delete(void* ptr, char* storage) { UNREACHABLE(); }
7492

75-
inline StreamBase* wrap() const {
76-
return wrap_;
77-
}
78-
79-
static void NewWriteWrap(const v8::FunctionCallbackInfo<v8::Value>& args) {
80-
CHECK(args.IsConstructCall());
81-
}
82-
8393
private:
8494
// People should not be using the non-placement new and delete operator on a
8595
// WriteWrap. Ensure this never happens.
86-
void* operator new(size_t size) { UNREACHABLE(); }
8796
void operator delete(void* ptr) { UNREACHABLE(); }
8897

8998
StreamBase* const wrap_;

src/tls_wrap.cc

+5-7
Original file line numberDiff line numberDiff line change
@@ -295,11 +295,10 @@ void TLSWrap::EncOut() {
295295

296296
Local<Object> req_wrap_obj =
297297
env()->write_wrap_constructor_function()->NewInstance();
298-
char* storage = new char[sizeof(WriteWrap)];
299-
WriteWrap* write_req = new(storage) WriteWrap(env(),
300-
req_wrap_obj,
301-
this,
302-
EncOutCb);
298+
WriteWrap* write_req = WriteWrap::New(env(),
299+
req_wrap_obj,
300+
this,
301+
EncOutCb);
303302

304303
uv_buf_t buf[ARRAY_SIZE(data)];
305304
for (size_t i = 0; i < count; i++)
@@ -315,8 +314,7 @@ void TLSWrap::EncOut() {
315314

316315
void TLSWrap::EncOutCb(WriteWrap* req_wrap, int status) {
317316
TLSWrap* wrap = req_wrap->wrap()->Cast<TLSWrap>();
318-
req_wrap->~WriteWrap();
319-
delete[] reinterpret_cast<char*>(req_wrap);
317+
req_wrap->Dispose();
320318

321319
// Handle error
322320
if (status) {

0 commit comments

Comments
 (0)