buffer: add NativeBuffer API

Due to a lot of the util.is* checks there was much unnecessary overhead
for the most common use case of Buffer. Which is creating a new Buffer
instance for data from incoming I/O. NativeBuffer is a simple way to
bypass all the unneeded checks and simply hand back a Buffer instance
while setting the length.
This commit is contained in:
Trevor Norris 2013-08-26 03:20:23 -07:00
parent 9ac75d1f06
commit 16a60ed2a3
2 changed files with 23 additions and 37 deletions

View File

@ -31,8 +31,6 @@ exports.Buffer = Buffer;
exports.SlowBuffer = SlowBuffer;
exports.INSPECT_MAX_BYTES = 50;
// add methods to Buffer prototype
buffer.setupBufferJS(Buffer, internal);
Buffer.poolSize = 8 * 1024;
var poolSize = Buffer.poolSize;
@ -57,13 +55,6 @@ function Buffer(subject, encoding) {
this.length = Buffer.byteLength(subject, encoding = encoding || 'utf8');
else if (util.isObject(subject))
this.length = +subject.length > 0 ? Math.floor(+subject.length) : 0;
else if (util.isUndefined(subject)) {
// undef first arg returns unallocated buffer, also assumes length passed.
// this is a stop-gap for now while look for better architecture.
// for internal use only.
this.length = encoding;
return;
}
else
throw new TypeError('must start with number, buffer, array or string');
@ -99,12 +90,25 @@ function Buffer(subject, encoding) {
function SlowBuffer(length) {
length = ~~length;
var b = new Buffer(undefined, length);
var b = new NativeBuffer(length);
alloc(b, length);
return b;
}
// Bypass all checks for instantiating unallocated Buffer required for
// Objects created in C++. Significantly faster than calling the Buffer
// function.
function NativeBuffer(length) {
this.length = length;
}
NativeBuffer.prototype = Buffer.prototype;
// add methods to Buffer prototype
buffer.setupBufferJS(NativeBuffer, internal);
// Static methods
Buffer.isBuffer = function isBuffer(b) {
@ -386,7 +390,7 @@ Buffer.prototype.slice = function(start, end) {
if (end < start)
end = start;
var buf = new Buffer();
var buf = new NativeBuffer();
sliceOnto(this, buf, start, end);
buf.length = end - start;
if (buf.length > 0)

View File

@ -124,19 +124,13 @@ Local<Object> New(Handle<String> string, enum encoding enc) {
}
// TODO(trevnorris): these have a flaw by needing to call the Buffer inst then
// Alloc. continue to look for a better architecture.
Local<Object> New(size_t length) {
HandleScope scope(node_isolate);
assert(length <= kMaxLength);
Handle<Value> argv[2];
// this is safe b/c Undefined and length fits in an SMI, so there's no risk
// of GC reclaiming the values prematurely.
argv[0] = Undefined(node_isolate);
argv[1] = Uint32::New(length, node_isolate);
Local<Object> obj = NewInstance(p_buffer_fn, ARRAY_SIZE(argv), argv);
Local<Value> arg = Uint32::NewFromUnsigned(length, node_isolate);
Local<Object> obj = NewInstance(p_buffer_fn, 1, &arg);
// TODO(trevnorris): done like this to handle HasInstance since only checks
// if external array data has been set, but would like to use a better
@ -163,12 +157,8 @@ Local<Object> New(const char* data, size_t length) {
assert(length <= kMaxLength);
Handle<Value> argv[2];
// this is safe b/c Undefined and length fits in an SMI, so there's no risk
// of GC reclaiming the values prematurely.
argv[0] = Undefined(node_isolate);
argv[1] = Uint32::New(length, node_isolate);
Local<Object> obj = NewInstance(p_buffer_fn, ARRAY_SIZE(argv), argv);
Local<Value> arg = Uint32::NewFromUnsigned(length, node_isolate);
Local<Object> obj = NewInstance(p_buffer_fn, 1, &arg);
// TODO(trevnorris): done like this to handle HasInstance since only checks
// if external array data has been set, but would like to use a better
@ -197,12 +187,8 @@ Local<Object> New(char* data,
assert(length <= kMaxLength);
Handle<Value> argv[2];
// this is safe b/c Undefined and length fits in an SMI, so there's no risk
// of GC reclaiming the values prematurely.
argv[0] = Undefined(node_isolate);
argv[1] = Uint32::New(length, node_isolate);
Local<Object> obj = NewInstance(p_buffer_fn, ARRAY_SIZE(argv), argv);
Local<Value> arg = Uint32::NewFromUnsigned(length, node_isolate);
Local<Object> obj = NewInstance(p_buffer_fn, 1, &arg);
smalloc::Alloc(obj, data, length, callback, hint);
@ -215,12 +201,8 @@ Local<Object> Use(char* data, uint32_t length) {
assert(length <= kMaxLength);
Handle<Value> argv[2];
// this is safe b/c Undefined and length fits in an SMI, so there's no risk
// of GC reclaiming the values prematurely.
argv[0] = Undefined(node_isolate);
argv[1] = Uint32::New(length, node_isolate);
Local<Object> obj = NewInstance(p_buffer_fn, ARRAY_SIZE(argv), argv);
Local<Value> arg = Uint32::NewFromUnsigned(length, node_isolate);
Local<Object> obj = NewInstance(p_buffer_fn, 1, &arg);
smalloc::Alloc(obj, data, length);