diff options
author | Mathias Stearn <mathias@10gen.com> | 2013-04-03 18:39:05 -0400 |
---|---|---|
committer | Eric Milkie <milkie@10gen.com> | 2013-04-05 22:21:47 -0400 |
commit | aefcffa1248b4830699ff84b367246ba1317d748 (patch) | |
tree | 09266bd3f90dba1060a79bb287c746c7d9850616 | |
parent | ee21ceb8d40329db2da65216b634c8f6f05628ab (diff) | |
download | mongo-aefcffa1248b4830699ff84b367246ba1317d748.tar.gz |
Use indexed rather than named Set() when converting to v8::Array
The meat of this change is in the Array case of mongoToV8Element.
mongoToV8() was removed since this was the only caller.
Conflicts:
src/mongo/scripting/engine_v8.cpp
-rw-r--r-- | src/mongo/scripting/engine_v8.cpp | 189 | ||||
-rw-r--r-- | src/mongo/scripting/engine_v8.h | 2 |
2 files changed, 10 insertions, 181 deletions
diff --git a/src/mongo/scripting/engine_v8.cpp b/src/mongo/scripting/engine_v8.cpp index 5ac935a0163..7c9403b7760 100644 --- a/src/mongo/scripting/engine_v8.cpp +++ b/src/mongo/scripting/engine_v8.cpp @@ -1255,183 +1255,6 @@ namespace mongo { return handle_scope.Close(idCons->NewInstance(1, argv)); } - v8::Local<v8::Object> V8Scope::mongoToV8(const BSONObj& m, bool array, bool readOnly) { - v8::HandleScope handle_scope; - v8::Handle<v8::Value> argv[3]; // arguments for v8 instance constructors - v8::Local<v8::ObjectTemplate> readOnlyObjects; - v8::Local<v8::Object> o; - - // handle DBRef. needs to come first. isn't it? (metagoto) - static string ref = "$ref"; - if (ref == m.firstElement().fieldName()) { - const BSONElement& id = m["$id"]; - if (!id.eoo()) { // there's no check on $id exitence in sm implementation. risky ? - v8::Function* dbRef = getNamedCons("DBRef"); - o = dbRef->NewInstance(); - } - } - - if (!o.IsEmpty()) { - readOnly = false; - } - else if (array) { - // NOTE Looks like it's impossible to add interceptors to v8 arrays. - // so array itself will never be read only, but its values can be - o = v8::Array::New(); - } - else if (!readOnly) { - o = v8::Object::New(); - } - else { - // NOTE Our readOnly implemention relies on undocumented ObjectTemplate - // functionality that may be fragile, but it still seems like the best option - // for now -- fwiw, the v8 docs are pretty sparse. I've determined experimentally - // that when property handlers are set for an object template, they will attach - // to objects previously created by that template. To get this to work, though, - // it is necessary to initialize the template's property handlers before - // creating objects from the template (as I have in the following few lines - // of code). - // NOTE In my first attempt, I configured the permanent property handlers before - // constructiong the object and replaced the Set() calls below with ForceSet(). - // However, it turns out that ForceSet() only bypasses handlers for named - // properties and not for indexed properties. - readOnlyObjects = v8::ObjectTemplate::New(); - // NOTE This internal field will store type info for special db types. For - // regular objects the field is unnecessary - for simplicity I'm creating just - // one readOnlyObjects template for objects where the field is & isn't necessary, - // assuming that the overhead of an internal field is slight. - readOnlyObjects->SetInternalFieldCount(1); - readOnlyObjects->SetNamedPropertyHandler(0); - readOnlyObjects->SetIndexedPropertyHandler(0); - o = readOnlyObjects->NewInstance(); - } - - mongo::BSONObj sub; - - for (BSONObjIterator i(m); i.more();) { - const BSONElement& f = i.next(); - - v8::Local<v8::Value> v; - v8::Handle<v8::String> name = v8StringData(f.fieldName()); - - switch (f.type()) { - case mongo::Code: - o->ForceSet(name, newFunction(f.valuestr())); - break; - case CodeWScope: - if (!f.codeWScopeObject().isEmpty()) - log() << "warning: CodeWScope doesn't transfer to db.eval" << endl; - o->ForceSet(name, newFunction(f.codeWScopeCode())); - break; - case mongo::Symbol: - case mongo::String: - o->ForceSet(name, v8::String::New(f.valuestr())); - break; - case mongo::jstOID: { - v8::Function * idCons = getObjectIdCons(); - argv[0] = v8::String::New(f.__oid().str().c_str()); - o->ForceSet(name, idCons->NewInstance(1, argv)); - break; - } - case mongo::NumberDouble: - case mongo::NumberInt: - o->ForceSet(name, v8::Number::New(f.number())); - break; - case mongo::Array: - sub = f.embeddedObject(); - o->ForceSet(name, mongoToV8(sub, true, readOnly)); - break; - case mongo::Object: - sub = f.embeddedObject(); - o->ForceSet(name, mongoToLZV8(sub, readOnly)); - break; - case mongo::Date: - o->ForceSet(name, v8::Date::New((double) ((long long)f.date().millis))); - break; - case mongo::Bool: - o->ForceSet(name, v8::Boolean::New(f.boolean())); - break; - case mongo::jstNULL: - case mongo::Undefined: // duplicate sm behavior - o->ForceSet(name, v8::Null()); - break; - case mongo::RegEx: { - v8::Function * regex = getNamedCons("RegExp"); - argv[0] = v8::String::New(f.regex()); - argv[1] = v8::String::New(f.regexFlags()); - o->ForceSet(name, regex->NewInstance(2, argv)); - break; - } - case mongo::BinData: { - int len; - const char *data = f.binData(len); - stringstream ss; - base64::encode(ss, data, len); - argv[0] = v8::Number::New(f.binDataType()); - argv[1] = v8::String::New(ss.str().c_str()); - o->ForceSet(name, getNamedCons("BinData")->NewInstance(2, argv)); - break; - } - case mongo::Timestamp: { - v8::Local<v8::Object> sub = readOnly ? readOnlyObjects->NewInstance() : - internalFieldObjects->NewInstance(); - sub->ForceSet(v8::String::New("t"), v8::Number::New(f.timestampTime() / 1000)); - sub->ForceSet(v8::String::New("i"), v8::Number::New(f.timestampInc())); - sub->SetInternalField(0, v8::Uint32::New(f.type())); - o->ForceSet(name, sub); - break; - } - case mongo::NumberLong: { - unsigned long long val = f.numberLong(); - v8::Function* numberLong = getNamedCons("NumberLong"); - double floatApprox = (double)(long long)val; - // values above 2^53 are not accurately represented in JS - if ((long long)val == (long long)floatApprox && val < 9007199254740992ULL) { - argv[0] = v8::Number::New(floatApprox); - o->ForceSet(name, numberLong->NewInstance(1, argv)); - } - else { - argv[0] = v8::Number::New(floatApprox); - argv[1] = v8::Integer::New(val >> 32); - argv[2] = v8::Integer::New((unsigned long)(val & 0x00000000ffffffff)); - o->ForceSet(name, numberLong->NewInstance(3, argv)); - } - break; - } - case mongo::MinKey: { - o->ForceSet(name, newMinKeyInstance()); - break; - } - case mongo::MaxKey: { - o->ForceSet(name, newMaxKeyInstance()); - break; - } - case mongo::DBRef: { - v8::Function* dbPointer = getNamedCons("DBPointer"); - argv[0] = v8StringData(f.dbrefNS()); - argv[1] = newId(f.dbrefOID()); - o->ForceSet(name, dbPointer->NewInstance(2, argv)); - break; - } - default: - cout << "can't handle type: "; - cout << f.type() << " "; - cout << f.toString(); - cout << endl; - break; - } - } - - if (!array && readOnly) { - readOnlyObjects->SetNamedPropertyHandler(0, NamedReadOnlySet, - 0, NamedReadOnlyDelete); - readOnlyObjects->SetIndexedPropertyHandler(0, IndexedReadOnlySet, - 0, IndexedReadOnlyDelete); - } - - return handle_scope.Close(o); - } - /** * converts a BSONObj to a Lazy V8 object */ @@ -1533,14 +1356,22 @@ namespace mongo { case mongo::NumberDouble: case mongo::NumberInt: return v8::Number::New(elem.number()); - case mongo::Array: + case mongo::Array: { // NB: This comment may no longer be accurate. // for arrays it's better to use non lazy object because: // - the lazy array is not a true v8 array and requires some v8 src change // for all methods to work // - it made several tests about 1.5x slower // - most times when an array is accessed, all its values will be used - return mongoToV8(elem.embeddedObject(), true, readOnly); + + // It is faster to allow the v8::Array to grow than call nFields() on the array + v8::Handle<v8::Array> array = v8::Array::New(); + int i = 0; + BSONForEach(subElem, elem.embeddedObject()) { + array->Set(i++, mongoToV8Element(subElem, readOnly)); + } + return array; + } case mongo::Object: return mongoToLZV8(elem.embeddedObject(), readOnly); case mongo::Date: diff --git a/src/mongo/scripting/engine_v8.h b/src/mongo/scripting/engine_v8.h index 5106d771250..d63df25e704 100644 --- a/src/mongo/scripting/engine_v8.h +++ b/src/mongo/scripting/engine_v8.h @@ -213,8 +213,6 @@ namespace mongo { /** * Convert BSON types to v8 Javascript types */ - v8::Local<v8::Object> mongoToV8(const mongo::BSONObj& m, bool array = 0, - bool readOnly = false); v8::Persistent<v8::Object> mongoToLZV8(const mongo::BSONObj& m, bool readOnly = false); v8::Handle<v8::Value> mongoToV8Element(const BSONElement& f, bool readOnly = false); |