summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorJason Carey <jcarey@argv.me>2015-10-06 20:08:03 -0400
committerJason Carey <jcarey@argv.me>2015-10-06 20:14:01 -0400
commit95060c27ed2dddcb6343a88f7aa405ed8a935ad7 (patch)
treeea6d2287cbdb7154d22af6335ae1f56ac7b6aba0 /src/mongo
parentb7104c6f2f597335c6b9890ff6b80243625a6258 (diff)
downloadmongo-95060c27ed2dddcb6343a88f7aa405ed8a935ad7.tar.gz
SERVER-19977 Intern JS Strings
Rather than supplying const char*'s throughout our use of the MozJS api, intern the strings and root their associated ids (to save on string parsing).
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/scripting/SConscript1
-rw-r--r--src/mongo/scripting/mozjs/bindata.cpp7
-rw-r--r--src/mongo/scripting/mozjs/bson.cpp3
-rw-r--r--src/mongo/scripting/mozjs/cursor.cpp5
-rw-r--r--src/mongo/scripting/mozjs/db.cpp7
-rw-r--r--src/mongo/scripting/mozjs/dbcollection.cpp8
-rw-r--r--src/mongo/scripting/mozjs/dbpointer.cpp5
-rw-r--r--src/mongo/scripting/mozjs/dbquery.cpp41
-rw-r--r--src/mongo/scripting/mozjs/dbref.cpp7
-rw-r--r--src/mongo/scripting/mozjs/implscope.cpp1
-rw-r--r--src/mongo/scripting/mozjs/implscope.h6
-rw-r--r--src/mongo/scripting/mozjs/internedstring.cpp65
-rw-r--r--src/mongo/scripting/mozjs/internedstring.defs49
-rw-r--r--src/mongo/scripting/mozjs/internedstring.h87
-rw-r--r--src/mongo/scripting/mozjs/jsthread.cpp4
-rw-r--r--src/mongo/scripting/mozjs/maxkey.cpp15
-rw-r--r--src/mongo/scripting/mozjs/minkey.cpp15
-rw-r--r--src/mongo/scripting/mozjs/mongo.cpp14
-rw-r--r--src/mongo/scripting/mozjs/numberlong.cpp36
-rw-r--r--src/mongo/scripting/mozjs/objectwrapper.cpp44
-rw-r--r--src/mongo/scripting/mozjs/objectwrapper.h4
-rw-r--r--src/mongo/scripting/mozjs/timestamp.cpp9
22 files changed, 341 insertions, 92 deletions
diff --git a/src/mongo/scripting/SConscript b/src/mongo/scripting/SConscript
index 24bc437dec6..4f92296f1c7 100644
--- a/src/mongo/scripting/SConscript
+++ b/src/mongo/scripting/SConscript
@@ -121,6 +121,7 @@ if usemozjs:
'mozjs/global.cpp',
'mozjs/idwrapper.cpp',
'mozjs/implscope.cpp',
+ 'mozjs/internedstring.cpp',
'mozjs/jscustomallocator.cpp',
'mozjs/jsstringwrapper.cpp',
'mozjs/jsthread.cpp',
diff --git a/src/mongo/scripting/mozjs/bindata.cpp b/src/mongo/scripting/mozjs/bindata.cpp
index e9f10cae125..ba07c3164ad 100644
--- a/src/mongo/scripting/mozjs/bindata.cpp
+++ b/src/mongo/scripting/mozjs/bindata.cpp
@@ -34,6 +34,7 @@
#include <cctype>
#include "mongo/scripting/mozjs/implscope.h"
+#include "mongo/scripting/mozjs/internedstring.h"
#include "mongo/scripting/mozjs/objectwrapper.h"
#include "mongo/scripting/mozjs/valuereader.h"
#include "mongo/scripting/mozjs/valuewriter.h"
@@ -157,7 +158,7 @@ void BinDataInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args) {
str::stream ss;
- ss << "BinData(" << o.getNumber("type") << ",\"" << *str << "\")";
+ ss << "BinData(" << o.getNumber(InternedString::type) << ",\"" << *str << "\")";
ValueReader(cx, args.rval()).fromStringData(ss.operator std::string());
}
@@ -215,8 +216,8 @@ void BinDataInfo::construct(JSContext* cx, JS::CallArgs args) {
JS::RootedValue len(cx);
len.setInt32(tmpBase64.length());
- o.defineProperty("len", len, JSPROP_READONLY);
- o.defineProperty("type", type, JSPROP_READONLY);
+ o.defineProperty(InternedString::len, len, JSPROP_READONLY);
+ o.defineProperty(InternedString::type, type, JSPROP_READONLY);
JS_SetPrivate(thisv, new std::string(std::move(str)));
diff --git a/src/mongo/scripting/mozjs/bson.cpp b/src/mongo/scripting/mozjs/bson.cpp
index 8155e083e9c..f2c30407845 100644
--- a/src/mongo/scripting/mozjs/bson.cpp
+++ b/src/mongo/scripting/mozjs/bson.cpp
@@ -35,6 +35,7 @@
#include "mongo/scripting/mozjs/idwrapper.h"
#include "mongo/scripting/mozjs/implscope.h"
+#include "mongo/scripting/mozjs/internedstring.h"
#include "mongo/scripting/mozjs/objectwrapper.h"
#include "mongo/scripting/mozjs/valuereader.h"
#include "mongo/scripting/mozjs/valuewriter.h"
@@ -251,7 +252,7 @@ void BSONInfo::postInstall(JSContext* cx, JS::HandleObject global, JS::HandleObj
JS::RootedValue value(cx);
value.setBoolean(true);
- ObjectWrapper(cx, proto).defineProperty("_bson", value, 0);
+ ObjectWrapper(cx, proto).defineProperty(InternedString::_bson, value, 0);
}
} // namespace mozjs
diff --git a/src/mongo/scripting/mozjs/cursor.cpp b/src/mongo/scripting/mozjs/cursor.cpp
index 072e2ffb999..4264fdfc23c 100644
--- a/src/mongo/scripting/mozjs/cursor.cpp
+++ b/src/mongo/scripting/mozjs/cursor.cpp
@@ -32,6 +32,7 @@
#include "mongo/scripting/mozjs/bson.h"
#include "mongo/scripting/mozjs/implscope.h"
+#include "mongo/scripting/mozjs/internedstring.h"
#include "mongo/scripting/mozjs/objectwrapper.h"
#include "mongo/scripting/mozjs/valuereader.h"
#include "mongo/scripting/mozjs/wrapconstrainedmethod.h"
@@ -81,7 +82,7 @@ void CursorInfo::Functions::next::call(JSContext* cx, JS::CallArgs args) {
ObjectWrapper o(cx, args.thisv());
BSONObj bson = cursor->next();
- bool ro = o.hasField("_ro") ? o.getBoolean("_ro") : false;
+ bool ro = o.hasField(InternedString::_ro) ? o.getBoolean(InternedString::_ro) : false;
// getOwned because cursor->next() gives us unowned bson from an internal
// buffer and we need to make a copy
@@ -111,7 +112,7 @@ void CursorInfo::Functions::objsLeftInBatch::call(JSContext* cx, JS::CallArgs ar
}
void CursorInfo::Functions::readOnly::call(JSContext* cx, JS::CallArgs args) {
- ObjectWrapper(cx, args.thisv()).setBoolean("_ro", true);
+ ObjectWrapper(cx, args.thisv()).setBoolean(InternedString::_ro, true);
args.rval().set(args.thisv());
}
diff --git a/src/mongo/scripting/mozjs/db.cpp b/src/mongo/scripting/mozjs/db.cpp
index 9a5d45b0984..181ee12befa 100644
--- a/src/mongo/scripting/mozjs/db.cpp
+++ b/src/mongo/scripting/mozjs/db.cpp
@@ -34,6 +34,7 @@
#include "mongo/db/operation_context.h"
#include "mongo/scripting/mozjs/idwrapper.h"
#include "mongo/scripting/mozjs/implscope.h"
+#include "mongo/scripting/mozjs/internedstring.h"
#include "mongo/scripting/mozjs/objectwrapper.h"
#include "mongo/scripting/mozjs/valuereader.h"
#include "mongo/scripting/mozjs/valuewriter.h"
@@ -85,7 +86,7 @@ void DBInfo::getProperty(JSContext* cx,
// no hit, create new collection
JS::RootedValue getCollection(cx);
- parentWrapper.getValue("getCollection", &getCollection);
+ parentWrapper.getValue(InternedString::getCollection, &getCollection);
if (!(getCollection.isObject() && JS_ObjectIsFunction(cx, getCollection.toObjectOrNull()))) {
uasserted(ErrorCodes::BadValue, "getCollection is not a function");
@@ -124,8 +125,8 @@ void DBInfo::construct(JSContext* cx, JS::CallArgs args) {
scope->getProto<DBInfo>().newObject(&thisv);
ObjectWrapper o(cx, thisv);
- o.setValue("_mongo", args.get(0));
- o.setValue("_name", args.get(1));
+ o.setValue(InternedString::_mongo, args.get(0));
+ o.setValue(InternedString::_name, args.get(1));
std::string dbName = ValueWriter(cx, args.get(1)).toString();
diff --git a/src/mongo/scripting/mozjs/dbcollection.cpp b/src/mongo/scripting/mozjs/dbcollection.cpp
index c4814251839..2cc03a752e1 100644
--- a/src/mongo/scripting/mozjs/dbcollection.cpp
+++ b/src/mongo/scripting/mozjs/dbcollection.cpp
@@ -67,10 +67,10 @@ void DBCollectionInfo::construct(JSContext* cx, JS::CallArgs args) {
scope->getProto<DBCollectionInfo>().newObject(&thisv);
ObjectWrapper o(cx, thisv);
- o.setValue("_mongo", args.get(0));
- o.setValue("_db", args.get(1));
- o.setValue("_shortName", args.get(2));
- o.setValue("_fullName", args.get(3));
+ o.setValue(InternedString::_mongo, args.get(0));
+ o.setValue(InternedString::_db, args.get(1));
+ o.setValue(InternedString::_shortName, args.get(2));
+ o.setValue(InternedString::_fullName, args.get(3));
std::string fullName = ValueWriter(cx, args.get(3)).toString();
diff --git a/src/mongo/scripting/mozjs/dbpointer.cpp b/src/mongo/scripting/mozjs/dbpointer.cpp
index 20c3882ba72..61a355c92c0 100644
--- a/src/mongo/scripting/mozjs/dbpointer.cpp
+++ b/src/mongo/scripting/mozjs/dbpointer.cpp
@@ -31,6 +31,7 @@
#include "mongo/scripting/mozjs/dbpointer.h"
#include "mongo/scripting/mozjs/implscope.h"
+#include "mongo/scripting/mozjs/internedstring.h"
#include "mongo/scripting/mozjs/objectwrapper.h"
#include "mongo/scripting/mozjs/valuereader.h"
#include "mongo/util/mongoutils/str.h"
@@ -56,8 +57,8 @@ void DBPointerInfo::construct(JSContext* cx, JS::CallArgs args) {
scope->getProto<DBPointerInfo>().newObject(&thisv);
ObjectWrapper o(cx, thisv);
- o.setValue("ns", args.get(0));
- o.setValue("id", args.get(1));
+ o.setValue(InternedString::ns, args.get(0));
+ o.setValue(InternedString::id, args.get(1));
args.rval().setObjectOrNull(thisv);
}
diff --git a/src/mongo/scripting/mozjs/dbquery.cpp b/src/mongo/scripting/mozjs/dbquery.cpp
index d3c68538884..c2543814505 100644
--- a/src/mongo/scripting/mozjs/dbquery.cpp
+++ b/src/mongo/scripting/mozjs/dbquery.cpp
@@ -32,6 +32,7 @@
#include "mongo/scripting/mozjs/idwrapper.h"
#include "mongo/scripting/mozjs/implscope.h"
+#include "mongo/scripting/mozjs/internedstring.h"
#include "mongo/scripting/mozjs/objectwrapper.h"
namespace mongo {
@@ -49,10 +50,10 @@ void DBQueryInfo::construct(JSContext* cx, JS::CallArgs args) {
scope->getProto<DBQueryInfo>().newObject(&thisv);
ObjectWrapper o(cx, thisv);
- o.setValue("_mongo", args.get(0));
- o.setValue("_db", args.get(1));
- o.setValue("_collection", args.get(2));
- o.setValue("_ns", args.get(3));
+ o.setValue(InternedString::_mongo, args.get(0));
+ o.setValue(InternedString::_db, args.get(1));
+ o.setValue(InternedString::_collection, args.get(2));
+ o.setValue(InternedString::_ns, args.get(3));
JS::RootedObject emptyObj(cx);
JS::RootedValue emptyObjVal(cx);
@@ -62,44 +63,44 @@ void DBQueryInfo::construct(JSContext* cx, JS::CallArgs args) {
nullVal.setNull();
if (args.length() > 4 && args.get(4).isObject()) {
- o.setValue("_query", args.get(4));
+ o.setValue(InternedString::_query, args.get(4));
} else {
- o.setValue("_query", emptyObjVal);
+ o.setValue(InternedString::_query, emptyObjVal);
}
if (args.length() > 5 && args.get(5).isObject()) {
- o.setValue("_fields", args.get(5));
+ o.setValue(InternedString::_fields, args.get(5));
} else {
- o.setValue("_fields", nullVal);
+ o.setValue(InternedString::_fields, nullVal);
}
if (args.length() > 6 && args.get(6).isNumber()) {
- o.setValue("_limit", args.get(6));
+ o.setValue(InternedString::_limit, args.get(6));
} else {
- o.setNumber("_limit", 0);
+ o.setNumber(InternedString::_limit, 0);
}
if (args.length() > 7 && args.get(7).isNumber()) {
- o.setValue("_skip", args.get(7));
+ o.setValue(InternedString::_skip, args.get(7));
} else {
- o.setNumber("_skip", 0);
+ o.setNumber(InternedString::_skip, 0);
}
if (args.length() > 8 && args.get(8).isNumber()) {
- o.setValue("_batchSize", args.get(8));
+ o.setValue(InternedString::_batchSize, args.get(8));
} else {
- o.setNumber("_batchSize", 0);
+ o.setNumber(InternedString::_batchSize, 0);
}
if (args.length() > 9 && args.get(9).isNumber()) {
- o.setValue("_options", args.get(9));
+ o.setValue(InternedString::_options, args.get(9));
} else {
- o.setNumber("_options", 0);
+ o.setNumber(InternedString::_options, 0);
}
- o.setValue("_cursor", nullVal);
- o.setNumber("_numReturned", 0);
- o.setBoolean("_special", false);
+ o.setValue(InternedString::_cursor, nullVal);
+ o.setNumber(InternedString::_numReturned, 0);
+ o.setBoolean(InternedString::_special, false);
args.rval().setObjectOrNull(thisv);
}
@@ -126,7 +127,7 @@ void DBQueryInfo::getProperty(JSContext* cx,
ObjectWrapper parentWrapper(cx, parent);
JS::RootedValue arrayAccess(cx);
- parentWrapper.getValue("arrayAccess", &arrayAccess);
+ parentWrapper.getValue(InternedString::arrayAccess, &arrayAccess);
if (arrayAccess.isObject() && JS_ObjectIsFunction(cx, arrayAccess.toObjectOrNull())) {
JS::AutoValueArray<1> args(cx);
diff --git a/src/mongo/scripting/mozjs/dbref.cpp b/src/mongo/scripting/mozjs/dbref.cpp
index 4200ebaa67f..e41a0d7af33 100644
--- a/src/mongo/scripting/mozjs/dbref.cpp
+++ b/src/mongo/scripting/mozjs/dbref.cpp
@@ -31,6 +31,7 @@
#include "mongo/scripting/mozjs/dbref.h"
#include "mongo/scripting/mozjs/implscope.h"
+#include "mongo/scripting/mozjs/internedstring.h"
#include "mongo/scripting/mozjs/objectwrapper.h"
namespace mongo {
@@ -51,14 +52,14 @@ void DBRefInfo::construct(JSContext* cx, JS::CallArgs args) {
scope->getProto<DBRefInfo>().newObject(&thisv);
ObjectWrapper o(cx, thisv);
- o.setValue("$ref", args.get(0));
- o.setValue("$id", args.get(1));
+ o.setValue(InternedString::dollar_ref, args.get(0));
+ o.setValue(InternedString::dollar_id, args.get(1));
if (args.length() == 3) {
if (!args.get(2).isString())
uasserted(ErrorCodes::BadValue, "DBRef 3rd parameter must be a string");
- o.setValue("$db", args.get(2));
+ o.setValue(InternedString::dollar_db, args.get(2));
}
args.rval().setObjectOrNull(thisv);
diff --git a/src/mongo/scripting/mozjs/implscope.cpp b/src/mongo/scripting/mozjs/implscope.cpp
index debb02f968b..a6621637973 100644
--- a/src/mongo/scripting/mozjs/implscope.cpp
+++ b/src/mongo/scripting/mozjs/implscope.cpp
@@ -242,6 +242,7 @@ MozJSImplScope::MozJSImplScope(MozJSScriptEngine* engine)
_globalProto(_context),
_global(_globalProto.getProto()),
_funcs(),
+ _internedStrings(_context),
_pendingKill(false),
_opId(0),
_opCtx(nullptr),
diff --git a/src/mongo/scripting/mozjs/implscope.h b/src/mongo/scripting/mozjs/implscope.h
index 1222ed38a24..56eda215fff 100644
--- a/src/mongo/scripting/mozjs/implscope.h
+++ b/src/mongo/scripting/mozjs/implscope.h
@@ -44,6 +44,7 @@
#include "mongo/scripting/mozjs/engine.h"
#include "mongo/scripting/mozjs/error.h"
#include "mongo/scripting/mozjs/global.h"
+#include "mongo/scripting/mozjs/internedstring.h"
#include "mongo/scripting/mozjs/jsthread.h"
#include "mongo/scripting/mozjs/maxkey.h"
#include "mongo/scripting/mozjs/minkey.h"
@@ -296,6 +297,10 @@ public:
void advanceGeneration() override;
+ JS::HandleId getInternedStringId(InternedString name) {
+ return _internedStrings.getInternedString(name);
+ }
+
private:
void _MozJSCreateFunction(const char* raw,
ScriptingFunction functionNumber,
@@ -348,6 +353,7 @@ private:
WrapType<GlobalInfo> _globalProto;
JS::HandleObject _global;
std::vector<JS::PersistentRootedValue> _funcs;
+ InternedStringTable _internedStrings;
std::atomic<bool> _pendingKill;
std::string _error;
unsigned int _opId; // op id for this scope
diff --git a/src/mongo/scripting/mozjs/internedstring.cpp b/src/mongo/scripting/mozjs/internedstring.cpp
new file mode 100644
index 00000000000..61510823f2c
--- /dev/null
+++ b/src/mongo/scripting/mozjs/internedstring.cpp
@@ -0,0 +1,65 @@
+/**
+ * Copyright (C) 2015 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/scripting/mozjs/internedstring.h"
+
+#include "mongo/scripting/mozjs/implscope.h"
+
+namespace mongo {
+namespace mozjs {
+
+InternedStringTable::InternedStringTable(JSContext* cx) {
+ JSAutoRequest ar(cx);
+
+ int i = 0;
+
+#define MONGO_MOZJS_INTERNED_STRING(name, str) \
+ do { \
+ auto s = JS_InternString(cx, str); \
+ if (!s) { \
+ uasserted(ErrorCodes::JSInterpreterFailure, "Failed to JS_InternString"); \
+ } \
+ _internedStrings[i++].init(cx, INTERNED_STRING_TO_JSID(cx, s)); \
+ } while (0);
+#include "mongo/scripting/mozjs/internedstring.defs"
+#undef MONGO_MOZJS_INTERNED_STRING
+}
+
+InternedStringTable::~InternedStringTable() {
+ for (auto&& x : _internedStrings) {
+ x.reset();
+ }
+}
+
+InternedStringId::InternedStringId(JSContext* cx, InternedString id)
+ : _id(cx, getScope(cx)->getInternedStringId(id)) {}
+
+} // namespace mozjs
+} // namespace mongo
diff --git a/src/mongo/scripting/mozjs/internedstring.defs b/src/mongo/scripting/mozjs/internedstring.defs
new file mode 100644
index 00000000000..377e86f1aaa
--- /dev/null
+++ b/src/mongo/scripting/mozjs/internedstring.defs
@@ -0,0 +1,49 @@
+/**
+ * This file uses X-macros to populate an enum as well as intern a number of
+ * strings for the InternedStringTable type. I.e. it's included multiple times
+ * with different definitions of MONGO_MOZJS_INTERNED_STRING.
+ */
+
+MONGO_MOZJS_INTERNED_STRING(arrayAccess, "arrayAccess")
+MONGO_MOZJS_INTERNED_STRING(_batchSize, "_batchSize")
+MONGO_MOZJS_INTERNED_STRING(bottom, "bottom")
+MONGO_MOZJS_INTERNED_STRING(_bson, "_bson")
+MONGO_MOZJS_INTERNED_STRING(_collection, "_collection")
+MONGO_MOZJS_INTERNED_STRING(constructor, "constructor")
+MONGO_MOZJS_INTERNED_STRING(_cursor, "_cursor")
+MONGO_MOZJS_INTERNED_STRING(_db, "_db")
+MONGO_MOZJS_INTERNED_STRING(dollar_db, "$db")
+MONGO_MOZJS_INTERNED_STRING(dollar_id, "$id")
+MONGO_MOZJS_INTERNED_STRING(dollar_ref, "$ref")
+MONGO_MOZJS_INTERNED_STRING(_fields, "_fields")
+MONGO_MOZJS_INTERNED_STRING(floatApprox, "floatApprox")
+MONGO_MOZJS_INTERNED_STRING(_fullName, "_fullName")
+MONGO_MOZJS_INTERNED_STRING(getCollection, "getCollection")
+MONGO_MOZJS_INTERNED_STRING(host, "host")
+MONGO_MOZJS_INTERNED_STRING(_id, "_id")
+MONGO_MOZJS_INTERNED_STRING(id, "id")
+MONGO_MOZJS_INTERNED_STRING(i, "i")
+MONGO_MOZJS_INTERNED_STRING(_JSThreadConfig, "_JSThreadConfig")
+MONGO_MOZJS_INTERNED_STRING(len, "len")
+MONGO_MOZJS_INTERNED_STRING(_limit, "_limit")
+MONGO_MOZJS_INTERNED_STRING(MaxKey, "MaxKey")
+MONGO_MOZJS_INTERNED_STRING(MinKey, "MinKey")
+MONGO_MOZJS_INTERNED_STRING(_mongo, "_mongo")
+MONGO_MOZJS_INTERNED_STRING(_name, "_name")
+MONGO_MOZJS_INTERNED_STRING(name, "name")
+MONGO_MOZJS_INTERNED_STRING(_ns, "_ns")
+MONGO_MOZJS_INTERNED_STRING(ns, "ns")
+MONGO_MOZJS_INTERNED_STRING(_numReturned, "_numReturned")
+MONGO_MOZJS_INTERNED_STRING(_options, "_options")
+MONGO_MOZJS_INTERNED_STRING(_query, "_query")
+MONGO_MOZJS_INTERNED_STRING(readOnly, "readOnly")
+MONGO_MOZJS_INTERNED_STRING(_ro, "_ro")
+MONGO_MOZJS_INTERNED_STRING(_shortName, "_shortName")
+MONGO_MOZJS_INTERNED_STRING(singleton, "singleton")
+MONGO_MOZJS_INTERNED_STRING(_skip, "_skip")
+MONGO_MOZJS_INTERNED_STRING(slaveOk, "slaveOk")
+MONGO_MOZJS_INTERNED_STRING(_special, "_special")
+MONGO_MOZJS_INTERNED_STRING(str, "str")
+MONGO_MOZJS_INTERNED_STRING(top, "top")
+MONGO_MOZJS_INTERNED_STRING(t, "t")
+MONGO_MOZJS_INTERNED_STRING(type, "type")
diff --git a/src/mongo/scripting/mozjs/internedstring.h b/src/mongo/scripting/mozjs/internedstring.h
new file mode 100644
index 00000000000..79c19c38d51
--- /dev/null
+++ b/src/mongo/scripting/mozjs/internedstring.h
@@ -0,0 +1,87 @@
+/**
+ * Copyright (C) 2015 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+#include <array>
+#include <jsapi.h>
+
+namespace mongo {
+namespace mozjs {
+
+/**
+ * An enum that includes members for each interned string we own. These values
+ * can be used with InteredStringId to get a handle to an id that matches that
+ * identifier, or directly in ObjectWrapper.
+ */
+enum class InternedString {
+#define MONGO_MOZJS_INTERNED_STRING(name, str) name,
+#include "mongo/scripting/mozjs/internedstring.defs"
+#undef MONGO_MOZJS_INTERNED_STRING
+ NUM_IDS,
+};
+
+/**
+ * Provides a handle to an interned string id.
+ */
+class InternedStringId {
+public:
+ InternedStringId(JSContext* cx, InternedString id);
+
+ operator JS::HandleId() {
+ return _id;
+ }
+
+ operator jsid() {
+ return _id;
+ }
+
+private:
+ JS::RootedId _id;
+};
+
+/**
+ * The scope global interned string table. This owns persistent roots to each
+ * id and can lookup ids by enum identifier
+ */
+class InternedStringTable {
+public:
+ explicit InternedStringTable(JSContext* cx);
+ ~InternedStringTable();
+
+ JS::HandleId getInternedString(InternedString id) {
+ return _internedStrings[static_cast<std::size_t>(id)];
+ }
+
+private:
+ std::array<JS::PersistentRootedId, static_cast<std::size_t>(InternedString::NUM_IDS)>
+ _internedStrings;
+};
+
+} // namespace mozjs
+} // namespace mongo
diff --git a/src/mongo/scripting/mozjs/jsthread.cpp b/src/mongo/scripting/mozjs/jsthread.cpp
index 35dd5537b5b..2e5ea289d84 100644
--- a/src/mongo/scripting/mozjs/jsthread.cpp
+++ b/src/mongo/scripting/mozjs/jsthread.cpp
@@ -225,7 +225,7 @@ namespace {
JSThreadConfig* getConfig(JSContext* cx, JS::CallArgs args) {
JS::RootedValue value(cx);
- ObjectWrapper(cx, args.thisv()).getValue("_JSThreadConfig", &value);
+ ObjectWrapper(cx, args.thisv()).getValue(InternedString::_JSThreadConfig, &value);
if (!value.isObject())
uasserted(ErrorCodes::BadValue, "_JSThreadConfig not an object");
@@ -255,7 +255,7 @@ void JSThreadInfo::Functions::init::call(JSContext* cx, JS::CallArgs args) {
JSThreadConfig* config = new JSThreadConfig(cx, args);
JS_SetPrivate(obj, config);
- ObjectWrapper(cx, args.thisv()).setObject("_JSThreadConfig", obj);
+ ObjectWrapper(cx, args.thisv()).setObject(InternedString::_JSThreadConfig, obj);
args.rval().setUndefined();
}
diff --git a/src/mongo/scripting/mozjs/maxkey.cpp b/src/mongo/scripting/mozjs/maxkey.cpp
index 78dae6a9719..6730da09b0d 100644
--- a/src/mongo/scripting/mozjs/maxkey.cpp
+++ b/src/mongo/scripting/mozjs/maxkey.cpp
@@ -30,6 +30,7 @@
#include "mongo/scripting/mozjs/maxkey.h"
+#include "mongo/scripting/mozjs/internedstring.h"
#include "mongo/scripting/mozjs/implscope.h"
#include "mongo/scripting/mozjs/objectwrapper.h"
#include "mongo/scripting/mozjs/valuereader.h"
@@ -44,10 +45,6 @@ const JSFunctionSpec MaxKeyInfo::methods[2] = {
const char* const MaxKeyInfo::className = "MaxKey";
-namespace {
-const char* const kSingleton = "singleton";
-} // namespace
-
void MaxKeyInfo::construct(JSContext* cx, JS::CallArgs args) {
call(cx, args);
}
@@ -64,14 +61,14 @@ void MaxKeyInfo::call(JSContext* cx, JS::CallArgs args) {
JS::RootedValue val(cx);
- if (!o.hasField(kSingleton)) {
+ if (!o.hasField(InternedString::singleton)) {
JS::RootedObject thisv(cx);
scope->getProto<MaxKeyInfo>().newObject(&thisv);
val.setObjectOrNull(thisv);
- o.setValue(kSingleton, val);
+ o.setValue(InternedString::singleton, val);
} else {
- o.getValue(kSingleton, &val);
+ o.getValue(InternedString::singleton, &val);
if (!getScope(cx)->getProto<MaxKeyInfo>().instanceOf(val))
uasserted(ErrorCodes::BadValue, "MaxKey singleton not of type MaxKey");
@@ -90,8 +87,8 @@ void MaxKeyInfo::postInstall(JSContext* cx, JS::HandleObject global, JS::HandleO
JS::RootedValue value(cx);
getScope(cx)->getProto<MaxKeyInfo>().newObject(&value);
- ObjectWrapper(cx, global).setValue("MaxKey", value);
- protoWrapper.setValue(kSingleton, value);
+ ObjectWrapper(cx, global).setValue(InternedString::MaxKey, value);
+ protoWrapper.setValue(InternedString::singleton, value);
}
} // namespace mozjs
diff --git a/src/mongo/scripting/mozjs/minkey.cpp b/src/mongo/scripting/mozjs/minkey.cpp
index 13644e0220a..0325a93dcb7 100644
--- a/src/mongo/scripting/mozjs/minkey.cpp
+++ b/src/mongo/scripting/mozjs/minkey.cpp
@@ -30,6 +30,7 @@
#include "mongo/scripting/mozjs/minkey.h"
+#include "mongo/scripting/mozjs/internedstring.h"
#include "mongo/scripting/mozjs/implscope.h"
#include "mongo/scripting/mozjs/objectwrapper.h"
#include "mongo/scripting/mozjs/valuereader.h"
@@ -44,10 +45,6 @@ const JSFunctionSpec MinKeyInfo::methods[2] = {
const char* const MinKeyInfo::className = "MinKey";
-namespace {
-const char* const kSingleton = "singleton";
-} // namespace
-
void MinKeyInfo::construct(JSContext* cx, JS::CallArgs args) {
call(cx, args);
}
@@ -64,14 +61,14 @@ void MinKeyInfo::call(JSContext* cx, JS::CallArgs args) {
JS::RootedValue val(cx);
- if (!o.hasField(kSingleton)) {
+ if (!o.hasField(InternedString::singleton)) {
JS::RootedObject thisv(cx);
scope->getProto<MinKeyInfo>().newObject(&thisv);
val.setObjectOrNull(thisv);
- o.setValue(kSingleton, val);
+ o.setValue(InternedString::singleton, val);
} else {
- o.getValue(kSingleton, &val);
+ o.getValue(InternedString::singleton, &val);
if (!getScope(cx)->getProto<MinKeyInfo>().instanceOf(val))
uasserted(ErrorCodes::BadValue, "MinKey singleton not of type MinKey");
@@ -90,8 +87,8 @@ void MinKeyInfo::postInstall(JSContext* cx, JS::HandleObject global, JS::HandleO
JS::RootedValue value(cx);
getScope(cx)->getProto<MinKeyInfo>().newObject(&value);
- ObjectWrapper(cx, global).setValue("MinKey", value);
- protoWrapper.setValue(kSingleton, value);
+ ObjectWrapper(cx, global).setValue(InternedString::MinKey, value);
+ protoWrapper.setValue(InternedString::singleton, value);
}
} // namespace mozjs
diff --git a/src/mongo/scripting/mozjs/mongo.cpp b/src/mongo/scripting/mozjs/mongo.cpp
index 684870aa5af..e6cad5fad6e 100644
--- a/src/mongo/scripting/mozjs/mongo.cpp
+++ b/src/mongo/scripting/mozjs/mongo.cpp
@@ -240,7 +240,7 @@ void MongoBase::Functions::insert::call(JSContext* cx, JS::CallArgs args) {
ObjectWrapper o(cx, args.thisv());
- if (o.hasField("readOnly") && o.getBoolean("readOnly"))
+ if (o.hasField(InternedString::readOnly) && o.getBoolean(InternedString::readOnly))
uasserted(ErrorCodes::BadValue, "js db in read only mode");
auto conn = getConnection(args);
@@ -257,10 +257,10 @@ void MongoBase::Functions::insert::call(JSContext* cx, JS::CallArgs args) {
ObjectWrapper ele(cx, elementObj);
- if (!ele.hasField("_id")) {
+ if (!ele.hasField(InternedString::_id)) {
JS::RootedValue value(cx);
scope->getProto<OIDInfo>().newInstance(&value);
- ele.setValue("_id", value);
+ ele.setValue(InternedString::_id, value);
}
return ValueWriter(cx, value).toBSON();
@@ -589,8 +589,8 @@ void MongoLocalInfo::construct(JSContext* cx, JS::CallArgs args) {
JS_SetPrivate(thisv, new std::shared_ptr<DBClientBase>(conn.release()));
- o.setBoolean("slaveOk", false);
- o.setString("host", "EMBEDDED");
+ o.setBoolean(InternedString::slaveOk, false);
+ o.setString(InternedString::host, "EMBEDDED");
args.rval().setObjectOrNull(thisv);
}
@@ -622,8 +622,8 @@ void MongoExternalInfo::construct(JSContext* cx, JS::CallArgs args) {
JS_SetPrivate(thisv, new std::shared_ptr<DBClientBase>(conn.release()));
- o.setBoolean("slaveOk", false);
- o.setString("host", host);
+ o.setBoolean(InternedString::slaveOk, false);
+ o.setString(InternedString::host, host);
args.rval().setObjectOrNull(thisv);
}
diff --git a/src/mongo/scripting/mozjs/numberlong.cpp b/src/mongo/scripting/mozjs/numberlong.cpp
index 0051d61eb94..68d747e85c3 100644
--- a/src/mongo/scripting/mozjs/numberlong.cpp
+++ b/src/mongo/scripting/mozjs/numberlong.cpp
@@ -53,12 +53,6 @@ const JSFunctionSpec NumberLongInfo::methods[5] = {
const char* const NumberLongInfo::className = "NumberLong";
-namespace {
-const char* const kTop = "top";
-const char* const kBottom = "bottom";
-const char* const kFloatApprox = "floatApprox";
-} // namespace
-
long long NumberLongInfo::ToNumberLong(JSContext* cx, JS::HandleValue thisv) {
JS::RootedObject obj(cx, thisv.toObjectOrNull());
return ToNumberLong(cx, obj);
@@ -67,18 +61,18 @@ long long NumberLongInfo::ToNumberLong(JSContext* cx, JS::HandleValue thisv) {
long long NumberLongInfo::ToNumberLong(JSContext* cx, JS::HandleObject thisv) {
ObjectWrapper o(cx, thisv);
- if (!o.hasField(kTop)) {
- if (!o.hasField(kFloatApprox))
+ if (!o.hasField(InternedString::top)) {
+ if (!o.hasField(InternedString::floatApprox))
uasserted(ErrorCodes::InternalError, "No top and no floatApprox fields");
- return o.getNumberLongLong(kFloatApprox);
+ return o.getNumberLongLong(InternedString::floatApprox);
}
- if (!o.hasField(kBottom))
+ if (!o.hasField(InternedString::bottom))
uasserted(ErrorCodes::InternalError, "top but no bottom field");
- return ((unsigned long long)((long long)o.getNumberLongLong(kTop) << 32) +
- (unsigned)(o.getNumberLongLong(kBottom)));
+ return ((unsigned long long)((long long)o.getNumberLongLong(InternedString::top) << 32) +
+ (unsigned)(o.getNumberLongLong(InternedString::bottom)));
}
void NumberLongInfo::Functions::valueOf::call(JSContext* cx, JS::CallArgs args) {
@@ -142,11 +136,11 @@ void NumberLongInfo::construct(JSContext* cx, JS::CallArgs args) {
JS::RootedValue bottom(cx);
if (args.length() == 0) {
- o.setNumber(kFloatApprox, 0);
+ o.setNumber(InternedString::floatApprox, 0);
} else if (args.length() == 1) {
auto arg = args.get(0);
if (arg.isNumber()) {
- o.setValue(kFloatApprox, arg);
+ o.setValue(InternedString::floatApprox, arg);
} else {
std::string str = ValueWriter(cx, arg).toString();
long long val;
@@ -161,11 +155,11 @@ void NumberLongInfo::construct(JSContext* cx, JS::CallArgs args) {
// values above 2^53 are not accurately represented in JS
if (val == INT64_MIN || std::abs(val) >= 9007199254740992LL) {
auto val64 = static_cast<unsigned long long>(val);
- o.setNumber(kFloatApprox, val);
- o.setNumber(kTop, val64 >> 32);
- o.setNumber(kBottom, val64 & 0x00000000ffffffff);
+ o.setNumber(InternedString::floatApprox, val);
+ o.setNumber(InternedString::top, val64 >> 32);
+ o.setNumber(InternedString::bottom, val64 & 0x00000000ffffffff);
} else {
- o.setNumber(kFloatApprox, val);
+ o.setNumber(InternedString::floatApprox, val);
}
}
} else {
@@ -182,9 +176,9 @@ void NumberLongInfo::construct(JSContext* cx, JS::CallArgs args) {
static_cast<double>(static_cast<uint32_t>(args.get(2).toNumber())))
uasserted(ErrorCodes::BadValue, "bottom must be a 32 bit unsigned number");
- o.setValue(kFloatApprox, args.get(0));
- o.setValue(kTop, args.get(1));
- o.setValue(kBottom, args.get(2));
+ o.setValue(InternedString::floatApprox, args.get(0));
+ o.setValue(InternedString::top, args.get(1));
+ o.setValue(InternedString::bottom, args.get(2));
}
args.rval().setObjectOrNull(thisv);
diff --git a/src/mongo/scripting/mozjs/objectwrapper.cpp b/src/mongo/scripting/mozjs/objectwrapper.cpp
index 014c668e9c7..8e1bc5aa92e 100644
--- a/src/mongo/scripting/mozjs/objectwrapper.cpp
+++ b/src/mongo/scripting/mozjs/objectwrapper.cpp
@@ -30,6 +30,8 @@
#include "mongo/scripting/mozjs/objectwrapper.h"
+#include <js/Conversions.h>
+
#include "mongo/base/error_codes.h"
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/platform/decimal128.h"
@@ -62,6 +64,13 @@ void ObjectWrapper::Key::get(JSContext* cx, JS::HandleObject o, JS::MutableHandl
return;
break;
}
+ case Type::InternedString: {
+ InternedStringId id(cx, _internedString);
+
+ if (JS_GetPropertyById(cx, o, id, value))
+ return;
+ break;
+ }
}
throwCurrentJSException(cx, ErrorCodes::InternalError, "Failed to get value on a JSObject");
@@ -84,6 +93,13 @@ void ObjectWrapper::Key::set(JSContext* cx, JS::HandleObject o, JS::HandleValue
return;
break;
}
+ case Type::InternedString: {
+ InternedStringId id(cx, _internedString);
+
+ if (JS_SetPropertyById(cx, o, id, value))
+ return;
+ break;
+ }
}
throwCurrentJSException(cx, ErrorCodes::InternalError, "Failed to set value on a JSObject");
@@ -109,6 +125,13 @@ void ObjectWrapper::Key::define(JSContext* cx,
return;
break;
}
+ case Type::InternedString: {
+ InternedStringId id(cx, _internedString);
+
+ if (JS_DefinePropertyById(cx, o, id, value, attrs))
+ return;
+ break;
+ }
}
throwCurrentJSException(cx, ErrorCodes::InternalError, "Failed to define value on a JSObject");
@@ -133,6 +156,13 @@ bool ObjectWrapper::Key::has(JSContext* cx, JS::HandleObject o) {
return has;
break;
}
+ case Type::InternedString: {
+ InternedStringId id(cx, _internedString);
+
+ if (JS_HasPropertyById(cx, o, id, &has))
+ return has;
+ break;
+ }
}
throwCurrentJSException(cx, ErrorCodes::InternalError, "Failed to has value on a JSObject");
@@ -156,6 +186,12 @@ void ObjectWrapper::Key::del(JSContext* cx, JS::HandleObject o) {
return;
break;
}
+ case Type::InternedString: {
+ InternedStringId id(cx, _internedString);
+
+ if (JS_DeleteProperty(cx, o, IdWrapper(cx, id).toString().c_str()))
+ break;
+ }
}
throwCurrentJSException(cx, ErrorCodes::InternalError, "Failed to delete value on a JSObject");
@@ -171,6 +207,10 @@ std::string ObjectWrapper::Key::toString(JSContext* cx) {
JS::RootedId id(cx, _id);
return IdWrapper(cx, id).toString();
}
+ case Type::InternedString: {
+ InternedStringId id(cx, _internedString);
+ return IdWrapper(cx, id).toString();
+ }
}
throwCurrentJSException(
@@ -470,9 +510,9 @@ std::string ObjectWrapper::getClassName() {
return jsclass->name;
JS::RootedValue ctor(_context);
- getValue("constructor", &ctor);
+ getValue(InternedString::constructor, &ctor);
- return ObjectWrapper(_context, ctor).getString("name");
+ return ObjectWrapper(_context, ctor).getString(InternedString::name);
}
} // namespace mozjs
diff --git a/src/mongo/scripting/mozjs/objectwrapper.h b/src/mongo/scripting/mozjs/objectwrapper.h
index 44f1d1ff71e..efc8039bf26 100644
--- a/src/mongo/scripting/mozjs/objectwrapper.h
+++ b/src/mongo/scripting/mozjs/objectwrapper.h
@@ -34,6 +34,7 @@
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/platform/decimal128.h"
#include "mongo/scripting/mozjs/exception.h"
+#include "mongo/scripting/mozjs/internedstring.h"
#include "mongo/scripting/mozjs/lifetimestack.h"
namespace mongo {
@@ -68,12 +69,14 @@ public:
Field,
Index,
Id,
+ InternedString,
};
public:
Key(const char* field) : _field(field), _type(Type::Field) {}
Key(uint32_t idx) : _idx(idx), _type(Type::Index) {}
Key(JS::HandleId id) : _id(id), _type(Type::Id) {}
+ Key(InternedString id) : _internedString(id), _type(Type::InternedString) {}
private:
void get(JSContext* cx, JS::HandleObject o, JS::MutableHandleValue value);
@@ -87,6 +90,7 @@ public:
const char* _field;
uint32_t _idx;
jsid _id;
+ InternedString _internedString;
};
Type _type;
};
diff --git a/src/mongo/scripting/mozjs/timestamp.cpp b/src/mongo/scripting/mozjs/timestamp.cpp
index 8659d8a4d85..198ee3af5b2 100644
--- a/src/mongo/scripting/mozjs/timestamp.cpp
+++ b/src/mongo/scripting/mozjs/timestamp.cpp
@@ -31,6 +31,7 @@
#include "mongo/scripting/mozjs/timestamp.h"
#include "mongo/scripting/mozjs/implscope.h"
+#include "mongo/scripting/mozjs/internedstring.h"
#include "mongo/scripting/mozjs/objectwrapper.h"
#include "mongo/scripting/mozjs/valuereader.h"
#include "mongo/scripting/mozjs/valuewriter.h"
@@ -49,8 +50,8 @@ void TimestampInfo::construct(JSContext* cx, JS::CallArgs args) {
ObjectWrapper o(cx, thisv);
if (args.length() == 0) {
- o.setNumber("t", 0);
- o.setNumber("i", 0);
+ o.setNumber(InternedString::t, 0);
+ o.setNumber(InternedString::i, 0);
} else if (args.length() == 2) {
if (!args.get(0).isNumber())
uasserted(ErrorCodes::BadValue, "Timestamp time must be a number");
@@ -64,8 +65,8 @@ void TimestampInfo::construct(JSContext* cx, JS::CallArgs args) {
str::stream() << "The first argument must be in seconds; " << t
<< " is too large (max " << largestVal << ")");
- o.setValue("t", args.get(0));
- o.setValue("i", args.get(1));
+ o.setValue(InternedString::t, args.get(0));
+ o.setValue(InternedString::i, args.get(1));
} else {
uasserted(ErrorCodes::BadValue, "Timestamp needs 0 or 2 arguments");
}