mirror of https://github.com/nodejs/node.git
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>pull/35604/head
parent
862cc28183
commit
e9ca7b9d8d
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
ARGS_THIS(args[0].As<Object>())
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue