buffer: implement Uint8Array backed Buffer
authorTrevor Norris <trev.norris@gmail.com>
Tue, 26 May 2015 18:42:14 +0000 (12:42 -0600)
committerRod Vagg <rod@vagg.org>
Tue, 4 Aug 2015 18:56:10 +0000 (11:56 -0700)
With V8 4.4 removing the external array data API currently used by
Buffer, the new implementation uses the Uint8Array to back Buffer.

Buffers now have a maximum size of Smi::kMaxLength, as defined by V8.
Which is ~2 GB on 64 bit and ~1 GB on 32 bit.

The flag --use-old-buffer allows using the old Buffer implementation.
This flag will be removed once V8 4.4 has landed.

The two JS Buffer implementations have been split into two files for
simplicity.

Use getter to return expected .parent/.offset values for backwards
compatibility.

PR-URL: https://github.com/nodejs/io.js/pull/1825
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
13 files changed:
lib/buffer.js
lib/internal/buffer_new.js [new file with mode: 0644]
lib/internal/buffer_old.js [new file with mode: 0644]
node.gyp
src/env.h
src/node.cc
src/node_buffer.cc
src/node_buffer.h
src/node_internals.h
src/util-inl.h
src/util.h
test/parallel/test-buffer-slice.js [deleted file]
test/parallel/test-buffer.js

index 568a1f4..641b542 100644 (file)
 /* eslint-disable require-buffer */
 'use strict';
 
