using v8::Handle;
using v8::HandleScope;
using v8::Local;
+using v8::Object;
using v8::PropertyAttribute;
using v8::PropertyCallbackInfo;
using v8::String;
args.GetReturnValue().Set((wrap->*Method)(args));
}
+
+WriteWrap* WriteWrap::New(Environment* env,
+ Local<Object> obj,
+ StreamBase* wrap,
+ DoneCb cb,
+ size_t extra) {
+ size_t storage_size = ROUND_UP(sizeof(WriteWrap), kAlignSize) + extra;
+ char* storage = new char[storage_size];
+
+ return new(storage) WriteWrap(env, obj, wrap, cb);
+}
+
+
+void WriteWrap::Dispose() {
+ this->~WriteWrap();
+ delete[] reinterpret_cast<char*>(this);
+}
+
+
+char* WriteWrap::Extra(size_t offset) {
+ return reinterpret_cast<char*>(this) +
+ ROUND_UP(sizeof(*this), kAlignSize) +
+ offset;
+}
+
} // namespace node
#endif // SRC_STREAM_BASE_INL_H_
#include "stream_base.h"
+#include "stream_base-inl.h"
#include "stream_wrap.h"
#include "node.h"
// Determine storage size first
size_t storage_size = 0;
for (size_t i = 0; i < count; i++) {
+ storage_size = ROUND_UP(storage_size, WriteWrap::kAlignSize);
+
Handle<Value> chunk = chunks->Get(i * 2);
if (Buffer::HasInstance(chunk))
else
chunk_size = StringBytes::StorageSize(env->isolate(), string, encoding);
- storage_size += chunk_size + 15;
+ storage_size += chunk_size;
}
if (storage_size > INT_MAX)
if (ARRAY_SIZE(bufs_) < count)
bufs = new uv_buf_t[count];
- storage_size += sizeof(WriteWrap);
- char* storage = new char[storage_size];
- WriteWrap* req_wrap =
- new(storage) WriteWrap(env, req_wrap_obj, this, AfterWrite);
+ WriteWrap* req_wrap = WriteWrap::New(env,
+ req_wrap_obj,
+ this,
+ AfterWrite,
+ storage_size);
uint32_t bytes = 0;
- size_t offset = sizeof(WriteWrap);
+ size_t offset = 0;
for (size_t i = 0; i < count; i++) {
Handle<Value> chunk = chunks->Get(i * 2);
}
// Write string
- offset = ROUND_UP(offset, 16);
+ offset = ROUND_UP(offset, WriteWrap::kAlignSize);
CHECK_LT(offset, storage_size);
- char* str_storage = storage + offset;
+ char* str_storage = req_wrap->Extra(offset);
size_t str_size = storage_size - offset;
Handle<String> string = chunk->ToString(env->isolate());
ClearError();
}
- if (err) {
- req_wrap->~WriteWrap();
- delete[] storage;
- }
+ if (err)
+ req_wrap->Dispose();
return err;
}
const char* data = Buffer::Data(args[1]);
size_t length = Buffer::Length(args[1]);
- char* storage;
WriteWrap* req_wrap;
uv_buf_t buf;
buf.base = const_cast<char*>(data);
CHECK_EQ(count, 1);
// Allocate, or write rest
- storage = new char[sizeof(WriteWrap)];
- req_wrap = new(storage) WriteWrap(env, req_wrap_obj, this, AfterWrite);
+ req_wrap = WriteWrap::New(env, req_wrap_obj, this, AfterWrite);
err = DoWrite(req_wrap, bufs, count, nullptr);
req_wrap->Dispatched();
req_wrap_obj->Set(env->async(), True(env->isolate()));
- if (err) {
- req_wrap->~WriteWrap();
- delete[] storage;
- }
+ if (err)
+ req_wrap->Dispose();
done:
const char* msg = Error();
return UV_ENOBUFS;
// Try writing immediately if write size isn't too big
- char* storage;
WriteWrap* req_wrap;
char* data;
char stack_storage[16384]; // 16kb
size_t data_size;
uv_buf_t buf;
- bool try_write = storage_size + 15 <= sizeof(stack_storage) &&
+ bool try_write = storage_size <= sizeof(stack_storage) &&
(!IsIPCPipe() || send_handle_obj.IsEmpty());
if (try_write) {
data_size = StringBytes::Write(env->isolate(),
CHECK_EQ(count, 1);
}
- storage = new char[sizeof(WriteWrap) + storage_size + 15];
- req_wrap = new(storage) WriteWrap(env, req_wrap_obj, this, AfterWrite);
+ req_wrap = WriteWrap::New(env, req_wrap_obj, this, AfterWrite, storage_size);
- data = reinterpret_cast<char*>(ROUND_UP(
- reinterpret_cast<uintptr_t>(storage) + sizeof(WriteWrap), 16));
+ data = req_wrap->Extra();
if (try_write) {
// Copy partial data
req_wrap->Dispatched();
req_wrap->object()->Set(env->async(), True(env->isolate()));
- if (err) {
- req_wrap->~WriteWrap();
- delete[] storage;
- }
+ if (err)
+ req_wrap->Dispose();
done:
const char* msg = Error();
if (req_wrap->object()->Has(env->oncomplete_string()))
req_wrap->MakeCallback(env->oncomplete_string(), ARRAY_SIZE(argv), argv);
- req_wrap->~WriteWrap();
- delete[] reinterpret_cast<char*>(req_wrap);
+ req_wrap->Dispose();
}
class WriteWrap: public ReqWrap<uv_write_t>,
public StreamReq<WriteWrap> {
public:
+ static inline WriteWrap* New(Environment* env,
+ v8::Local<v8::Object> obj,
+ StreamBase* wrap,
+ DoneCb cb,
+ size_t extra = 0);
+ inline void Dispose();
+ inline char* Extra(size_t offset = 0);
+
+ inline StreamBase* wrap() const { return wrap_; }
+
+ static void NewWriteWrap(const v8::FunctionCallbackInfo<v8::Value>& args) {
+ CHECK(args.IsConstructCall());
+ }
+
+ static const size_t kAlignSize = 16;
+
+ protected:
WriteWrap(Environment* env,
v8::Local<v8::Object> obj,
StreamBase* wrap,
Wrap(obj, this);
}
+ void* operator new(size_t size) = delete;
void* operator new(size_t size, char* storage) { return storage; }
// This is just to keep the compiler happy. It should never be called, since
// we don't use exceptions in node.
void operator delete(void* ptr, char* storage) { UNREACHABLE(); }
- inline StreamBase* wrap() const {
- return wrap_;
- }
-
- static void NewWriteWrap(const v8::FunctionCallbackInfo<v8::Value>& args) {
- CHECK(args.IsConstructCall());
- }
-
private:
// People should not be using the non-placement new and delete operator on a
// WriteWrap. Ensure this never happens.
- void* operator new(size_t size) { UNREACHABLE(); }
void operator delete(void* ptr) { UNREACHABLE(); }
StreamBase* const wrap_;