diff options
author | Jason Carey <jcarey@argv.me> | 2015-10-06 20:23:08 -0400 |
---|---|---|
committer | Jason Carey <jcarey@argv.me> | 2015-10-06 20:26:14 -0400 |
commit | 8d65462cd4b56fd12d3fbe8799ee78be677bae38 (patch) | |
tree | f86313611afb4c9e4e5e04238f0e88f830ed49c2 /src/mongo | |
parent | 95060c27ed2dddcb6343a88f7aa405ed8a935ad7 (diff) | |
download | mongo-8d65462cd4b56fd12d3fbe8799ee78be677bae38.tar.gz |
SERVER-19977 Offer a stack based JSStringWrapper
Small string optimization for encoding utf8 strings from JS strings on
the stack. Additions to the api to use on stack buffers.
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/scripting/mozjs/bson.cpp | 7 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/idwrapper.cpp | 11 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/idwrapper.h | 2 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/jsstringwrapper.cpp | 29 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/jsstringwrapper.h | 4 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/objectwrapper.cpp | 51 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/objectwrapper.h | 2 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/valuewriter.cpp | 11 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/valuewriter.h | 1 |
9 files changed, 82 insertions, 36 deletions
diff --git a/src/mongo/scripting/mozjs/bson.cpp b/src/mongo/scripting/mozjs/bson.cpp index f2c30407845..9f0a6125d22 100644 --- a/src/mongo/scripting/mozjs/bson.cpp +++ b/src/mongo/scripting/mozjs/bson.cpp @@ -194,15 +194,16 @@ void BSONInfo::resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, boo } IdWrapper idw(cx, id); + JSStringWrapper jsstr; - if (!holder->_readOnly && holder->_removed.count(idw.toString())) { + auto sname = idw.toStringData(&jsstr); + + if (!holder->_readOnly && holder->_removed.find(sname.toString()) != holder->_removed.end()) { return; } ObjectWrapper o(cx, obj); - std::string sname = IdWrapper(cx, id).toString(); - if (holder->_obj.hasField(sname)) { auto elem = holder->_obj[sname]; diff --git a/src/mongo/scripting/mozjs/idwrapper.cpp b/src/mongo/scripting/mozjs/idwrapper.cpp index 2c701037a22..89c24807d53 100644 --- a/src/mongo/scripting/mozjs/idwrapper.cpp +++ b/src/mongo/scripting/mozjs/idwrapper.cpp @@ -41,15 +41,22 @@ namespace mozjs { IdWrapper::IdWrapper(JSContext* cx, JS::HandleId value) : _context(cx), _value(cx, value) {} std::string IdWrapper::toString() const { + JSStringWrapper jsstr; + return toStringData(&jsstr).toString(); +} + +StringData IdWrapper::toStringData(JSStringWrapper* jsstr) const { if (JSID_IS_STRING(_value)) { - return JSStringWrapper(_context, JSID_TO_STRING(_value)).toString(); + *jsstr = JSStringWrapper(_context, JSID_TO_STRING(_value)); } else if (JSID_IS_INT(_value)) { - return std::to_string(JSID_TO_INT(_value)); + *jsstr = JSStringWrapper(JSID_TO_INT(_value)); } else { throwCurrentJSException(_context, ErrorCodes::TypeMismatch, "Cannot toString() non-string and non-integer jsid"); } + + return jsstr->toStringData(); } uint32_t IdWrapper::toInt32() const { diff --git a/src/mongo/scripting/mozjs/idwrapper.h b/src/mongo/scripting/mozjs/idwrapper.h index 4865e5e0aec..0ba380c64cb 100644 --- a/src/mongo/scripting/mozjs/idwrapper.h +++ b/src/mongo/scripting/mozjs/idwrapper.h @@ -32,6 +32,7 @@ #include <string> #include "mongo/base/string_data.h" +#include "mongo/scripting/mozjs/jsstringwrapper.h" namespace mongo { namespace mozjs { @@ -51,6 +52,7 @@ public: * Converts to a string. This coerces for integers */ std::string toString() const; + StringData toStringData(JSStringWrapper* jsstr) const; /** * Converts to an int. This throws if the id is not an integer diff --git a/src/mongo/scripting/mozjs/jsstringwrapper.cpp b/src/mongo/scripting/mozjs/jsstringwrapper.cpp index 8261b44a2fe..2732c98607b 100644 --- a/src/mongo/scripting/mozjs/jsstringwrapper.cpp +++ b/src/mongo/scripting/mozjs/jsstringwrapper.cpp @@ -41,7 +41,11 @@ namespace mongo { namespace mozjs { -JSStringWrapper::JSStringWrapper(JSContext* cx, JSString* str) : _context(cx) { +JSStringWrapper::JSStringWrapper(std::int32_t value) : _isSet(true) { + _length = sprintf(_buf, "%d", value); +} + +JSStringWrapper::JSStringWrapper(JSContext* cx, JSString* str) : _isSet(true) { if (!str) throwCurrentJSException(cx, ErrorCodes::InternalError, "Cannot encode null JSString"); @@ -56,20 +60,21 @@ JSStringWrapper::JSStringWrapper(JSContext* cx, JSString* str) : _context(cx) { _length = JS::GetDeflatedUTF8StringLength(flat); - JS::RootedString rstr(cx, str); - - JSAutoByteString abs; - abs.encodeUtf8(cx, rstr); - - if (!abs) - throwCurrentJSException(cx, ErrorCodes::InternalError, "Failed to encode JSString"); + char* out; + if (_length < sizeof(_buf)) { + out = _buf; + } else { + _str.reset(new char[_length + 1]); + out = _str.get(); + } - _str.reset(new char[_length]); - std::memcpy(_str.get(), abs.ptr(), _length); + JS::DeflateStringToUTF8Buffer(flat, mozilla::RangedPtr<char>(out, _length)); + out[_length] = '\0'; } StringData JSStringWrapper::toStringData() const { - return StringData(_str.get(), _length); + invariant(_isSet); + return StringData(_str ? _str.get() : _buf, _length); } std::string JSStringWrapper::toString() const { @@ -77,7 +82,7 @@ std::string JSStringWrapper::toString() const { } JSStringWrapper::operator bool() const { - return _str.get(); + return _isSet; } } // namespace mozjs diff --git a/src/mongo/scripting/mozjs/jsstringwrapper.h b/src/mongo/scripting/mozjs/jsstringwrapper.h index 9a0ee21e900..ec94593bd05 100644 --- a/src/mongo/scripting/mozjs/jsstringwrapper.h +++ b/src/mongo/scripting/mozjs/jsstringwrapper.h @@ -45,6 +45,7 @@ class JSStringWrapper { public: JSStringWrapper() = default; JSStringWrapper(JSContext* cx, JSString* str); + JSStringWrapper(std::int32_t val); StringData toStringData() const; std::string toString() const; @@ -52,9 +53,10 @@ public: explicit operator bool() const; private: - JSContext* _context = nullptr; std::unique_ptr<char[]> _str; size_t _length = 0; + char _buf[64]; + bool _isSet = false; }; } // namespace mozjs diff --git a/src/mongo/scripting/mozjs/objectwrapper.cpp b/src/mongo/scripting/mozjs/objectwrapper.cpp index 8e1bc5aa92e..e467dfe8b48 100644 --- a/src/mongo/scripting/mozjs/objectwrapper.cpp +++ b/src/mongo/scripting/mozjs/objectwrapper.cpp @@ -198,23 +198,40 @@ void ObjectWrapper::Key::del(JSContext* cx, JS::HandleObject o) { } std::string ObjectWrapper::Key::toString(JSContext* cx) { - switch (_type) { - case Type::Field: - return _field; - case Type::Index: - return std::to_string(_idx); - case Type::Id: { - JS::RootedId id(cx, _id); - return IdWrapper(cx, id).toString(); - } - case Type::InternedString: { - InternedStringId id(cx, _internedString); - return IdWrapper(cx, id).toString(); - } + JSStringWrapper jsstr; + return toStringData(cx, &jsstr).toString(); +} + +StringData ObjectWrapper::Key::toStringData(JSContext* cx, JSStringWrapper* jsstr) { + if (_type == Type::Field) { + return _field; } - throwCurrentJSException( - cx, ErrorCodes::InternalError, "Failed to toString a ObjectWrapper::Key"); + if (_type == Type::Index) { + *jsstr = JSStringWrapper(_idx); + return jsstr->toStringData(); + } + + JS::RootedId rid(cx); + + if (_type == Type::Id) { + rid.set(_id); + } else { + InternedStringId id(cx, _internedString); + rid.set(id); + } + + if (JSID_IS_INT(rid)) { + *jsstr = JSStringWrapper(JSID_TO_INT(rid)); + return jsstr->toStringData(); + } + + if (JSID_IS_STRING(rid)) { + *jsstr = JSStringWrapper(cx, JSID_TO_STRING(rid)); + return jsstr->toStringData(); + } + + uasserted(ErrorCodes::BadValue, "Couldn't convert key to String"); } ObjectWrapper::ObjectWrapper(JSContext* cx, JS::HandleObject obj) @@ -500,7 +517,9 @@ void ObjectWrapper::_writeField(BSONObjBuilder* b, ValueWriter x(_context, value); x.setOriginalBSON(originalParent); - x.writeThis(b, key.toString(_context), frames); + JSStringWrapper jsstr; + + x.writeThis(b, key.toStringData(_context, &jsstr), frames); } std::string ObjectWrapper::getClassName() { diff --git a/src/mongo/scripting/mozjs/objectwrapper.h b/src/mongo/scripting/mozjs/objectwrapper.h index efc8039bf26..4463cd99c98 100644 --- a/src/mongo/scripting/mozjs/objectwrapper.h +++ b/src/mongo/scripting/mozjs/objectwrapper.h @@ -35,6 +35,7 @@ #include "mongo/platform/decimal128.h" #include "mongo/scripting/mozjs/exception.h" #include "mongo/scripting/mozjs/internedstring.h" +#include "mongo/scripting/mozjs/jsstringwrapper.h" #include "mongo/scripting/mozjs/lifetimestack.h" namespace mongo { @@ -85,6 +86,7 @@ public: void define(JSContext* cx, JS::HandleObject o, JS::HandleValue value, unsigned attrs); void del(JSContext* cx, JS::HandleObject o); std::string toString(JSContext* cx); + StringData toStringData(JSContext* cx, JSStringWrapper* jsstr); union { const char* _field; diff --git a/src/mongo/scripting/mozjs/valuewriter.cpp b/src/mongo/scripting/mozjs/valuewriter.cpp index 6f57d48c460..33097e99e18 100644 --- a/src/mongo/scripting/mozjs/valuewriter.cpp +++ b/src/mongo/scripting/mozjs/valuewriter.cpp @@ -121,7 +121,13 @@ BSONObj ValueWriter::toBSON() { } std::string ValueWriter::toString() { - return JSStringWrapper(_context, JS::ToString(_context, _value)).toString(); + JSStringWrapper jsstr; + return toStringData(&jsstr).toString(); +} + +StringData ValueWriter::toStringData(JSStringWrapper* jsstr) { + *jsstr = JSStringWrapper(_context, JS::ToString(_context, _value)); + return jsstr->toStringData(); } double ValueWriter::toNumber() { @@ -192,7 +198,8 @@ void ValueWriter::writeThis(BSONObjBuilder* b, (std::string::npos == sd.find('\0'))); if (_value.isString()) { - b->append(sd, toString()); + JSStringWrapper jsstr; + b->append(sd, toStringData(&jsstr)); } else if (_value.isNumber()) { double val = toNumber(); diff --git a/src/mongo/scripting/mozjs/valuewriter.h b/src/mongo/scripting/mozjs/valuewriter.h index 65f6f418d09..9947f61d741 100644 --- a/src/mongo/scripting/mozjs/valuewriter.h +++ b/src/mongo/scripting/mozjs/valuewriter.h @@ -54,6 +54,7 @@ public: * toNumber() */ std::string toString(); + StringData toStringData(JSStringWrapper* jsstr); int type(); double toNumber(); int32_t toInt32(); |