-const binding = process.binding('buffer');
-const smalloc = process.binding('smalloc');
-const internalUtil = require('internal/util');
-const alloc = smalloc.alloc;
-const truncate = smalloc.truncate;
-const sliceOnto = smalloc.sliceOnto;
-const kMaxLength = smalloc.kMaxLength;
-
-exports.Buffer = Buffer;
-exports.SlowBuffer = SlowBuffer;
-exports.INSPECT_MAX_BYTES = 50;
-
-
-Buffer.poolSize = 8 * 1024;
-var poolSize, poolOffset, allocPool;
-
-
-function createPool() {
-  poolSize = Buffer.poolSize;
-  allocPool = alloc({}, poolSize);
-  poolOffset = 0;
-}
-createPool();
-
-function Buffer(arg) {
-  if (!(this instanceof Buffer)) {
-    // Avoid going through an ArgumentsAdaptorTrampoline in the common case.
-    if (arguments.length > 1)
-      return new Buffer(arg, arguments[1]);
-
-    return new Buffer(arg);
-  }
-
-  this.length = 0;
-  this.parent = undefined;
-
-  // Common case.
-  if (typeof(arg) === 'number') {
-    fromNumber(this, arg);
-    return;
-  }
-
-  // Slightly less common case.
-  if (typeof(arg) === 'string') {
-    fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8');
-    return;
-  }
-
-  // Unusual.
-  fromObject(this, arg);
-}
-
-function fromNumber(that, length) {
-  allocate(that, length < 0 ? 0 : checked(length) | 0);
-}
-
-function fromString(that, string, encoding) {
-  if (typeof(encoding) !== 'string' || encoding === '')
-    encoding = 'utf8';
-
-  // Assumption: byteLength() return value is always < kMaxLength.
-  var length = byteLength(string, encoding) | 0;
-  allocate(that, length);
-
-  var actual = that.write(string, encoding) | 0;
-  if (actual !== length) {
-    // Fix up for truncated base64 input.  Don't bother returning
-    // the unused two or three bytes to the pool.
-    that.length = actual;
-    truncate(that, actual);
-  }
-}
-
-function fromObject(that, object) {
-  if (object instanceof Buffer)
-    return fromBuffer(that, object);
-
-  if (Array.isArray(object))
-    return fromArray(that, object);
-
-  if (object == null)
-    throw new TypeError('must start with number, buffer, array or string');
-
-  if (object.buffer instanceof ArrayBuffer)
-    return fromTypedArray(that, object);
-
-  if (object.length)
-    return fromArrayLike(that, object);
-
-  return fromJsonObject(that, object);
-}
-
-function fromBuffer(that, buffer) {
-  var length = checked(buffer.length) | 0;
-  allocate(that, length);
-  buffer.copy(that, 0, 0, length);
-}
-
-function fromArray(that, array) {
-  var length = checked(array.length) | 0;
-  allocate(that, length);
-  for (var i = 0; i < length; i += 1)
-    that[i] = array[i] & 255;
-}
-
-// Duplicate of fromArray() to keep fromArray() monomorphic.
-function fromTypedArray(that, array) {
-  var length = checked(array.length) | 0;
-  allocate(that, length);
-  // Truncating the elements is probably not what people expect from typed
-  // arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior
-  // of the old Buffer constructor.
-  for (var i = 0; i < length; i += 1)
-    that[i] = array[i] & 255;
-}
-
-function fromArrayLike(that, array) {
-  var length = checked(array.length) | 0;
-  allocate(that, length);
-  for (var i = 0; i < length; i += 1)
-    that[i] = array[i] & 255;
-}
-
-// Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object.
-// Returns a zero-length buffer for inputs that don't conform to the spec.
-function fromJsonObject(that, object) {
-  var array;
-  var length = 0;
-
-  if (object.type === 'Buffer' && Array.isArray(object.data)) {
-    array = object.data;
-    length = checked(array.length) | 0;
-  }
-  allocate(that, length);
-
-  for (var i = 0; i < length; i += 1)
-    that[i] = array[i] & 255;
-}
-
-function allocate(that, length) {
-  var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1;
-  if (fromPool)
-    that.parent = palloc(that, length);
-  else
-    alloc(that, length);
-  that.length = length;
-}
-
-function palloc(that, length) {
-  if (length > poolSize - poolOffset)
-    createPool();
-
-  var start = poolOffset;
-  var end = start + length;
-  var buf = sliceOnto(allocPool, that, start, end);
-  poolOffset = end;
-
-  // Ensure aligned slices
-  if (poolOffset & 0x7) {
-    poolOffset |= 0x7;
-    poolOffset++;
-  }
-
-  return buf;
-}
-
-function checked(length) {
-  // Note: cannot use `length < kMaxLength` here because that fails when
-  // length is NaN (which is otherwise coerced to zero.)
-  if (length >= kMaxLength) {
-    throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
-                         'size: 0x' + kMaxLength.toString(16) + ' bytes');
-  }
-  return length >>> 0;
-}
-
-function SlowBuffer(length) {
-  length = length >>> 0;
-  if (length > kMaxLength) {
-    throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
-                         'size: 0x' + kMaxLength.toString(16) + ' bytes');
-  }
-  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 >>> 0;
-  // Set this to keep the object map the same.
-  this.parent = undefined;
-}
-NativeBuffer.prototype = Buffer.prototype;
-
-
-// add methods to Buffer prototype
-binding.setupBufferJS(NativeBuffer);
-
-
-// Static methods
-
-Buffer.isBuffer = function isBuffer(b) {
-  return b instanceof Buffer;
-};
-
-
-Buffer.compare = function compare(a, b) {
-  if (!(a instanceof Buffer) ||
-      !(b instanceof Buffer))
-    throw new TypeError('Arguments must be Buffers');
-
-  if (a === b)
-    return 0;
-
-  return binding.compare(a, b);
-};
-
-
-Buffer.isEncoding = function(encoding) {
-  switch ((encoding + '').toLowerCase()) {
-    case 'hex':
-    case 'utf8':
-    case 'utf-8':
-    case 'ascii':
-    case 'binary':
-    case 'base64':
-    case 'ucs2':
-    case 'ucs-2':
-    case 'utf16le':
-    case 'utf-16le':
-    case 'raw':
-      return true;
-
-    default:
-      return false;
-  }
-};
-
-
-Buffer.concat = function(list, length) {
-  if (!Array.isArray(list))
-    throw new TypeError('list argument must be an Array of Buffers.');
-
-  if (list.length === 0)
-    return new Buffer(0);
-  else if (list.length === 1)
-    return list[0];
-
-  if (length === undefined) {
-    length = 0;
-    for (var i = 0; i < list.length; i++)
-      length += list[i].length;
-  } else {
-    length = length >>> 0;
-  }
-
-  var buffer = new Buffer(length);
-  var pos = 0;
-  for (var i = 0; i < list.length; i++) {
-    var buf = list[i];
-    buf.copy(buffer, pos);
-    pos += buf.length;
-  }
-
-  return buffer;
-};
-
-
-function base64ByteLength(str, bytes) {
-  // Handle padding
-  if (str.charCodeAt(bytes - 1) === 0x3D)
-    bytes--;
-  if (bytes > 1 && str.charCodeAt(bytes - 1) === 0x3D)
-    bytes--;
-
-  // Base64 ratio: 3/4
-  return (bytes * 3) >>> 2;
-}
-
-
-function byteLength(string, encoding) {
-  if (typeof string !== 'string')
-    string = '' + string;
-
-  var len = string.length;
-  if (len === 0)
-    return 0;
-
-  // Use a for loop to avoid recursion
-  var loweredCase = false;
-  for (;;) {
-    switch (encoding) {
-      case 'ascii':
-      case 'binary':
-      // Deprecated
-      case 'raw':
-      case 'raws':
-        return len;
-
-      case 'utf8':
-      case 'utf-8':
-        return binding.byteLengthUtf8(string);
-
-      case 'ucs2':
-      case 'ucs-2':
-      case 'utf16le':
-      case 'utf-16le':
-        return len * 2;
-
-      case 'hex':
-        return len >>> 1;
-
-      case 'base64':
-        return base64ByteLength(string, len);
-
-      default:
-        // The C++ binding defaulted to UTF8, we should too.
-        if (loweredCase)
-          return binding.byteLengthUtf8(string);
-
-        encoding = ('' + encoding).toLowerCase();
-        loweredCase = true;
-    }
-  }
-}
-
-Buffer.byteLength = byteLength;
-
-function slowToString(encoding, start, end) {
-  var loweredCase = false;
-
-  start = start >>> 0;
-  end = end === undefined || end === Infinity ? this.length : end >>> 0;
-
-  if (!encoding) encoding = 'utf8';
-  if (start < 0) start = 0;
-  if (end > this.length) end = this.length;
-  if (end <= start) return '';
-
-  while (true) {
-    switch (encoding) {
-      case 'hex':
-        return this.hexSlice(start, end);
-
-      case 'utf8':
-      case 'utf-8':
-        return this.utf8Slice(start, end);
-
-      case 'ascii':
-        return this.asciiSlice(start, end);
-
-      case 'binary':
-        return this.binarySlice(start, end);
-
-      case 'base64':
-        return this.base64Slice(start, end);
-
-      case 'ucs2':
-      case 'ucs-2':
-      case 'utf16le':
-      case 'utf-16le':
-        return this.ucs2Slice(start, end);
-
-      default:
-        if (loweredCase)
-          throw new TypeError('Unknown encoding: ' + encoding);
-        encoding = (encoding + '').toLowerCase();
-        loweredCase = true;
-    }
-  }
-}
-
-
-Buffer.prototype.toString = function() {
-  const length = this.length | 0;
-  if (arguments.length === 0)
-    return this.utf8Slice(0, length);
-  return slowToString.apply(this, arguments);
-};
-
-
-Buffer.prototype.equals = function equals(b) {
-  if (!(b instanceof Buffer))
-    throw new TypeError('Argument must be a Buffer');
-
-  if (this === b)
-    return true;
-
-  return binding.compare(this, b) === 0;
-};
-
-
-// Inspect
-Buffer.prototype.inspect = function inspect() {
-  var str = '';
-  var max = exports.INSPECT_MAX_BYTES;
-  if (this.length > 0) {
-    str = this.toString('hex', 0, max).match(/.{2}/g).join(' ');
-    if (this.length > max)
-      str += ' ... ';
-  }
-  return '<' + this.constructor.name + ' ' + str + '>';
-};
-
-
-Buffer.prototype.compare = function compare(b) {
-  if (!(b instanceof Buffer))
-    throw new TypeError('Argument must be a Buffer');
-
-  if (this === b)
-    return 0;
-
-  return binding.compare(this, b);
-};
-
-
-Buffer.prototype.indexOf = function indexOf(val, byteOffset) {
-  if (byteOffset > 0x7fffffff)
-    byteOffset = 0x7fffffff;
-  else if (byteOffset < -0x80000000)
-    byteOffset = -0x80000000;
-  byteOffset >>= 0;
-
-  if (typeof val === 'string')
-    return binding.indexOfString(this, val, byteOffset);
-  if (val instanceof Buffer)
-    return binding.indexOfBuffer(this, val, byteOffset);
-  if (typeof val === 'number')
-    return binding.indexOfNumber(this, val, byteOffset);
-
-  throw new TypeError('val must be string, number or Buffer');
-};
-
-
-Buffer.prototype.fill = function fill(val, start, end) {
-  start = start >> 0;
-  end = (end === undefined) ? this.length : end >> 0;
-
-  if (start < 0 || end > this.length)
-    throw new RangeError('out of range index');
-  if (end <= start)
-    return this;
-
-  if (typeof val !== 'string') {
-    val = val >>> 0;
-  } else if (val.length === 1) {
-    var code = val.charCodeAt(0);
-    if (code < 256)
-      val = code;
-  }
-
-  binding.fill(this, val, start, end);
-
-  return this;
-};
-
-
-// XXX remove in v0.13
-Buffer.prototype.get = internalUtil.deprecate(function get(offset) {
-  offset = ~~offset;
-  if (offset < 0 || offset >= this.length)
-    throw new RangeError('index out of range');
-  return this[offset];
-}, 'Buffer.get is deprecated. Use array indexes instead.');
-
-
-// XXX remove in v0.13
-Buffer.prototype.set = internalUtil.deprecate(function set(offset, v) {
-  offset = ~~offset;
-  if (offset < 0 || offset >= this.length)
-    throw new RangeError('index out of range');
-  return this[offset] = v;
-}, 'Buffer.set is deprecated. Use array indexes instead.');
-
-
-// TODO(trevnorris): fix these checks to follow new standard
-// write(string, offset = 0, length = buffer.length, encoding = 'utf8')
-var writeWarned = false;
-const writeMsg = 'Buffer.write(string, encoding, offset, length) is ' +
-                 'deprecated. Use write(string[, offset[, length]]' +
-                 '[, encoding]) instead.';
-Buffer.prototype.write = function(string, offset, length, encoding) {
-  // Buffer#write(string);
-  if (offset === undefined) {
-    encoding = 'utf8';
-    length = this.length;
-    offset = 0;
-
-  // Buffer#write(string, encoding)
-  } else if (length === undefined && typeof offset === 'string') {
-    encoding = offset;
-    length = this.length;
-    offset = 0;
-
-  // Buffer#write(string, offset[, length][, encoding])
-  } else if (isFinite(offset)) {
-    offset = offset >>> 0;
-    if (isFinite(length)) {
-      length = length >>> 0;
-      if (encoding === undefined)
-        encoding = 'utf8';
-    } else {
-      encoding = length;
-      length = undefined;
-    }
-
-  // XXX legacy write(string, encoding, offset, length) - remove in v0.13
-  } else {
-    writeWarned = internalUtil.printDeprecationMessage(writeMsg, writeWarned);
-    var swap = encoding;
-    encoding = offset;
-    offset = length >>> 0;
-    length = swap;
-  }
-
-  var remaining = this.length - offset;
-  if (length === undefined || length > remaining)
-    length = remaining;
-
-  if (string.length > 0 && (length < 0 || offset < 0))
-    throw new RangeError('attempt to write outside buffer bounds');
-
-  if (!encoding)
-    encoding = 'utf8';
-
-  var loweredCase = false;
-  for (;;) {
-    switch (encoding) {
-      case 'hex':
-        return this.hexWrite(string, offset, length);
-
-      case 'utf8':
-      case 'utf-8':
-        return this.utf8Write(string, offset, length);
-
-      case 'ascii':
-        return this.asciiWrite(string, offset, length);
-
-      case 'binary':
-        return this.binaryWrite(string, offset, length);
-
-      case 'base64':
-        // Warning: maxLength not taken into account in base64Write
-        return this.base64Write(string, offset, length);
-
-      case 'ucs2':
-      case 'ucs-2':
-      case 'utf16le':
-      case 'utf-16le':
-        return this.ucs2Write(string, offset, length);
-
-      default:
-        if (loweredCase)
-          throw new TypeError('Unknown encoding: ' + encoding);
-        encoding = ('' + encoding).toLowerCase();
-        loweredCase = true;
-    }
-  }
-};
-
-
-Buffer.prototype.toJSON = function() {
-  return {
-    type: 'Buffer',
-    data: Array.prototype.slice.call(this, 0)
-  };
-};
-
-
-// TODO(trevnorris): currently works like Array.prototype.slice(), which
-// doesn't follow the new standard for throwing on out of range indexes.
-Buffer.prototype.slice = function(start, end) {
-  var len = this.length;
-  start = ~~start;
-  end = end === undefined ? len : ~~end;
-
-  if (start < 0) {
-    start += len;
-    if (start < 0)
-      start = 0;
-  } else if (start > len) {
-    start = len;
-  }
-
-  if (end < 0) {
-    end += len;
-    if (end < 0)
-      end = 0;
-  } else if (end > len) {
-    end = len;
-  }
-
-  if (end < start)
-    end = start;
-
-  var buf = new NativeBuffer();
-  sliceOnto(this, buf, start, end);
-  buf.length = end - start;
-  if (buf.length > 0)
-    buf.parent = this.parent === undefined ? this : this.parent;
-
-  return buf;
-};
-
-
-function checkOffset(offset, ext, length) {
-  if (offset + ext > length)
-    throw new RangeError('index out of range');
-}
-
-
-Buffer.prototype.readUIntLE = function(offset, byteLength, noAssert) {
-  offset = offset >>> 0;
-  byteLength = byteLength >>> 0;
-  if (!noAssert)
-    checkOffset(offset, byteLength, this.length);
-
-  var val = this[offset];
-  var mul = 1;
-  var i = 0;
-  while (++i < byteLength && (mul *= 0x100))
-    val += this[offset + i] * mul;
-
-  return val;
-};
-
-
-Buffer.prototype.readUIntBE = function(offset, byteLength, noAssert) {
-  offset = offset >>> 0;
-  byteLength = byteLength >>> 0;
-  if (!noAssert)
-    checkOffset(offset, byteLength, this.length);
-
-  var val = this[offset + --byteLength];
-  var mul = 1;
-  while (byteLength > 0 && (mul *= 0x100))
-    val += this[offset + --byteLength] * mul;
-
-  return val;
-};
-
-
-Buffer.prototype.readUInt8 = function(offset, noAssert) {
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkOffset(offset, 1, this.length);
-  return this[offset];
-};
-
-
-Buffer.prototype.readUInt16LE = function(offset, noAssert) {
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkOffset(offset, 2, this.length);
-  return this[offset] | (this[offset + 1] << 8);
-};
-
-
-Buffer.prototype.readUInt16BE = function(offset, noAssert) {
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkOffset(offset, 2, this.length);
-  return (this[offset] << 8) | this[offset + 1];
-};
-
-
-Buffer.prototype.readUInt32LE = function(offset, noAssert) {
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkOffset(offset, 4, this.length);
-
-  return ((this[offset]) |
-      (this[offset + 1] << 8) |
-      (this[offset + 2] << 16)) +
-      (this[offset + 3] * 0x1000000);
-};
-
-
-Buffer.prototype.readUInt32BE = function(offset, noAssert) {
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkOffset(offset, 4, this.length);
-
-  return (this[offset] * 0x1000000) +
-      ((this[offset + 1] << 16) |
-      (this[offset + 2] << 8) |
-      this[offset + 3]);
-};
-
-
-Buffer.prototype.readIntLE = function(offset, byteLength, noAssert) {
-  offset = offset >>> 0;
-  byteLength = byteLength >>> 0;
-  if (!noAssert)
-    checkOffset(offset, byteLength, this.length);
-
-  var val = this[offset];
-  var mul = 1;
-  var i = 0;
-  while (++i < byteLength && (mul *= 0x100))
-    val += this[offset + i] * mul;
-  mul *= 0x80;
-
-  if (val >= mul)
-    val -= Math.pow(2, 8 * byteLength);
-
-  return val;
-};
-
-
-Buffer.prototype.readIntBE = function(offset, byteLength, noAssert) {
-  offset = offset >>> 0;
-  byteLength = byteLength >>> 0;
-  if (!noAssert)
-    checkOffset(offset, byteLength, this.length);
-
-  var i = byteLength;
-  var mul = 1;
-  var val = this[offset + --i];
-  while (i > 0 && (mul *= 0x100))
-    val += this[offset + --i] * mul;
-  mul *= 0x80;
-
-  if (val >= mul)
-    val -= Math.pow(2, 8 * byteLength);
-
-  return val;
-};
-
-
-Buffer.prototype.readInt8 = function(offset, noAssert) {
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkOffset(offset, 1, this.length);
-  var val = this[offset];
-  return !(val & 0x80) ? val : (0xff - val + 1) * -1;
-};
-
-
-Buffer.prototype.readInt16LE = function(offset, noAssert) {
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkOffset(offset, 2, this.length);
-  var val = this[offset] | (this[offset + 1] << 8);
-  return (val & 0x8000) ? val | 0xFFFF0000 : val;
-};
-
-
-Buffer.prototype.readInt16BE = function(offset, noAssert) {
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkOffset(offset, 2, this.length);
-  var val = this[offset + 1] | (this[offset] << 8);
-  return (val & 0x8000) ? val | 0xFFFF0000 : val;
-};
-
-
-Buffer.prototype.readInt32LE = function(offset, noAssert) {
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkOffset(offset, 4, this.length);
-
-  return (this[offset]) |
-      (this[offset + 1] << 8) |
-      (this[offset + 2] << 16) |
-      (this[offset + 3] << 24);
-};
-
-
-Buffer.prototype.readInt32BE = function(offset, noAssert) {
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkOffset(offset, 4, this.length);
-
-  return (this[offset] << 24) |
-      (this[offset + 1] << 16) |
-      (this[offset + 2] << 8) |
-      (this[offset + 3]);
-};
-
-
-Buffer.prototype.readFloatLE = function readFloatLE(offset, noAssert) {
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkOffset(offset, 4, this.length);
-  return binding.readFloatLE(this, offset);
-};
-
-
-Buffer.prototype.readFloatBE = function readFloatBE(offset, noAssert) {
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkOffset(offset, 4, this.length);
-  return binding.readFloatBE(this, offset);
-};
-
-
-Buffer.prototype.readDoubleLE = function readDoubleLE(offset, noAssert) {
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkOffset(offset, 8, this.length);
-  return binding.readDoubleLE(this, offset);
-};
-
-
-Buffer.prototype.readDoubleBE = function readDoubleBE(offset, noAssert) {
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkOffset(offset, 8, this.length);
-  return binding.readDoubleBE(this, offset);
-};
-
-
-function checkInt(buffer, value, offset, ext, max, min) {
-  if (!(buffer instanceof Buffer))
-    throw new TypeError('buffer must be a Buffer instance');
-  if (value > max || value < min)
-    throw new TypeError('value is out of bounds');
-  if (offset + ext > buffer.length)
-    throw new RangeError('index out of range');
-}
-
-
-Buffer.prototype.writeUIntLE = function(value, offset, byteLength, noAssert) {
-  value = +value;
-  offset = offset >>> 0;
-  byteLength = byteLength >>> 0;
-  if (!noAssert)
-    checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0);
-
-  var mul = 1;
-  var i = 0;
-  this[offset] = value;
-  while (++i < byteLength && (mul *= 0x100))
-    this[offset + i] = (value / mul) >>> 0;
-
-  return offset + byteLength;
-};
-
-
-Buffer.prototype.writeUIntBE = function(value, offset, byteLength, noAssert) {
-  value = +value;
-  offset = offset >>> 0;
-  byteLength = byteLength >>> 0;
-  if (!noAssert)
-    checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0);
-
-  var i = byteLength - 1;
-  var mul = 1;
-  this[offset + i] = value;
-  while (--i >= 0 && (mul *= 0x100))
-    this[offset + i] = (value / mul) >>> 0;
-
-  return offset + byteLength;
-};
-
-
-Buffer.prototype.writeUInt8 = function(value, offset, noAssert) {
-  value = +value;
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkInt(this, value, offset, 1, 0xff, 0);
-  this[offset] = value;
-  return offset + 1;
-};
-
-
-Buffer.prototype.writeUInt16LE = function(value, offset, noAssert) {
-  value = +value;
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkInt(this, value, offset, 2, 0xffff, 0);
-  this[offset] = value;
-  this[offset + 1] = (value >>> 8);
-  return offset + 2;
-};
-
-
-Buffer.prototype.writeUInt16BE = function(value, offset, noAssert) {
-  value = +value;
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkInt(this, value, offset, 2, 0xffff, 0);
-  this[offset] = (value >>> 8);
-  this[offset + 1] = value;
-  return offset + 2;
-};
-
-
-Buffer.prototype.writeUInt32LE = function(value, offset, noAssert) {
-  value = +value;
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkInt(this, value, offset, 4, 0xffffffff, 0);
-  this[offset + 3] = (value >>> 24);
-  this[offset + 2] = (value >>> 16);
-  this[offset + 1] = (value >>> 8);
-  this[offset] = value;
-  return offset + 4;
-};
-
-
-Buffer.prototype.writeUInt32BE = function(value, offset, noAssert) {
-  value = +value;
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkInt(this, value, offset, 4, 0xffffffff, 0);
-  this[offset] = (value >>> 24);
-  this[offset + 1] = (value >>> 16);
-  this[offset + 2] = (value >>> 8);
-  this[offset + 3] = value;
-  return offset + 4;
-};
-
-
-Buffer.prototype.writeIntLE = function(value, offset, byteLength, noAssert) {
-  value = +value;
-  offset = offset >>> 0;
-  if (!noAssert) {
-    checkInt(this,
-             value,
-             offset,
-             byteLength,
-             Math.pow(2, 8 * byteLength - 1) - 1,
-             -Math.pow(2, 8 * byteLength - 1));
-  }
-
-  var i = 0;
-  var mul = 1;
-  var sub = value < 0 ? 1 : 0;
-  this[offset] = value;
-  while (++i < byteLength && (mul *= 0x100))
-    this[offset + i] = ((value / mul) >> 0) - sub;
-
-  return offset + byteLength;
-};
-
-
-Buffer.prototype.writeIntBE = function(value, offset, byteLength, noAssert) {
-  value = +value;
-  offset = offset >>> 0;
-  if (!noAssert) {
-    checkInt(this,
-             value,
-             offset,
-             byteLength,
-             Math.pow(2, 8 * byteLength - 1) - 1,
-             -Math.pow(2, 8 * byteLength - 1));
-  }
-
-  var i = byteLength - 1;
-  var mul = 1;
-  var sub = value < 0 ? 1 : 0;
-  this[offset + i] = value;
-  while (--i >= 0 && (mul *= 0x100))
-    this[offset + i] = ((value / mul) >> 0) - sub;
-
-  return offset + byteLength;
-};
-
-
-Buffer.prototype.writeInt8 = function(value, offset, noAssert) {
-  value = +value;
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkInt(this, value, offset, 1, 0x7f, -0x80);
-  this[offset] = value;
-  return offset + 1;
-};
-
-
-Buffer.prototype.writeInt16LE = function(value, offset, noAssert) {
-  value = +value;
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkInt(this, value, offset, 2, 0x7fff, -0x8000);
-  this[offset] = value;
-  this[offset + 1] = (value >>> 8);
-  return offset + 2;
-};
-
-
-Buffer.prototype.writeInt16BE = function(value, offset, noAssert) {
-  value = +value;
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkInt(this, value, offset, 2, 0x7fff, -0x8000);
-  this[offset] = (value >>> 8);
-  this[offset + 1] = value;
-  return offset + 2;
-};
-
-
-Buffer.prototype.writeInt32LE = function(value, offset, noAssert) {
-  value = +value;
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);
-  this[offset] = value;
-  this[offset + 1] = (value >>> 8);
-  this[offset + 2] = (value >>> 16);
-  this[offset + 3] = (value >>> 24);
-  return offset + 4;
-};
-
-
-Buffer.prototype.writeInt32BE = function(value, offset, noAssert) {
-  value = +value;
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);
-  this[offset] = (value >>> 24);
-  this[offset + 1] = (value >>> 16);
-  this[offset + 2] = (value >>> 8);
-  this[offset + 3] = value;
-  return offset + 4;
-};
-
-
-function checkFloat(buffer, value, offset, ext) {
-  if (!(buffer instanceof Buffer))
-    throw new TypeError('buffer must be a Buffer instance');
-  if (offset + ext > buffer.length)
-    throw new RangeError('index out of range');
+if (process.useOldBuffer) {
+  module.exports = require('internal/buffer_old');
+} else {
+  module.exports = require('internal/buffer_new');
 }
-
-
-Buffer.prototype.writeFloatLE = function writeFloatLE(val, offset, noAssert) {
-  val = +val;
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkFloat(this, val, offset, 4);
-  binding.writeFloatLE(this, val, offset);
-  return offset + 4;
-};
-
-
-Buffer.prototype.writeFloatBE = function writeFloatBE(val, offset, noAssert) {
-  val = +val;
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkFloat(this, val, offset, 4);
-  binding.writeFloatBE(this, val, offset);
-  return offset + 4;
-};
-
-
-Buffer.prototype.writeDoubleLE = function writeDoubleLE(val, offset, noAssert) {
-  val = +val;
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkFloat(this, val, offset, 8);
-  binding.writeDoubleLE(this, val, offset);
-  return offset + 8;
-};
-
-
-Buffer.prototype.writeDoubleBE = function writeDoubleBE(val, offset, noAssert) {
-  val = +val;
-  offset = offset >>> 0;
-  if (!noAssert)
-    checkFloat(this, val, offset, 8);
-  binding.writeDoubleBE(this, val, offset);
-  return offset + 8;
-};
-
-// ES6 iterator
-
-var ITERATOR_KIND_KEYS = 1;
-var ITERATOR_KIND_ENTRIES = 3;
-
-function BufferIteratorResult(value, done) {
-  this.value = value;
-  this.done = done;
-}
-
-var resultCache = new Array(256);
-
-for (var i = 0; i < 256; i++)
-  resultCache[i] = Object.freeze(new BufferIteratorResult(i, false));
-
-var finalResult = Object.freeze(new BufferIteratorResult(undefined, true));
-
-function BufferIterator(buffer, kind) {
-  this._buffer = buffer;
-  this._kind = kind;
-  this._index = 0;
-}
-
-BufferIterator.prototype.next = function() {
-  var buffer = this._buffer;
-  var kind = this._kind;
-  var index = this._index;
-
-  if (index >= buffer.length)
-    return finalResult;
-
-  this._index++;
-
-  if (kind === ITERATOR_KIND_ENTRIES)
-    return new BufferIteratorResult([index, buffer[index]], false);
-
-  return new BufferIteratorResult(index, false);
-};
-
-function BufferValueIterator(buffer) {
-  BufferIterator.call(this, buffer, null);
-}
-
-BufferValueIterator.prototype.next = function() {
-  var buffer = this._buffer;
-  var index = this._index;
-
-  if (index >= buffer.length)
-    return finalResult;
-
-  this._index++;
-
-  return resultCache[buffer[index]];
-};
-
-
-BufferIterator.prototype[Symbol.iterator] = function() {
-  return this;
-};
-
-BufferValueIterator.prototype[Symbol.iterator] =
-    BufferIterator.prototype[Symbol.iterator];
-
-Buffer.prototype.keys = function() {
-  return new BufferIterator(this, ITERATOR_KIND_KEYS);
-};
-
-Buffer.prototype.entries = function() {
-  return new BufferIterator(this, ITERATOR_KIND_ENTRIES);
-};
-
-Buffer.prototype.values = function() {
-  return new BufferValueIterator(this);
-};
-
-Buffer.prototype[Symbol.iterator] = Buffer.prototype.values;
diff --git a/lib/internal/buffer_new.js b/lib/internal/buffer_new.js
new file mode 100644 (file)
index 0000000..c082ed8
--- /dev/null
@@ -0,0 +1,1020 @@
+'use strict';
+
+const binding = process.binding('buffer');
+const internalUtil = require('internal/util');
+
+exports.Buffer = Buffer;
+exports.SlowBuffer = SlowBuffer;
+exports.INSPECT_MAX_BYTES = 50;
+
+
+Buffer.poolSize = 8 * 1024;
+var poolSize, poolOffset, allocPool;
+
+
+function createPool() {
+  poolSize = Buffer.poolSize;
+  allocPool = binding.create(poolSize);
+  poolOffset = 0;
+}
+
+
+function Buffer(arg) {
+  // Common case.
+  if (typeof arg === 'number') {
+    // If less than zero, or NaN.
+    if (arg < 0 || arg !== arg)
+      arg = 0;
+    return allocate(arg);
+  }
+
+  // Slightly less common case.
+  if (typeof arg === 'string') {
+    return fromString(arg, arguments[1]);
+  }
+
+  // Unusual.
+  return fromObject(arg);
+};
+
+Buffer.prototype.__proto__ = Uint8Array.prototype;
+Buffer.__proto__ = Uint8Array;
+
+
+binding.setupBufferJS(Buffer.prototype);
+// Buffer prototype must be past before creating our first pool.
+createPool();
+
+
+function SlowBuffer(length) {
+  if (length < 0)
+    length = 0;
+  return binding.create(length);
+};
+
+SlowBuffer.prototype.__proto__ = Buffer.prototype;
+SlowBuffer.__proto__ = Buffer;
+
+
+function allocate(size) {
+  if (size === 0)
+    return binding.create(0);
+  if (size < (Buffer.poolSize >>> 1)) {
+    if (size > (poolSize - poolOffset))
+      createPool();
+    var b = binding.slice(allocPool, poolOffset, poolOffset + size);
+    poolOffset += size;
+    return b;
+  } else {
+    return binding.create(size);
+  }
+}
+
+
+function fromString(string, encoding) {
+  if (typeof encoding !== 'string' || encoding === '')
+    encoding = 'utf8';
+
+  var length = byteLength(string, encoding);
+  if (length >= (Buffer.poolSize >>> 1))
+    return binding.createFromString(string, encoding);
+
+  if (length > (poolSize - poolOffset))
+    createPool();
+  var actual = allocPool.write(string, poolOffset, encoding);
+  var b = binding.slice(allocPool, poolOffset, poolOffset + actual);
+  poolOffset += actual;
+  return b;
+}
+
+
+function fromObject(obj) {
+  if (obj instanceof Buffer) {
+    var b = allocate(obj.length);
+    obj.copy(b, 0, 0, obj.length);
+    return b;
+  }
+
+  if (Array.isArray(obj)) {
+    var length = obj.length;
+    var b = allocate(length);
+    for (var i = 0; i < length; i++)
+      b[i] = obj[i] & 255;
+    return b;
+  }
+
+  // TODO(trevnorris): This will fail for an actual ArrayBuffer.
+  if (obj.buffer instanceof ArrayBuffer || obj.length) {
+    var length;
+    if (typeof obj.length !== 'number' || obj.length !== obj.length)
+      length = 0;
+    else
+      length = obj.length;
+    var b = allocate(length);
+    for (var i = 0; i < length; i++) {
+      b[i] = obj[i] & 255;
+    }
+    return b;
+  }
+
+  if (obj.type === 'Buffer' && Array.isArray(obj.data)) {
+    var array = obj.data;
+    var b = allocate(array.length);
+    for (var i = 0; i < array.length; i++)
+      b[i] = array[i] & 255;
+    return b;
+  }
+
+  throw new TypeError('must start with number, buffer, array or string');
+}
+
+
+// Static methods
+
+Buffer.isBuffer = function isBuffer(b) {
+  return b instanceof Buffer;
+};
+
+
+Buffer.compare = function compare(a, b) {
+  if (!(a instanceof Buffer) ||
+      !(b instanceof Buffer)) {
+    throw new TypeError('Arguments must be Buffers');
+  }
+
+  if (a === b) {
+    return 0;
+  }
+
+  return binding.compare(a, b);
+};
+
+
+Buffer.isEncoding = function(encoding) {
+  var loweredCase = false;
+  for (;;) {
+    switch (encoding) {
+      case 'hex':
+      case 'utf8':
+      case 'utf-8':
+      case 'ascii':
+      case 'binary':
+      case 'base64':
+      case 'ucs2':
+      case 'ucs-2':
+      case 'utf16le':
+      case 'utf-16le':
+      case 'raw':
+        return true;
+
+      default:
+        if (loweredCase)
+          return false;
+        encoding = ('' + encoding).toLowerCase();
+        loweredCase = true;
+    }
+  }
+};
+
+
+Buffer.concat = function(list, length) {
+  if (!Array.isArray(list))
+    throw new TypeError('list argument must be an Array of Buffers.');
+
+  if (list.length === 0)
+    return new Buffer(0);
+  else if (list.length === 1)
+    return list[0];
+
+  if (length === undefined) {
+    length = 0;
+    for (var i = 0; i < list.length; i++)
+      length += list[i].length;
+  } else {
+    length = length >>> 0;
+  }
+
+  var buffer = new Buffer(length);
+  var pos = 0;
+  for (var i = 0; i < list.length; i++) {
+    var buf = list[i];
+    buf.copy(buffer, pos);
+    pos += buf.length;
+  }
+
+  return buffer;
+};
+
+
+function base64ByteLength(str, bytes) {
+  // Handle padding
+  if (str.charCodeAt(bytes - 1) === 0x3D)
+    bytes--;
+  if (bytes > 1 && str.charCodeAt(bytes - 1) === 0x3D)
+    bytes--;
+
+  // Base64 ratio: 3/4
+  return (bytes * 3) >>> 2;
+}
+
+
+function byteLength(string, encoding) {
+  if (typeof string !== 'string')
+    string = '' + string;
+
+  var len = string.length;
+  if (len === 0)
+    return 0;
+
+  // Use a for loop to avoid recursion
+  var loweredCase = false;
+  for (;;) {
+    switch (encoding) {
+      case 'ascii':
+      case 'binary':
+      // Deprecated
+      case 'raw':
+      case 'raws':
+        return len;
+
+      case 'utf8':
+      case 'utf-8':
+        return binding.byteLengthUtf8(string);
+
+      case 'ucs2':
+      case 'ucs-2':
+      case 'utf16le':
+      case 'utf-16le':
+        return len * 2;
+
+      case 'hex':
+        return len >>> 1;
+
+      case 'base64':
+        return base64ByteLength(string, len);
+
+      default:
+        // The C++ binding defaulted to UTF8, we should too.
+        if (loweredCase)
+          return binding.byteLengthUtf8(string);
+
+        encoding = ('' + encoding).toLowerCase();
+        loweredCase = true;
+    }
+  }
+}
+
+Buffer.byteLength = byteLength;
+
+
+// For backwards compatibility.
+Object.defineProperty(Buffer.prototype, 'parent', {
+  enumerable: true,
+  get: function() {
+    if (this.byteLength === 0 ||
+        this.byteLength === this.buffer.byteLength) {
+      return undefined;
+    }
+    return this.buffer;
+  }
+});
+Object.defineProperty(Buffer.prototype, 'offset', {
+  enumerable: true,
+  get: function() {
+    return this.byteOffset;
+  }
+});
+
+
+// toString(encoding, start=0, end=buffer.length)
+Buffer.prototype.toString = function(encoding, start, end) {
+  var loweredCase = false;
+
+  start = start >>> 0;
+  end = end === undefined || end === Infinity ? this.length : end >>> 0;
+
+  if (!encoding) encoding = 'utf8';
+  if (start < 0) start = 0;
+  if (end > this.length) end = this.length;
+  if (end <= start) return '';
+
+  while (true) {
+    switch (encoding) {
+      case 'hex':
+        return this.hexSlice(start, end);
+
+      case 'utf8':
+      case 'utf-8':
+        return this.utf8Slice(start, end);
+
+      case 'ascii':
+        return this.asciiSlice(start, end);
+
+      case 'binary':
+        return this.binarySlice(start, end);
+
+      case 'base64':
+        return this.base64Slice(start, end);
+
+      case 'ucs2':
+      case 'ucs-2':
+      case 'utf16le':
+      case 'utf-16le':
+        return this.ucs2Slice(start, end);
+
+      default:
+        if (loweredCase)
+          throw new TypeError('Unknown encoding: ' + encoding);
+        encoding = (encoding + '').toLowerCase();
+        loweredCase = true;
+    }
+  }
+};
+
+
+Buffer.prototype.equals = function equals(b) {
+  if (!(b instanceof Buffer))
+    throw new TypeError('Argument must be a Buffer');
+
+  if (this === b)
+    return true;
+
+  return binding.compare(this, b) === 0;
+};
+
+
+// Inspect
+Buffer.prototype.inspect = function inspect() {
+  var str = '';
+  var max = exports.INSPECT_MAX_BYTES;
+  if (this.length > 0) {
+    str = this.toString('hex', 0, max).match(/.{2}/g).join(' ');
+    if (this.length > max)
+      str += ' ... ';
+  }
+  return '<' + this.constructor.name + ' ' + str + '>';
+};
+
+
+Buffer.prototype.compare = function compare(b) {
+  if (!(b instanceof Buffer))
+    throw new TypeError('Argument must be a Buffer');
+
+  if (this === b)
+    return 0;
+
+  return binding.compare(this, b);
+};
+
+
+Buffer.prototype.indexOf = function indexOf(val, byteOffset) {
+  if (byteOffset > 0x7fffffff)
+    byteOffset = 0x7fffffff;
+  else if (byteOffset < -0x80000000)
+    byteOffset = -0x80000000;
+  byteOffset >>= 0;
+
+  if (typeof val === 'string')
+    return binding.indexOfString(this, val, byteOffset);
+  if (val instanceof Buffer)
+    return binding.indexOfBuffer(this, val, byteOffset);
+  if (typeof val === 'number')
+    return binding.indexOfNumber(this, val, byteOffset);
+
+  throw new TypeError('val must be string, number or Buffer');
+};
+
+
+Buffer.prototype.fill = function fill(val, start, end) {
+  start = start >> 0;
+  end = (end === undefined) ? this.length : end >> 0;
+
+  if (start < 0 || end > this.length)
+    throw new RangeError('out of range index');
+  if (end <= start)
+    return this;
+
+  if (typeof val !== 'string') {
+    val = val >>> 0;
+  } else if (val.length === 1) {
+    var code = val.charCodeAt(0);
+    if (code < 256)
+      val = code;
+  }
+
+  binding.fill(this, val, start, end);
+
+  return this;
+};
+
+
+// XXX remove in v0.13
+Buffer.prototype.get = internalUtil.deprecate(function get(offset) {
+  offset = ~~offset;
+  if (offset < 0 || offset >= this.length)
+    throw new RangeError('index out of range');
+  return this[offset];
+}, '.get() is deprecated. Access using array indexes instead.');
+
+
+// XXX remove in v0.13
+Buffer.prototype.set = internalUtil.deprecate(function set(offset, v) {
+  offset = ~~offset;
+  if (offset < 0 || offset >= this.length)
+    throw new RangeError('index out of range');
+  return this[offset] = v;
+}, '.set() is deprecated. Set using array indexes instead.');
+
+
+// TODO(trevnorris): fix these checks to follow new standard
+// write(string, offset = 0, length = buffer.length, encoding = 'utf8')
+var writeWarned = false;
+const writeMsg = '.write(string, encoding, offset, length) is deprecated.' +
+                 ' Use write(string[, offset[, length]][, encoding]) instead.';
+Buffer.prototype.write = function(string, offset, length, encoding) {
+  // Buffer#write(string);
+  if (offset === undefined) {
+    encoding = 'utf8';
+    length = this.length;
+    offset = 0;
+
+  // Buffer#write(string, encoding)
+  } else if (length === undefined && typeof offset === 'string') {
+    encoding = offset;
+    length = this.length;
+    offset = 0;
+
+  // Buffer#write(string, offset[, length][, encoding])
+  } else if (isFinite(offset)) {
+    offset = offset >>> 0;
+    if (isFinite(length)) {
+      length = length >>> 0;
+      if (encoding === undefined)
+        encoding = 'utf8';
+    } else {
+      encoding = length;
+      length = undefined;
+    }
+
+  // XXX legacy write(string, encoding, offset, length) - remove in v0.13
+  } else {
+    if (!writeWarned) {
+      if (process.throwDeprecation)
+        throw new Error(writeMsg);
+      else if (process.traceDeprecation)
+        console.trace(writeMsg);
+      else
+        console.error(writeMsg);
+      writeWarned = true;
+    }
+
+    var swap = encoding;
+    encoding = offset;
+    offset = length >>> 0;
+    length = swap;
+  }
+
+  var remaining = this.length - offset;
+  if (length === undefined || length > remaining)
+    length = remaining;
+
+  if (string.length > 0 && (length < 0 || offset < 0))
+    throw new RangeError('attempt to write outside buffer bounds');
+
+  if (!encoding)
+    encoding = 'utf8';
+
+  var loweredCase = false;
+  for (;;) {
+    switch (encoding) {
+      case 'hex':
+        return this.hexWrite(string, offset, length);
+
+      case 'utf8':
+      case 'utf-8':
+        return this.utf8Write(string, offset, length);
+
+      case 'ascii':
+        return this.asciiWrite(string, offset, length);
+
+      case 'binary':
+        return this.binaryWrite(string, offset, length);
+
+      case 'base64':
+        // Warning: maxLength not taken into account in base64Write
+        return this.base64Write(string, offset, length);
+
+      case 'ucs2':
+      case 'ucs-2':
+      case 'utf16le':
+      case 'utf-16le':
+        return this.ucs2Write(string, offset, length);
+
+      default:
+        if (loweredCase)
+          throw new TypeError('Unknown encoding: ' + encoding);
+        encoding = ('' + encoding).toLowerCase();
+        loweredCase = true;
+    }
+  }
+};
+
+
+Buffer.prototype.toJSON = function() {
+  return {
+    type: 'Buffer',
+    data: Array.prototype.slice.call(this, 0)
+  };
+};
+
+
+// TODO(trevnorris): currently works like Array.prototype.slice(), which
+// doesn't follow the new standard for throwing on out of range indexes.
+Buffer.prototype.slice = function slice(start, end) {
+  var len = this.length;
+  start = ~~start;
+  end = end === undefined ? len : ~~end;
+
+  if (start < 0) {
+    start += len;
+    if (start < 0)
+      start = 0;
+  } else if (start > len) {
+    start = len;
+  }
+
+  if (end < 0) {
+    end += len;
+    if (end < 0)
+      end = 0;
+  } else if (end > len) {
+    end = len;
+  }
+
+  if (end < start)
+    end = start;
+
+  return binding.slice(this, start, end);
+};
+
+
+function checkOffset(offset, ext, length) {
+  if (offset + ext > length)
+    throw new RangeError('index out of range');
+}
+
+
+Buffer.prototype.readUIntLE = function(offset, byteLength, noAssert) {
+  offset = offset >>> 0;
+  byteLength = byteLength >>> 0;
+  if (!noAssert)
+    checkOffset(offset, byteLength, this.length);
+
+  var val = this[offset];
+  var mul = 1;
+  var i = 0;
+  while (++i < byteLength && (mul *= 0x100))
+    val += this[offset + i] * mul;
+
+  return val;
+};
+
+
+Buffer.prototype.readUIntBE = function(offset, byteLength, noAssert) {
+  offset = offset >>> 0;
+  byteLength = byteLength >>> 0;
+  if (!noAssert)
+    checkOffset(offset, byteLength, this.length);
+
+  var val = this[offset + --byteLength];
+  var mul = 1;
+  while (byteLength > 0 && (mul *= 0x100))
+    val += this[offset + --byteLength] * mul;
+
+  return val;
+};
+
+
+Buffer.prototype.readUInt8 = function(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 1, this.length);
+  return this[offset];
+};
+
+
+Buffer.prototype.readUInt16LE = function(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 2, this.length);
+  return this[offset] | (this[offset + 1] << 8);
+};
+
+
+Buffer.prototype.readUInt16BE = function(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 2, this.length);
+  return (this[offset] << 8) | this[offset + 1];
+};
+
+
+Buffer.prototype.readUInt32LE = function(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 4, this.length);
+
+  return ((this[offset]) |
+      (this[offset + 1] << 8) |
+      (this[offset + 2] << 16)) +
+      (this[offset + 3] * 0x1000000);
+};
+
+
+Buffer.prototype.readUInt32BE = function(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 4, this.length);
+
+  return (this[offset] * 0x1000000) +
+      ((this[offset + 1] << 16) |
+      (this[offset + 2] << 8) |
+      this[offset + 3]);
+};
+
+
+Buffer.prototype.readIntLE = function(offset, byteLength, noAssert) {
+  offset = offset >>> 0;
+  byteLength = byteLength >>> 0;
+  if (!noAssert)
+    checkOffset(offset, byteLength, this.length);
+
+  var val = this[offset];
+  var mul = 1;
+  var i = 0;
+  while (++i < byteLength && (mul *= 0x100))
+    val += this[offset + i] * mul;
+  mul *= 0x80;
+
+  if (val >= mul)
+    val -= Math.pow(2, 8 * byteLength);
+
+  return val;
+};
+
+
+Buffer.prototype.readIntBE = function(offset, byteLength, noAssert) {
+  offset = offset >>> 0;
+  byteLength = byteLength >>> 0;
+  if (!noAssert)
+    checkOffset(offset, byteLength, this.length);
+
+  var i = byteLength;
+  var mul = 1;
+  var val = this[offset + --i];
+  while (i > 0 && (mul *= 0x100))
+    val += this[offset + --i] * mul;
+  mul *= 0x80;
+
+  if (val >= mul)
+    val -= Math.pow(2, 8 * byteLength);
+
+  return val;
+};
+
+
+Buffer.prototype.readInt8 = function(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 1, this.length);
+  var val = this[offset];
+  return !(val & 0x80) ? val : (0xff - val + 1) * -1;
+};
+
+
+Buffer.prototype.readInt16LE = function(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 2, this.length);
+  var val = this[offset] | (this[offset + 1] << 8);
+  return (val & 0x8000) ? val | 0xFFFF0000 : val;
+};
+
+
+Buffer.prototype.readInt16BE = function(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 2, this.length);
+  var val = this[offset + 1] | (this[offset] << 8);
+  return (val & 0x8000) ? val | 0xFFFF0000 : val;
+};
+
+
+Buffer.prototype.readInt32LE = function(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 4, this.length);
+
+  return (this[offset]) |
+      (this[offset + 1] << 8) |
+      (this[offset + 2] << 16) |
+      (this[offset + 3] << 24);
+};
+
+
+Buffer.prototype.readInt32BE = function(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 4, this.length);
+
+  return (this[offset] << 24) |
+      (this[offset + 1] << 16) |
+      (this[offset + 2] << 8) |
+      (this[offset + 3]);
+};
+
+
+Buffer.prototype.readFloatLE = function readFloatLE(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 4, this.length);
+  return binding.readFloatLE(this, offset);
+};
+
+
+Buffer.prototype.readFloatBE = function readFloatBE(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 4, this.length);
+  return binding.readFloatBE(this, offset);
+};
+
+
+Buffer.prototype.readDoubleLE = function readDoubleLE(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 8, this.length);
+  return binding.readDoubleLE(this, offset);
+};
+
+
+Buffer.prototype.readDoubleBE = function readDoubleBE(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 8, this.length);
+  return binding.readDoubleBE(this, offset);
+};
+
+
+function checkInt(buffer, value, offset, ext, max, min) {
+  if (!(buffer instanceof Buffer))
+    throw new TypeError('buffer must be a Buffer instance');
+  if (value > max || value < min)
+    throw new TypeError('value is out of bounds');
+  if (offset + ext > buffer.length)
+    throw new RangeError('index out of range');
+}
+
+
+Buffer.prototype.writeUIntLE = function(value, offset, byteLength, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  byteLength = byteLength >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0);
+
+  var mul = 1;
+  var i = 0;
+  this[offset] = value;
+  while (++i < byteLength && (mul *= 0x100))
+    this[offset + i] = (value / mul) >>> 0;
+
+  return offset + byteLength;
+};
+
+
+Buffer.prototype.writeUIntBE = function(value, offset, byteLength, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  byteLength = byteLength >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0);
+
+  var i = byteLength - 1;
+  var mul = 1;
+  this[offset + i] = value;
+  while (--i >= 0 && (mul *= 0x100))
+    this[offset + i] = (value / mul) >>> 0;
+
+  return offset + byteLength;
+};
+
+
+Buffer.prototype.writeUInt8 = function(value, offset, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, 1, 0xff, 0);
+  this[offset] = value;
+  return offset + 1;
+};
+
+
+Buffer.prototype.writeUInt16LE = function(value, offset, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, 2, 0xffff, 0);
+  this[offset] = value;
+  this[offset + 1] = (value >>> 8);
+  return offset + 2;
+};
+
+
+Buffer.prototype.writeUInt16BE = function(value, offset, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, 2, 0xffff, 0);
+  this[offset] = (value >>> 8);
+  this[offset + 1] = value;
+  return offset + 2;
+};
+
+
+Buffer.prototype.writeUInt32LE = function(value, offset, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, 4, 0xffffffff, 0);
+  this[offset + 3] = (value >>> 24);
+  this[offset + 2] = (value >>> 16);
+  this[offset + 1] = (value >>> 8);
+  this[offset] = value;
+  return offset + 4;
+};
+
+
+Buffer.prototype.writeUInt32BE = function(value, offset, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, 4, 0xffffffff, 0);
+  this[offset] = (value >>> 24);
+  this[offset + 1] = (value >>> 16);
+  this[offset + 2] = (value >>> 8);
+  this[offset + 3] = value;
+  return offset + 4;
+};
+
+
+Buffer.prototype.writeIntLE = function(value, offset, byteLength, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert) {
+    checkInt(this,
+             value,
+             offset,
+             byteLength,
+             Math.pow(2, 8 * byteLength - 1) - 1,
+             -Math.pow(2, 8 * byteLength - 1));
+  }
+
+  var i = 0;
+  var mul = 1;
+  var sub = value < 0 ? 1 : 0;
+  this[offset] = value;
+  while (++i < byteLength && (mul *= 0x100))
+    this[offset + i] = ((value / mul) >> 0) - sub;
+
+  return offset + byteLength;
+};
+
+
+Buffer.prototype.writeIntBE = function(value, offset, byteLength, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert) {
+    checkInt(this,
+             value,
+             offset,
+             byteLength,
+             Math.pow(2, 8 * byteLength - 1) - 1,
+             -Math.pow(2, 8 * byteLength - 1));
+  }
+
+  var i = byteLength - 1;
+  var mul = 1;
+  var sub = value < 0 ? 1 : 0;
+  this[offset + i] = value;
+  while (--i >= 0 && (mul *= 0x100))
+    this[offset + i] = ((value / mul) >> 0) - sub;
+
+  return offset + byteLength;
+};
+
+
+Buffer.prototype.writeInt8 = function(value, offset, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, 1, 0x7f, -0x80);
+  this[offset] = value;
+  return offset + 1;
+};
+
+
+Buffer.prototype.writeInt16LE = function(value, offset, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, 2, 0x7fff, -0x8000);
+  this[offset] = value;
+  this[offset + 1] = (value >>> 8);
+  return offset + 2;
+};
+
+
+Buffer.prototype.writeInt16BE = function(value, offset, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, 2, 0x7fff, -0x8000);
+  this[offset] = (value >>> 8);
+  this[offset + 1] = value;
+  return offset + 2;
+};
+
+
+Buffer.prototype.writeInt32LE = function(value, offset, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);
+  this[offset] = value;
+  this[offset + 1] = (value >>> 8);
+  this[offset + 2] = (value >>> 16);
+  this[offset + 3] = (value >>> 24);
+  return offset + 4;
+};
+
+
+Buffer.prototype.writeInt32BE = function(value, offset, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);
+  this[offset] = (value >>> 24);
+  this[offset + 1] = (value >>> 16);
+  this[offset + 2] = (value >>> 8);
+  this[offset + 3] = value;
+  return offset + 4;
+};
+
+
+function checkFloat(buffer, value, offset, ext) {
+  if (!(buffer instanceof Buffer))
+    throw new TypeError('buffer must be a Buffer instance');
+  if (offset + ext > buffer.length)
+    throw new RangeError('index out of range');
+}
+
+
+Buffer.prototype.writeFloatLE = function writeFloatLE(val, offset, noAssert) {
+  val = +val;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkFloat(this, val, offset, 4);
+  binding.writeFloatLE(this, val, offset);
+  return offset + 4;
+};
+
+
+Buffer.prototype.writeFloatBE = function writeFloatBE(val, offset, noAssert) {
+  val = +val;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkFloat(this, val, offset, 4);
+  binding.writeFloatBE(this, val, offset);
+  return offset + 4;
+};
+
+
+Buffer.prototype.writeDoubleLE = function writeDoubleLE(val, offset, noAssert) {
+  val = +val;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkFloat(this, val, offset, 8);
+  binding.writeDoubleLE(this, val, offset);
+  return offset + 8;
+};
+
+
+Buffer.prototype.writeDoubleBE = function writeDoubleBE(val, offset, noAssert) {
+  val = +val;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkFloat(this, val, offset, 8);
+  binding.writeDoubleBE(this, val, offset);
+  return offset + 8;
+};
diff --git a/lib/internal/buffer_old.js b/lib/internal/buffer_old.js
new file mode 100644 (file)
index 0000000..d892fd6
--- /dev/null
@@ -0,0 +1,1140 @@
+'use strict';
+
+const binding = process.binding('buffer');
+const smalloc = process.binding('smalloc');
+const internalUtil = require('internal/util');
+const alloc = smalloc.alloc;
+const truncate = smalloc.truncate;
+const sliceOnto = smalloc.sliceOnto;
+const kMaxLength = smalloc.kMaxLength;
+
+exports.Buffer = Buffer;
+exports.SlowBuffer = SlowBuffer;
+exports.INSPECT_MAX_BYTES = 50;
+
+
+Buffer.poolSize = 8 * 1024;
+var poolSize, poolOffset, allocPool;
+
+
+function createPool() {
+  poolSize = Buffer.poolSize;
+  allocPool = alloc({}, poolSize);
+  poolOffset = 0;
+}
+createPool();
+
+function Buffer(arg) {
+  if (!(this instanceof Buffer)) {
+    // Avoid going through an ArgumentsAdaptorTrampoline in the common case.
+    if (arguments.length > 1)
+      return new Buffer(arg, arguments[1]);
+
+    return new Buffer(arg);
+  }
+
+  this.length = 0;
+  this.parent = undefined;
+
+  // Common case.
+  if (typeof(arg) === 'number') {
+    fromNumber(this, arg);
+    return;
+  }
+
+  // Slightly less common case.
+  if (typeof(arg) === 'string') {
+    fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8');
+    return;
+  }
+
+  // Unusual.
+  fromObject(this, arg);
+}
+
+function fromNumber(that, length) {
+  allocate(that, length < 0 ? 0 : checked(length) | 0);
+}
+
+function fromString(that, string, encoding) {
+  if (typeof(encoding) !== 'string' || encoding === '')
+    encoding = 'utf8';
+
+  // Assumption: byteLength() return value is always < kMaxLength.
+  var length = byteLength(string, encoding) | 0;
+  allocate(that, length);
+
+  var actual = that.write(string, encoding) | 0;
+  if (actual !== length) {
+    // Fix up for truncated base64 input.  Don't bother returning
+    // the unused two or three bytes to the pool.
+    that.length = actual;
+    truncate(that, actual);
+  }
+}
+
+function fromObject(that, object) {
+  if (object instanceof Buffer)
+    return fromBuffer(that, object);
+
+  if (Array.isArray(object))
+    return fromArray(that, object);
+
+  if (object == null)
+    throw new TypeError('must start with number, buffer, array or string');
+
+  if (object.buffer instanceof ArrayBuffer)
+    return fromTypedArray(that, object);
+
+  if (object.length)
+    return fromArrayLike(that, object);
+
+  return fromJsonObject(that, object);
+}
+
+function fromBuffer(that, buffer) {
+  var length = checked(buffer.length) | 0;
+  allocate(that, length);
+  buffer.copy(that, 0, 0, length);
+}
+
+function fromArray(that, array) {
+  var length = checked(array.length) | 0;
+  allocate(that, length);
+  for (var i = 0; i < length; i += 1)
+    that[i] = array[i] & 255;
+}
+
+// Duplicate of fromArray() to keep fromArray() monomorphic.
+function fromTypedArray(that, array) {
+  var length = checked(array.length) | 0;
+  allocate(that, length);
+  // Truncating the elements is probably not what people expect from typed
+  // arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior
+  // of the old Buffer constructor.
+  for (var i = 0; i < length; i += 1)
+    that[i] = array[i] & 255;
+}
+
+function fromArrayLike(that, array) {
+  var length = checked(array.length) | 0;
+  allocate(that, length);
+  for (var i = 0; i < length; i += 1)
+    that[i] = array[i] & 255;
+}
+
+// Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object.
+// Returns a zero-length buffer for inputs that don't conform to the spec.
+function fromJsonObject(that, object) {
+  var array;
+  var length = 0;
+
+  if (object.type === 'Buffer' && Array.isArray(object.data)) {
+    array = object.data;
+    length = checked(array.length) | 0;
+  }
+  allocate(that, length);
+
+  for (var i = 0; i < length; i += 1)
+    that[i] = array[i] & 255;
+}
+
+function allocate(that, length) {
+  var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1;
+  if (fromPool)
+    that.parent = palloc(that, length);
+  else
+    alloc(that, length);
+  that.length = length;
+}
+
+function palloc(that, length) {
+  if (length > poolSize - poolOffset)
+    createPool();
+
+  var start = poolOffset;
+  var end = start + length;
+  var buf = sliceOnto(allocPool, that, start, end);
+  poolOffset = end;
+
+  // Ensure aligned slices
+  if (poolOffset & 0x7) {
+    poolOffset |= 0x7;
+    poolOffset++;
+  }
+
+  return buf;
+}
+
+function checked(length) {
+  // Note: cannot use `length < kMaxLength` here because that fails when
+  // length is NaN (which is otherwise coerced to zero.)
+  if (length >= kMaxLength) {
+    throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
+                         'size: 0x' + kMaxLength.toString(16) + ' bytes');
+  }
+  return length >>> 0;
+}
+
+function SlowBuffer(length) {
+  length = length >>> 0;
+  if (length > kMaxLength) {
+    throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
+                         'size: 0x' + kMaxLength.toString(16) + ' bytes');
+  }
+  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 >>> 0;
+  // Set this to keep the object map the same.
+  this.parent = undefined;
+}
+NativeBuffer.prototype = Buffer.prototype;
+
+
+// add methods to Buffer prototype
+binding.setupBufferJS(NativeBuffer);
+
+
+// Static methods
+
+Buffer.isBuffer = function isBuffer(b) {
+  return b instanceof Buffer;
+};
+
+
+Buffer.compare = function compare(a, b) {
+  if (!(a instanceof Buffer) ||
+      !(b instanceof Buffer))
+    throw new TypeError('Arguments must be Buffers');
+
+  if (a === b)
+    return 0;
+
+  return binding.compare(a, b);
+};
+
+
+Buffer.isEncoding = function(encoding) {
+  switch ((encoding + '').toLowerCase()) {
+    case 'hex':
+    case 'utf8':
+    case 'utf-8':
+    case 'ascii':
+    case 'binary':
+    case 'base64':
+    case 'ucs2':
+    case 'ucs-2':
+    case 'utf16le':
+    case 'utf-16le':
+    case 'raw':
+      return true;
+
+    default:
+      return false;
+  }
+};
+
+
+Buffer.concat = function(list, length) {
+  if (!Array.isArray(list))
+    throw new TypeError('list argument must be an Array of Buffers.');
+
+  if (list.length === 0)
+    return new Buffer(0);
+  else if (list.length === 1)
+    return list[0];
+
+  if (length === undefined) {
+    length = 0;
+    for (var i = 0; i < list.length; i++)
+      length += list[i].length;
+  } else {
+    length = length >>> 0;
+  }
+
+  var buffer = new Buffer(length);
+  var pos = 0;
+  for (var i = 0; i < list.length; i++) {
+    var buf = list[i];
+    buf.copy(buffer, pos);
+    pos += buf.length;
+  }
+
+  return buffer;
+};
+
+
+function base64ByteLength(str, bytes) {
+  // Handle padding
+  if (str.charCodeAt(bytes - 1) === 0x3D)
+    bytes--;
+  if (bytes > 1 && str.charCodeAt(bytes - 1) === 0x3D)
+    bytes--;
+
+  // Base64 ratio: 3/4
+  return (bytes * 3) >>> 2;
+}
+
+
+function byteLength(string, encoding) {
+  if (typeof string !== 'string')
+    string = '' + string;
+
+  var len = string.length;
+  if (len === 0)
+    return 0;
+
+  // Use a for loop to avoid recursion
+  var loweredCase = false;
+  for (;;) {
+    switch (encoding) {
+      case 'ascii':
+      case 'binary':
+      // Deprecated
+      case 'raw':
+      case 'raws':
+        return len;
+
+      case 'utf8':
+      case 'utf-8':
+        return binding.byteLengthUtf8(string);
+
+      case 'ucs2':
+      case 'ucs-2':
+      case 'utf16le':
+      case 'utf-16le':
+        return len * 2;
+
+      case 'hex':
+        return len >>> 1;
+
+      case 'base64':
+        return base64ByteLength(string, len);
+
+      default:
+        // The C++ binding defaulted to UTF8, we should too.
+        if (loweredCase)
+          return binding.byteLengthUtf8(string);
+
+        encoding = ('' + encoding).toLowerCase();
+        loweredCase = true;
+    }
+  }
+}
+
+Buffer.byteLength = byteLength;
+
+// toString(encoding, start=0, end=buffer.length)
+Buffer.prototype.toString = function(encoding, start, end) {
+  var loweredCase = false;
+
+  start = start >>> 0;
+  end = end === undefined || end === Infinity ? this.length : end >>> 0;
+
+  if (!encoding) encoding = 'utf8';
+  if (start < 0) start = 0;
+  if (end > this.length) end = this.length;
+  if (end <= start) return '';
+
+  while (true) {
+    switch (encoding) {
+      case 'hex':
+        return this.hexSlice(start, end);
+
+      case 'utf8':
+      case 'utf-8':
+        return this.utf8Slice(start, end);
+
+      case 'ascii':
+        return this.asciiSlice(start, end);
+
+      case 'binary':
+        return this.binarySlice(start, end);
+
+      case 'base64':
+        return this.base64Slice(start, end);
+
+      case 'ucs2':
+      case 'ucs-2':
+      case 'utf16le':
+      case 'utf-16le':
+        return this.ucs2Slice(start, end);
+
+      default:
+        if (loweredCase)
+          throw new TypeError('Unknown encoding: ' + encoding);
+        encoding = (encoding + '').toLowerCase();
+        loweredCase = true;
+    }
+  }
+};
+
+
+Buffer.prototype.equals = function equals(b) {
+  if (!(b instanceof Buffer))
+    throw new TypeError('Argument must be a Buffer');
+
+  if (this === b)
+    return true;
+
+  return binding.compare(this, b) === 0;
+};
+
+
+// Inspect
+Buffer.prototype.inspect = function inspect() {
+  var str = '';
+  var max = exports.INSPECT_MAX_BYTES;
+  if (this.length > 0) {
+    str = this.toString('hex', 0, max).match(/.{2}/g).join(' ');
+    if (this.length > max)
+      str += ' ... ';
+  }
+  return '<' + this.constructor.name + ' ' + str + '>';
+};
+
+
+Buffer.prototype.compare = function compare(b) {
+  if (!(b instanceof Buffer))
+    throw new TypeError('Argument must be a Buffer');
+
+  if (this === b)
+    return 0;
+
+  return binding.compare(this, b);
+};
+
+
+Buffer.prototype.indexOf = function indexOf(val, byteOffset) {
+  if (byteOffset > 0x7fffffff)
+    byteOffset = 0x7fffffff;
+  else if (byteOffset < -0x80000000)
+    byteOffset = -0x80000000;
+  byteOffset >>= 0;
+
+  if (typeof val === 'string')
+    return binding.indexOfString(this, val, byteOffset);
+  if (val instanceof Buffer)
+    return binding.indexOfBuffer(this, val, byteOffset);
+  if (typeof val === 'number')
+    return binding.indexOfNumber(this, val, byteOffset);
+
+  throw new TypeError('val must be string, number or Buffer');
+};
+
+
+Buffer.prototype.fill = function fill(val, start, end) {
+  start = start >> 0;
+  end = (end === undefined) ? this.length : end >> 0;
+
+  if (start < 0 || end > this.length)
+    throw new RangeError('out of range index');
+  if (end <= start)
+    return this;
+
+  if (typeof val !== 'string') {
+    val = val >>> 0;
+  } else if (val.length === 1) {
+    var code = val.charCodeAt(0);
+    if (code < 256)
+      val = code;
+  }
+
+  binding.fill(this, val, start, end);
+
+  return this;
+};
+
+
+// XXX remove in v0.13
+Buffer.prototype.get = internalUtil.deprecate(function get(offset) {
+  offset = ~~offset;
+  if (offset < 0 || offset >= this.length)
+    throw new RangeError('index out of range');
+  return this[offset];
+}, '.get() is deprecated. Access using array indexes instead.');
+
+
+// XXX remove in v0.13
+Buffer.prototype.set = internalUtil.deprecate(function set(offset, v) {
+  offset = ~~offset;
+  if (offset < 0 || offset >= this.length)
+    throw new RangeError('index out of range');
+  return this[offset] = v;
+}, '.set() is deprecated. Set using array indexes instead.');
+
+
+// TODO(trevnorris): fix these checks to follow new standard
+// write(string, offset = 0, length = buffer.length, encoding = 'utf8')
+var writeWarned = false;
+const writeMsg = '.write(string, encoding, offset, length) is deprecated.' +
+                 ' Use write(string[, offset[, length]][, encoding]) instead.';
+Buffer.prototype.write = function(string, offset, length, encoding) {
+  // Buffer#write(string);
+  if (offset === undefined) {
+    encoding = 'utf8';
+    length = this.length;
+    offset = 0;
+
+  // Buffer#write(string, encoding)
+  } else if (length === undefined && typeof offset === 'string') {
+    encoding = offset;
+    length = this.length;
+    offset = 0;
+
+  // Buffer#write(string, offset[, length][, encoding])
+  } else if (isFinite(offset)) {
+    offset = offset >>> 0;
+    if (isFinite(length)) {
+      length = length >>> 0;
+      if (encoding === undefined)
+        encoding = 'utf8';
+    } else {
+      encoding = length;
+      length = undefined;
+    }
+
+  // XXX legacy write(string, encoding, offset, length) - remove in v0.13
+  } else {
+    writeWarned = internalUtil.printDeprecationMessage(writeMsg, writeWarned);
+    var swap = encoding;
+    encoding = offset;
+    offset = length >>> 0;
+    length = swap;
+  }
+
+  var remaining = this.length - offset;
+  if (length === undefined || length > remaining)
+    length = remaining;
+
+  if (string.length > 0 && (length < 0 || offset < 0))
+    throw new RangeError('attempt to write outside buffer bounds');
+
+  if (!encoding)
+    encoding = 'utf8';
+
+  var loweredCase = false;
+  for (;;) {
+    switch (encoding) {
+      case 'hex':
+        return this.hexWrite(string, offset, length);
+
+      case 'utf8':
+      case 'utf-8':
+        return this.utf8Write(string, offset, length);
+
+      case 'ascii':
+        return this.asciiWrite(string, offset, length);
+
+      case 'binary':
+        return this.binaryWrite(string, offset, length);
+
+      case 'base64':
+        // Warning: maxLength not taken into account in base64Write
+        return this.base64Write(string, offset, length);
+
+      case 'ucs2':
+      case 'ucs-2':
+      case 'utf16le':
+      case 'utf-16le':
+        return this.ucs2Write(string, offset, length);
+
+      default:
+        if (loweredCase)
+          throw new TypeError('Unknown encoding: ' + encoding);
+        encoding = ('' + encoding).toLowerCase();
+        loweredCase = true;
+    }
+  }
+};
+
+
+Buffer.prototype.toJSON = function() {
+  return {
+    type: 'Buffer',
+    data: Array.prototype.slice.call(this, 0)
+  };
+};
+
+
+// TODO(trevnorris): currently works like Array.prototype.slice(), which
+// doesn't follow the new standard for throwing on out of range indexes.
+Buffer.prototype.slice = function(start, end) {
+  var len = this.length;
+  start = ~~start;
+  end = end === undefined ? len : ~~end;
+
+  if (start < 0) {
+    start += len;
+    if (start < 0)
+      start = 0;
+  } else if (start > len) {
+    start = len;
+  }
+
+  if (end < 0) {
+    end += len;
+    if (end < 0)
+      end = 0;
+  } else if (end > len) {
+    end = len;
+  }
+
+  if (end < start)
+    end = start;
+
+  var buf = new NativeBuffer();
+  sliceOnto(this, buf, start, end);
+  buf.length = end - start;
+  if (buf.length > 0)
+    buf.parent = this.parent === undefined ? this : this.parent;
+
+  return buf;
+};
+
+
+function checkOffset(offset, ext, length) {
+  if (offset + ext > length)
+    throw new RangeError('index out of range');
+}
+
+
+Buffer.prototype.readUIntLE = function(offset, byteLength, noAssert) {
+  offset = offset >>> 0;
+  byteLength = byteLength >>> 0;
+  if (!noAssert)
+    checkOffset(offset, byteLength, this.length);
+
+  var val = this[offset];
+  var mul = 1;
+  var i = 0;
+  while (++i < byteLength && (mul *= 0x100))
+    val += this[offset + i] * mul;
+
+  return val;
+};
+
+
+Buffer.prototype.readUIntBE = function(offset, byteLength, noAssert) {
+  offset = offset >>> 0;
+  byteLength = byteLength >>> 0;
+  if (!noAssert)
+    checkOffset(offset, byteLength, this.length);
+
+  var val = this[offset + --byteLength];
+  var mul = 1;
+  while (byteLength > 0 && (mul *= 0x100))
+    val += this[offset + --byteLength] * mul;
+
+  return val;
+};
+
+
+Buffer.prototype.readUInt8 = function(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 1, this.length);
+  return this[offset];
+};
+
+
+Buffer.prototype.readUInt16LE = function(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 2, this.length);
+  return this[offset] | (this[offset + 1] << 8);
+};
+
+
+Buffer.prototype.readUInt16BE = function(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 2, this.length);
+  return (this[offset] << 8) | this[offset + 1];
+};
+
+
+Buffer.prototype.readUInt32LE = function(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 4, this.length);
+
+  return ((this[offset]) |
+      (this[offset + 1] << 8) |
+      (this[offset + 2] << 16)) +
+      (this[offset + 3] * 0x1000000);
+};
+
+
+Buffer.prototype.readUInt32BE = function(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 4, this.length);
+
+  return (this[offset] * 0x1000000) +
+      ((this[offset + 1] << 16) |
+      (this[offset + 2] << 8) |
+      this[offset + 3]);
+};
+
+
+Buffer.prototype.readIntLE = function(offset, byteLength, noAssert) {
+  offset = offset >>> 0;
+  byteLength = byteLength >>> 0;
+  if (!noAssert)
+    checkOffset(offset, byteLength, this.length);
+
+  var val = this[offset];
+  var mul = 1;
+  var i = 0;
+  while (++i < byteLength && (mul *= 0x100))
+    val += this[offset + i] * mul;
+  mul *= 0x80;
+
+  if (val >= mul)
+    val -= Math.pow(2, 8 * byteLength);
+
+  return val;
+};
+
+
+Buffer.prototype.readIntBE = function(offset, byteLength, noAssert) {
+  offset = offset >>> 0;
+  byteLength = byteLength >>> 0;
+  if (!noAssert)
+    checkOffset(offset, byteLength, this.length);
+
+  var i = byteLength;
+  var mul = 1;
+  var val = this[offset + --i];
+  while (i > 0 && (mul *= 0x100))
+    val += this[offset + --i] * mul;
+  mul *= 0x80;
+
+  if (val >= mul)
+    val -= Math.pow(2, 8 * byteLength);
+
+  return val;
+};
+
+
+Buffer.prototype.readInt8 = function(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 1, this.length);
+  var val = this[offset];
+  return !(val & 0x80) ? val : (0xff - val + 1) * -1;
+};
+
+
+Buffer.prototype.readInt16LE = function(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 2, this.length);
+  var val = this[offset] | (this[offset + 1] << 8);
+  return (val & 0x8000) ? val | 0xFFFF0000 : val;
+};
+
+
+Buffer.prototype.readInt16BE = function(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 2, this.length);
+  var val = this[offset + 1] | (this[offset] << 8);
+  return (val & 0x8000) ? val | 0xFFFF0000 : val;
+};
+
+
+Buffer.prototype.readInt32LE = function(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 4, this.length);
+
+  return (this[offset]) |
+      (this[offset + 1] << 8) |
+      (this[offset + 2] << 16) |
+      (this[offset + 3] << 24);
+};
+
+
+Buffer.prototype.readInt32BE = function(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 4, this.length);
+
+  return (this[offset] << 24) |
+      (this[offset + 1] << 16) |
+      (this[offset + 2] << 8) |
+      (this[offset + 3]);
+};
+
+
+Buffer.prototype.readFloatLE = function readFloatLE(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 4, this.length);
+  return binding.readFloatLE(this, offset);
+};
+
+
+Buffer.prototype.readFloatBE = function readFloatBE(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 4, this.length);
+  return binding.readFloatBE(this, offset);
+};
+
+
+Buffer.prototype.readDoubleLE = function readDoubleLE(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 8, this.length);
+  return binding.readDoubleLE(this, offset);
+};
+
+
+Buffer.prototype.readDoubleBE = function readDoubleBE(offset, noAssert) {
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkOffset(offset, 8, this.length);
+  return binding.readDoubleBE(this, offset);
+};
+
+
+function checkInt(buffer, value, offset, ext, max, min) {
+  if (!(buffer instanceof Buffer))
+    throw new TypeError('buffer must be a Buffer instance');
+  if (value > max || value < min)
+    throw new TypeError('value is out of bounds');
+  if (offset + ext > buffer.length)
+    throw new RangeError('index out of range');
+}
+
+
+Buffer.prototype.writeUIntLE = function(value, offset, byteLength, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  byteLength = byteLength >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0);
+
+  var mul = 1;
+  var i = 0;
+  this[offset] = value;
+  while (++i < byteLength && (mul *= 0x100))
+    this[offset + i] = (value / mul) >>> 0;
+
+  return offset + byteLength;
+};
+
+
+Buffer.prototype.writeUIntBE = function(value, offset, byteLength, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  byteLength = byteLength >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0);
+
+  var i = byteLength - 1;
+  var mul = 1;
+  this[offset + i] = value;
+  while (--i >= 0 && (mul *= 0x100))
+    this[offset + i] = (value / mul) >>> 0;
+
+  return offset + byteLength;
+};
+
+
+Buffer.prototype.writeUInt8 = function(value, offset, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, 1, 0xff, 0);
+  this[offset] = value;
+  return offset + 1;
+};
+
+
+Buffer.prototype.writeUInt16LE = function(value, offset, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, 2, 0xffff, 0);
+  this[offset] = value;
+  this[offset + 1] = (value >>> 8);
+  return offset + 2;
+};
+
+
+Buffer.prototype.writeUInt16BE = function(value, offset, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, 2, 0xffff, 0);
+  this[offset] = (value >>> 8);
+  this[offset + 1] = value;
+  return offset + 2;
+};
+
+
+Buffer.prototype.writeUInt32LE = function(value, offset, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, 4, 0xffffffff, 0);
+  this[offset + 3] = (value >>> 24);
+  this[offset + 2] = (value >>> 16);
+  this[offset + 1] = (value >>> 8);
+  this[offset] = value;
+  return offset + 4;
+};
+
+
+Buffer.prototype.writeUInt32BE = function(value, offset, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, 4, 0xffffffff, 0);
+  this[offset] = (value >>> 24);
+  this[offset + 1] = (value >>> 16);
+  this[offset + 2] = (value >>> 8);
+  this[offset + 3] = value;
+  return offset + 4;
+};
+
+
+Buffer.prototype.writeIntLE = function(value, offset, byteLength, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert) {
+    checkInt(this,
+             value,
+             offset,
+             byteLength,
+             Math.pow(2, 8 * byteLength - 1) - 1,
+             -Math.pow(2, 8 * byteLength - 1));
+  }
+
+  var i = 0;
+  var mul = 1;
+  var sub = value < 0 ? 1 : 0;
+  this[offset] = value;
+  while (++i < byteLength && (mul *= 0x100))
+    this[offset + i] = ((value / mul) >> 0) - sub;
+
+  return offset + byteLength;
+};
+
+
+Buffer.prototype.writeIntBE = function(value, offset, byteLength, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert) {
+    checkInt(this,
+             value,
+             offset,
+             byteLength,
+             Math.pow(2, 8 * byteLength - 1) - 1,
+             -Math.pow(2, 8 * byteLength - 1));
+  }
+
+  var i = byteLength - 1;
+  var mul = 1;
+  var sub = value < 0 ? 1 : 0;
+  this[offset + i] = value;
+  while (--i >= 0 && (mul *= 0x100))
+    this[offset + i] = ((value / mul) >> 0) - sub;
+
+  return offset + byteLength;
+};
+
+
+Buffer.prototype.writeInt8 = function(value, offset, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, 1, 0x7f, -0x80);
+  this[offset] = value;
+  return offset + 1;
+};
+
+
+Buffer.prototype.writeInt16LE = function(value, offset, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, 2, 0x7fff, -0x8000);
+  this[offset] = value;
+  this[offset + 1] = (value >>> 8);
+  return offset + 2;
+};
+
+
+Buffer.prototype.writeInt16BE = function(value, offset, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, 2, 0x7fff, -0x8000);
+  this[offset] = (value >>> 8);
+  this[offset + 1] = value;
+  return offset + 2;
+};
+
+
+Buffer.prototype.writeInt32LE = function(value, offset, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);
+  this[offset] = value;
+  this[offset + 1] = (value >>> 8);
+  this[offset + 2] = (value >>> 16);
+  this[offset + 3] = (value >>> 24);
+  return offset + 4;
+};
+
+
+Buffer.prototype.writeInt32BE = function(value, offset, noAssert) {
+  value = +value;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);
+  this[offset] = (value >>> 24);
+  this[offset + 1] = (value >>> 16);
+  this[offset + 2] = (value >>> 8);
+  this[offset + 3] = value;
+  return offset + 4;
+};
+
+
+function checkFloat(buffer, value, offset, ext) {
+  if (!(buffer instanceof Buffer))
+    throw new TypeError('buffer must be a Buffer instance');
+  if (offset + ext > buffer.length)
+    throw new RangeError('index out of range');
+}
+
+
+Buffer.prototype.writeFloatLE = function writeFloatLE(val, offset, noAssert) {
+  val = +val;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkFloat(this, val, offset, 4);
+  binding.writeFloatLE(this, val, offset);
+  return offset + 4;
+};
+
+
+Buffer.prototype.writeFloatBE = function writeFloatBE(val, offset, noAssert) {
+  val = +val;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkFloat(this, val, offset, 4);
+  binding.writeFloatBE(this, val, offset);
+  return offset + 4;
+};
+
+
+Buffer.prototype.writeDoubleLE = function writeDoubleLE(val, offset, noAssert) {
+  val = +val;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkFloat(this, val, offset, 8);
+  binding.writeDoubleLE(this, val, offset);
+  return offset + 8;
+};
+
+
+Buffer.prototype.writeDoubleBE = function writeDoubleBE(val, offset, noAssert) {
+  val = +val;
+  offset = offset >>> 0;
+  if (!noAssert)
+    checkFloat(this, val, offset, 8);
+  binding.writeDoubleBE(this, val, offset);
+  return offset + 8;
+};
+
+// ES6 iterator
+
+var ITERATOR_KIND_KEYS = 1;
+var ITERATOR_KIND_ENTRIES = 3;
+
+function BufferIteratorResult(value, done) {
+  this.value = value;
+  this.done = done;
+}
+
+var resultCache = new Array(256);
+
+for (var i = 0; i < 256; i++)
+  resultCache[i] = Object.freeze(new BufferIteratorResult(i, false));
+
+var finalResult = Object.freeze(new BufferIteratorResult(undefined, true));
+
+function BufferIterator(buffer, kind) {
+  this._buffer = buffer;
+  this._kind = kind;
+  this._index = 0;
+}
+
+BufferIterator.prototype.next = function() {
+  var buffer = this._buffer;
+  var kind = this._kind;
+  var index = this._index;
+
+  if (index >= buffer.length)
+    return finalResult;
+
+  this._index++;
+
+  if (kind === ITERATOR_KIND_ENTRIES)
+    return new BufferIteratorResult([index, buffer[index]], false);
+
+  return new BufferIteratorResult(index, false);
+};
+
+function BufferValueIterator(buffer) {
+  BufferIterator.call(this, buffer, null);
+}
+
+BufferValueIterator.prototype.next = function() {
+  var buffer = this._buffer;
+  var index = this._index;
+
+  if (index >= buffer.length)
+    return finalResult;
+
+  this._index++;
+
+  return resultCache[buffer[index]];
+};
+
+
+BufferIterator.prototype[Symbol.iterator] = function() {
+  return this;
+};
+
+BufferValueIterator.prototype[Symbol.iterator] =
+    BufferIterator.prototype[Symbol.iterator];
+
+Buffer.prototype.keys = function() {
+  return new BufferIterator(this, ITERATOR_KIND_KEYS);
+};
+
+Buffer.prototype.entries = function() {
+  return new BufferIterator(this, ITERATOR_KIND_ENTRIES);
+};
+
+Buffer.prototype.values = function() {
+  return new BufferValueIterator(this);
+};
+
+Buffer.prototype[Symbol.iterator] = Buffer.prototype.values;
index dfa08ce..197f439 100644 (file)
--- a/node.gyp
+++ b/node.gyp
@@ -69,8 +69,9 @@
       'lib/v8.js',
       'lib/vm.js',
       'lib/zlib.js',
