summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2013-04-11 18:20:33 -0400
committerMathias Stearn <mathias@10gen.com>2013-04-24 16:59:03 -0400
commitdccfd557ce411b890b708cbc259a14e023263a8e (patch)
tree462e160e5a7dcede90cbba52823697e5a28673e0 /src
parent6cea3cbbca67f682d16b93a50f9a90a4b7f2b405 (diff)
downloadmongo-dccfd557ce411b890b708cbc259a14e023263a8e.tar.gz
Add V8String class to avoid copying v8::Strings into std::strings
Still need to copy once into v8::Utf8Value but this saves the second copy
Diffstat (limited to 'src')
-rw-r--r--src/mongo/base/string_data.h15
-rw-r--r--src/mongo/scripting/engine_v8.cpp56
-rw-r--r--src/mongo/scripting/engine_v8.h18
-rw-r--r--src/mongo/scripting/v8_utils.cpp7
-rw-r--r--src/mongo/scripting/v8_utils.h42
5 files changed, 96 insertions, 42 deletions
diff --git a/src/mongo/base/string_data.h b/src/mongo/base/string_data.h
index f764549f700..f2285cc5376 100644
--- a/src/mongo/base/string_data.h
+++ b/src/mongo/base/string_data.h
@@ -23,6 +23,8 @@
#include <limits>
#include <string>
+#include <third_party/murmurhash3/MurmurHash3.h>
+
namespace mongo {
using std::string;
@@ -126,6 +128,19 @@ namespace mongo {
string toString() const { return string(_data, size()); }
char operator[] ( unsigned pos ) const { return _data[pos]; }
+ /**
+ * Functor compatible with std::hash for std::unordered_{map,set}
+ * Warning: The hash function is subject to change. Do not use in cases where hashes need
+ * to be consistent across versions.
+ */
+ struct Hasher {
+ size_t operator() (const StringData& str) const {
+ unsigned out;
+ MurmurHash3_x86_32(str.rawData(), str.size(), 0, &out);
+ return out;
+ }
+ };
+
private:
const char* _data; // is not guaranted to be null terminated (see "notes" above)
mutable size_t _size; // 'size' does not include the null terminator
diff --git a/src/mongo/scripting/engine_v8.cpp b/src/mongo/scripting/engine_v8.cpp
index 1f144468d16..d0155ce37f1 100644
--- a/src/mongo/scripting/engine_v8.cpp
+++ b/src/mongo/scripting/engine_v8.cpp
@@ -163,12 +163,12 @@ namespace mongo {
int outIndex = 0;
V8Scope* scope = getScope(info.GetIsolate());
- unordered_set<string> added;
+ unordered_set<StringData, StringData::Hasher> added;
// note here that if keys are parseable number, v8 will access them using index
for (BSONObjIterator it(obj); it.more();) {
const BSONElement& f = it.next();
- string sname = f.fieldName();
- if (holder->_removed.count(sname))
+ StringData sname (f.fieldName(), f.fieldNameSize()-1);
+ if (holder->_removed.count(sname.toString()))
continue;
v8::Handle<v8::String> name = scope->v8StringData(sname);
@@ -182,7 +182,7 @@ namespace mongo {
const int len = fields->Length();
for (int field=0; field < len; field++) {
v8::Handle<v8::String> name = fields->Get(field).As<v8::String>();
- string sname = toSTLString(name);
+ V8String sname (name);
if (added.count(sname))
continue;
out->Set(outIndex++, name);
@@ -301,15 +301,13 @@ namespace mongo {
v8::Handle<v8::Value> NamedReadOnlySet(v8::Local<v8::String> property,
v8::Local<v8::Value> value,
const v8::AccessorInfo& info) {
- string key = toSTLString(property);
- cout << "cannot write property " << key << " to read-only object" << endl;
+ cout << "cannot write property " << V8String(property) << " to read-only object" << endl;
return value;
}
v8::Handle<v8::Boolean> NamedReadOnlyDelete(v8::Local<v8::String> property,
const v8::AccessorInfo& info) {
- string key = toSTLString(property);
- cout << "cannot delete property " << key << " from read-only object" << endl;
+ cout << "cannot delete property " << V8String(property) << " from read-only object" << endl;
return v8::Boolean::New(false);
}
@@ -621,7 +619,7 @@ namespace mongo {
v8::External::Cast(*args.Callee()->Get(scope->strLitToV8("_native_data")));
BSONObjBuilder b;
for (int i = 0; i < args.Length(); ++i)
- scope->v8ToMongoElement(b, str::stream() << i, args[i]);
+ scope->v8ToMongoElement(b, BSONObjBuilder::numStr(i), args[i]);
BSONObj nativeArgs = b.obj();
ret = function(nativeArgs, data->Value());
}
@@ -901,7 +899,7 @@ namespace mongo {
// --- functions -----
- bool hasFunctionIdentifier(const string& code) {
+ bool hasFunctionIdentifier(const StringData& code) {
if (code.size() < 9 || code.find("function") != 0 )
return false;
@@ -1078,7 +1076,7 @@ namespace mongo {
if (printResult && !result->IsUndefined()) {
// appears to only be used by shell
- cout << toSTLString(result) << endl;
+ cout << V8String(result) << endl;
}
return true;
@@ -1455,7 +1453,7 @@ namespace mongo {
}
void V8Scope::v8ToMongoNumber(BSONObjBuilder& b,
- const string& elementName,
+ const StringData& elementName,
v8::Handle<v8::Value> value,
BSONObj* originalParent) {
double val = value->ToNumber()->Value();
@@ -1472,7 +1470,7 @@ namespace mongo {
}
void V8Scope::v8ToMongoNumberLong(BSONObjBuilder& b,
- const string& elementName,
+ const StringData& elementName,
v8::Handle<v8::Object> obj) {
// TODO might be nice to potentially speed this up with an indexed internal
// field, but I don't yet know how to use an ObjectTemplate with a
@@ -1490,7 +1488,7 @@ namespace mongo {
}
void V8Scope::v8ToMongoInternal(BSONObjBuilder& b,
- const string& elementName,
+ const StringData& elementName,
v8::Handle<v8::Object> obj) {
uint32_t bsonTypeRaw = obj->GetInternalField(0)->ToUint32()->Value();
BSONType bsonType = static_cast<BSONType>(bsonTypeRaw);
@@ -1513,17 +1511,18 @@ namespace mongo {
}
void V8Scope::v8ToMongoRegex(BSONObjBuilder& b,
- const string& elementName,
+ const StringData& elementName,
v8::Handle<v8::Object> v8Regex) {
- string regex = toSTLString(v8Regex);
+ V8String v8RegexString (v8Regex);
+ StringData regex = v8RegexString;
regex = regex.substr(1);
- string r = regex.substr(0 ,regex.rfind("/"));
- string o = regex.substr(regex.rfind("/") + 1);
+ StringData r = regex.substr(0 ,regex.rfind('/'));
+ StringData o = regex.substr(regex.rfind('/') + 1);
b.appendRegex(elementName, r, o);
}
void V8Scope::v8ToMongoDBRef(BSONObjBuilder& b,
- const string& elementName,
+ const StringData& elementName,
v8::Handle<v8::Object> obj) {
OID oid;
v8::Local<v8::Value> theid = obj->Get(strLitToV8("id"));
@@ -1533,7 +1532,7 @@ namespace mongo {
}
void V8Scope::v8ToMongoBinData(BSONObjBuilder& b,
- const string& elementName,
+ const StringData& elementName,
v8::Handle<v8::Object> obj) {
int len = obj->Get(strLitToV8("len"))->ToInt32()->Value();
b.appendBinData(elementName,
@@ -1543,7 +1542,7 @@ namespace mongo {
}
void V8Scope::v8ToMongoObjectID(BSONObjBuilder& b,
- const string& elementName,
+ const StringData& elementName,
v8::Handle<v8::Object> obj) {
OID oid;
oid.init(toSTLString(obj->Get(strLitToV8("str"))));
@@ -1551,7 +1550,7 @@ namespace mongo {
}
void V8Scope::v8ToMongoObject(BSONObjBuilder& b,
- const string& elementName,
+ const StringData& elementName,
v8::Handle<v8::Value> value,
int depth,
BSONObj* originalParent) {
@@ -1587,17 +1586,17 @@ namespace mongo {
}
}
- void V8Scope::v8ToMongoElement(BSONObjBuilder & b, const string& sname,
+ void V8Scope::v8ToMongoElement(BSONObjBuilder & b, const StringData& sname,
v8::Handle<v8::Value> value, int depth,
BSONObj* originalParent) {
if (value->IsString()) {
- b.append(sname, toSTLString(value));
+ b.append(sname, V8String(value));
return;
}
if (value->IsFunction()) {
uassert(16716, "cannot convert native function to BSON",
!value->ToObject()->Has(strLitToV8("_v8_function")));
- b.appendCode(sname, toSTLString(value));
+ b.appendCode(sname, V8String(value));
return;
}
if (value->IsNumber()) {
@@ -1667,11 +1666,12 @@ namespace mongo {
v8::Local<v8::Array> names = o->GetOwnPropertyNames();
for (unsigned int i=0; i<names->Length(); i++) {
v8::Local<v8::String> name = names->Get(i)->ToString();
- v8::Local<v8::Value> value = o->Get(name);
- const string sname = toSTLString(name);
- if (depth == 0 && sname == "_id")
+
+ if (depth == 0 && name->StrictEquals(strLitToV8("_id")))
continue; // already handled above
+ V8String sname(name);
+ v8::Local<v8::Value> value = o->Get(name);
v8ToMongoElement(b, sname, value, depth + 1, &originalBSON);
}
return b.obj();
diff --git a/src/mongo/scripting/engine_v8.h b/src/mongo/scripting/engine_v8.h
index 0b1e2d173b4..2f6c1868c25 100644
--- a/src/mongo/scripting/engine_v8.h
+++ b/src/mongo/scripting/engine_v8.h
@@ -223,36 +223,36 @@ namespace mongo {
*/
mongo::BSONObj v8ToMongo(v8::Handle<v8::Object> obj, int depth = 0);
void v8ToMongoElement(BSONObjBuilder& b,
- const string& sname,
+ const StringData& sname,
v8::Handle<v8::Value> value,
int depth = 0,
BSONObj* originalParent = 0);
void v8ToMongoObject(BSONObjBuilder& b,
- const string& sname,
+ const StringData& sname,
v8::Handle<v8::Value> value,
int depth,
BSONObj* originalParent);
void v8ToMongoNumber(BSONObjBuilder& b,
- const string& elementName,
+ const StringData& elementName,
v8::Handle<v8::Value> value,
BSONObj* originalParent);
void v8ToMongoNumberLong(BSONObjBuilder& b,
- const string& elementName,
+ const StringData& elementName,
v8::Handle<v8::Object> obj);
void v8ToMongoInternal(BSONObjBuilder& b,
- const string& elementName,
+ const StringData& elementName,
v8::Handle<v8::Object> obj);
void v8ToMongoRegex(BSONObjBuilder& b,
- const string& elementName,
+ const StringData& elementName,
v8::Handle<v8::Object> v8Regex);
void v8ToMongoDBRef(BSONObjBuilder& b,
- const string& elementName,
+ const StringData& elementName,
v8::Handle<v8::Object> obj);
void v8ToMongoBinData(BSONObjBuilder& b,
- const string& elementName,
+ const StringData& elementName,
v8::Handle<v8::Object> obj);
void v8ToMongoObjectID(BSONObjBuilder& b,
- const string& elementName,
+ const StringData& elementName,
v8::Handle<v8::Object> obj);
v8::Function* getNamedCons(const char* name);
diff --git a/src/mongo/scripting/v8_utils.cpp b/src/mongo/scripting/v8_utils.cpp
index fa6099d61e1..ec6357e99a4 100644
--- a/src/mongo/scripting/v8_utils.cpp
+++ b/src/mongo/scripting/v8_utils.cpp
@@ -35,10 +35,7 @@ using namespace std;
namespace mongo {
std::string toSTLString(const v8::Handle<v8::Value>& o) {
- v8::String::Utf8Value str(o);
- massert(16686, "error converting js type to Utf8Value", *str);
- std::string s(*str, str.length());
- return s;
+ return StringData(V8String(o)).toString();
}
/** Get the properties of an object (and its prototype) as a comma-delimited string */
@@ -96,7 +93,7 @@ namespace mongo {
// arguments need to be copied into the isolate, go through bson
BSONObjBuilder b;
for(int i = 0; i < args.Length(); ++i) {
- scope->v8ToMongoElement(b, mongoutils::str::stream() << "arg" << i, args[i]);
+ scope->v8ToMongoElement(b, "arg" + BSONObjBuilder::numStr(i), args[i]);
}
_args = b.obj();
}
diff --git a/src/mongo/scripting/v8_utils.h b/src/mongo/scripting/v8_utils.h
index 7f753d36bd3..299e1f6eef9 100644
--- a/src/mongo/scripting/v8_utils.h
+++ b/src/mongo/scripting/v8_utils.h
@@ -23,6 +23,9 @@
#include <string>
#include <v8.h>
+#include <mongo/base/string_data.h>
+#include <mongo/util/assert_util.h>
+
namespace mongo {
#define jsassert(x,msg) uassert(16664, (msg), (x))
@@ -38,6 +41,45 @@ namespace mongo {
/** Simple v8 object to string conversion helper */
std::string toSTLString(const v8::Handle<v8::Value>& o);
+ /** Like toSTLString but doesn't allocate a new std::string
+ *
+ * This owns the string's memory so you need to be careful not to let the
+ * converted StringDatas outlive the V8Scope object. These rules are the
+ * same as converting from a std::string into a StringData.
+ *
+ * Safe:
+ * void someFunction(StringData argument);
+ * v8::Handle<v8::String> aString;
+ *
+ * someFunction(V8String(aString)); // passing down stack as temporary
+ *
+ * V8String named (aString);
+ * someFunction(named); // passing up stack as named value
+ *
+ * StringData sd = named; // scope of sd is less than named
+ *
+ * Unsafe:
+ * StringData _member;
+ *
+ * StringData returningFunction() {
+ * StringData sd = V8String(aString); // sd outlives the temporary
+ *
+ * V8String named(aString)
+ * _member = named; // _member outlives named scope
+ *
+ * return V8String(aString); // passing up stack
+ * }
+ */
+ class V8String {
+ public:
+ explicit V8String(const v8::Handle<v8::Value>& o) :_str(o) {
+ massert(16686, "error converting js type to Utf8Value", *_str);
+ }
+ operator StringData () const { return StringData(*_str, _str.length()); }
+ private:
+ v8::String::Utf8Value _str;
+ };
+
/** Get the properties of an object (and it's prototype) as a comma-delimited string */
std::string v8ObjectToString(const v8::Handle<v8::Object>& o);