diff options
author | Mathias Stearn <mathias@10gen.com> | 2013-04-10 18:32:29 -0400 |
---|---|---|
committer | Dan Pasette <dan@10gen.com> | 2013-06-18 12:40:47 -0400 |
commit | 9d9e10d86ae139493b8492434fb98ffb5ace1f1f (patch) | |
tree | 7f40551380f0bc72cd66692b1e3d9ac5a61d0e2c | |
parent | 277b05b6e148292e742aa9896efae7b15b4b4925 (diff) | |
download | mongo-9d9e10d86ae139493b8492434fb98ffb5ace1f1f.tar.gz |
Cache conversion of string literals to V8 Strings
-rw-r--r-- | src/mongo/scripting/engine_v8.cpp | 108 | ||||
-rw-r--r-- | src/mongo/scripting/engine_v8.h | 32 |
2 files changed, 83 insertions, 57 deletions
diff --git a/src/mongo/scripting/engine_v8.cpp b/src/mongo/scripting/engine_v8.cpp index fe90ec9fdec..a8a77d88334 100644 --- a/src/mongo/scripting/engine_v8.cpp +++ b/src/mongo/scripting/engine_v8.cpp @@ -518,7 +518,7 @@ namespace mongo { lzObjectTemplate->SetIndexedPropertyHandler(indexedGet, indexedSet, 0, indexedDelete, namedEnumerator); lzObjectTemplate->NewInstance()->GetPrototype()->ToObject()->ForceSet( - v8::String::New("_bson"), + strLitToV8("_bson"), v8::Boolean::New(true), v8::DontEnum); @@ -529,7 +529,7 @@ namespace mongo { roObjectTemplate->SetIndexedPropertyHandler(indexedGetRO, IndexedReadOnlySet, 0, IndexedReadOnlyDelete, 0); roObjectTemplate->NewInstance()->GetPrototype()->ToObject()->ForceSet( - v8::String::New("_bson"), + strLitToV8("_bson"), v8::Boolean::New(true), v8::DontEnum); @@ -541,7 +541,7 @@ namespace mongo { lzArrayTemplate->SetInternalFieldCount(1); lzArrayTemplate->SetIndexedPropertyHandler(indexedGet, 0, 0, 0, 0); lzArrayTemplate->NewInstance()->GetPrototype()->ToObject()->ForceSet( - v8::String::New("_bson"), + strLitToV8("_bson"), v8::Boolean::New(true), v8::DontEnum); @@ -615,10 +615,10 @@ namespace mongo { v8::HandleScope handle_scope; try { v8::Local<v8::External> f = - v8::External::Cast(*args.Callee()->Get(v8::String::New("_native_function"))); + v8::External::Cast(*args.Callee()->Get(scope->strLitToV8("_native_function"))); NativeFunction function = (NativeFunction)(f->Value()); v8::Local<v8::External> data = - v8::External::Cast(*args.Callee()->Get(v8::String::New("_native_data"))); + 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]); @@ -646,7 +646,7 @@ namespace mongo { return v8::Undefined(); v8::Local<v8::External> f = - v8::External::Cast(*args.Callee()->Get(v8::String::New("_v8_function"))); + v8::External::Cast(*args.Callee()->Get(scope->strLitToV8("_v8_function"))); v8Function function = (v8Function)(f->Value()); v8::Handle<v8::Value> ret; string exceptionText; @@ -1017,14 +1017,14 @@ namespace mongo { v8::Handle<v8::Object> resultObject = result->ToObject(); // must validate the handle because TerminateExecution may have // been thrown after the above checks - if (!resultObject.IsEmpty() && resultObject->Has(v8StringData("_v8_function"))) { + if (!resultObject.IsEmpty() && resultObject->Has(strLitToV8("_v8_function"))) { log() << "storing native function as return value" << endl; _lastRetIsNativeCode = true; } else { _lastRetIsNativeCode = false; } - _global->ForceSet(v8::String::New("__returnValue"), result); + _global->ForceSet(strLitToV8("__returnValue"), result); } return 0; @@ -1073,7 +1073,7 @@ namespace mongo { if (checkV8ErrorState(result, try_catch, reportError, assertOnError)) return false; - _global->ForceSet(v8StringData("__lastres__"), result); + _global->ForceSet(strLitToV8("__lastres__"), result); if (printResult && !result->IsUndefined()) { // appears to only be used by shell @@ -1091,8 +1091,8 @@ namespace mongo { void V8Scope::injectNative(const char *field, NativeFunction func, v8::Handle<v8::Object>& obj, void* data) { v8::Handle<v8::FunctionTemplate> ft = createV8Function(nativeCallback); - ft->Set(v8::String::New("_native_function"), v8::External::New((void*)func)); - ft->Set(v8::String::New("_native_data"), v8::External::New(data)); + ft->Set(strLitToV8("_native_function"), v8::External::New((void*)func)); + ft->Set(strLitToV8("_native_data"), v8::External::New(data)); ft->SetClassName(v8StringData(field)); obj->ForceSet(v8StringData(field), ft->GetFunction()); } @@ -1119,7 +1119,7 @@ namespace mongo { v8::Handle<v8::FunctionTemplate> V8Scope::createV8Function(v8Function func) { v8::Handle<v8::FunctionTemplate> ft = v8::FunctionTemplate::New(v8Callback); - ft->Set(v8::String::New("_v8_function"), v8::External::New(reinterpret_cast<void*>(func)), + ft->Set(strLitToV8("_v8_function"), v8::External::New(reinterpret_cast<void*>(func)), static_cast<v8::PropertyAttribute>(v8::DontEnum | v8::ReadOnly)); return ft; } @@ -1154,7 +1154,7 @@ namespace mongo { injectV8Function("load", load); // install the Mongo function object and instantiate the 'db' global - _global->ForceSet(v8StringData("Mongo"), + _global->ForceSet(strLitToV8("Mongo"), getMongoFunctionTemplate(this, true)->GetFunction()); execCoreFiles(); exec("_mongo = new Mongo();", "local connect 2", false, true, true, 0); @@ -1183,7 +1183,7 @@ namespace mongo { injectV8Function("load", load); // install the Mongo function object - _global->ForceSet(v8StringData("Mongo"), + _global->ForceSet(strLitToV8("Mongo"), getMongoFunctionTemplate(this, false)->GetFunction()); execCoreFiles(); _connectState = EXTERNAL; @@ -1192,16 +1192,16 @@ namespace mongo { void V8Scope::installDBAccess() { v8::Handle<v8::FunctionTemplate> db = createV8Function(dbInit); db->InstanceTemplate()->SetNamedPropertyHandler(collectionGetter, collectionSetter); - _global->ForceSet(v8StringData("DB"), db->GetFunction()); + _global->ForceSet(strLitToV8("DB"), db->GetFunction()); v8::Handle<v8::FunctionTemplate> dbCollection = createV8Function(collectionInit); dbCollection->InstanceTemplate()->SetNamedPropertyHandler(collectionGetter, collectionSetter); - _global->ForceSet(v8StringData("DBCollection"), dbCollection->GetFunction()); + _global->ForceSet(strLitToV8("DBCollection"), dbCollection->GetFunction()); v8::Handle<v8::FunctionTemplate> dbQuery = createV8Function(dbQueryInit); dbQuery->InstanceTemplate()->SetIndexedPropertyHandler(dbQueryIndexAccess); - _global->ForceSet(v8StringData("DBQuery"), dbQuery->GetFunction()); + _global->ForceSet(strLitToV8("DBQuery"), dbQuery->GetFunction()); } void V8Scope::installBSONTypes() { @@ -1209,19 +1209,19 @@ namespace mongo { injectV8Function("DBRef", dbRefInit, _global); injectV8Function("DBPointer", dbPointerInit, _global); - _global->ForceSet(v8StringData("BinData"), + _global->ForceSet(strLitToV8("BinData"), getBinDataFunctionTemplate(this)->GetFunction()); - _global->ForceSet(v8StringData("UUID"), + _global->ForceSet(strLitToV8("UUID"), createV8Function(uuidInit)->GetFunction()); - _global->ForceSet(v8StringData("MD5"), + _global->ForceSet(strLitToV8("MD5"), createV8Function(md5Init)->GetFunction()); - _global->ForceSet(v8StringData("HexData"), + _global->ForceSet(strLitToV8("HexData"), createV8Function(hexDataInit)->GetFunction()); - _global->ForceSet(v8StringData("NumberLong"), + _global->ForceSet(strLitToV8("NumberLong"), getNumberLongFunctionTemplate(this)->GetFunction()); - _global->ForceSet(v8StringData("NumberInt"), + _global->ForceSet(strLitToV8("NumberInt"), getNumberIntFunctionTemplate(this)->GetFunction()); - _global->ForceSet(v8StringData("Timestamp"), + _global->ForceSet(strLitToV8("Timestamp"), getTimestampFunctionTemplate(this)->GetFunction()); BSONObjBuilder b; @@ -1229,10 +1229,10 @@ namespace mongo { b.appendMinKey(""); BSONObj o = b.obj(); BSONObjIterator i(o); - _global->ForceSet(v8StringData("MaxKey"), mongoToV8Element(i.next()), v8::ReadOnly); - _global->ForceSet(v8StringData("MinKey"), mongoToV8Element(i.next()), v8::ReadOnly); - _global->Get(v8StringData("Object"))->ToObject()->ForceSet( - v8StringData("bsonsize"), + _global->ForceSet(strLitToV8("MaxKey"), mongoToV8Element(i.next()), v8::ReadOnly); + _global->ForceSet(strLitToV8("MinKey"), mongoToV8Element(i.next()), v8::ReadOnly); + _global->Get(strLitToV8("Object"))->ToObject()->ForceSet( + strLitToV8("bsonsize"), createV8Function(bsonsize)->GetFunction()); } @@ -1325,9 +1325,9 @@ namespace mongo { myTemplate->SetCallAsFunctionHandler(minKeyToJson); v8::Local<v8::Object> instance = myTemplate->NewInstance(); - instance->ForceSet(v8::String::New("tojson"), + instance->ForceSet(strLitToV8("tojson"), v8::FunctionTemplate::New(minKeyToJson)->GetFunction(), v8::ReadOnly); - instance->ForceSet(v8::String::New("toString"), + instance->ForceSet(strLitToV8("toString"), v8::FunctionTemplate::New(minKeyToJson)->GetFunction(), v8::ReadOnly); instance->SetInternalField(0, v8::Uint32::New( mongo::MinKey )); return instance; @@ -1348,9 +1348,9 @@ namespace mongo { myTemplate->SetCallAsFunctionHandler(maxKeyToJson); v8::Local<v8::Object> instance = myTemplate->NewInstance(); - instance->ForceSet(v8::String::New("tojson"), + instance->ForceSet(strLitToV8("tojson"), v8::FunctionTemplate::New(maxKeyToJson)->GetFunction(), v8::ReadOnly); - instance->ForceSet(v8::String::New("toString"), + instance->ForceSet(strLitToV8("toString"), v8::FunctionTemplate::New(maxKeyToJson)->GetFunction(), v8::ReadOnly); instance->SetInternalField(0, v8::Uint32::New( mongo::MaxKey )); return instance; @@ -1477,13 +1477,13 @@ namespace mongo { // field, but I don't yet know how to use an ObjectTemplate with a // constructor. long long val; - if (!obj->Has(v8StringData("top"))) { - val = static_cast<int64_t>(obj->Get(v8StringData("floatApprox"))->NumberValue()); + if (!obj->Has(strLitToV8("top"))) { + val = static_cast<int64_t>(obj->Get(strLitToV8("floatApprox"))->NumberValue()); } else { val = static_cast<int64_t>(( - static_cast<uint64_t>(obj->Get(v8StringData("top"))->ToInt32()->Value()) << 32) + - static_cast<uint32_t>(obj->Get(v8StringData("bottom"))->ToInt32()->Value())); + static_cast<uint64_t>(obj->Get(strLitToV8("top"))->ToInt32()->Value()) << 32) + + static_cast<uint32_t>(obj->Get(strLitToV8("bottom"))->ToInt32()->Value())); } b.append(elementName, val); } @@ -1496,8 +1496,8 @@ namespace mongo { case Timestamp: b.appendTimestamp(elementName, Date_t(static_cast<uint64_t>( - obj->Get(v8::String::New("t"))->ToNumber()->Value() * 1000 )), - obj->Get(v8::String::New("i"))->ToInt32()->Value()); + obj->Get(strLitToV8("t"))->ToNumber()->Value() * 1000 )), + obj->Get(strLitToV8("i"))->ToInt32()->Value()); return; case MinKey: b.appendMinKey(elementName); @@ -1524,19 +1524,19 @@ namespace mongo { const string& elementName, v8::Handle<v8::Object> obj) { OID oid; - v8::Local<v8::Value> theid = obj->Get(v8StringData("id")); - oid.init(toSTLString(theid->ToObject()->Get(v8StringData("str")))); - string ns = toSTLString(obj->Get(v8StringData("ns"))); + v8::Local<v8::Value> theid = obj->Get(strLitToV8("id")); + oid.init(toSTLString(theid->ToObject()->Get(strLitToV8("str")))); + string ns = toSTLString(obj->Get(strLitToV8("ns"))); b.appendDBRef(elementName, ns, oid); } void V8Scope::v8ToMongoBinData(BSONObjBuilder& b, const string& elementName, v8::Handle<v8::Object> obj) { - int len = obj->Get(v8StringData("len"))->ToInt32()->Value(); + int len = obj->Get(strLitToV8("len"))->ToInt32()->Value(); b.appendBinData(elementName, len, - mongo::BinDataType(obj->Get(v8StringData("type"))->ToInt32()->Value()), + mongo::BinDataType(obj->Get(strLitToV8("type"))->ToInt32()->Value()), base64::decode(toSTLString(obj->GetInternalField(0))).c_str()); } @@ -1544,7 +1544,7 @@ namespace mongo { const string& elementName, v8::Handle<v8::Object> obj) { OID oid; - oid.init(toSTLString(obj->Get(v8StringData("str")))); + oid.init(toSTLString(obj->Get(strLitToV8("str")))); b.appendOID(elementName, &oid); } @@ -1567,16 +1567,16 @@ namespace mongo { if (proto->IsRegExp()) v8ToMongoRegex(b, elementName, obj); else if (proto->IsObject() && - proto->ToObject()->HasRealNamedProperty(v8::String::New("isObjectId"))) + proto->ToObject()->HasRealNamedProperty(strLitToV8("isObjectId"))) v8ToMongoObjectID(b, elementName, obj); - else if (!obj->GetHiddenValue(v8::String::New("__NumberLong")).IsEmpty()) + else if (!obj->GetHiddenValue(strLitToV8("__NumberLong")).IsEmpty()) v8ToMongoNumberLong(b, elementName, obj); - else if (!obj->GetHiddenValue(v8::String::New("__NumberInt")).IsEmpty()) + else if (!obj->GetHiddenValue(strLitToV8("__NumberInt")).IsEmpty()) b.append(elementName, - obj->GetHiddenValue(v8::String::New("__NumberInt"))->Int32Value()); - else if (!value->ToObject()->GetHiddenValue(v8::String::New("__DBPointer")).IsEmpty()) + obj->GetHiddenValue(strLitToV8("__NumberInt"))->Int32Value()); + else if (!value->ToObject()->GetHiddenValue(strLitToV8("__DBPointer")).IsEmpty()) v8ToMongoDBRef(b, elementName, obj); - else if (!value->ToObject()->GetHiddenValue(v8::String::New("__BinData")).IsEmpty()) + else if (!value->ToObject()->GetHiddenValue(strLitToV8("__BinData")).IsEmpty()) v8ToMongoBinData(b, elementName, obj); else { // nested object or array @@ -1594,7 +1594,7 @@ namespace mongo { } if (value->IsFunction()) { uassert(16716, "cannot convert native function to BSON", - !value->ToObject()->Has(v8StringData("_v8_function"))); + !value->ToObject()->Has(strLitToV8("_v8_function"))); b.appendCode(sname, toSTLString(value)); return; } @@ -1643,7 +1643,7 @@ namespace mongo { BSONObj V8Scope::v8ToMongo(v8::Handle<v8::Object> o, int depth) { BSONObj originalBSON; - if (o->Has(v8::String::New("_bson"))) { + if (o->Has(strLitToV8("_bson"))) { originalBSON = unwrapBSONObj(o); BSONHolder* holder = unwrapHolder(o); if (holder && !holder->_modified) { @@ -1657,8 +1657,8 @@ namespace mongo { // We special case the _id field in top-level objects and move it to the front. // This matches other drivers behavior and makes finding the _id field quicker in BSON. if (depth == 0) { - if (o->HasOwnProperty(v8::String::New("_id"))) { - v8ToMongoElement(b, "_id", o->Get(v8::String::New("_id")), 0, &originalBSON); + if (o->HasOwnProperty(strLitToV8("_id"))) { + v8ToMongoElement(b, "_id", o->Get(strLitToV8("_id")), 0, &originalBSON); } } diff --git a/src/mongo/scripting/engine_v8.h b/src/mongo/scripting/engine_v8.h index b86d063afae..e9ce457400b 100644 --- a/src/mongo/scripting/engine_v8.h +++ b/src/mongo/scripting/engine_v8.h @@ -23,6 +23,7 @@ #include "mongo/base/disallow_copying.h" #include "mongo/client/dbclientinterface.h" #include "mongo/client/dbclientcursor.h" +#include "mongo/platform/unordered_map.h" #include "mongo/scripting/engine.h" #include "mongo/scripting/v8_deadline_monitor.h" #include "mongo/scripting/v8_profiler.h" @@ -201,9 +202,9 @@ namespace mongo { virtual void injectNative(const char* field, NativeFunction func, void* data = 0); void injectNative(const char* field, NativeFunction func, v8::Handle<v8::Object>& obj, void* data = 0); - void injectV8Function(const char* field, v8Function func); - void injectV8Function(const char* field, v8Function func, v8::Handle<v8::Object>& obj); - void injectV8Function(const char* field, v8Function func, v8::Handle<v8::Template>& t); + void injectV8Function(const char* name, v8Function func); + void injectV8Function(const char* name, v8Function func, v8::Handle<v8::Object>& obj); + void injectV8Function(const char* name, v8Function func, v8::Handle<v8::Template>& t); v8::Handle<v8::FunctionTemplate> createV8Function(v8Function func); virtual ScriptingFunction _createFunction(const char* code, ScriptingFunction functionNumber = 0); @@ -362,6 +363,27 @@ namespace mongo { bool reportError = true, bool assertOnError = true); + template <size_t N> + v8::Handle<v8::String> strLitToV8(const char (&str)[N]) { + // Note that _strLitMap is keyed on string pointer not string + // value. This is OK because each string literal has a constant + // pointer for the program's lifetime. This works best if (but does + // not require) the linker interns all string literals giving + // identical strings used in different places the same pointer. + + StrLitMap::iterator it = _strLitMap.find(str); + if (it != _strLitMap.end()) + return it->second; + + StringData sd (str, StringData::LiteralTag()); + v8::Handle<v8::String> v8Str = v8StringData(sd); + + // We never need to Dispose since this should last as long as V8Scope exists + _strLitMap[str] = v8::Persistent<v8::String>::New(v8Str); + + return v8Str; + } + V8ScriptEngine* _engine; v8::Persistent<v8::Context> _context; @@ -381,6 +403,10 @@ namespace mongo { v8::Isolate* _isolate; V8CpuProfiler _cpuProfiler; + // See comments in strLitToV8 + typedef unordered_map<const char*, v8::Handle<v8::String> > StrLitMap; + StrLitMap _strLitMap; + mongo::mutex _interruptLock; // protects interruption-related flags bool _inNativeExecution; // protected by _interruptLock bool _pendingKill; // protected by _interruptLock |