summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrevor Norris <trev.norris@gmail.com>2014-10-01 15:42:02 -0700
committerTrevor Norris <trev.norris@gmail.com>2014-10-01 15:59:55 -0700
commite9ca7b9d8de68e13d40698f34145e2a0428aa9d7 (patch)
tree01afe04f827ce83ae2a846abb2404d8c749a4069
parent862cc28183b03f0e1a67b052b5c8250a3e2e8995 (diff)
downloadnode-e9ca7b9d8de68e13d40698f34145e2a0428aa9d7.tar.gz
buffer: mv floating point read/write checks to JS
Performance improvement by moving checks for floating point operations to JS and doing the operation on a protected internal function that assumes all arguments are correct. Still abort if the operation overflows memory. This can only be caused if the Buffer's length property isn't the same as the actual internal length. Signed-off-by: Trevor Norris <trev.norris@gmail.com>
-rw-r--r--lib/buffer.js80
-rw-r--r--src/node_buffer.cc60
2 files changed, 99 insertions, 41 deletions
diff --git a/lib/buffer.js b/lib/buffer.js
index 7fd297559..80f6a4271 100644
--- a/lib/buffer.js
+++ b/lib/buffer.js
@@ -581,6 +581,38 @@ Buffer.prototype.readInt32BE = function(offset, noAssert) {
};
+Buffer.prototype.readFloatLE = function readFloatLE(offset, noAssert) {
+ offset = offset >>> 0;
+ if (!noAssert)
+ checkOffset(offset, 4, this.length);
+ return internal.readFloatLE(this, offset);
+};
+
+
+Buffer.prototype.readFloatBE = function readFloatBE(offset, noAssert) {
+ offset = offset >>> 0;
+ if (!noAssert)
+ checkOffset(offset, 4, this.length);
+ return internal.readFloatBE(this, offset);
+};
+
+
+Buffer.prototype.readDoubleLE = function readDoubleLE(offset, noAssert) {
+ offset = offset >>> 0;
+ if (!noAssert)
+ checkOffset(offset, 8, this.length);
+ return internal.readDoubleLE(this, offset);
+};
+
+
+Buffer.prototype.readDoubleBE = function readDoubleBE(offset, noAssert) {
+ offset = offset >>> 0;
+ if (!noAssert)
+ checkOffset(offset, 8, this.length);
+ return internal.readDoubleBE(this, offset);
+};
+
+
function checkInt(buffer, value, offset, ext, max, min) {
if (!(buffer instanceof Buffer))
throw new TypeError('buffer must be a Buffer instance');
@@ -705,3 +737,51 @@ Buffer.prototype.writeInt32BE = function(value, offset, noAssert) {
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);
+ internal.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);
+ internal.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);
+ internal.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);
+ internal.writeDoubleBE(this, val, offset);
+ return offset + 8;
+};
diff --git a/src/node_buffer.cc b/src/node_buffer.cc
index 8be551d9b..3f8de59b4 100644
--- a/src/node_buffer.cc
+++ b/src/node_buffer.cc
@@ -462,17 +462,10 @@ static inline void Swizzle(char* start, unsigned int len) {
template <typename T, enum Endianness endianness>
void ReadFloatGeneric(const FunctionCallbackInfo<Value>& args) {
- Environment* env = Environment::GetCurrent(args.GetIsolate());
- bool doAssert = !args[1]->BooleanValue();
- size_t offset;
+ ARGS_THIS(args[0].As<Object>());
- CHECK_NOT_OOB(ParseArrayIndex(args[0], 0, &offset));
-
- if (doAssert) {
- size_t len = Length(args.This());
- if (offset + sizeof(T) > len || offset + sizeof(T) < offset)
- return env->ThrowRangeError("Trying to read beyond buffer length");
- }
+ uint32_t offset = args[1]->Uint32Value();
+ CHECK_LE(offset + sizeof(T), obj_length);
union NoAlias {
T val;
@@ -480,8 +473,7 @@ void ReadFloatGeneric(const FunctionCallbackInfo<Value>& args) {
};
union NoAlias na;
- const void* data = args.This()->GetIndexedPropertiesExternalArrayData();
- const char* ptr = static_cast<const char*>(data) + offset;
+ const char* ptr = static_cast<const char*>(obj_data) + offset;
memcpy(na.bytes, ptr, sizeof(na.bytes));
if (endianness != GetEndianness())
Swizzle(na.bytes, sizeof(na.bytes));
@@ -512,24 +504,11 @@ void ReadDoubleBE(const FunctionCallbackInfo<Value>& args) {
template <typename T, enum Endianness endianness>
uint32_t WriteFloatGeneric(const FunctionCallbackInfo<Value>& args) {
- Environment* env = Environment::GetCurrent(args.GetIsolate());
- bool doAssert = !args[2]->BooleanValue();
-
- T val = static_cast<T>(args[0]->NumberValue());
- size_t offset;
-
- if (!ParseArrayIndex(args[1], 0, &offset)) {
- env->ThrowRangeError("out of range index");
- return 0;
- }
+ ARGS_THIS(args[0].As<Object>())
- if (doAssert) {
- size_t len = Length(args.This());
- if (offset + sizeof(T) > len || offset + sizeof(T) < offset) {
- env->ThrowRangeError("Trying to write beyond buffer length");
- return 0;
- }
- }
+ T val = args[1]->NumberValue();
+ uint32_t offset = args[2]->Uint32Value();
+ CHECK_LE(offset + sizeof(T), obj_length);
union NoAlias {
T val;
@@ -537,8 +516,7 @@ uint32_t WriteFloatGeneric(const FunctionCallbackInfo<Value>& args) {
};
union NoAlias na = { val };
- void* data = args.This()->GetIndexedPropertiesExternalArrayData();
- char* ptr = static_cast<char*>(data) + offset;
+ char* ptr = static_cast<char*>(obj_data) + offset;
if (endianness != GetEndianness())
Swizzle(na.bytes, sizeof(na.bytes));
memcpy(ptr, na.bytes, sizeof(na.bytes));
@@ -643,16 +621,6 @@ void SetupBufferJS(const FunctionCallbackInfo<Value>& args) {
NODE_SET_METHOD(proto, "ucs2Write", Ucs2Write);
NODE_SET_METHOD(proto, "utf8Write", Utf8Write);
- NODE_SET_METHOD(proto, "readDoubleBE", ReadDoubleBE);
- NODE_SET_METHOD(proto, "readDoubleLE", ReadDoubleLE);
- NODE_SET_METHOD(proto, "readFloatBE", ReadFloatBE);
- NODE_SET_METHOD(proto, "readFloatLE", ReadFloatLE);
-
- NODE_SET_METHOD(proto, "writeDoubleBE", WriteDoubleBE);
- NODE_SET_METHOD(proto, "writeDoubleLE", WriteDoubleLE);
- NODE_SET_METHOD(proto, "writeFloatBE", WriteFloatBE);
- NODE_SET_METHOD(proto, "writeFloatLE", WriteFloatLE);
-
NODE_SET_METHOD(proto, "copy", Copy);
// for backwards compatibility
@@ -668,6 +636,16 @@ void SetupBufferJS(const FunctionCallbackInfo<Value>& args) {
NODE_SET_METHOD(internal, "byteLength", ByteLength);
NODE_SET_METHOD(internal, "compare", Compare);
NODE_SET_METHOD(internal, "fill", Fill);
+
+ NODE_SET_METHOD(internal, "readDoubleBE", ReadDoubleBE);
+ NODE_SET_METHOD(internal, "readDoubleLE", ReadDoubleLE);
+ NODE_SET_METHOD(internal, "readFloatBE", ReadFloatBE);
+ NODE_SET_METHOD(internal, "readFloatLE", ReadFloatLE);
+
+ NODE_SET_METHOD(internal, "writeDoubleBE", WriteDoubleBE);
+ NODE_SET_METHOD(internal, "writeDoubleLE", WriteDoubleLE);
+ NODE_SET_METHOD(internal, "writeFloatBE", WriteFloatBE);
+ NODE_SET_METHOD(internal, "writeFloatLE", WriteFloatLE);
}