-
       'lib/internal/child_process.js',
+      'lib/internal/buffer_old.js',
+      'lib/internal/buffer_new.js',
       'lib/internal/freelist.js',
       'lib/internal/smalloc.js',
       'lib/internal/socket_list.js',
index 7289521..84beabc 100644 (file)
--- a/src/env.h
+++ b/src/env.h
@@ -231,6 +231,7 @@ namespace node {
   V(async_hooks_post_function, v8::Function)                                  \
   V(binding_cache_object, v8::Object)                                         \
   V(buffer_constructor_function, v8::Function)                                \
+  V(buffer_prototype_object, v8::Object)                                      \
   V(context, v8::Context)                                                     \
   V(domain_array, v8::Array)                                                  \
   V(fs_stats_constructor_function, v8::Function)                              \
index 631a595..4d699e8 100644 (file)
@@ -5,6 +5,7 @@
 #include "node_http_parser.h"
 #include "node_javascript.h"
 #include "node_version.h"
+#include "node_internals.h"
 
 #if defined HAVE_PERFCTR
 #include "node_counters.h"
@@ -147,6 +148,8 @@ static uv_async_t dispatch_debug_messages_async;
 static Isolate* node_isolate = nullptr;
 static v8::Platform* default_platform;
 
+bool using_old_buffer = false;
+
 class ArrayBufferAllocator : public ArrayBuffer::Allocator {
  public:
   // Impose an upper limit to avoid out of memory errors that bring down
@@ -166,23 +169,17 @@ ArrayBufferAllocator ArrayBufferAllocator::the_singleton;
 
 
 void* ArrayBufferAllocator::Allocate(size_t length) {
-  if (length > kMaxLength)
-    return nullptr;
-  char* data = new char[length];
-  memset(data, 0, length);
-  return data;
+  return calloc(length, 1);
 }
 
 
 void* ArrayBufferAllocator::AllocateUninitialized(size_t length) {
-  if (length > kMaxLength)
-    return nullptr;
-  return new char[length];
+  return malloc(length);
 }
 
 
 void ArrayBufferAllocator::Free(void* data, size_t length) {
-  delete[] static_cast<char*>(data);
+  free(data);
 }
 
 
@@ -2836,6 +2833,11 @@ void SetupProcessObject(Environment* env,
     READONLY_PROPERTY(process, "traceDeprecation", True(env->isolate()));
   }
 
+  // --use-old_buffer
+  if (using_old_buffer) {
+    READONLY_PROPERTY(process, "useOldBuffer", True(env->isolate()));
+  }
+
   size_t exec_path_len = 2 * PATH_MAX;
   char* exec_path = new char[exec_path_len];
   Local<String> exec_path_value;
@@ -3067,6 +3069,7 @@ static void PrintHelp() {
          "  --track-heap-objects  track heap object allocations for heap "
          "snapshots\n"
          "  --v8-options          print v8 command line options\n"
+         "  --use-old-buffer      Revert to old Buffer implementation\n"
 #if defined(NODE_HAVE_I18N_SUPPORT)
          "  --icu-data-dir=dir    set ICU data load path to dir\n"
          "                          (overrides NODE_ICU_DATA)\n"
@@ -3204,6 +3207,10 @@ static void ParseArgs(int* argc,
 #endif
     } else if (strcmp(arg, "--expose-internals") == 0 ||
                strcmp(arg, "--expose_internals") == 0) {
+    } else if (strcmp(arg, "--use-old-buffer") == 0 ||
+               strcmp(arg, "--use_old_buffer") == 0) {
+      using_old_buffer = true;
+
       // consumed in js
     } else {
       // V8 option.  Pass through as-is.
index 3f42981..d339807 100644 (file)
@@ -5,6 +5,8 @@
 #include "env-inl.h"
 #include "smalloc.h"
 #include "string_bytes.h"
+#include "util.h"
+#include "util-inl.h"
 #include "v8-profiler.h"
 #include "v8.h"
 
   size_t name##_length;                                                     \
   char* name##_data;
 
+#define SPREAD_ARG(val, name)                                                 \
+  CHECK((val)->IsUint8Array());                                               \
+  Local<Uint8Array> name = (val).As<Uint8Array>();                            \
+  ArrayBuffer::Contents name##_c = name->Buffer()->GetContents();             \
+  size_t name##_offset = name->ByteOffset();                                  \
+  name##_length = name->ByteLength();                                         \
+  name##_data = static_cast<char*>(name##_c.Data()) + name##_offset;          \
+  if (name##_length > 0)                                                      \
+    CHECK_NE(name##_data, nullptr);
+
 #define ARGS_THIS(argT, name)                                                 \
   Local<Object> name = argT;                                                  \
   name##_length = name->GetIndexedPropertiesExternalArrayDataLength();        \
@@ -48,6 +60,8 @@
 namespace node {
 namespace Buffer {
 
+using v8::ArrayBuffer;
+using v8::ArrayBufferCreationMode;
 using v8::Context;
 using v8::EscapableHandleScope;
 using v8::Function;
@@ -61,6 +75,7 @@ using v8::Number;
 using v8::Object;
 using v8::String;
 using v8::Uint32;
+using v8::Uint8Array;
 using v8::Value;
 
 
@@ -70,10 +85,19 @@ bool HasInstance(Handle<Value> val) {
 
 
 bool HasInstance(Handle<Object> obj) {
-  if (!obj->HasIndexedPropertiesInExternalArrayData())
+  if (using_old_buffer) {
+    if (!obj->HasIndexedPropertiesInExternalArrayData())
+      return false;
+    v8::ExternalArrayType type =
+        obj->GetIndexedPropertiesExternalArrayDataType();
+    return type == v8::kExternalUint8Array;
+  }
+
+  if (!obj->IsUint8Array())
     return false;
-  v8::ExternalArrayType type = obj->GetIndexedPropertiesExternalArrayDataType();
-  return type == v8::kExternalUint8Array;
+  Local<Uint8Array> array = obj.As<Uint8Array>();
+  Environment* env = Environment::GetCurrent(array->GetIsolate());
+  return array->GetPrototype()->StrictEquals(env->buffer_prototype_object());
 }
 
 
@@ -86,8 +110,15 @@ char* Data(Handle<Value> val) {
 
 
 char* Data(Handle<Object> obj) {
-  CHECK(obj->HasIndexedPropertiesInExternalArrayData());
-  return static_cast<char*>(obj->GetIndexedPropertiesExternalArrayData());
+  if (using_old_buffer) {
+    CHECK(obj->HasIndexedPropertiesInExternalArrayData());
+    return static_cast<char*>(obj->GetIndexedPropertiesExternalArrayData());
+  }
+
+  CHECK(obj->IsUint8Array());
+  Local<Uint8Array> ui = obj.As<Uint8Array>();
+  ArrayBuffer::Contents ab_c = ui->Buffer()->GetContents();
+  return static_cast<char*>(ab_c.Data()) + ui->ByteOffset();
 }
 
 
@@ -98,8 +129,14 @@ size_t Length(Handle<Value> val) {
 
 
 size_t Length(Handle<Object> obj) {
-  CHECK(obj->HasIndexedPropertiesInExternalArrayData());
-  return obj->GetIndexedPropertiesExternalArrayDataLength();
+  if (using_old_buffer) {
+    CHECK(obj->HasIndexedPropertiesInExternalArrayData());
+    return obj->GetIndexedPropertiesExternalArrayDataLength();
+  }
+
+  CHECK(obj->IsUint8Array());
+  Local<Uint8Array> ui = obj.As<Uint8Array>();
+  return ui->ByteLength();
 }
 
 
@@ -107,11 +144,20 @@ Local<Object> New(Isolate* isolate, Handle<String> string, enum encoding enc) {
   EscapableHandleScope scope(isolate);
 
   size_t length = StringBytes::Size(isolate, string, enc);
+  char* data = static_cast<char*>(malloc(length));
 
-  Local<Object> buf = New(isolate, length);
-  char* data = Buffer::Data(buf);
-  StringBytes::Write(isolate, data, length, string, enc);
+  if (data == nullptr)
+    return Local<Object>();
 
+  size_t actual = StringBytes::Write(isolate, data, length, string, enc);
+  CHECK(actual <= length);
+
+  if (actual < length) {
+    data = static_cast<char*>(realloc(data, actual));
+    CHECK_NE(data, nullptr);
+  }
+
+  Local<Object> buf = Use(isolate, data, actual);
   return scope.Escape(buf);
 }
 
@@ -123,19 +169,44 @@ Local<Object> New(Isolate* isolate, size_t length) {
 }
 
 
-// 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(Environment* env, size_t length) {
   EscapableHandleScope scope(env->isolate());
 
-  CHECK_LE(length, kMaxLength);
+  if (using_old_buffer) {
+    CHECK_LE(length, kMaxLength);
 
-  Local<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
-  Local<Object> obj = env->buffer_constructor_function()->NewInstance(1, &arg);
+    Local<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
+    Local<Object> obj =
+        env->buffer_constructor_function()->NewInstance(1, &arg);
 
-  smalloc::Alloc(env, obj, length);
+    smalloc::Alloc(env, obj, length);
 
-  return scope.Escape(obj);
+    return scope.Escape(obj);
+  }
+
+  // V8 currently only allows a maximum Typed Array index of max Smi.
+  if (!IsValidSmi(length)) {
+    return Local<Object>();
+  }
+
+  void* data;
+  if (length > 0) {
+    data = malloc(length);
+    // NOTE: API change. Must check .IsEmpty() on the return object to see if
+    // the data was able to be allocated.
+    if (data == nullptr)
+      return Local<Object>();
+  } else {
+    data = nullptr;
+  }
+  Local<ArrayBuffer> ab =
+    ArrayBuffer::New(env->isolate(),
+        data,
+        length,
+        ArrayBufferCreationMode::kInternalized);
+  Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
+  ui->SetPrototype(env->buffer_prototype_object());
+  return scope.Escape(ui);
 }
 
 
@@ -147,33 +218,59 @@ Local<Object> New(Isolate* isolate, const char* data, size_t length) {
 }
 
 
-// TODO(trevnorris): for backwards compatibility this is left to copy the data,
-// but for consistency w/ the other should use data. And a copy version renamed
-// to something else.
+// Make a copy of "data". Why this isn't called "Copy", we'll never know.
 Local<Object> New(Environment* env, const char* data, size_t length) {
   EscapableHandleScope scope(env->isolate());
 
-  CHECK_LE(length, kMaxLength);
+  if (using_old_buffer) {
+    CHECK_LE(length, kMaxLength);
+
+    Local<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
+    Local<Object> obj =
+        env->buffer_constructor_function()->NewInstance(1, &arg);
+
+    char* new_data;
+    if (length > 0) {
+      new_data = static_cast<char*>(malloc(length));
+      if (new_data == nullptr)
+        FatalError("node::Buffer::New(const char*, size_t)", "Out Of Memory");
+      memcpy(new_data, data, length);
+    } else {
+      new_data = nullptr;
+    }
 
-  Local<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
-  Local<Object> obj = env->buffer_constructor_function()->NewInstance(1, &arg);
+    smalloc::Alloc(env, obj, new_data, length);
 
-  // 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
-  // approach if v8 provided one.
-  char* new_data;
+    return scope.Escape(obj);
+  }
+
+  // V8 currently only allows a maximum Typed Array index of max Smi.
+  if (!IsValidSmi(length)) {
+    return Local<Object>();
+  }
+
+  void* new_data;
   if (length > 0) {
-    new_data = static_cast<char*>(malloc(length));
+    CHECK_NE(data, nullptr);
+    new_data = malloc(length);
+    // NOTE: API change. Must check .IsEmpty() on the return object to see if
+    // the data was able to be allocated.
     if (new_data == nullptr)
-      FatalError("node::Buffer::New(const char*, size_t)", "Out Of Memory");
+      return Local<Object>();
     memcpy(new_data, data, length);
   } else {
     new_data = nullptr;
   }
 
-  smalloc::Alloc(env, obj, new_data, length);
+  Local<ArrayBuffer> ab =
+    ArrayBuffer::New(env->isolate(),
+        new_data,
+        length,
+        ArrayBufferCreationMode::kInternalized);
+  Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
+  ui->SetPrototype(env->buffer_prototype_object());
 
-  return scope.Escape(obj);
+  return scope.Escape(ui);
 }
 
 
@@ -196,6 +293,7 @@ Local<Object> New(Environment* env,
                   void* hint) {
   EscapableHandleScope scope(env->isolate());
 
+  // TODO(trevnorris): IMPLEMENT
   CHECK_LE(length, kMaxLength);
 
   Local<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
@@ -207,7 +305,7 @@ Local<Object> New(Environment* env,
 }
 
 
-Local<Object> Use(Isolate* isolate, char* data, uint32_t length) {
+Local<Object> Use(Isolate* isolate, char* data, size_t length) {
   Environment* env = Environment::GetCurrent(isolate);
   EscapableHandleScope handle_scope(env->isolate());
   Local<Object> obj = Buffer::Use(env, data, length);
@@ -215,17 +313,98 @@ Local<Object> Use(Isolate* isolate, char* data, uint32_t length) {
 }
 
 
-Local<Object> Use(Environment* env, char* data, uint32_t length) {
+Local<Object> Use(Environment* env, char* data, size_t length) {
   EscapableHandleScope scope(env->isolate());
 
-  CHECK_LE(length, kMaxLength);
+  if (using_old_buffer) {
+    CHECK_LE(length, kMaxLength);
 
-  Local<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
-  Local<Object> obj = env->buffer_constructor_function()->NewInstance(1, &arg);
+    Local<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
+    Local<Object> obj =
+        env->buffer_constructor_function()->NewInstance(1, &arg);
 
-  smalloc::Alloc(env, obj, data, length);
+    smalloc::Alloc(env, obj, data, length);
 
-  return scope.Escape(obj);
+    return scope.Escape(obj);
+  }
+
+  if (length > 0) {
+    CHECK_NE(data, nullptr);
+    CHECK(IsValidSmi(length));
+  }
+
+  Local<ArrayBuffer> ab =
+      ArrayBuffer::New(env->isolate(),
+                       data,
+                       length,
+                       ArrayBufferCreationMode::kInternalized);
+  Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
+  ui->SetPrototype(env->buffer_prototype_object());
+  return scope.Escape(ui);
+}
+
+
+void Create(const FunctionCallbackInfo<Value>& args) {
+  Isolate* isolate = args.GetIsolate();
+  Environment* env = Environment::GetCurrent(args);
+
+  CHECK(args[0]->IsNumber());
+
+  int64_t length = args[0]->IntegerValue();
+
+  if (!IsValidSmi(length)) {
+    return env->ThrowRangeError("invalid Buffer length");
+  }
+
+  void* data;
+  if (length > 0) {
+    data = malloc(length);
+    if (data == nullptr)
+      return env->ThrowRangeError("invalid Buffer length");
+  } else {
+    data = nullptr;
+  }
+
+  Local<ArrayBuffer> ab =
+      ArrayBuffer::New(isolate,
+                       data,
+                       length,
+                       ArrayBufferCreationMode::kInternalized);
+  Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
+  ui->SetPrototype(env->buffer_prototype_object());
+  args.GetReturnValue().Set(ui);
+}
+
+
+void CreateFromString(const FunctionCallbackInfo<Value>& args) {
+  CHECK(args[0]->IsString());
+  CHECK(args[1]->IsString());
+
+  enum encoding enc = ParseEncoding(args.GetIsolate(),
+                                    args[1].As<String>(),
+                                    UTF8);
+  Local<Object> buf = New(args.GetIsolate(), args[0].As<String>(), enc);
+  args.GetReturnValue().Set(buf);
+}
+
+
+void Slice(const FunctionCallbackInfo<Value>& args) {
+  CHECK(args[0]->IsUint8Array());
+  CHECK(args[1]->IsNumber());
+  CHECK(args[2]->IsNumber());
+  Environment* env = Environment::GetCurrent(args);
+  Local<Uint8Array> ab_ui = args[0].As<Uint8Array>();
+  Local<ArrayBuffer> ab = ab_ui->Buffer();
+  ArrayBuffer::Contents ab_c = ab->GetContents();
+  size_t offset = ab_ui->ByteOffset();
+  size_t start = args[1]->NumberValue() + offset;
+  size_t end = args[2]->NumberValue() + offset;
+  CHECK_GE(end, start);
+  size_t size = end - start;
+  CHECK_GE(ab_c.ByteLength(), start + size);
+  Local<Uint8Array> ui = Uint8Array::New(ab, start, size);
+  ui->SetPrototype(env->buffer_prototype_object());
+  args.GetReturnValue().Set(ui);
 }
 
 
@@ -237,7 +416,12 @@ void StringSlice(const FunctionCallbackInfo<Value>& args) {
   THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
 
   ARGS_THIS_DEC(ts_obj);
-  ARGS_THIS(args.This(), ts_obj);
+
+  if (using_old_buffer) {
+    ARGS_THIS(args.This(), ts_obj);
+  } else {
+    SPREAD_ARG(args.This(), ts_obj);
+  }
 
   if (ts_obj_length == 0)
     return args.GetReturnValue().SetEmptyString();
@@ -252,10 +436,16 @@ void StringSlice(const FunctionCallbackInfo<Value>& args) {
 template <>
 void StringSlice<UCS2>(const FunctionCallbackInfo<Value>& args) {
   Environment* env = Environment::GetCurrent(args);
-  ARGS_THIS_DEC(ts_obj);
 
   THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
-  ARGS_THIS(args.This(), ts_obj);
+
+  ARGS_THIS_DEC(ts_obj);
+
+  if (using_old_buffer) {
+    ARGS_THIS(args.This(), ts_obj);
+  } else {
+    SPREAD_ARG(args.This(), ts_obj);
+  }
 
   if (ts_obj_length == 0)
     return args.GetReturnValue().SetEmptyString();
@@ -329,11 +519,22 @@ void Copy(const FunctionCallbackInfo<Value> &args) {
 
   THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
   THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
-  Local<Object> target_obj = args[0].As<Object>();
 
-  size_t target_length = target->GetIndexedPropertiesExternalArrayDataLength();
-  char* target_data = static_cast<char*>(
-      target->GetIndexedPropertiesExternalArrayData());
+  Local<Object> target_obj = args[0]->ToObject(env->isolate());
+
+  ARGS_THIS_DEC(ts_obj);
+  ARGS_THIS_DEC(target);
+
+  if (using_old_buffer) {
+    ARGS_THIS(args.This(), ts_obj);
+    target_length = target_obj->GetIndexedPropertiesExternalArrayDataLength();
+    target_data = static_cast<char*>(
+        target_obj->GetIndexedPropertiesExternalArrayData());
+  } else {
+    SPREAD_ARG(args.This(), ts_obj);
+    SPREAD_ARG(target_obj, target);
+  }
+
   size_t target_start;
   size_t source_start;
   size_t source_end;
@@ -364,7 +565,12 @@ void Copy(const FunctionCallbackInfo<Value> &args) {
 void Fill(const FunctionCallbackInfo<Value>& args) {
   THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
   ARGS_THIS_DEC(ts_obj);
-  ARGS_THIS(args[0].As<Object>(), ts_obj);
+
+  if (using_old_buffer) {
+    ARGS_THIS(args[0].As<Object>(), ts_obj);
+  } else {
+    SPREAD_ARG(args[0], ts_obj);
+  }
 
   size_t start = args[2]->Uint32Value();
   size_t end = args[3]->Uint32Value();
@@ -409,7 +615,12 @@ void StringWrite(const FunctionCallbackInfo<Value>& args) {
   ARGS_THIS_DEC(ts_obj);
 
   THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
-  ARGS_THIS(args.This(), ts_obj);
+
+  if (using_old_buffer) {
+    ARGS_THIS(args.This(), ts_obj);
+  } else {
+    SPREAD_ARG(args.This(), ts_obj);
+  }
 
   if (!args[0]->IsString())
     return env->ThrowTypeError("Argument must be a string");
@@ -487,7 +698,12 @@ template <typename T, enum Endianness endianness>
 void ReadFloatGeneric(const FunctionCallbackInfo<Value>& args) {
   THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
   ARGS_THIS_DEC(ts_obj);
-  ARGS_THIS(args[0].As<Object>(), ts_obj);
+
+  if (using_old_buffer) {
+    ARGS_THIS(args[0].As<Object>(), ts_obj);
+  } else {
+    SPREAD_ARG(args[0], ts_obj);
+  }
 
   uint32_t offset = args[1]->Uint32Value();
   CHECK_LE(offset + sizeof(T), ts_obj_length);
@@ -530,7 +746,12 @@ void ReadDoubleBE(const FunctionCallbackInfo<Value>& args) {
 template <typename T, enum Endianness endianness>
 uint32_t WriteFloatGeneric(const FunctionCallbackInfo<Value>& args) {
   ARGS_THIS_DEC(ts_obj);
-  ARGS_THIS(args[0].As<Object>(), ts_obj);
+
+  if (using_old_buffer) {
+    ARGS_THIS(args[0].As<Object>(), ts_obj);
+  } else {
+    SPREAD_ARG(args[0], ts_obj);
+  }
 
   T val = args[1]->NumberValue();
   uint32_t offset = args[2]->Uint32Value();
@@ -588,26 +809,27 @@ void Compare(const FunctionCallbackInfo<Value> &args) {
   THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
   THROW_AND_RETURN_UNLESS_BUFFER(env, args[1]);
 
-  Local<Object> obj_a = args[0].As<Object>();
-  char* obj_a_data =
-      static_cast<char*>(obj_a->GetIndexedPropertiesExternalArrayData());
-  size_t obj_a_len = obj_a->GetIndexedPropertiesExternalArrayDataLength();
+  ARGS_THIS_DEC(obj_a);
+  ARGS_THIS_DEC(obj_b);
 
-  Local<Object> obj_b = args[1].As<Object>();
-  char* obj_b_data =
-      static_cast<char*>(obj_b->GetIndexedPropertiesExternalArrayData());
-  size_t obj_b_len = obj_b->GetIndexedPropertiesExternalArrayDataLength();
+  if (using_old_buffer) {
+    ARGS_THIS(args[0].As<Object>(), obj_a);
+    ARGS_THIS(args[1].As<Object>(), obj_b);
+  } else {
+    SPREAD_ARG(args[0], obj_a);
+    SPREAD_ARG(args[1], obj_b);
+  }
 
-  size_t cmp_length = MIN(obj_a_len, obj_b_len);
+  size_t cmp_length = MIN(obj_a_length, obj_b_length);
 
   int32_t val = memcmp(obj_a_data, obj_b_data, cmp_length);
 
   // Normalize val to be an integer in the range of [1, -1] since
   // implementations of memcmp() can vary by platform.
   if (val == 0) {
-    if (obj_a_len > obj_b_len)
+    if (obj_a_length > obj_b_length)
       val = 1;
-    else if (obj_a_len < obj_b_len)
+    else if (obj_a_length < obj_b_length)
       val = -1;
   } else {
     if (val > 0)
@@ -642,7 +864,12 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
 
   THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
   ARGS_THIS_DEC(ts_obj);
-  ARGS_THIS(args[0].As<Object>(), ts_obj);
+
+  if (using_old_buffer) {
+    ARGS_THIS(args[0].As<Object>(), ts_obj);
+  } else {
+    SPREAD_ARG(args[0], ts_obj);
+  }
 
   node::Utf8Value str(args.GetIsolate(), args[1]);
   int32_t offset_i32 = args[2]->Int32Value();
@@ -675,7 +902,12 @@ void IndexOfBuffer(const FunctionCallbackInfo<Value>& args) {
 
   THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
   ARGS_THIS_DEC(ts_obj);
-  ARGS_THIS(args[0].As<Object>(), ts_obj);
+
+  if (using_old_buffer) {
+    ARGS_THIS(args[0].As<Object>(), ts_obj);
+  } else {
+    SPREAD_ARG(args[0], ts_obj);
+  }
 
   Local<Object> buf = args[1].As<Object>();
   int32_t offset_i32 = args[2]->Int32Value();
@@ -714,7 +946,12 @@ void IndexOfNumber(const FunctionCallbackInfo<Value>& args) {
 
   THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
   ARGS_THIS_DEC(ts_obj);
-  ARGS_THIS(args[0].As<Object>(), ts_obj);
+
+  if (using_old_buffer) {
+    ARGS_THIS(args[0].As<Object>(), ts_obj);
+  } else {
+    SPREAD_ARG(args[0], ts_obj);
+  }
 
   uint32_t needle = args[1]->Uint32Value();
   int32_t offset_i32 = args[2]->Int32Value();
@@ -743,15 +980,20 @@ void IndexOfNumber(const FunctionCallbackInfo<Value>& args) {
 void SetupBufferJS(const FunctionCallbackInfo<Value>& args) {
   Environment* env = Environment::GetCurrent(args);
 
-  CHECK(args[0]->IsFunction());
-
-  Local<Function> bv = args[0].As<Function>();
-  env->set_buffer_constructor_function(bv);
-  Local<Value> proto_v = bv->Get(env->prototype_string());
-
-  CHECK(proto_v->IsObject());
+  Local<Object> proto;
 
-  Local<Object> proto = proto_v.As<Object>();
+  if (using_old_buffer) {
+    CHECK(args[0]->IsFunction());
+    Local<Function> bv = args[0].As<Function>();
+    env->set_buffer_constructor_function(bv);
+    Local<Value> proto_v = bv->Get(env->prototype_string());
+    CHECK(proto_v->IsObject());
+    proto = proto_v.As<Object>();
+  } else {
+    CHECK(args[0]->IsObject());
+    proto = args[0].As<Object>();
+    env->set_buffer_prototype_object(proto);
+  }
 
   env->SetMethod(proto, "asciiSlice", AsciiSlice);
   env->SetMethod(proto, "base64Slice", Base64Slice);
@@ -770,9 +1012,11 @@ void SetupBufferJS(const FunctionCallbackInfo<Value>& args) {
   env->SetMethod(proto, "copy", Copy);
 
   // for backwards compatibility
-  proto->ForceSet(env->offset_string(),
-                  Uint32::New(env->isolate(), 0),
-                  v8::ReadOnly);
+  if (using_old_buffer) {
+    proto->ForceSet(env->offset_string(),
+                    Uint32::New(env->isolate(), 0),
+                    v8::ReadOnly);
+  }
 }
 
 
@@ -782,7 +1026,10 @@ void Initialize(Handle<Object> target,
   Environment* env = Environment::GetCurrent(context);
 
   env->SetMethod(target, "setupBufferJS", SetupBufferJS);
+  env->SetMethod(target, "create", Create);
+  env->SetMethod(target, "createFromString", CreateFromString);
 
+  env->SetMethod(target, "slice", Slice);
   env->SetMethod(target, "byteLengthUtf8", ByteLengthUtf8);
   env->SetMethod(target, "compare", Compare);
   env->SetMethod(target, "fill", Fill);
index 2e64997..4b1b2cd 100644 (file)
@@ -63,9 +63,9 @@ NODE_DEPRECATED("Use New(isolate, ...)",
 // TODO(trevnorris): should be New() for consistency
 NODE_EXTERN v8::Local<v8::Object> Use(v8::Isolate* isolate,
                                       char* data,
-                                      uint32_t len);
+                                      size_t len);
 NODE_DEPRECATED("Use Use(isolate, ...)",
-                inline v8::Local<v8::Object> Use(char* data, uint32_t len) {
+                inline v8::Local<v8::Object> Use(char* data, size_t len) {
   return Use(v8::Isolate::GetCurrent(), data, len);
 })
 
@@ -95,7 +95,7 @@ v8::Local<v8::Object> New(Environment* env,
                           size_t length,
                           smalloc::FreeCallback callback,
                           void* hint);
-v8::Local<v8::Object> Use(Environment* env, char* data, uint32_t length);
+v8::Local<v8::Object> Use(Environment* env, char* data, size_t length);
 #endif  // defined(NODE_WANT_INTERNALS)
 
 }  // namespace Buffer
index c99b2fe..e5f7458 100644 (file)
@@ -17,6 +17,8 @@ namespace node {
 // Forward declaration
 class Environment;
 
+extern bool using_old_buffer;
+
 // If persistent.IsWeak() == false, then do not call persistent.Reset()
 // while the returned Local<T> is still in scope, it will destroy the
 // reference to the object.
index 75bdb47..308c9b2 100644 (file)
@@ -198,6 +198,14 @@ TypeName* Unwrap(v8::Local<v8::Object> object) {
   return static_cast<TypeName*>(pointer);
 }
 
+inline bool IsValidSmi(int64_t value) {
+  if (sizeof(int32_t) == sizeof(intptr_t)) {
+    return value >= -0x40000000LL && value <= 0x3fffffffLL;
+  } else {
+    return value >= -0x80000000LL && value <= 0x7fffffffLL;
+  }
+}
+
 }  // namespace node
 
 #endif  // SRC_UTIL_INL_H_
index ea17a15..3ca79c0 100644 (file)
@@ -195,6 +195,8 @@ class Utf8Value {
     char str_st_[1024];
 };
 
+inline bool IsValidSmi(int64_t value);
+
 }  // namespace node
 
 #endif  // SRC_UTIL_H_
diff --git a/test/parallel/test-buffer-slice.js b/test/parallel/test-buffer-slice.js
deleted file mode 100644 (file)
index 53434ea..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-'use strict';
-var common = require('../common');
-var assert = require('assert');
-
-var Buffer = require('buffer').Buffer;
-
-var buff = new Buffer(Buffer.poolSize + 1);
-var slicedBuffer = buff.slice();
-assert.equal(slicedBuffer.parent,
-             buff,
-             'slicedBufffer should have its parent set to the original ' +
-             ' buffer');
index 27a211b..443da05 100644 (file)
@@ -329,8 +329,6 @@ assert.equal(b.parent, d.parent);
 var b = new SlowBuffer(5);
 var c = b.slice(0, 4);
 var d = c.slice(0, 2);
-assert.equal(b, c.parent);
-assert.equal(b, d.parent);
 
 
 // Bug regression test
@@ -1075,10 +1073,6 @@ assert.equal(buf.readInt8(0), -1);
   // try to slice a zero length Buffer
   // see https://github.com/joyent/node/issues/5881
   SlowBuffer(0).slice(0, 1);
-  // make sure a zero length slice doesn't set the .parent attribute
-  assert.equal(Buffer(5).slice(0, 0).parent, undefined);
-  // and make sure a proper slice does have a parent
-  assert.ok(typeof Buffer(5).slice(0, 5).parent === 'object');
 })();
 
 // Regression test for #5482: should throw but not assert in C++ land.
@@ -1105,11 +1099,11 @@ assert.throws(function() {
 
 
 assert.throws(function() {
-  new Buffer(smalloc.kMaxLength + 1);
+  new Buffer((-1 >>> 0) + 1);
 }, RangeError);
 
 assert.throws(function() {
-  new SlowBuffer(smalloc.kMaxLength + 1);
+  new SlowBuffer((-1 >>> 0) + 1);
 }, RangeError);
 
 if (common.hasCrypto) {